C++ to C# interop -- wrapper class?

Please support our C# advertiser: Intel Parallel Studio Home
Thread Solved

Join Date: Jun 2008
Posts: 56
Reputation: ninjaneer is an unknown quantity at this point 
Solved Threads: 6
ninjaneer ninjaneer is offline Offline
Junior Poster in Training

C++ to C# interop -- wrapper class?

 
0
  #1
Jul 22nd, 2008
hi! I'm trying to get the following C++ class (contained in a DLL):
  1.  
  2. __declspec(dllexport) class ThreadManager {
  3. public:
  4. __declspec(dllexport) static UINT32 setThreadPriority(UINT32 tPriority);
  5.  
  6. __declspec(dllexport) static UINT32 setPriorityClass(UINT32 pClass);
  7.  
  8. __declspec(dllexport) static UINT32 setProcessorMask(UINT32 pAffinity);
  9.  
  10. __declspec(dllexport) static UINT32 changeMATLABSeed(UINT32 inputSeed);
  11.  
  12. static BOOL setHandles(HANDLE* thread, HANDLE* process);
  13.  
  14. __declspec(dllexport) static BOOL testFun(UINT32 testInt);
  15.  
  16. static UINT initializeProgram(ostream* consoleStream);
  17. };

into C#... in which I have the following class:

  1. class ThreadManagerWrapper
  2. {
  3. [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)]
  4. public static extern UInt32 setThreadPriority(UInt32 tPriority);
  5.  
  6. [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)]
  7. public static extern UInt32 setPriorityClass(UInt32 pClass);
  8.  
  9. [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)]
  10. public static extern UInt32 setProcessorMask(UInt32 pAffinity);
  11.  
  12. [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)]
  13. public static extern UInt32 changeMATLABSeed(UInt32 inputSeed);
  14.  
  15. [DllImport("MATLABCPPThreadLibrary.dll", CharSet = CharSet.Auto)]
  16. public static extern Boolean testFun(UInt32 testInt);
  17.  
  18. };
everything compiles fine... but when I call 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.
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 39
Reputation: nvmobius is an unknown quantity at this point 
Solved Threads: 4
nvmobius nvmobius is offline Offline
Light Poster

Re: C++ to C# interop -- wrapper class?

 
0
  #2
Jul 28th, 2008
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.
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 56
Reputation: ninjaneer is an unknown quantity at this point 
Solved Threads: 6
ninjaneer ninjaneer is offline Offline
Junior Poster in Training

Re: C++ to C# interop -- wrapper class?

 
0
  #3
Jul 29th, 2008
Originally Posted by nvmobius View Post
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.
okay. Now I've created a CLI/CLR class library... most of my issues before were due to not properly updating my DLL reference in C# *D'OH!*

Now I've just got one little problem, the following is an unmanaged method in a managed class (is that allowed?)

  1. UINT MATLABNamespace::MATLABFunctionThreader::createMATLABThread(LPVOID printString)
  2. {
  3. mwArray mxInversions, mxSample, mxTime;
  4.  
  5. inverterFunction(3, mxInversions, mxSample, mxTime);
  6.  
  7. return 0;
  8. }

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.
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 39
Reputation: nvmobius is an unknown quantity at this point 
Solved Threads: 4
nvmobius nvmobius is offline Offline
Light Poster

Re: C++ to C# interop -- wrapper class?

 
0
  #4
Jul 29th, 2008
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
  1. #include "stdafx.h"
in your .cpp file and
  1. #include <vcclr.h>
  2. using namespace System;
in your .h file.
  1. String ^ Namespace::NativeToString( const char * charArray ) {
  2. String ^ returnValue = String::Empty;
  3.  
  4. while ( *charArray != '\0' ) {
  5. returnValue += (char)*charArray;
  6. charArray++;
  7. }
  8.  
  9. return returnValue;
  10. }
  11.  
  12. const char * Namespace::StringToNative( String ^ str ) {
  13. array<Char, 1> ^ charArray = str->ToCharArray();
  14. size_t size = charArray->Length + 1;
  15. char * returnValue = (char *)malloc(size * sizeof(char));
  16.  
  17. for ( int i = 0 ; i < charArray->Length ; i++ ) {
  18. returnValue[i] = (char)charArray[i];
  19. }
  20. // allocated an extra char for null
  21. returnValue[charArray->Length] = '\0';
  22.  
  23. return returnValue;
  24. }
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 56
Reputation: ninjaneer is an unknown quantity at this point 
Solved Threads: 6
ninjaneer ninjaneer is offline Offline
Junior Poster in Training

Re: C++ to C# interop -- wrapper class?

 
0
  #5
Jul 29th, 2008
Originally Posted by nvmobius View Post
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
  1. #include "stdafx.h"
in your .cpp file and
  1. #include <vcclr.h>
  2. using namespace System;
in your .h file.
I didn't have my MATLABlib.lib included... I can use the managed code now.


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?
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 39
Reputation: nvmobius is an unknown quantity at this point 
Solved Threads: 4
nvmobius nvmobius is offline Offline
Light Poster

Re: C++ to C# interop -- wrapper class?

 
0
  #6
Jul 29th, 2008
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!
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 56
Reputation: ninjaneer is an unknown quantity at this point 
Solved Threads: 6
ninjaneer ninjaneer is offline Offline
Junior Poster in Training

Re: C++ to C# interop -- wrapper class?

 
0
  #7
Jul 29th, 2008
Originally Posted by nvmobius View Post
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!
woah hey! That makes sense... I'll try it and close the thread if it works.
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 56
Reputation: ninjaneer is an unknown quantity at this point 
Solved Threads: 6
ninjaneer ninjaneer is offline Offline
Junior Poster in Training

Re: C++ to C# interop -- wrapper class?

 
0
  #8
Jul 29th, 2008
Originally Posted by nvmobius View Post
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!
Okay... I think I've almost got it... I just need to figure out what delegates are...

Here's what I've done so far:

MATLABDataWrapper is an unmanaged class who holds information I get from calling a MATLAB function
  1.  
  2. class MATLABDataWrapper
  3. {
  4. public:
  5.  
  6. //data members... I know these guys should be private, but nobody'll really access em'
  7. mwArray mxInversions;
  8. mwArray mxSample;
  9. mwArray mxTime;
  10.  
  11. String^ MATLABNamespace::MATLABDataWrapper::toString(void)
  12. {
  13. char buffer[100]; //my data out should never be larger than 100 spaces... I /think/
  14.  
  15. //annoying hoop to jump through to turn my mwStrings into strings.
  16. sprintf_s ( buffer, 100, "%s\t%s\t%s",
  17. (const char*)this->mxInversions.ToString(),
  18. (const char*)this->mxSample.ToString(),
  19. (const char*)this->mxTime.ToString());
  20.  
  21. //copy the buffer to a new string? gcnew creates a garbage collected string...
  22. String ^outputStr = gcnew String(buffer,0,100);
  23.  
  24. /return the garbage collected string, but trim the blanks off the end.
  25. return outputStr->Trim();
  26. }
  27.  
  28. };

the following is the function that will be used within AfxBeginThread
  1. //must return UINT and can only have one param of type LPVOID
  2. UINT MATLABNamespace::MATLABFunctionThreader::createMATLABThread(LPVOID pointerToDataWrapper)
  3. {
  4.  
  5. //create a new pointer on the inside the function
  6. //and point it to the data location 'outside'
  7. MATLABDataWrapper *pointer = (MATLABDataWrapper *)pointerToDataWrapper;
  8.  
  9. //create data arrays
  10. mwArray mxInversions, mxSample, mxTime;
  11.  
  12. //call MATLAB function
  13. inverterFunction(3, mxInversions, mxSample, mxTime);
  14.  
  15. //access the memory outside the function,
  16. //and store the data values in appropriate slots.
  17. pointer->mxInversions = mxInversions;
  18. pointer->mxSample = mxSample;
  19. pointer->mxTime = mxTime;
  20.  
  21. //exit with 'success'
  22. return 0;
  23. }

And here's where I call AfxBeginThread to create my worker thread:

  1. //create a data struct to store data in...
  2. MATLABNamespace::MATLABDataWrapper dataContainer;
  3.  
  4. //start a worker thread
  5. AfxBeginThread(MATLABNamespace::MATLABFunctionThreader::createMATLABThread,
  6. &dataContainer,//address of data container is passed in as LPVOID
  7. 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
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 39
Reputation: nvmobius is an unknown quantity at this point 
Solved Threads: 4
nvmobius nvmobius is offline Offline
Light Poster

Re: C++ to C# interop -- wrapper class?

 
1
  #9
Jul 29th, 2008
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
Last edited by nvmobius; Jul 29th, 2008 at 5:17 pm.
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 56
Reputation: ninjaneer is an unknown quantity at this point 
Solved Threads: 6
ninjaneer ninjaneer is offline Offline
Junior Poster in Training

Re: C++ to C# interop -- wrapper class?

 
0
  #10
Jul 29th, 2008
Originally Posted by nvmobius View Post
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?
Reply With Quote Quick reply to this message  
Reply

This thread has been marked solved.
Perhaps start a new thread instead?
Message:



Other Threads in the C# Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC