[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.interop

Calling a C function from C# with struct' as a parameter.

Treadstone

10/8/2007 9:30:00 AM

Hi,

Being a newbie to C# and having worked with C all the way, I am stuck
with an interop problem.

I have a DLL exporting certain functions (and written in C).
The signature of 1 such function is as follows:

extern "C"
{
__declspec(dllexport) int EnumerateDevice(DEVICE **DeviceList);
}

struct DEVICE
{
int DeviceNo;
DEVICE *next;
};

I need to call this function from my C# code. How do I go about doing
this? I went through some interop samples but most of them use basic
data types (int and char) as parameters in their examples.

Any code sample in this regard would be useful.

Thanks in advance.

Regards,
Treadstone

13 Answers

Christof Nordiek

10/8/2007 10:30:00 AM

0

"Treadstone" <u.bhargav@gmail.com> schrieb im Newsbeitrag
news:1191835812.718931.174920@o80g2000hse.googlegroups.com...
> Hi,
>
> Being a newbie to C# and having worked with C all the way, I am stuck
> with an interop problem.
>
> I have a DLL exporting certain functions (and written in C).
> The signature of 1 such function is as follows:
>
Do you know this link:
http://www.p...

It doesn't contain your method, but has some examples, of Marshalling
structs witch P/Invoke.

HTH
Christof

Nicholas Paldino [.NET/C# MVP]

10/8/2007 3:06:00 PM

0

Treadstone,

First, you are going to have to define the structure:

[StructLayout(LayoutKind.Sequential)]
public struct Device
{
public int DeviceNo;
public IntPtr Next;
}

You use an IntPtr for the Next parameter because you are going to
marshal it manually when you need it. Then, you define your API like this:

[DllImport("dllname.dll")]
static int EnumerateDevice(ref IntPtr DeviceList);

You would then call the api passing an IntPtr to your method. When you
get it back, you would call the static PtrToStructure method on the Marshal
class to get an instance of the Device structure back. You would also need
to do this for next item in the list, as pointed out by the Next field on
the structure.

Finally, you will probably have to deallocate the memory allocated by
the call to EnumerateDevice, as well as all the items pointed to by the Next
field in each of the structures in the enumeration.


--
- Nicholas Paldino [.NET/C# MVP]
- mvp@spam.guard.caspershouse.com



"Treadstone" <u.bhargav@gmail.com> wrote in message
news:1191835812.718931.174920@o80g2000hse.googlegroups.com...
> Hi,
>
> Being a newbie to C# and having worked with C all the way, I am stuck
> with an interop problem.
>
> I have a DLL exporting certain functions (and written in C).
> The signature of 1 such function is as follows:
>
> extern "C"
> {
> __declspec(dllexport) int EnumerateDevice(DEVICE **DeviceList);
> }
>
> struct DEVICE
> {
> int DeviceNo;
> DEVICE *next;
> };
>
> I need to call this function from my C# code. How do I go about doing
> this? I went through some interop samples but most of them use basic
> data types (int and char) as parameters in their examples.
>
> Any code sample in this regard would be useful.
>
> Thanks in advance.
>
> Regards,
> Treadstone
>

Treadstone

10/9/2007 6:18:00 AM

0

Nicholas,

I defined the structure in the manner suggested by you, along with the
DllImport declaration.
However, the moment I called either Marshal.AllocCoTaskMem or
Marshal.AllocHGlobal or Marshal.PtrToStructure, I am getting a
System.NotSupported exception.

My code inside my function is as follows:

//BEGINNING OF CODE SNIPPET

IntPtr DeviceList = IntPtr.Zero;
DEVICE device = new DEVICE( ); //The DEVICE structure has been defined
already.

Marshal.AllocHGlobal(Marshal.SizeOf(device); //This gives me a
System.NotSupportedException

//My function call
iReturnValue = EnumerateDevice(ref DeviceList);

Marshal.PtrToStructure(DeviceList, device) //If I do not invoke the
Marshal.AllocHGlobal call, then
the //
System.NotSupportedException occurs here.

//END OF CODE SNIPPET

I tried the Marshal.PtrToStructure with all possible combinations of
the overloaded methods, but ended up with the same result.
Am I making some mistake while calling the methods of Marshal (such as
AllocHGlobal/ AllocCoTaskMem/PtrToStrucuture)? Or does it have
something to do with the version of VS2005?

Thanks in Advance.

Christof: Thanks for the pointer to the website. It has been of great
help to me.

Regards,
Treadstone

mh

10/10/2007 11:47:00 AM

0


Marshal.StructureToPtr(device, DeviceList, true);
iReturnValue = EnumerateDevice(ref DeviceList);
DEVICE retdevice = (DEVICE)Marshal.PtrToStructure(DeviceList,
typeof(DEVICE))

MH

On Oct 8, 10:18 pm, Treadstone <u.bhar...@gmail.com> wrote:
> Nicholas,
>
> I defined the structure in the manner suggested by you, along with the
> DllImport declaration.
> However, the moment I called either Marshal.AllocCoTaskMem or
> Marshal.AllocHGlobal or Marshal.PtrToStructure, I am getting a
> System.NotSupported exception.
>
> My code inside my function is as follows:
>
> //BEGINNING OF CODE SNIPPET
>
> IntPtr DeviceList = IntPtr.Zero;
> DEVICE device = new DEVICE( ); //The DEVICE structure has been defined
> already.
>
> Marshal.AllocHGlobal(Marshal.SizeOf(device); //This gives me a
> System.NotSupportedException
>
> //My function call
> iReturnValue = EnumerateDevice(ref DeviceList);
>
> Marshal.PtrToStructure(DeviceList, device) //If I do not invoke the
> Marshal.AllocHGlobal call, then
> the //
> System.NotSupportedException occurs here.
>
> //END OF CODE SNIPPET
>
> I tried the Marshal.PtrToStructure with all possible combinations of
> the overloaded methods, but ended up with the same result.
> Am I making some mistake while calling the methods of Marshal (such as
> AllocHGlobal/ AllocCoTaskMem/PtrToStrucuture)? Or does it have
> something to do with the version of VS2005?
>
> Thanks in Advance.
>
> Christof: Thanks for the pointer to the website. It has been of great
> help to me.
>
> Regards,
> Treadstone


Treadstone

10/11/2007 3:11:00 PM

0


MH,

Tried that as well. Still the same result.
I'm getting a System.NotSupportedException in the first statement
itself:

Marshal.StructureToPtr(device, DeviceList, true); //This method
throws an exception.

Tried with various permutations and combinations as well but in vain.

Thanks in advance.

Regards,
Treadstone

mh

10/12/2007 12:37:00 PM

0

Add a constructor to the the DEVICE structure to initialize the
variables.


[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct DEVICE
{
public int DeviceNo;
public IntPtr Next;
public DEVICE(int _DeviceNo, IntPtr _Next)
{
DeviceNo = _DeviceNo;
Next = _Next;
}
}

//This part works without throwing any exceptions

DEVICE device = new DEVICE(0 , IntPtr.Zero);
IntPtr DeviceList = Marshal.AllocHGlobal(Marshal.SizeOf(device));
Marshal.StructureToPtr(device, DeviceList, true);
//..

MH


On Oct 11, 7:11 am, Treadstone <u.bhar...@gmail.com> wrote:
> MH,
>
> Tried that as well. Still the same result.
> I'm getting a System.NotSupportedException in the first statement
> itself:
>
> Marshal.StructureToPtr(device, DeviceList, true); //This method
> throws an exception.
>
> Tried with various permutations and combinations as well but in vain.
>
> Thanks in advance.
>
> Regards,
> Treadstone


Treadstone

10/15/2007 12:28:00 PM

0

MH,

Thanks a ton. That worked. But the addition of another variable into
the structure saw to it that my woes did not end.
A variable of type string was added into the structure.

My new structure in my C Dll is as follows:

struct DEVICE
{
int DeviceNo;
string DeviceName;
DEVICE *next;
}

>From few of the interop articles that I went through, I understood
that a string has to be declared as an IntPtr.
So, in my C# code, here are the modifications I made:

public struct DEVICE
{
public int DeviceNo;
public IntPtr DeviceName;
public IntPtr Next;
}

// In my code.
DEVICE device = new DEVICE( );
IntPtr DeviceList = Marshal.AllocHGlobal(Marshal.SizeOf(device));
device.DeviceName = Marshal.AllocHGlobal(256);

//My function call
iReturnValue = EnumerateDevice(ref DeviceList); // The EnumerateDevice
returns all the device names in range.
DEVICE retdevice = (DEVICE)Marshal.PtrToStructure(DeviceList,
typeof(DEVICE)) ;

//Here I am trying to access the DeviceName that is returned by the
EnumerateDevice Function.
string MyString = Marshal.PtrToStringUni(device.DeviceName); //code
fails here.

The moment I try something like this, the active sync connection to my
mobile (on which the application is running) breaks down.

Am I doing some elementary mistake here?

Thanks in advance.

Regards,
Treadstone.




mh

10/15/2007 1:14:00 PM

0

If possible, try to redefine DeviceName as char* or wchar* rather than
string in the C dll. In most cases .NET can not handle C/C++ strings
properly or not at all. Also depending on the DeviceName (ANSI/W) data
type, you need to use either PtrToStringUni or PtrToStringAnsi
versions.

struct DEVICE
{
int DeviceNo;
char *DeviceName; //wchar*
DEVICE *next;
}

MH

On Oct 15, 4:28 am, Treadstone <u.bhar...@gmail.com> wrote:
> MH,
>
> Thanks a ton. That worked. But the addition of another variable into
> the structure saw to it that my woes did not end.
> A variable of type string was added into the structure.
>
> My new structure in my C Dll is as follows:
>
> struct DEVICE
> {
> int DeviceNo;
> string DeviceName;
> DEVICE *next;
>
> }
> >From few of the interop articles that I went through, I understood
>
> that a string has to be declared as an IntPtr.
> So, in my C# code, here are the modifications I made:
>
> public struct DEVICE
> {
> public int DeviceNo;
> public IntPtr DeviceName;
> public IntPtr Next;
>
> }
>
> // In my code.
> DEVICE device = new DEVICE( );
> IntPtr DeviceList = Marshal.AllocHGlobal(Marshal.SizeOf(device));
> device.DeviceName = Marshal.AllocHGlobal(256);
>
> //My function call
> iReturnValue = EnumerateDevice(ref DeviceList); // The EnumerateDevice
> returns all the device names in range.
> DEVICE retdevice = (DEVICE)Marshal.PtrToStructure(DeviceList,
> typeof(DEVICE)) ;
>
> //Here I am trying to access the DeviceName that is returned by the
> EnumerateDevice Function.
> string MyString = Marshal.PtrToStringUni(device.DeviceName); //code
> fails here.
>
> The moment I try something like this, the active sync connection to my
> mobile (on which the application is running) breaks down.
>
> Am I doing some elementary mistake here?
>
> Thanks in advance.
>
> Regards,
> Treadstone.


Treadstone

10/15/2007 2:08:00 PM

0


MH,

Tried that as well. (Changing the data type to char* / wchar*). :(
Also, tried using the PtrToStringUni and PtrToStringBSTR
(PtrToStringAnsi isn't suppported with Compact Framework, I presume).

Each time I use the PtrToStringUni method, the application hangs and
the connection to my device is broken. It doesn't even throw an
exception.

Thanks.
Treadstone.

mh

10/15/2007 5:58:00 PM

0

How are you allocating the string in the C dll? Are you using
SysAllocString, GlobalAlloc, malloc, ...?

MH

On Oct 15, 6:07 am, Treadstone <u.bhar...@gmail.com> wrote:
> MH,
>
> Tried that as well. (Changing the data type to char* / wchar*). :(
> Also, tried using the PtrToStringUni and PtrToStringBSTR
> (PtrToStringAnsi isn't suppported with Compact Framework, I presume).
>
> Each time I use the PtrToStringUni method, the application hangs and
> the connection to my device is broken. It doesn't even throw an
> exception.
>
> Thanks.
> Treadstone.