943,626 Members | Top Members by Rank

Ad:
  • C# Discussion Thread
  • Marked Solved
  • Views: 19827
  • C# RSS
You are currently viewing page 1 of this multi-page discussion thread
Jul 22nd, 2008
0

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

Expand Post »
hi! I'm trying to get the following C++ class (contained in a DLL):
C# Syntax (Toggle Plain Text)
  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:

C# Syntax (Toggle Plain Text)
  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.
Reputation Points: 10
Solved Threads: 6
Junior Poster in Training
ninjaneer is offline Offline
56 posts
since Jun 2008
Jul 28th, 2008
0

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

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.
Reputation Points: 11
Solved Threads: 4
Light Poster
nvmobius is offline Offline
39 posts
since Jul 2008
Jul 29th, 2008
0

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

Click to Expand / Collapse  Quote originally posted by nvmobius ...
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?)

C# Syntax (Toggle Plain Text)
  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.
Reputation Points: 10
Solved Threads: 6
Junior Poster in Training
ninjaneer is offline Offline
56 posts
since Jun 2008
Jul 29th, 2008
0

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

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
C# Syntax (Toggle Plain Text)
  1. #include "stdafx.h"
in your .cpp file and
C# Syntax (Toggle Plain Text)
  1. #include <vcclr.h>
  2. using namespace System;
in your .h file.
C# Syntax (Toggle Plain Text)
  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. }
Reputation Points: 11
Solved Threads: 4
Light Poster
nvmobius is offline Offline
39 posts
since Jul 2008
Jul 29th, 2008
0

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

Click to Expand / Collapse  Quote originally posted by nvmobius ...
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
C# Syntax (Toggle Plain Text)
  1. #include "stdafx.h"
in your .cpp file and
C# Syntax (Toggle Plain Text)
  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?
Reputation Points: 10
Solved Threads: 6
Junior Poster in Training
ninjaneer is offline Offline
56 posts
since Jun 2008
Jul 29th, 2008
0

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

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!
Reputation Points: 11
Solved Threads: 4
Light Poster
nvmobius is offline Offline
39 posts
since Jul 2008
Jul 29th, 2008
0

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

Click to Expand / Collapse  Quote originally posted by nvmobius ...
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.
Reputation Points: 10
Solved Threads: 6
Junior Poster in Training
ninjaneer is offline Offline
56 posts
since Jun 2008
Jul 29th, 2008
0

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

Click to Expand / Collapse  Quote originally posted by nvmobius ...
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
C# Syntax (Toggle Plain Text)
  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
C# Syntax (Toggle Plain Text)
  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:

C# Syntax (Toggle Plain Text)
  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
Reputation Points: 10
Solved Threads: 6
Junior Poster in Training
ninjaneer is offline Offline
56 posts
since Jun 2008
Jul 29th, 2008
1

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

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.
Reputation Points: 11
Solved Threads: 4
Light Poster
nvmobius is offline Offline
39 posts
since Jul 2008
Jul 29th, 2008
0

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

Click to Expand / Collapse  Quote originally posted by nvmobius ...
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?
Reputation Points: 10
Solved Threads: 6
Junior Poster in Training
ninjaneer is offline Offline
56 posts
since Jun 2008

This thread is solved

Either the thread starter or a moderator has marked this thread as solved. You can most likely trust the responses and answers given. There is most likely no reason for any further responses to be posted here. If you have a related question, please start a new thread in this forum instead.

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C# Forum Timeline: Delegate Events
Next Thread in C# Forum Timeline: NumericUpDown - No maximum or minimum





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC