Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C++ C#
Hi,
 
I am a C/C++ programmer, but I was asked to update a program that was written in C# to communicate with a device. My knowledge of C# is very basic. The previous version was totally written in C#, but now the API that in fact access the device was changed to C. I found out that I can import the C function APIs by using:
 
[DllImport("myapi.dll")]
public static extern int myfunct( 
                                 [MarshalAs(UnmanagedType.LPTStr)] string lpDeviceName,
                                 IntPtr hpDevice);
 
In C this function prototype is:
 
int myFunct( LPTStr lpDeviceName, HANDLE* hpDevice );
 
Where HANDLE is defined as :
 
typedef void *HANDLE;
 
However this function does not work as expected. In fact, in the C# code call what kind of type I should declare and pass to the C# method?
 
// Later edit I aplogize for the fake answer.
 
I am facing a new problem now. I have a C structure like:
 
struct MyStruct
{  unsigned char* ptr;  
int ptr_size;}
 
This pointer filled with values by a C API function, thus in C I only pass to the function a buffer large enough to hold the data.
To convert this to C# way I can do:
 
[StructLayout(LayoutKind.Sequential)]
public class MyStruct
{  IntPtr ptr;// this is a pointer to a buffer that will  
   int size;  // be filled with values by the C API
};// Next I instantiate itMyStruct ms = new MyStruct();
 

Now, the odd part comes in. I have a simple C# array as :
 
byte[] RESET = new byte[]{ 0x00, 0x00, 0x80, 0x00};
 
OK, now ptr must point to RESET, so how could this be done? Ptr needs to hold the address it self....
Thanks a lot for the help!
Posted 16-Jul-10 8:32am
Edited 21-Jul-10 3:50am
v2
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

Well your code would appear to be correct, I suspect the problem is more likely to be with the actual values of the parameters that you are passing to the C routine. Try using the debugger or add some logging code to verify your parameters.
  Permalink  
Comments
Nishant Sivakumar at 17-Jul-10 7:42am
   
Reason for my vote of 5
Worth 5.
danielgomes at 19-Jul-10 7:36am
   
Hey Thanks for the help! I "over debbugued it" already :-). I made it work by writting a "bridge" DLL which made all the things, but my boss reject it as he wants me to do all the thing in C# :-(
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

In my (limited) experience there are three potential issues here.
 
1. As Richard suggested - are you using correct values for the parameters? Particularly hpdevice. Is this a pointer that you have previously retrieved from another unmanaged function call? If not, that could be your issue.
 
2. Strings with P/Invoke can be troublesome. Try using a System.Text.StringBuider instead as it has built in marshalling capabilities.
[DllImport("myapi.dll")]
public static extern int myfunct(
    StringBuilder lpDeviceName,
    IntPtr hpDevice);
 
3. Unlikely but is hpDevice supposed to be a pointer to a pointer? This happens alot in C/C++ and it's a pain sometimes to work out what's going on.
  Permalink  
v2
Comments
Nishant Sivakumar at 17-Jul-10 7:42am
   
Reason for my vote of 5
Good answer, and worth 5.
danielgomes at 19-Jul-10 7:42am
   
Reason for my vote of 5
It was StringBuilder!
DaveyM69 at 19-Jul-10 16:10pm
   
Glad you got it sorted! Strings are pesky little buggers as in .NET they are not null terminated char arrays as they are in C/C++ so pointers from the managed world are often not valid as string pointers in the unmanaged world even when using the MarshalAs attribute. StringBuilder has all this stuff taken care of deep down inside fortunately.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 4

To question 2

The problem with your byte[] is it can be moved around in memory. To stop that you would need to pin RESET. Have a look at the GCHandle structure inparticular:
GCHandle.Alloc(object, GCHandleType.Pinned) and DON'T FORGET to use
GCHandle.Free() when done with it, and to get the pointer
GCHandle.AddrOfPinnedObject().
  Permalink  
Comments
danielgomes at 20-Jul-10 10:26am
   
Reason for my vote of 5
Thanks that helped me!
danielgomes at 20-Jul-10 10:29am
   
It was kind of "tricky" but it worked in the end. Specially I had to instantiate the struct above statically ( i.e. do not use new ) otherwise it will always pass an address to the function and it already passes a reference ( ref keyword ) so it won't work unless it is static.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 5

please check this.
 
Modifying an array of structures (default marshaling)[^]
 
-praveen
  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Maciej Los 295
1 OriginalGriff 273
2 Aajmot Sk 234
3 Marcin Kozub 205
4 Richard MacCutchan 200
0 OriginalGriff 7,903
1 Sergey Alexandrovich Kryukov 7,127
2 DamithSL 5,604
3 Manas Bhardwaj 4,986
4 Maciej Los 4,820


Advertise | Privacy | Mobile
Web04 | 2.8.1411023.1 | Last Updated 5 Jul 2014
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100