|
I met a problem when I tried to wrap unmanaged class into managed class with managed C++.
First, I built a static library, VcClass.lib, from the following source code with VC++ 6.0 :
/* interface.h */
#include <windows.h>
class CMyClassA
{
public:
BYTE *m_pBuf;
int m_bufLen;
CMyClassA() { m_pBuf = NULL; m_bufLen = 0; }
~CMyClassA() { FreeBuf(); }
HRESULT LoadBuf(BYTE *pBuf, DWORD dwBufLen);
private:
HRESULT FreeBuf(void);
};
class CMyClassB
{
public:
CMyClassB() { m_pA = NULL; }
~CMyClassB() { m_pA = NULL; }
HRESULT Func(CMyClassA *pClassA);
HRESULT Func2(void);
private:
CMyClassA *m_pA;
};
#endif
/* VcClass.cpp */
#include <stdio.h>
#include "interface.h"
HRESULT CMyClassA::LoadBuf(BYTE *pBuf, DWORD dwBufLen)
{
m_bufLen = dwBufLen;
m_pBuf = new BYTE[m_bufLen];
memcpy(m_pBuf, pBuf, m_bufLen);
return 0;
}
HRESULT CMyClassA::FreeBuf(void)
{
m_bufLen = 0;
delete [] m_pBuf;
return 0;
}
HRESULT CMyClassB::Func(CMyClassA *pClassA)
{
m_pA->m_pBuf = pClassA->m_pBuf;
m_pA->m_bufLen = pClassA->m_bufLen;
for (int i=0; i<m_pa->m_bufLen; i++)
printf("buf[%d] = %d\n", i, m_pA->m_pBuf[i]);
return 0;
}
HRESULT CMyClassB::Func2(void)
{
if (m_pA->m_pBuf == NULL) {
printf("buf is empty, call Func() first!\n");
return 1;
}
for (int i=0; i<m_pa->m_bufLen; i++)
printf("buf[%d] = %d\n", i, m_pA->m_pBuf[i]);
return 0;
}
then, I wrote two wrapped classes with VC++ 7.0 and compiled them into a DLL:
#include "interface.h"
using namespace System;
namespace McClass
{
public __gc class McMyClassA
{
public:
McMyClassA() { m_pClassA = new CMyClassA; }
~McMyClassA() { delete m_pClassA; }
int LoadBuf(System::Byte Buf[], int Len)
{
System::Byte __pin * p = &Buf[0];
return m_pClassA->LoadBuf(p, Len);
}
void *GetA() { return (void*)m_pClassA; }
private:
CMyClassA * m_pClassA;
};
public __gc class McMyClassB
{
public:
McMyClassB() { m_pClassB = new CMyClassB; }
~McMyClassB() { delete m_pClassB; }
int Func(McMyClassA *pMA)
{
CMyClassA *pA = (CMyClassA*)pMA->GetA();
return m_pClassB->Func(pA);
}
int Func2(void)
{
return m_pClassB->Func2();
}
private:
CMyClassB * m_pClassB;
};
}
Finally, I wrote an application with C# to call the DLL:
using System;
using McClass;
namespace CSharpApp
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
int i;
McMyClassA classA = new McMyClassA();
McMyClassB classB = new McMyClassB();
Byte[] buf = new Byte[10];
for (i = 0; i<10; i++)
buf[i] = 54;
classA.LoadBuf(buf, 10);
classB.Func(classA);
Console.WriteLine("OK.");
classB.Func2();
Console.WriteLine("OK.");
}
}
}
When I run the C# application, a NullRefrenceException occurred and the additional information is :
Unhandled Exception: System.NullReferenceException: Object reference not set to
an instance of an object.
at CMyClassB.Func(CMyClassB* , CMyClassA* )
at McClass.McMyClassB.Func(McMyClassA pMA)
at CSharpApp.Class1.Main(String[] args)
I think that the exception occurs because I used a wrong approach to pass a pointer of MyClassA into an instance of MyClassB.
So, what is the right way to do it? Data Marshal?
I hope MyClassA is independent on MyClassB, therefore I don’t want to merge MyClassA and MyClassB into one class.
Please help me!
Thank you very much!
|
|
|
|
|
sorry, I made a mistake.
please don't reply.
thanks.
|
|
|
|
|
deadlock, this is the problem of not logging in before posting. You could have deleted the thread.
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
Hello All,
Why do we need the static constructors in MC++? Is it to show that we have something to learn from C#?
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
I am having difficulty handling a vector<std::string> that is returned from unmanaged code and then converting it to an ArrayList of String. I get the following error: cannot convert parameter 1 from 'std::string' to 'System::Object __gc *
How do I Marshal this?
#ifndef __STAT_H__
#define __STAT_H__
#include <vector>
#include <string>
// Unmanaged file
class CStatus
{
public:
std::vector<std::string> statuses;
CStatus() {}
};
#endif
// EOF
// in Managed file
ArrayList statuses = new ArrayList();
CStatus stat;
int iReturn = SubmitJob( stat);
for (unsigned int ivector = 0; ivector < stat.statuses.size(); ivector++)
{
statuses->Add((stat.statuses[ivector])); // ERROR occurs
}
Thanks for all advice.
|
|
|
|
|
You only have to marshal your strings to CLR Strings, since all CLR reference types (including String) are based on Object. Then you can Add() your Strings to an ArrayList.
If your std::strings are strictly lower ASCII (and I do mean 7-bit ASCII, not MBCS/ANSI), the following method will work:
using namespace System;<br />
using namespace System::Collections;<br />
using namespace System::Text;<br />
using namespace std;<br />
<br />
vector<string> vec;<br />
string s = "a std::string";<br />
vec.push_back(s);<br />
<br />
ASCIIEncoding *enc = new ASCIIEncoding();<br />
String *sCopy = new String(vec[0].c_str(), 0, vec[0].size(), enc);<br />
<br />
ArrayList *al = new ArrayList();<br />
al->Add(sCopy);
For anything beyond English, you will need to use either Marshal::PtrToStringAnsi() or MultiByteToWideChar(). I could explain that if it's what you need instead.
Cheers
|
|
|
|
|
I want to create a simple web-page that contains a button that, when pressed, reads data from a database (Access) and produces graphs with the data retrieved.
How should I do this with Visual C++? Maybe ActiveX programming?
I need general orientation and online tutorials on this.
I'd appreciate any help regarding this, thanks.
-- narada
|
|
|
|
|
Search MSDN for ".Net", "C#" and "Web Controls"
Or if you do not like .Net
Serach for "ATL" and "Web Server"
Or if you want to use Active X
Search for "ATL" , "COM" "Active X" and "WEB page"
Or if you want to go one level below
search for "ISAPI"
etc..
You have many choices, you have to chose the approach according to you level, time constraints and general direction of the company (some people prefer Perl )
|
|
|
|
|
Thanks so much!
-- narada
|
|
|
|
|
Hello everyone.
How can build an exe file by VS .NET to execute it on Windows_98?
Thank you
|
|
|
|
|
If you're using traditional unmanaged C++ then you should be able to deploy it as with any previous Visual C++ output. If you use MFC then you can link statically to prevent having to send out anything other than the EXE. If you're linking to the shared MFC library then you'll have to distribute the MFCxx.dll too.
If you're using Managed C++ (and I'm assuming you are since its in the MC++ forum) then you'll have to install the .NET Runtime on the target machine too.
The code compiled from VC#, VB.NET or VC++ using /clr will be MSIL, this is then JIT compiled when its first run courtesy of the .NET CLR.
The .NET Runtime ought to be on the VS.NET CDs somewhere, alternatively it'll be available from MSDN -- sorry I don't have the link off-hand.
--
Paul
"If you can keep your head when all around you have lost theirs, then you probably haven't understood the seriousness of the situation."
- David Brent, from "The Office"
MS Messenger: paul@oobaloo.co.uk
Sonork: 100.22446
|
|
|
|
|
For future reference we would appreciate it if you would not post the same question more then once across the different message boards, I believe you asked this exact question in the .NET Framework board also. Thanks
"We will thrive in the new environment, leaping across space and time, everywhere and nowhere, like air or radiation, redundant, self-replicating, and always evolving." -unspecified individual
|
|
|
|
|
In unmanaged C++ code, I have a vector of a class of instances that contains a vector of instances of another class (which actually also contains a vector of instances of another class).
public class1
{
private:
double xLocation;
double yLocation;
vector <subclass1> sub1;
//methods, etc.
}
public Subclass1
{
private:
double zLocation;
vector <subclass2> sub2;
//methods, etc.
}
public Subclass2
{
private:
double value1;
double value2;
//methods, etc.
}
I get this all populated in unmanaged C++ code. However, I then need to get this to a C# front end via managed C++. Should I convert this structure in the managed file? Convert the vectors to ArrayLists? What is the best way to do this? Has anyone done this? Thanks for any help/advice.
|
|
|
|
|
It is unclear exactly how you need to pass the vector data, whether anything needs to be modified in C#, and so forth. One question is whether you could re-implement all this in MC++ (or C#) from scratch to begin with. That is, populate ArrayLists from the get-go.
If you have no choice but to pass unmanaged stuff to managed code, you will likely need to copy everything into managed (GC-collected) memory. If everything is largely primitive types (except the vectors, of course), then that shouldn't be too bad. If you need to pass values/changes back to unmanaged code, you will have to copy again. Obviously, it is best to minimise how much data must be marshaled back and forth between unmanaged and managed memory.
If the "vectors" need to be dynamic within C#, then ArrayList seems like a reasonable choice, though performance will not be as good (if nothing else but because everything will have to be handled by pointers to the base Object class). If performance is not a major consideration, then go that way. If nothing needs to be modified (i.e., not dynamic) in C#, then __gc[] arrays are more efficient, and more flexible in MC++ than in C#.
If you can be more specific about how the vectors need to be used, perhaps I could be more specific with any suggestions. I have been swimming in the regions between C++ and MC++ for quite a while now.
Cheers
|
|
|
|
|
Hi, I just swtiched to the .NET for my programming. I have
an error for my first Visual C++ .Net project:
error LNK2001: unresolved external symbol "public:
__thiscall TEnv::TEnv(float)" (??0TEnv@@$$FQAE@M@Z)
What I did is the following:
1. Open a blank solution.
2. Add a new project Test (Managed C++ Application)
3. Add another new project TObject (Managed C++ Class
Library)
4. Define a class TEnv in the TObject with the constructor
TEnv(float t), but this constructor is implemented in
the .cpp file.
Then I begin to use class TEnv in the main() function
inside project Test... I got this error. I am afraid the
project setting is wrong, but I haven't be able to figure
out why. It works in the good old days in Visual Studio...
Thanks, and Merry Xmas!
|
|
|
|
|
|
In Visual C++ .Net we created a managed class, whose definition is
in myclass.h, and implementation is in myclass.cpp.
After that we created a library based on these files (DLL).
Now we want to use this class in our application (EXE).
We perform compilation from a command line (it is a requirement).
In our application, we write #include "myclass.h" and also
#using "mydll.dll", but now we get an error during compilation.
Compiler generates an error because declaration of our class is
both in the header and the DLL, since we used #using directive.
But if we remove #using, then compiler does not understand
where our class' members are.
Thus, we should not include our header file, but should add
an option /FUmydll.dll to the compiler (cl.exe), then everything
works.
Question: is it possible to avoid adding a compiler option /FU,
so that we could include our header file in our application and
the DLL was linked dynamically (i.e., during run-time as in MFC),
not statically? In other words, is it possible to use #include
instead of #using as in MFC?
|
|
|
|
|
zaza_nata wrote:
In other words, is it possible to use #include
instead of #using as in MFC?
The short answar: No...
- Anders
Money talks, but all mine ever says is "Goodbye!"
|
|
|
|
|
I'm living a trouble with managed c++ that below code doesn't work properly so it has generated following error;
test.cpp(25) : error C2440: '=' : cannot convert from 'classB __gc *' to 'void *'
Cannot convert a managed type to an unmanaged type
Code at following;
<br />
typedef struct {<br />
void* memberA;<br />
} classA;<br />
<br />
typedef struct {<br />
int int_memberB;<br />
char* cp_memberB;<br />
} classB;<br />
<br />
__gc class ManagedClass {<br />
private:<br />
classA m_classA;<br />
classB m_classB;<br />
<br />
public:<br />
ManagedClass()<br />
{<br />
m_classA.memberA = &m_classB;<br />
}<br />
<br />
virtual ~ManagedClass()<br />
{<br />
}<br />
};<br />
How can i solve that problem?
Some must watch while some must sleep...
OGED
|
|
|
|
|
Ahmet Orkun GEDiK posted:
Cannot convert a managed type to an unmanaged type
You are trying to keep a pointer to a managed object, in an unmanaged class. Managed objects live on the GC heap, which is not the same as regular heap memory. Locations/pointers to managed stuff can actually change during an app's lifetime (which would invalidate your pointer), and .Net does not update pointers in unmanaged objects, only in managed ones.
Although there are ways to coerce .Net to reveal the numeric address of managed objects, it would require pinning the managed object first, then using it for a very short period of time before unpinning it. If not, the GC is prevented from managing its heap properly. It would be more appropriate to get a pointer to a managed object (such as m_classB here) for use by an unmanaged object, as needed, and for no longer.
If you could explain how you need to use a managed pointer in an unmanaged context, perhaps I could provide a solution.
Cheers
|
|
|
|
|
Is that mean we cannot use old libraries or structures?
Ahmet Orkun GEDiK
|
|
|
|
|
Ahmet Orkun GEDiK wrote:
Is that mean we cannot use old libraries or structures?
No, unmanaged structures can be used, and in general C++ library routines can be mixed-in with MC++. The catch is in how managed and unmanaged code is used together. Managed data can usually be "marshaled" over to unmanaged stuff, but the way your first post was written, an unmanaged type tried to hold a pointer to a managed object, and for an unknown amount of time. Data from managed objects can be copied over to unmanaged code, but unmanaged code should not try to keep pointers to managed objects around. Only managed code should keep pointers around to other managed objects.
In other words, managed code is fairly happy referencing unmanaged data, but it's not so simple the other way around.
|
|
|
|
|
Ok. Sounds great. But how will i solve my problem ?
typdefsampleDlg.cpp(26) : error C2440: '=' : cannot convert from 'SAMPLE __gc *__w64 ' to 'void *'
Cannot convert a managed type to an unmanaged type
Can you give an example to me ?
Ahmet Orkun GEDiK
|
|
|
|
|
You do not store a managed pointer in an unmanaged object. If you could explain why you wanted to store it, and what it was to be used for, perhaps I could explain a workaround, but without that information, I can't provide a suggestion.
|
|
|
|
|
Ok. I'm using a library that uses standart C++ routines. One function need to assignment such as following;
RFC_OPTIONS rfc_option;
RFC_CONNOPT_R3ONLY rfc_connopt;
rfc_option.connopt = & rfc_connopt;
type definitions at below;
typedef struct
{
rfc_char_t * hostname;
int sysnr;
rfc_char_t * gateway_host;
rfc_char_t * gateway_service;
}
RFC_CONNOPT_R3ONLY;
typedef struct
{
rfc_char_t * destination;
RFC_MODE mode;
void * connopt;
rfc_char_t * client;
rfc_char_t * user;
rfc_char_t * password;
rfc_char_t * language;
int trace;
}
RFC_OPTIONS;
So as i metioned, rfc_option.connopt = & rfc_connopt; has generate error.
Ahmet Orkun GEDiK
|
|
|
|
|