| | |
C++ to C# interop -- wrapper class?
Please support our C# advertiser: Intel Parallel Studio Home
Thread Solved |
•
•
Join Date: Jun 2008
Posts: 56
Reputation:
Solved Threads: 6
hi! I'm trying to get the following C++ class (contained in a DLL):
into C#... in which I have the following class:
everything compiles fine... but when I call
Unable to load DLL 'MATLABCPPThreadLibrary.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
I've been reading a selection of tutorials on creating wrapper classes or doing p/invokes... and I think I've created a monster...
anyone out there familiar with C++ -> C# interop wanna give me a step-by-step on how to wrap my C++ code? or perhaps want to give me a link to a /good/ tutorial? (seriously... most of them out there are utter crap ;_; )
C# Syntax (Toggle Plain Text)
__declspec(dllexport) class ThreadManager { public: __declspec(dllexport) static UINT32 setThreadPriority(UINT32 tPriority); __declspec(dllexport) static UINT32 setPriorityClass(UINT32 pClass); __declspec(dllexport) static UINT32 setProcessorMask(UINT32 pAffinity); __declspec(dllexport) static UINT32 changeMATLABSeed(UINT32 inputSeed); static BOOL setHandles(HANDLE* thread, HANDLE* process); __declspec(dllexport) static BOOL testFun(UINT32 testInt); static UINT initializeProgram(ostream* consoleStream); };
into C#... in which I have the following class:
C# Syntax (Toggle Plain Text)
class ThreadManagerWrapper { [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)] public static extern UInt32 setThreadPriority(UInt32 tPriority); [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)] public static extern UInt32 setPriorityClass(UInt32 pClass); [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)] public static extern UInt32 setProcessorMask(UInt32 pAffinity); [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)] public static extern UInt32 changeMATLABSeed(UInt32 inputSeed); [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)] public static extern Boolean testFun(UInt32 testInt); };
ThreadManagerWrapper.testFun(1); everything crashes, and VS 2005 informs me:Unable to load DLL 'MATLABCPPThreadLibrary.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
I've been reading a selection of tutorials on creating wrapper classes or doing p/invokes... and I think I've created a monster...
anyone out there familiar with C++ -> C# interop wanna give me a step-by-step on how to wrap my C++ code? or perhaps want to give me a link to a /good/ tutorial? (seriously... most of them out there are utter crap ;_; )
Last edited by ninjaneer; Jul 22nd, 2008 at 1:10 pm.
•
•
Join Date: Jul 2008
Posts: 39
Reputation:
Solved Threads: 4
You'd be better off (if possible) creating a mixed managed/native DLL in C++/CLI and adding that DLL as a reference to your C# project.
•
•
Join Date: Jun 2008
Posts: 56
Reputation:
Solved Threads: 6
•
•
•
•
You'd be better off (if possible) creating a mixed managed/native DLL in C++/CLI and adding that DLL as a reference to your C# project.
Now I've just got one little problem, the following is an unmanaged method in a managed class (is that allowed?)
C# Syntax (Toggle Plain Text)
UINT MATLABNamespace::MATLABFunctionThreader::createMATLABThread(LPVOID printString) { mwArray mxInversions, mxSample, mxTime; inverterFunction(3, mxInversions, mxSample, mxTime); return 0; }
Basically I want to be able to send out mxInversions mxSample and mxTime to my C# GUI... but I'm having trouble doing it, it seems like every time I try and pass something out through printString I get in trouble with the managed code compiler -- it tells me stuff like "you can't use unmanaged code inside managed code"
Am I going to have to wrap my unmanaged functions in order to call them? I thought CLR solved this nonsense and allowed me to have unmanaged code?
I don't want to export the unmanaged code to C#, I just want my managed DLL to do some unmanaged work behind the scenes before passing out a managed output string...
thanks for your help thus far.
•
•
Join Date: Jul 2008
Posts: 39
Reputation:
Solved Threads: 4
Look at these two pieces of code, they mix managed and unmanaged just fine. More than likely you've not included a header file that you need in order to compile with managed code. make sure that you have
in your .cpp file and
in your .h file.
C# Syntax (Toggle Plain Text)
#include "stdafx.h"
C# Syntax (Toggle Plain Text)
#include <vcclr.h> using namespace System;
C# Syntax (Toggle Plain Text)
String ^ Namespace::NativeToString( const char * charArray ) { String ^ returnValue = String::Empty; while ( *charArray != '\0' ) { returnValue += (char)*charArray; charArray++; } return returnValue; } const char * Namespace::StringToNative( String ^ str ) { array<Char, 1> ^ charArray = str->ToCharArray(); size_t size = charArray->Length + 1; char * returnValue = (char *)malloc(size * sizeof(char)); for ( int i = 0 ; i < charArray->Length ; i++ ) { returnValue[i] = (char)charArray[i]; } // allocated an extra char for null returnValue[charArray->Length] = '\0'; return returnValue; }
•
•
Join Date: Jun 2008
Posts: 56
Reputation:
Solved Threads: 6
•
•
•
•
Look at these two pieces of code, they mix managed and unmanaged just fine. More than likely you've not included a header file that you need in order to compile with managed code. make sure that you have
in your .cpp file andC# Syntax (Toggle Plain Text)
#include "stdafx.h"
in your .h file.C# Syntax (Toggle Plain Text)
#include <vcclr.h> using namespace System;
Do you have a reference to any tutorials on these weirdo managed pointer things?
What I'm really trying to do is use MFC's
AfxBeginThread(functionHandle, LPVOID, threadPriority) . I am allowed to pass in a LPVIOD for my function parameters, and I'd like that to be a pointer to a data-containing struct, then within the function referred to by functionHandle I want to populate that struct, and make the pointer point to it...
Does that make sense?
•
•
Join Date: Jul 2008
Posts: 39
Reputation:
Solved Threads: 4
Good catch on the .lib file, after using C# for a while you tend to forget about stuff like that.
I don't have any where to point you for C++/CLI information other than MSDN. I've learned mostly through trial and error, and various books I've picked up. For the most part managed pointers behave just like native pointers, but they point to a different heap, and you don't need to call delete on them.
As for AfxBeginThread, what I think you're looking for is this:
The managed heap and native heaps are kept seperate, therefore you cannot get a void * to point into the managed heap. What you need to do is copy the struct from the managed to the native heap, then cast your void * and call AfxBeginThread with the pointer to the native heap.
I know it's annoying, but just think about how the memory is physically structured and you'll quickly understand why you need to do this. The overhead should be minimal. G'luck!
I don't have any where to point you for C++/CLI information other than MSDN. I've learned mostly through trial and error, and various books I've picked up. For the most part managed pointers behave just like native pointers, but they point to a different heap, and you don't need to call delete on them.
As for AfxBeginThread, what I think you're looking for is this:
The managed heap and native heaps are kept seperate, therefore you cannot get a void * to point into the managed heap. What you need to do is copy the struct from the managed to the native heap, then cast your void * and call AfxBeginThread with the pointer to the native heap.
I know it's annoying, but just think about how the memory is physically structured and you'll quickly understand why you need to do this. The overhead should be minimal. G'luck!
•
•
Join Date: Jun 2008
Posts: 56
Reputation:
Solved Threads: 6
•
•
•
•
Good catch on the .lib file, after using C# for a while you tend to forget about stuff like that.
I don't have any where to point you for C++/CLI information other than MSDN. I've learned mostly through trial and error, and various books I've picked up. For the most part managed pointers behave just like native pointers, but they point to a different heap, and you don't need to call delete on them.
As for AfxBeginThread, what I think you're looking for is this:
The managed heap and native heaps are kept seperate, therefore you cannot get a void * to point into the managed heap. What you need to do is copy the struct from the managed to the native heap, then cast your void * and call AfxBeginThread with the pointer to the native heap.
I know it's annoying, but just think about how the memory is physically structured and you'll quickly understand why you need to do this. The overhead should be minimal. G'luck!
•
•
Join Date: Jun 2008
Posts: 56
Reputation:
Solved Threads: 6
•
•
•
•
Good catch on the .lib file, after using C# for a while you tend to forget about stuff like that.
I don't have any where to point you for C++/CLI information other than MSDN. I've learned mostly through trial and error, and various books I've picked up. For the most part managed pointers behave just like native pointers, but they point to a different heap, and you don't need to call delete on them.
As for AfxBeginThread, what I think you're looking for is this:
The managed heap and native heaps are kept seperate, therefore you cannot get a void * to point into the managed heap. What you need to do is copy the struct from the managed to the native heap, then cast your void * and call AfxBeginThread with the pointer to the native heap.
I know it's annoying, but just think about how the memory is physically structured and you'll quickly understand why you need to do this. The overhead should be minimal. G'luck!
Here's what I've done so far:
MATLABDataWrapper is an unmanaged class who holds information I get from calling a MATLAB function
C# Syntax (Toggle Plain Text)
class MATLABDataWrapper { public: //data members... I know these guys should be private, but nobody'll really access em' mwArray mxInversions; mwArray mxSample; mwArray mxTime; String^ MATLABNamespace::MATLABDataWrapper::toString(void) { char buffer[100]; //my data out should never be larger than 100 spaces... I /think/ //annoying hoop to jump through to turn my mwStrings into strings. sprintf_s ( buffer, 100, "%s\t%s\t%s", (const char*)this->mxInversions.ToString(), (const char*)this->mxSample.ToString(), (const char*)this->mxTime.ToString()); //copy the buffer to a new string? gcnew creates a garbage collected string... String ^outputStr = gcnew String(buffer,0,100); /return the garbage collected string, but trim the blanks off the end. return outputStr->Trim(); } };
the following is the function that will be used within AfxBeginThread
C# Syntax (Toggle Plain Text)
//must return UINT and can only have one param of type LPVOID UINT MATLABNamespace::MATLABFunctionThreader::createMATLABThread(LPVOID pointerToDataWrapper) { //create a new pointer on the inside the function //and point it to the data location 'outside' MATLABDataWrapper *pointer = (MATLABDataWrapper *)pointerToDataWrapper; //create data arrays mwArray mxInversions, mxSample, mxTime; //call MATLAB function inverterFunction(3, mxInversions, mxSample, mxTime); //access the memory outside the function, //and store the data values in appropriate slots. pointer->mxInversions = mxInversions; pointer->mxSample = mxSample; pointer->mxTime = mxTime; //exit with 'success' return 0; }
And here's where I call AfxBeginThread to create my worker thread:
C# Syntax (Toggle Plain Text)
//create a data struct to store data in... MATLABNamespace::MATLABDataWrapper dataContainer; //start a worker thread AfxBeginThread(MATLABNamespace::MATLABFunctionThreader::createMATLABThread, &dataContainer,//address of data container is passed in as LPVOID THREAD_PRIORITY_NORMAL); //assume normal thread priority...
Currently my compiler is complaining:
error C3374: can't take address of 'MATLABNamespace::MATLABFunctionThreader::createMATLABThread'
unless creating delegate instance
Aside from not making a delegate, is there anything glaringly wrong with my approach thus far? I think I've done everything right (like creating a pointer on the inside for the separate heap?) But I'm new to this managed code world...
I'll check out the delegate stuff myself, but any tips you wanna send my way would be appreciated as well.
Last edited by ninjaneer; Jul 29th, 2008 at 4:47 pm. Reason: spacing errors
•
•
Join Date: Jul 2008
Posts: 39
Reputation:
Solved Threads: 4
Is createMATLABThread managed or native? If it's managed, you need to create a delegate to pass.
Delegates are manage codes version of function pointers. So, I don't think you're getting from using one.
Otherwise I think it looks OK. Not sure about casting a System:
tring as a (const char *) like that, especially since managed strings use utf-16 and not 8bit chars. The compiler may be smart enough to handle this correctly for you however. I've always used the methods I posted above to do string conversion, mostly because I hate strings. :-P
I have this page bookmarked from a long time ago, I found it fairly useful then; and you might now.
http://msdn.microsoft.com/en-us/magazine/cc301810.aspx
Delegates are manage codes version of function pointers. So, I don't think you're getting from using one.
Otherwise I think it looks OK. Not sure about casting a System:
tring as a (const char *) like that, especially since managed strings use utf-16 and not 8bit chars. The compiler may be smart enough to handle this correctly for you however. I've always used the methods I posted above to do string conversion, mostly because I hate strings. :-PI have this page bookmarked from a long time ago, I found it fairly useful then; and you might now.
http://msdn.microsoft.com/en-us/magazine/cc301810.aspx
Last edited by nvmobius; Jul 29th, 2008 at 5:17 pm.
•
•
Join Date: Jun 2008
Posts: 56
Reputation:
Solved Threads: 6
•
•
•
•
Is createMATLABThread managed or native? If it's managed, you need to create a delegate to pass.
Delegates are manage codes version of function pointers. So, I don't think you're getting from using one.
Otherwise I think it looks OK. Not sure about casting a System:tring as a (const char *) like that, especially since managed strings use utf-16 and not 8bit chars. The compiler may be smart enough to handle this correctly for you however. I've always used the methods I posted above to do string conversion, mostly because I hate strings. :-P
I have this page bookmarked from a long time ago, I found it fairly useful then; and you might now.
http://msdn.microsoft.com/en-us/magazine/cc301810.aspx
I am not casting System:
tring as (const char*) that is a special proprietary class called mwString being cast into a char array via the sprintf_s function.I moved
UINT createMATLABThread(LPVOID pointerToDataWrapper); outside of my managed class definition to try and get around the delegate thing... but now it appears now that I am unable to call my MFC DLL in that code bit due to DLL access errors...I think I'll move it back in and try to use a delegate, and I'll read that link as soon as I get home from work (time to clock out
)it may be useful to note that I am relying on another DLL to provide my MATLAB functions... is there any special hoop I've got to jump through to allow my managed class to call a function from an unmanaged DLL? Or can CLR not directly consume unmanaged functions from a DLL?
![]() |
Other Threads in the C# Forum
- Previous Thread: Delegate Events
- Next Thread: NumericUpDown - No maximum or minimum
| Thread Tools | Search this Thread |
.net access ado.net algorithm array backup barchart bitmap box broadcast buttons c# check checkbox client color combobox control conversion csharp custom database datagrid datagridview dataset datetime decryption degrees development draganddrop drawing encryption enum event excel file files form format forms function gdi+ httpwebrequest i18n image imageprocessing index input install java label list listbox listener mandelbrot math microsystems mouseclick mysql operator path photoshop picturebox pixelinversion post programming radians regex remote remoting richtextbox saving serialization server sleep socket sql statistics stream string table tcp text textbox thread time timer update uploadatextfile usercontrol users validation view visualstudio webbrowser whileloop windows winforms wpf xml





