|
Thanks for your help guys. I have a c++ MFC DLL, written in Visual c++ 6.0. This DLL is currently called from an Excel VBA application and has some callbacks back to Excel in it. I have rewritten all of the VBA code into a non-VSTO shared managed add-in in c#, written in VS2005. I want the managed addin to call the c++ DLL the same way VBA used to. In its current form if I add a reference in the managed addin to the c++ DLL, a message says that it is not a valid assembly or COM component. If I compile the c++ DLL in VS2005 without the /clr switch it makes no difference, except that the Excel VBA application does not work anymore. If I try to use a DLLImport with the c++ DLL, I receive a "memory may be corrupt" message. The c++ DLL exports about 30 functions, as specified in a DEF file. Do I need a Managed c++ wrapper around these functions to access them from C#. Is there some boilerplate code to use? Does it depend on what the functions are?
Sample of the first function exported:
extern "C"<br />
short int DLLFUNC FunctionX()
DLLFUNC defined:
#ifndef DLLFUNC<br />
#ifdef WIN32<br />
#define DLLFUNC _stdcall<br />
#else<br />
#define DLLFUNC WINAPI _export // DLL functions are FAR PASCAL _export<br />
#endif<br />
#endif
Regards
alias47
|
|
|
|
|
Hello,
alias47 wrote: Do I need a Managed c++ wrapper around these functions to access them from C#?
Yes.
alias47 wrote: Is there some boilerplate code to use?
Check out this CP article: Using Microsoft Interoperability Libraries.
alias47 wrote: Does it depend on what the functions are?
No.
Best,
Jun
|
|
|
|
|
I *really* need someone to help me out.. I am wasting heaps of time trying to access this unmanaged c++ DLL from C#. It is a showstopper.
Let me check my understanding on a few issues:
IJW: Does IJW mean "Just compile unmanaged c++ code in VS2005" and then reference the unmanaged DLL in C#. If so, this does not work.
COM: How can I tell that the unmanaged c++ DLL is not COM-based? (Apart fromn the message I receive when trying to reference the DLL from C#)
PInvoke: When using this from C# to the c++ DLL, I receive a message about corrupt memory. Is this because the type of the argument is incorrect? In c++ the type is IDispatch. In C# I am passing an object type. In fact it is an Excel.Application type which is being cast to object that I am passing. Will this PInvoke technique possibly work if I pass a different type?
The article http://www.codeproject.com/useritems/usingcppdll.asp seems comprehensive, but I wonder whether I need to do any/all of this.
The unmanaged c++ DLL works prefectly currently with Excel. I guess that is because excel is itself unmanaged? Is the approach found http://groups.google.com/group/microsoft.public.dotnet.languages.vc/browse_thread/thread/8c538b0e1bbf020b/cac8b5f6bb7932ef%23cac8b5f6bb7932ef
too simplistic?
Surely there is an app in vs2005 that autogenerates the managed wrapper? Surely? Like http://www.codeproject.com/dotnet/NativeWrapper.asp
Regards
alias47
|
|
|
|
|
alias47 wrote: IJW: Does IJW mean "Just compile unmanaged c++ code in VS2005" and then reference the unmanaged DLL in C#.
The first half is correct. IJW only compiles unmanaged code and leave it in the unmanaged context. It won't make it callable by managed code, meaning you can't add unmanaged DLLs as references to managed projects.
alias47 wrote: COM: How can I tell that the unmanaged c++ DLL is not COM-based? (Apart fromn the message I receive when trying to reference the DLL from C#)
Your header and source files should indicate COM interfaces and their implementations. If your modules has implemented IDispatch, then the module is a COM-based. Check this site for how to PInvoke COM in managed C++.
alias47 wrote: PInvoke: When using this from C# to the c++ DLL, I receive a message about corrupt memory. Is this because the type of the argument is incorrect? In c++ the type is IDispatch. In C# I am passing an object type. In fact it is an Excel.Application type which is being cast to object that I am passing. Will this PInvoke technique possibly work if I pass a different type?
Probably because the first two issues have not been resolved properly.
Best,
Jun
|
|
|
|
|
Jun Du wrote: Your header and source files should indicate COM interfaces and their implementations. If your modules has implemented IDispatch, then the module is a COM-based. Check this site for how to PInvoke COM in managed C++.
Hey Jun,
he just has an MFC DLL with some exported functions. I don't think it's a COM DLL. So all he seems to need is a bunch of DllImport definitions.
|
|
|
|
|
That is what I first thought too. Actually on his another discussion thread on the same topic, he said it's not a COM module. But somewhere in this thread, he indeed mentioned IDispatch interface. I guess he needs to know what he is asking first.
Best,
Jun
|
|
|
|
|
Jun Du wrote: I guess he needs to know what he is asking first.
Yes, he does.
|
|
|
|
|
alias47 wrote: In its current form if I add a reference in the managed addin to the c++ DLL, a message says that it is not a valid assembly or COM component.
You don't need to add a reference. You can call imported functions from C# using the DllImport mechanism. That's all you'd need for your scenario.
|
|
|
|
|
|
alias47 wrote: anyone?
Looks like the people answering questions are not in your time zone
|
|
|
|
|
This is a total newbie question. I have a MSDN subsciption and have installed VS 2005. Where do I go to install Managed Extensions for C++.
Regards
alias47
|
|
|
|
|
File/New/Project/C++/CLR
It's already there.
Christian Graus - Microsoft MVP - C++
Metal Musings - Rex and my new metal blog
|
|
|
|
|
Thank you for your help. CLR does not seem like an obvious name for Managed c++ though. Oh well.
|
|
|
|
|
It's called C++/CLR now, it has a new name because of the changes in 2.0. CLR stands for Common Language Runtime.
Christian Graus - Microsoft MVP - C++
Metal Musings - Rex and my new metal blog
|
|
|
|
|
Christian Graus wrote: It's called C++/CLR now, it has a new name because of the changes in 2.0. CLR stands for Common Language Runtime.
C++/CLI actually - Common Language Infrastructure
|
|
|
|
|
*sigh* I don't know where that stupid mistake came from.
Christian Graus - Microsoft MVP - C++
Metal Musings - Rex and my new metal blog
|
|
|
|
|
Christian Graus wrote: I don't know where that stupid mistake came from.
STL.NET was renamed to STL/CLR - maybe that stuck on your mind.
|
|
|
|
|
I set up a DLL to define a class library. At first I set up the DLL as a native Win32 build. The calling app, however, was a C++/CLI app. The code below works fine:
<br />
#ifdef EXPORTING <br />
#define MYAPI __declspec(dllexport) <br />
#else <br />
#define MYAPI __declspec(dllimport) <br />
#endif <br />
<br />
class MYAPI MyClass() <br />
{ <br />
public: <br />
MyClass(); <br />
int DoSomething(); <br />
} <br />
<br />
<br />
#include "MyDll.h" <br />
... <br />
MyClass *x = new MyClass(); <br />
System::Console::WriteLine(System::String::Format("You got {0}", x->DoSomething()); <br />
delete x; <br />
...<br />
Building the main app with a project reference to the MyDll.dll, everything is FINE. Works great!
Now, after a little while I decided that my native class wants to have invoke some managed code (like file I/O). To do this, of course, I now have to build the DLL with the /clr option. This, in turn, totally breaks my class calling code in the main app. Mind you, I have not even added any managed code to the class yet. Just adding the /clr option and rebuilding the project killed everything.
To be specific, I get linker error messages for every public class symbol in the class, saying that the symbol is not defined. Remember, the main app project was already set to reference the dll. But for the fun of it I tried removing the project reference and manually adding #using <mydll.dll>. This did not help.
What do I need to do to get rid of the linker errors? Why is everything fine when I build the DLL as a Win32 dll?
Thanks for your help.
|
|
|
|
|
Could you copy/paste the linker errors here?
|
|
|
|
|
I made my original post without the code in front of me, so I had the wrong class name. In the error messages below, CClass32 is the native class in the DLL I am calling (a.k.a. "MyClass" in the original post). The errors were generated building the calling app with a project refernce to the DLL built with the /clr switch. When the DLL is built with no CLR support, the calling app builds with no errors or warnings.
Also, sorry for the misinformation. I forgot I got out of console mode and tried plugging this into a windows form. In the form class, I declared a private variable "pc" as a pointer to CClass32. I put a call to pc->DoSomething() in the destructor because the whole project is just a learning test (so I was too lazy to set up a button click event in the form). That's why these error messages look like they do. I don't actually expect to execute the app. But I do need to understand this whole process and need this test to build before I embark on porting one of my very large c++ 6.0 projects into a semi-managed .NET application.
Having said that, here are the errors:
Error 1 error LNK2028: unresolved token (0A000017) "public: int __thiscall CClass32::DoSomething(void)" (?DoSomething@CClass32@@$$FQAEHXZ) referenced in function "private: __clrcall CLIGLTest2::Form1::~Form1(void)" (??1Form1@CLIGLTest2@@$$FA$AAM@XZ) CLIGLTest2.obj
Error 2 error LNK2019: unresolved external symbol "public: int __thiscall CClass32::DoSomething(void)" (?DoSomething@CClass32@@$$FQAEHXZ) referenced in function "private: __clrcall CLIGLTest2::Form1::~Form1(void)" (??1Form1@CLIGLTest2@@$$FA$AAM@XZ) CLIGLTest2.obj
Error 3 fatal error LNK1120: 2 unresolved externals C:\Files\VsNet 2005\CLIGLTest2\Debug\CLIGLTest2.exe 1
When I add in the form constructor the code pc = new CClass32(); the errors are doubled, producing similar messages saying that the symbol "public: __thiscall CClass32::CClass32(void)" is not defined. So it's like the DLL doesn't even exist as far as the calling app is concerned. But as I said, I used the IDE to point to the DLL where CClass32 is defined, so I know it's not a malformed #using directive or something.
-- modified at 22:38 Thursday 17th August, 2006
|
|
|
|
|
Looks to me that the class is not exported properly. Can you show how you've exported the class?
Never mind - you've shown that in the first post. But the errors you get are typical of an incorrect attempt at exporting a class.
It'd be best to create a fresh example DLL (compiled as /clr) that exports a native class. Then first use it from a native caller, then try from a mixed-mode caller. That'd help you identify what you did wrong in your first project.
|
|
|
|
|
OK. I Started a solution from scratch, but I am still faced with the same issues. I think I can simplify the question, though:
Simply put, how do I import a native class from a mixed-mode DLL into a mixed-mode app? I can import a managed class easily from a /clr DLL. I can import a native class from a Win32 DLL easily. But I can't import a native class from a /clr DLL.
Thanks.
|
|
|
|
|
Xpnctoc wrote: But I can't import a native class from a /clr DLL.
There are many details involved, are you following any article or something?
led mike
|
|
|
|
|
No, I'm not following an article. Can you point me to a good one?
All of the articles I've come across are for other types of operations, such as importing a class from a Win32 DLL where you don't have access to the DLL source, going through the headache of using dumpbin.exe to find the public symbols and then constructing wrapper classes and such. But this is overkill for me.
I just need to know why, when I have reference an assembly built with the /clr option, I can import managed classes but not native ones. I just haven't found an article that address that issue from that viewpoint.
|
|
|
|
|
Xpnctoc wrote: OK. I Started a solution from scratch, but I am still faced with the same issues. I think I can simplify the question, though:
Simply put, how do I import a native class from a mixed-mode DLL into a mixed-mode app? I can import a managed class easily from a /clr DLL. I can import a native class from a Win32 DLL easily. But I can't import a native class from a /clr DLL.
I created a test DLL and a test EXE. I export a class from the DLL and use that class in the EXE. Both DLL and EXE are compiled with /clr and it works as expected.
Perhaps you have forgotten to add the export lib to the EXE project?
You can use the following line directly in your cpp file :-
#pragma comment(lib, "Path to DLL/DllName.lib")
|
|
|
|