How to use COM Interop in C#

N

Nataraj1978

I have a requirement to use a dll written in Visual C++ 6.0 in my C#
application. In order to establish the link between my application and the
dll, I have written a ATL COM Component in Visual C++.NET [visual studio .NET
version 8]. This COM component is referenced in my C# application. The COM
component statically links with the 6.0 dll.

I am facing problems in passing data from C# to the dll through the COM
component.

Description:
1. The dll exposes a function as:
__declspec(dllexport) int __stdcall ProblemFunction(int param1, BYTE param2,
BYTE param3, BYTE *param4, DWORD *param5);

2. In the COM wrapper component, I have declared an interface method as:
[id(25), helpstring("method ProblemFunc")] HRESULT ProblemFunc([in] SHORT
param1, [in] BYTE param2, [in] BYTE param3, [in, out] BYTE* param4, [in, out]
LONG* param5, [out, retval] BYTE* param6);

where, param6 is used to return the value returned by dll function to the C#
client application.

The implementation of this interface function is given below:
STDMETHODIMP
Wrapper::problemFunc(SHORT param1, BYTE param2, BYTE param3, BYTE* param4,
LONG* param5, BYTE* param6)
{
*param6 = ProblemFunction(param1, param2, param3, param4, (DWORD*)param5);
return S_OK;
}

3. In the C# client application, I am calling the COM function as:
byte returnValue = DllWrapperObject.ProblemFunc(value1, (byte)value2, (byte)
value3, ref value4, ref value5);

Here, I am facing problems passing value4 and value5 because:
a. For value4 I need to pass a structure.
b. For value5 I need to pass the size of the structure being passed in value4.


The structure to be passed is as required by the dll. The C++ structure is:
typedef struct
{
DWORD var1;
DWORD var2;

struct
{
DWORD var3;
char var4[16];
DWORD var5;
} var6[3];
} TEST_STRUCT;

I wrote the structure's equivalent in C# as a class as I had to create an
array. The C# implementation of the above given structure is:
internal class InnerStruct
{
long var3;
char[] var4 = new char[16];
long var5;

internal static int GetSizeOfClass()
{
return (sizeof(long) + sizeof(char) * 16 + sizeof(long));
}
}

internal class TestStruct
{
long var1;
long var2;
InnerStruct[] var6 = new InnerStruct[3];

internal static int GetSizeOfClass()
{
return (sizeof(long) * 2 + InnerStruct.GetSizeOfClass() * 3);
}
}


Questions:
1. Is there any better way to define the structure equivalent in C#?
2. How can I get the size of the structure/class for passing it to the dll?
3. How to pass the handle of the structure/class object from C# to the dll so
that it can fill it up and return it to the client app for future usage?
 
W

Willy Denoyette [MVP]

Why don't you call the DLL function directly using PInvoke interop?

Willy.

|I have a requirement to use a dll written in Visual C++ 6.0 in my C#
| application. In order to establish the link between my application and the
| dll, I have written a ATL COM Component in Visual C++.NET [visual studio
..NET
| version 8]. This COM component is referenced in my C# application. The COM
| component statically links with the 6.0 dll.
|
| I am facing problems in passing data from C# to the dll through the COM
| component.
|
| Description:
| 1. The dll exposes a function as:
| __declspec(dllexport) int __stdcall ProblemFunction(int param1, BYTE
param2,
| BYTE param3, BYTE *param4, DWORD *param5);
|
| 2. In the COM wrapper component, I have declared an interface method as:
| [id(25), helpstring("method ProblemFunc")] HRESULT ProblemFunc([in] SHORT
| param1, [in] BYTE param2, [in] BYTE param3, [in, out] BYTE* param4, [in,
out]
| LONG* param5, [out, retval] BYTE* param6);
|
| where, param6 is used to return the value returned by dll function to the
C#
| client application.
|
| The implementation of this interface function is given below:
| STDMETHODIMP
| Wrapper::problemFunc(SHORT param1, BYTE param2, BYTE param3, BYTE* param4,
| LONG* param5, BYTE* param6)
| {
| *param6 = ProblemFunction(param1, param2, param3, param4, (DWORD*)param5);
| return S_OK;
| }
|
| 3. In the C# client application, I am calling the COM function as:
| byte returnValue = DllWrapperObject.ProblemFunc(value1, (byte)value2,
(byte)
| value3, ref value4, ref value5);
|
| Here, I am facing problems passing value4 and value5 because:
| a. For value4 I need to pass a structure.
| b. For value5 I need to pass the size of the structure being passed in
value4.
|
|
| The structure to be passed is as required by the dll. The C++ structure
is:
| typedef struct
| {
| DWORD var1;
| DWORD var2;
|
| struct
| {
| DWORD var3;
| char var4[16];
| DWORD var5;
| } var6[3];
| } TEST_STRUCT;
|
| I wrote the structure's equivalent in C# as a class as I had to create an
| array. The C# implementation of the above given structure is:
| internal class InnerStruct
| {
| long var3;
| char[] var4 = new char[16];
| long var5;
|
| internal static int GetSizeOfClass()
| {
| return (sizeof(long) + sizeof(char) * 16 + sizeof(long));
| }
| }
|
| internal class TestStruct
| {
| long var1;
| long var2;
| InnerStruct[] var6 = new InnerStruct[3];
|
| internal static int GetSizeOfClass()
| {
| return (sizeof(long) * 2 + InnerStruct.GetSizeOfClass() * 3);
| }
| }
|
|
| Questions:
| 1. Is there any better way to define the structure equivalent in C#?
| 2. How can I get the size of the structure/class for passing it to the
dll?
| 3. How to pass the handle of the structure/class object from C# to the dll
so
| that it can fill it up and return it to the client app for future usage?
 
N

Nataraj1978

I can use PInvoke interop, but as I am new to Interop, I need some code
sample that I can follow, also since the structure that I need pass to the
dll is bit complex, I am unaware as to how to do it.

If you can please provide me some sample code, it will be of great help.

For your information, I am sending the structure details:
when using the dll from VC++ code, we pass a structure to it as a byte
pointer. The dll will populate the structure and return it back to us for
future use.

The structure in VC++ is defined as:
typedef struct
{
DWORD var1;
DWORD var2;

struct
{
DWORD var3;
char var4[16];
DWORD var5;
} var6[3];
} TEST_STRUCT;

In C#, I tried to define the structure as: [StructLayout(LayoutKind.
Sequential, CharSet = CharSet.Ansi)]
internal struct InnerStruct
{
public int var3;
[MarshalAs(ByValTStr, SizeConst = 16)]
public string var4;
public int var5
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct TestStruct
{
public int var1;
public int var2;
public InnerStruct[3] var6;
}

so that I could get the structure size as:
uint structSize = Marshal.Sizeof( typeof( TestStruct ) );

when I compile the code, I get the error as:
Array size cannot be specified in a variable declaration (try initializing
with a 'new' expression).

so I tried by changing the code as:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct TestStruct
{
public int var1;
public int var2;
public InnerStruct[] var6 = new InnerStruct[3];
}

for this I got the error as:
'TestStruct': cannot have instance field initializers in structs.

so I made the following changes to the structure definition:
internal enum StructSizeConstants
{
innerStructSize = 3,
stringLength = 16
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct InnerStruct
{
public long var3;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)StructSizeConstants.
stringLength)]
public string var4;
public long var5;
}

internal class TestStruct
{
public long var1;
public long var2;
public var3[] InnerStruct = new InnerStruct[(int)StructSizeConstants.
innerStructSize];
}

then I tried to get the length as:
int tempSize = Marshal.SizeOf(typeof(TestStruct));

and created a byte array as:
byte[] tempByteArray = new byte[Marshal.SizeOf(typeof(TestStruct))];

then I called the function as:
byte returnValue = DllWrapperObject.ProblemFunc(value1, (byte)value2, (byte)
value3, ref value4[0], ref value5);

The compilation goes fine, but I get a runtime error as:
Type 'TestApp.Structures.TestStruct' cannot be marshaled as an unmanaged
structure; no meaningful size or offset can be computed.

Can you please help me out...

Regards,
Nataraj.
 
G

Guest

hi Nataraj1978,
use the P Invoque to cal a function in a dll is very easy. here is an
example how to do it in c#. this example is a part of a project i wrote last
Year.

The Class SerisedClass is the one who is initiating the communication with
the Dll.
The Dll i am communicating with in the "SerisedDll"
since i want to pass an enum element to my Dll, i have to define how the
enum in that dll looks like . thats why you can see the enum in the
SerisesClass.
To call the function in my code, i just need to call it like this:
SerisedClass. sadio_reset( SerisedClass.slot_type.CARD_0);

here is the code of the SerisedClass:
Caution : you have to write " public static extern" before the function you
are calling.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiplexerModul
{
public class SerisedClass
{
public enum slot_type
{
CARD_0 = 0,
CARD_1 = 1,
CARD_2 = 2,
CARD_3 = 3,
CARD_4 = 4,
CARD_5 = 5,
CARD_6 = 6,
CARD_7 = 7
};

[DllImport("Serised.dll")]
public static extern int sadio_reset( slot_type slot_nr);


}
}

I hope this will solve your problem. if not, just mail me.
cu



Nataraj1978 said:
I can use PInvoke interop, but as I am new to Interop, I need some code
sample that I can follow, also since the structure that I need pass to the
dll is bit complex, I am unaware as to how to do it.

If you can please provide me some sample code, it will be of great help.

For your information, I am sending the structure details:
when using the dll from VC++ code, we pass a structure to it as a byte
pointer. The dll will populate the structure and return it back to us for
future use.

The structure in VC++ is defined as:
typedef struct
{
DWORD var1;
DWORD var2;

struct
{
DWORD var3;
char var4[16];
DWORD var5;
} var6[3];
} TEST_STRUCT;

In C#, I tried to define the structure as: [StructLayout(LayoutKind.
Sequential, CharSet = CharSet.Ansi)]
internal struct InnerStruct
{
public int var3;
[MarshalAs(ByValTStr, SizeConst = 16)]
public string var4;
public int var5
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct TestStruct
{
public int var1;
public int var2;
public InnerStruct[3] var6;
}

so that I could get the structure size as:
uint structSize = Marshal.Sizeof( typeof( TestStruct ) );

when I compile the code, I get the error as:
Array size cannot be specified in a variable declaration (try initializing
with a 'new' expression).

so I tried by changing the code as:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct TestStruct
{
public int var1;
public int var2;
public InnerStruct[] var6 = new InnerStruct[3];
}

for this I got the error as:
'TestStruct': cannot have instance field initializers in structs.

so I made the following changes to the structure definition:
internal enum StructSizeConstants
{
innerStructSize = 3,
stringLength = 16
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct InnerStruct
{
public long var3;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)StructSizeConstants.
stringLength)]
public string var4;
public long var5;
}

internal class TestStruct
{
public long var1;
public long var2;
public var3[] InnerStruct = new InnerStruct[(int)StructSizeConstants.
innerStructSize];
}

then I tried to get the length as:
int tempSize = Marshal.SizeOf(typeof(TestStruct));

and created a byte array as:
byte[] tempByteArray = new byte[Marshal.SizeOf(typeof(TestStruct))];

then I called the function as:
byte returnValue = DllWrapperObject.ProblemFunc(value1, (byte)value2, (byte)
value3, ref value4[0], ref value5);

The compilation goes fine, but I get a runtime error as:
Type 'TestApp.Structures.TestStruct' cannot be marshaled as an unmanaged
structure; no meaningful size or offset can be computed.

Can you please help me out...

Regards,
Nataraj.
Why don't you call the DLL function directly using PInvoke interop?

Willy.
 
N

Nataraj1978

Thanks for the example on using PInvoke Willy... but as I have mentioned
earlier, I am facing problems in accomplishing the following tasks:

1. Defining the equivalent complex structure in C#.
2. Determining the size of the structure using sizeof or its equivalent.
3. Passing the structure object from C# to the VC++ 6.0 dll as a byte pointer.


It would be of great help if you could provide me some information on these...


Regards,
Nataraj
hi Nataraj1978,
use the P Invoque to cal a function in a dll is very easy. here is an
example how to do it in c#. this example is a part of a project i wrote last
Year.

The Class SerisedClass is the one who is initiating the communication with
the Dll.
The Dll i am communicating with in the "SerisedDll"
since i want to pass an enum element to my Dll, i have to define how the
enum in that dll looks like . thats why you can see the enum in the
SerisesClass.
To call the function in my code, i just need to call it like this:
SerisedClass. sadio_reset( SerisedClass.slot_type.CARD_0);

here is the code of the SerisedClass:
Caution : you have to write " public static extern" before the function you
are calling.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiplexerModul
{
public class SerisedClass
{
public enum slot_type
{
CARD_0 = 0,
CARD_1 = 1,
CARD_2 = 2,
CARD_3 = 3,
CARD_4 = 4,
CARD_5 = 5,
CARD_6 = 6,
CARD_7 = 7
};

[DllImport("Serised.dll")]
public static extern int sadio_reset( slot_type slot_nr);

}
}

I hope this will solve your problem. if not, just mail me.
cu
I can use PInvoke interop, but as I am new to Interop, I need some code
sample that I can follow, also since the structure that I need pass to the
[quoted text clipped - 104 lines]
 
G

Guest

Nataraj1978,
if you can understand the example i send then u will solve ur problem. just
try to understand how it works. for ur struct you will just have to replace
the enum in my example with ur structure. Note that u can pass the structure
the structure to ur function in the dll only if ur function is expecting the
struct as parameter.

Regards
Entwickler

Nataraj1978 said:
Thanks for the example on using PInvoke Willy... but as I have mentioned
earlier, I am facing problems in accomplishing the following tasks:

1. Defining the equivalent complex structure in C#.
2. Determining the size of the structure using sizeof or its equivalent.
3. Passing the structure object from C# to the VC++ 6.0 dll as a byte pointer.


It would be of great help if you could provide me some information on these...


Regards,
Nataraj
hi Nataraj1978,
use the P Invoque to cal a function in a dll is very easy. here is an
example how to do it in c#. this example is a part of a project i wrote last
Year.

The Class SerisedClass is the one who is initiating the communication with
the Dll.
The Dll i am communicating with in the "SerisedDll"
since i want to pass an enum element to my Dll, i have to define how the
enum in that dll looks like . thats why you can see the enum in the
SerisesClass.
To call the function in my code, i just need to call it like this:
SerisedClass. sadio_reset( SerisedClass.slot_type.CARD_0);

here is the code of the SerisedClass:
Caution : you have to write " public static extern" before the function you
are calling.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace MultiplexerModul
{
public class SerisedClass
{
public enum slot_type
{
CARD_0 = 0,
CARD_1 = 1,
CARD_2 = 2,
CARD_3 = 3,
CARD_4 = 4,
CARD_5 = 5,
CARD_6 = 6,
CARD_7 = 7
};

[DllImport("Serised.dll")]
public static extern int sadio_reset( slot_type slot_nr);

}
}

I hope this will solve your problem. if not, just mail me.
cu
I can use PInvoke interop, but as I am new to Interop, I need some code
sample that I can follow, also since the structure that I need pass to the
[quoted text clipped - 104 lines]
 
W

Willy Denoyette [MVP]

When using PInvoke to call the DLL export function, you'll have to custom
marshal the structures.
Following is a sample how you can achieve this....

[C++]
....

typedef struct
{
int var1;
int var2;

struct
{
int var3;
char var4[16];
int var5;
} var6[3];
} TEST_STRUCT;

extern "C" {
__declspec( dllexport ) void Test(TEST_STRUCT* p);
}
// fuction that takes a pointer to a struct of type TEST_STRUCT (or any
other pointer, bu then you need a cast)
void Test(TEST_STRUCT* p)
{
// optionally clear structure passed-in
// memset(p, 0, sizeof(TEST_STRUCT));
// fill struct with some data
p->var1 = 123;
p->var2 = 456;
for (int i = 0; i < 3; i++)
{
p->var6.var3 = i;
p->var6.var5 = i * i;
}
return;
}


[C#]
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class TestStruct
{
public int var1;
public int var2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3 * 24)] // Size of
Inner * number elem.
public byte[] InnerArray;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class Inner
{
public int var3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
public char[] var4;
public int var5;
}

//---------------
static void ex2()
{

TestStruct ts = new TestStruct();
Inner tsInner = new Inner();
int innerLength = 3; // numer Inner elements
Inner[] arInner = new Inner[innerLength];
int arBytes = Marshal.SizeOf(tsInner);
IntPtr ptrts = Marshal.AllocHGlobal( Marshal.SizeOf(ts));
IntPtr ptria = Marshal.AllocHGlobal(arBytes);
Test(ptrts); // call function
// marshal back and dump the data returned...
Marshal.PtrToStructure(ptrts, ts);
Console.WriteLine(ts.var1);
Console.WriteLine(ts.var2);
for (int i = 0; i < innerLength; i++ )
{
int displ = i * arBytes;
Marshal.Copy(ts.InnerArray, displ , ptria, arBytes);
tsInner = new Inner();
Marshal.PtrToStructure(ptria, tsInner);
arInner = tsInner;
}
for (int n = 0; n < arInner.Length ; n++)
{
Console.WriteLine("{0} - {1}", arInner[n].var3, arInner[n].var5);
}

Marshal.FreeHGlobal(ptrts);
Marshal.FreeHGlobal(ptria);
}

Willy.


|I can use PInvoke interop, but as I am new to Interop, I need some code
| sample that I can follow, also since the structure that I need pass to the
| dll is bit complex, I am unaware as to how to do it.
|
| If you can please provide me some sample code, it will be of great help.
|
| For your information, I am sending the structure details:
| when using the dll from VC++ code, we pass a structure to it as a byte
| pointer. The dll will populate the structure and return it back to us for
| future use.
|
| The structure in VC++ is defined as:
| typedef struct
| {
| DWORD var1;
| DWORD var2;
|
| struct
| {
| DWORD var3;
| char var4[16];
| DWORD var5;
| } var6[3];
| } TEST_STRUCT;
|
| In C#, I tried to define the structure as: [StructLayout(LayoutKind.
| Sequential, CharSet = CharSet.Ansi)]
| internal struct InnerStruct
| {
| public int var3;
| [MarshalAs(ByValTStr, SizeConst = 16)]
| public string var4;
| public int var5
| }
| [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
| internal struct TestStruct
| {
| public int var1;
| public int var2;
| public InnerStruct[3] var6;
| }
|
| so that I could get the structure size as:
| uint structSize = Marshal.Sizeof( typeof( TestStruct ) );
|
| when I compile the code, I get the error as:
| Array size cannot be specified in a variable declaration (try initializing
| with a 'new' expression).
|
| so I tried by changing the code as:
| [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
| internal struct TestStruct
| {
| public int var1;
| public int var2;
| public InnerStruct[] var6 = new InnerStruct[3];
| }
|
| for this I got the error as:
| 'TestStruct': cannot have instance field initializers in structs.
|
| so I made the following changes to the structure definition:
| internal enum StructSizeConstants
| {
| innerStructSize = 3,
| stringLength = 16
| }
|
| [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
| internal struct InnerStruct
| {
| public long var3;
| [MarshalAs(UnmanagedType.ByValTStr, SizeConst =
(int)StructSizeConstants.
| stringLength)]
| public string var4;
| public long var5;
| }
|
| internal class TestStruct
| {
| public long var1;
| public long var2;
| public var3[] InnerStruct = new InnerStruct[(int)StructSizeConstants.
| innerStructSize];
| }
|
| then I tried to get the length as:
| int tempSize = Marshal.SizeOf(typeof(TestStruct));
|
| and created a byte array as:
| byte[] tempByteArray = new byte[Marshal.SizeOf(typeof(TestStruct))];
|
| then I called the function as:
| byte returnValue = DllWrapperObject.ProblemFunc(value1, (byte)value2,
(byte)
| value3, ref value4[0], ref value5);
|
| The compilation goes fine, but I get a runtime error as:
| Type 'TestApp.Structures.TestStruct' cannot be marshaled as an unmanaged
| structure; no meaningful size or offset can be computed.
|
| Can you please help me out...
|
| Regards,
| Nataraj.
|
| Willy Denoyette [MVP] wrote:
| >Why don't you call the DLL function directly using PInvoke interop?
| >
| >Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top