random thoughts, formed in the twisted mind of a coder... RSS 2.0
# Friday, August 29, 2008

Update: Please read the article "Marshalling Compiler" about an online Marshalling Compiler which takes a C style header as input and converts it into an import of a native DLL in managed C# source code.

The compiler can be found at: http://mc.rednael.com

When you (or your bosses) have made the choice to develop your software in Microsoft’s .Net languages, like C-Sharp (C#), J-Sharp or VB, there may come a time when you need some functionality from a native DLL (or C++ DLL) which is not written in .Net and doesn’t support a COM interface.

In such a case you need at least a C style header file (.h) or a firm description of the DLL’s methods and inner workings. With that information you can write a wrapper-class in your favorite .Net language, which will enable you to use the DLL as if it was written in .Net.
I will be using C# code to show you how I’ve done this.

For my project I had access to a header file (including helpful comments) that was provided by the author. This provided me with enough information to write my wrapper-class.

First of all we need to know a little about types. Native types v.s. managed. There are a few native types that you can use without conversion between .Net code and the DLL.

Interoperable types are:
• int (and all integral types, like short, long, ushort, uint and ulong)
• float (and all other floating point types, like double)
• byte (it’s an unsigned integral type actually)
• * (pointer, only in unsafe mode)
• void (not really a type though)

There might be some others which look like they are interoperable, but in fact they are not:
• char (C-style char is one byte, .Net char is two bytes (unicode))
• bool (C-style bool is actually an integral type)
• enum (C-style enum is an integral type, .Net style can have many types)

So, for any type that is not interoperable, you’ll need to manually convert them in order to use them. Also, for sake of usefulness, you should convert a regular pointer (*) to the IntPtr type. That way the code that uses your wrapper-class does not have to use the keyword “unsafe”.

But how to convert them? Well, first we need to have a look a the method (or function) definition. Below you see an example from a C-style header file:

typedef struct _sysRef sysRef;

unsigned int initSystem(const char *fileName, sysRef **system);

Let me explain a bit about the above example. The first line defines an empty structure, to be used as a reference pointer. The second line defines a function which takes  two parameters, filename and system . Filename is a pointer to the first element of a null-terminated array of C-style chars. System is a reference to a pointer to a struct. Also, the function returns a value of type unsigned int.

Now the first question is not how to convert, but what to convert. Namely, there is no need to convert the empty structure. Its only function is to be a reference point (where you point a pointer to). So we can simply use a void* to hold the same reference.

To use any native DLL in your .Net code, You first have import the function from the DLL. This is just like declaring a method.
Below you see the import which uses only interoperable types:

[DllImport(@“C:\mylib.dll”, EntryPoint = "initSystem")]
public static extern uint initSystem(void* fileName, void* system);

Now, don’t worry. Your wrapper interface is not going to expose the pointers. Instead I don’t want to pass the uint (in this case an error code) as a return value, but instead I want to pass the pointer to the system as a return value. I’ll convert the uint error code into an exception.

My wrapper will expose an interface such as:

public static IntPtr initSystem(string _fileName)

When you look at the examples, you may have noticed the original system parameter is made out of two pointers(**). It  works like this. The first pointer points to the next pointer which points to the structure. It’s called a referenced pointer.
Why is this done? Well, in this case it is to use the parameter as an output parameter. The idea is that you allocate memory to hold a pointer, and pass a pointer to that allocated memory as the parameter. Then, in that allocated memory, the function writes a pointer to the structure. So that when the function is finished and returns, the pointer to the allocated memory now actually points to the pointer (written by the function). The only thing left to do now is to de-reference the pointer, so that you can use it.

Then the filename parameter. It’s originally a constant char*. A pointer to the first element of an array of chars. As you know, native chars are not the same as .Net chars so we need to convert this param. We do know how the native char array is built up in memory. Namely, a native char is similar to one byte and a native array of bytes simply consists of bytes in a row. The end of the array is defined by a null-byte at the end of the array.

So, to wrap this function we need to do to manual conversions. The example below shows how you can do so:

public static IntPtr initSystem(string _fileName)
{
  IntPtr refPtr  = IntPtr.Zero;
  IntPtr filePtr = IntPtr.Zero;

  try
  {
    //convert from string to pointers
    filePtr = Marshal.StringToHGlobalAnsi(_fileName);

    //alloc mem for system pointer
    refPtr = Marshal.AllocHGlobal(IntPtr.Size);

    //call external method
    uint err = initSystem(filePtr.ToPointer(), refPtr.ToPointer());
    
    //check for errors
    if (err != 0)
      throw new Exception(“Error is: “ + err);

    //unreference system pointer
    return Marshal.ReadIntPtr(refPtr);
  }
  finally
  {
    //clean up memory
    if (refPtr != IntPtr.Zero)
      Marshal.FreeHGlobal(refPtr);
    if (filePtr != IntPtr.Zero)
      Marshal.FreeHGlobal(filePtr);
  }
}

Let’s first look at the filename parameter. In my wrapper it’s a string, in the import it’s a void*. So the string needs to be converted to a void*. This void* must point to an sequential list of bytes (one for each character in the filename) terminated by a null byte.
.Net has made this easy for you. Simply use the Marshal.StringToHGlobalAnsi. This method allocates new memory on the heap and copies and converts all the characters in the string to that newly allocated memory. It results into an IntPtr object. This object contains the method ToPointer, which passes you the void*.
BE SURE to free the IntPtr! As said, memory has been allocated on the heap. This allocation will not be freed by GarbageCollector. You have to do this yourself by invoking the method Marshal.FreeHGlobal, passing the IntPtr as the parameter.
When you do not free your allocated memory, eventually all memory will be allocated by your program resulting in out-of-memory errors. We call this a memory leak.

Now, the system parameter is a bit less easy. First we need to allocate enough memory to hold a pointer. This we do by calling Marshal.AllocHGlobal. The parameter specifies the number of bytes to allocate. For a pointer on a 32 bit machine, this is 4 bytes. To be sure that your program also runs on other types of machines, don’t just type in 4, but use the static Size property of the IntPtr class. This property always contains the right number of bytes for the current system.
Again, this method also returns a IntPtr object which can be converted to an void*.
After the external function returns, the allocated memory now contains a pointer to the system object. Simply read it out by calling Marshal.ReadIntPtr. You pass the pointer to the allocated memory and the method will read the (4) bytes and convert that into an IntPtr. This is the IntPtr we need. The pointer is now de-referenced.
Again, be sure to free the allocated memory, as otherwise you have created a memory leak. When you free the memory, it will not wipeout the de-referenced pointer as the Marshal.ReadIntPtr method has created a new pointer for you in managed memory.

For more questions, leave a comment and I will try to answer.

 

UPDATE: How to pass structures

This update is an answer on Paulo's comment.

Hi Paulo,

Well actually marshalling structs is quite well documented by Microsoft, you only need to know how to find it, as they have made it quite hard to find.

Take a look at the StructLayoutAttribute class and the examples that come with it.
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx

Please know this about structs in a .Net environment... they’re not like C++ structures. Structs in .Net are more like classes, with their own constructors, properties and methods. But you are able to shape the structures of interoperable types with the StructLayoutAttribute class.

I would use the LayoutKind.Explicit as this gives me complete control over memory placement. It also enables you to skip some uninteresting fields of the structure by simply leaving some blank space in your structure.

There are several ways to pass the struct.
from the example on MSDN:

[DllImport("kernel32.dll")]
public static extern void GetSystemTime([MarshalAs(UnmanagedType.LPStruct)]MySystemTime st);

As you can see in the example, you can simply define the marshalling in the import.

Though this is probably the easiest way to do it, it’s not the way I’m feeling comfortable with. This is mainly because (probably like you) I originally come from an Assembly/C++ environment where I know what is going on and I’m the big cheese of control in my software. It must be crystal clear to me when to allocate or free memory, etc.

So to keep control, I would rather create the structure, fill the fields and use the System.Runtime.InteropServices.GCHandle to pin the structure and pass the pointer as parameter to the method.
(please note that the GCHandle itself is also a structure and not a class :-))

The following is a complete example:

[DllImport(DLL, EntryPoint = "SomeFunction")]
public static extern void* SomeFunction(void* structure);

//-------------------------------------------------------------------------
[StructLayout(LayoutKind.Explicit, Size=3)] public struct SomeStruct { [FieldOffset(0)]public byte fieldOne; [FieldOffset(1)]public ushort fieldTwo; } //------------------------------------------------------------------------- [StructLayout(LayoutKind.Explicit, Size=3)] public struct SomeOtherStruct { [FieldOffset(0)]public ushort fieldA; [FieldOffset(2)]public byte fieldB; } //------------------------------------------------------------------------- public static SomeStruct test(SomeOtherStruct _myStruct) { GCHandle hndl = new GCHandle(); try { //get pinned pointer to struct hndl = GCHandle.Alloc(_myStruct, GCHandleType.Pinned); IntPtr pntr = hndl.AddrOfPinnedObject(); //call external method IntPtr structOut = new IntPtr(SomeFunction(pntr.ToPointer())); //return the structure return (SomeStruct)Marshal.PtrToStructure(structOut, typeof(SomeStruct)); } finally { //cleanup memory if (hndl.IsAllocated) hndl.Free(); } }

Please make sure that the returned structure does not need to be freed, or if it does, free it :) The Marshal.PtrToStructure method creates a new structure with no references to the returned pointer.

If all of this doesn’t suit your style, you can also simply allocate a specific size of unmanaged memory and map all the variables (pointers) yourself, or even copy the values directly to that block of unmanaged memory.

Update: Please read the article "Marshalling Compiler" about an online Marshalling Compiler which takes a C style header as input and converts it into an import of a native DLL in managed C# source code.

 

Friday, August 29, 2008 2:25:57 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [64]
.Net | Marshalling
Monday, September 01, 2008 5:47:50 AM (W. Europe Daylight Time, UTC+02:00)
Good day

Great write up sir. This comes at an important time in my life as I am being forced to write C# for a hardware device. Being an EE major, this has been the first thing I have read in weeks of reading online which finally explained in terms I can understand the need for interoperability. The level of abstraction in .NET is mind boggling. At this point, I already miss assembly. =(

I do have one question though, what if the function which needs importation has structs for all its arguments? Something similar to the following:
CustomStruct1 FunctionName (CustomStruct2* Input1, CustomStruct3* Input3)

Do I need to create a wrapper for each struct? To make things more complicated, what if a CustomStruct3 is made up of native types AND another struct?

Thanks from the Philippines
PauloA
Monday, September 01, 2008 4:21:21 PM (W. Europe Daylight Time, UTC+02:00)
Hi Paulo,
I've updated the blog post. It should answer most of your questions.

To go into "what if a CustomStruct3 is made up of native types AND another struct?",
When you need to use a structure within a structure, simply use a void* (native type) to point to the other structure.
Something like:

[StructLayout(LayoutKind.Explicit, Size=6)]
public struct SomeStruct
{
[FieldOffset(0)]public void* structPointer;
[FieldOffset(4)]public ushort fieldTwo;
}

Note that I've used 4 bytes for a pointer in this case. This is good for all 32 bit systems.
You can fill the structPointer field by pinning the other structure using GCHandle (and use AddrOfPinnedObject() and ToPointer() to get your void*)

Always keep in mind, a native structure (C++ type structure) is nothing more than a map (defined at compile time), which is simply placed over of a block of memory.

Saturday, October 18, 2008 12:02:56 PM (W. Europe Daylight Time, UTC+02:00)
Hi ,
My name is Marco and I'm writing few application where I need to use DLL writed in C .
Reading this article I solved some situations , but I have a situation that I can't solve .

The problem is when I call a C function with following parameter .

int MyCFunction( char* filenames[] );

Where I must pass a an array of filenames . I try many different solution but I have everytime an exception about access to memory .

Can You advise how to pass this paratemer .
Monday, October 20, 2008 9:25:30 AM (W. Europe Daylight Time, UTC+02:00)
Hi Marco,

Let me explain how such an array of strings is mapped in memory.

As you know, a string in C is actually a row of chars, ending with null byte. Such a string is represented by char*. And it points to the first byte of the string.

A C-style array also a row in memory, but not of type char, but of type * (pointer). But it's not ending with a null terminator. In most cases where you would pass a non-fixed array, you must also pass the size of the array. This is because there is no way of telling the size of the array (without looking at the heap).
The start of the array is represented by a *.

So in the case of an array of strings, you would look at...
1, a char**, which points to the start of the array
2, the array is a sequential row of char*
3, a char*, which points to the start of the string
4, the string is a sequential row of char elements

which translates to .Net like this...
1, a void*, which points to the start of the array
2, the array is a sequential row of void*
3, a void*, which points to the start of the string
4, the string is a sequential row of byte elements

So what you should pass to your function would simply be a void*, pointing to the start of the array.

Is this sufficient for you, or do you need an example?

Monday, October 20, 2008 9:52:53 AM (W. Europe Daylight Time, UTC+02:00)
Please note that if this still doesn't work, it might be that your C function expects a string of w_char instead of char.
w_char (type wchar_t) is a non-native type which allows the use of unicode characters.

The above memory mapping is mostly the same, only you have to convert your .Net strings to unicode strings (which are made up of two bytes per character) instead of ASCII strings.
Thursday, October 30, 2008 7:19:29 PM (W. Europe Standard Time, UTC+01:00)
Hi,
i need to use bulk-copy utils from C API in C#, but i have problems with it. Can u help with some sample?
link to lib manual:
http://manuals.sybase.com/onlinebooks/group-sd/sdg1251e/comlib/@Generic__BookTextView/11076;hf=0;pt=11828#X
Roman
Friday, October 31, 2008 5:17:05 AM (W. Europe Standard Time, UTC+01:00)
Hi Roman,

What are the problems you're facing? Please elaborate on the issue.

Thursday, November 06, 2008 7:42:16 PM (W. Europe Standard Time, UTC+01:00)
how to pass hidden structure? (header file uses anonymous structure tags to define the hidden structures.)
here header file: http://files.edin.dk/php/win32/dev/php_build/sybase/include/cstypes.h
i need CS_CONTEXT and CS_CONNECTION.
function: cs_ctx_alloc(version, context);
CS_INT version;
CS_CONTEXT **context;

Roman
Friday, November 07, 2008 9:33:28 AM (W. Europe Standard Time, UTC+01:00)
Hi Roman,

Ah I see what you mean. The CS_CONTEXT and CS_CONNECTION are void pointers (void*)!
So they are actually pointers pointing to an undefined structure/type in memory.

See them as just a pointer to a memory location. They are simply used by the functions to pass references, but they are not used at all by your library. So, don't worry about casting it to anything. Just handle it like any void*.

Please take a look at my example above where I do the explanation of...

typedef struct _sysRef sysRef;
unsigned int initSystem(const char *fileName, sysRef **system);

You will see that the sysRef is also just a void*.

Good luck.

Monday, November 10, 2008 10:55:43 AM (W. Europe Standard Time, UTC+01:00)
Hi Martijn,
Great article but i think i have an other problem. ^^
I work with OpenInventor and have to save a SoNode-pointer (SoNode*) in an .Net-TreeNode.
I've found the Tag in TreeNode.Tag and it requires an System.Object but i have only a nativ pointer to SoNode.
Can you please give me an advice how to do it?

I want to handle the MouseNodeClick-event in a managed-c class. So if i click a TreeNode in the TreeView i want to get the native SoNode-pointer back from the TreeNode.Tag to change some content.

buy
Martin
Martin
Monday, November 10, 2008 10:56:20 AM (W. Europe Standard Time, UTC+01:00)
i mean bye ... sry :D
Martin
Monday, November 10, 2008 7:39:24 PM (W. Europe Standard Time, UTC+01:00)
Hi!
Thanx a lot for your article and answers. It works!
I appreciate your help.

Best regards,
Roman.
Roman
Friday, November 14, 2008 12:04:02 PM (W. Europe Standard Time, UTC+01:00)
I have a c++ decompression routine in a header file as follows:
int lzo1z_decompress ( unsigned char* src, short src_len,
unsigned char* dst, unsigned int* dst_len,
lzo_voidp wrkmem /* NOT USED */ );

For using the same I have created a wrapper method in c++ as follows:
void _stdcall DecompressData(unsigned char* inData,short SizeofData,unsigned char* outData
,unsigned int SizeOfDataOut)
{
int rCode;
unsigned int eCode=0; /* decompression error code */
try{
rCode = lzo1z_decompress(inData , SizeofData ,
outData , &SizeOfDataOut , &eCode);
}catch(...)
{
//return null;
}
}

For calling the same function in .net I have created a method declaration as follows:
[DllImport("IntermediateDll.dll")]
public static extern void DecompressData(byte[] inData, Int16 SizeofData, byte[] outData, Int32 SizeOfDataOut);

and while calling the method in C# I am using the following code:
byte[] temp = new byte[CompressionLength];
Array.Copy(TotalBuffer, 6, temp, 0, CompressionLength);
byte[] outCsharpData = new byte[1024];
Int32 outLength = 1024;
try
{
DLLCall.DecompressData(temp, CompressionLength, outCsharpData, outLength);
}
catch (Exception ex)
{ CLogger.Reference.LogException(ex.StackTrace); }

I am able to call the code successfully but then it gives me that the stack is corruted error. Is there something which I am not passing incorrectly or not handling memory correctly.

Greatly appreciate your help.

Regards,
Sidharth Shah
Sidharth
Friday, November 14, 2008 4:12:54 PM (W. Europe Standard Time, UTC+01:00)
Hi Sidhart,

So, If I understand correctly you have the C++ function like this:
void DecompressData(unsigned char* inData, short SizeofData, unsigned char* outData, unsigned int SizeOfDataOut)

What I'd expect your program should do with this function is:
1) create an input buffer of chars (bytes) to hold the input
2) create an output buffer of chars (bytes) to hold the output
3) call the function and pass the input buffer (and it's size), and pass the output buffer (and it's size)
4) the function returns and the output buffer contains the output (and the number of bytes of the output is always the same!!! otherwise you should pass the SizeOfDataOut as a reference)

For this, I would expect the C# import would look like this:
[DllImport("IntermediateDll.dll", EntryPoint = "SomeFunction")]
public static extern void DecompressData(void* inData, short SizeofData, void* outData, uint SizeOfDataOut);

You would then:
1) convert the input void* as described in the article
2) pass the SizeofData as a normal short
3) create an output buffer using Marshal.AllocHGlobal (and don't forget to free it once your done or when an exception occurs!)
4) convert the IntPtr of the output buffer to an void* using the ToPointer method.
5) pass the SizeOfDataOut as a normal uint
6) call the function
7) Convert the output buffer using the Marshal.PtrToStringAnsi method
8) free up the input buffer and output buffer.

That should do the trick.

Friday, November 14, 2008 9:18:30 PM (W. Europe Standard Time, UTC+01:00)
Hi All,

Thanks for the article.
I have an issue.
Iam using ICU 3rd party dlls of c/c++ and need to use them in my C# application to implement certain functionalities.

STEP1:
I have to use a method Transliterate() of C++ class Transliterator.

I could use this to get to Transliterate()
[DllImport("icuin40.dll", EntryPoint = "transliterate")]
public static extern void transliterate(IntPtr input);

STEP2:
But, to make use of transliterate method, I need to create an instance of Transliterator class of C++.
How should I get an instance of c++ Transliterator class in C#.
In c++,
Transliterator *myTrans = Transliterator::createInstance("Latin-Greek", UTRANS_FORWARD, status);
But, How should I implement this in C#?

Thanks in advance..
Can you pl shed some light on this..

Regards,
Rohin
Rohin
Tuesday, November 18, 2008 4:07:25 PM (W. Europe Standard Time, UTC+01:00)
Hi all ,

I've a little bit similar situation as Sidharth. But I think I need example to see and understand how it work.
Can you provide it.

Actually I've such function undeer c++ //cannot change it
DLL_API UINT FindPositions (LPCSTR szInputFilename, long *StartPos, long *EndPos, char *Author, long authLength, char *DLL_VERSION)
and in the c#
[DllImport("mydll.dll", EntryPoint = "FindPositions", CallingConvention = CallingConvention.Cdecl)]
public extern static int _LoadDll(
[MarshalAs(UnmanagedType.LPStr)] string Path,
ref long StartPos,
ref long StopPos,
[MarshalAs(UnmanagedType.LPStr)] string Author,
int MAX_AUTH_LENGTH,
[MarshalAs(UnmanagedType.LPStr)] string DLL_VERSION);


after then I call my function and the "long" variables (as StartPos and StopPos) are visible (jupii) but Author and DLL_VERSION are whole time empty.

How can I solve it quickly ?

P.S. I don't receive any failure or error.

Best Regards and thx in andvance
Marceli
Tuesday, November 18, 2008 4:44:08 PM (W. Europe Standard Time, UTC+01:00)
Hi Rohin,

I don't think you can actually do such a thing. I'm not even sure you can make a complete class external from within C++.

You could check all the exports of your DLL by using:
dumpbin /exports [PATH TO DLL]

If you find an entrypoint to your class, put the name or ordinal in the EntryPoint field of the DLLImport attribute.

Please keep me up to date if you do find an export of your class. We'll figure it out.

Wednesday, November 19, 2008 9:04:34 AM (W. Europe Standard Time, UTC+01:00)
So the entry point is exactly the name of the exported function from my dll , isn't
I already copied the dll under /bin/ because without that I received error.

But the problem is that not all variables are visible (as I described). This DLL was checked under VC++6 and works fine!
I've only the problem under C# to use it :(

BR
Marceli
Wednesday, November 19, 2008 10:38:49 AM (W. Europe Standard Time, UTC+01:00)
Hi Marceli,

So you want to use this C++ function:
DLL_API UINT FindPositions (LPCSTR szInputFilename, long *StartPos, long *EndPos, char *Author, long authLength, char *DLL_VERSION)

Where I assume the following:
- szInputFilename = in
- StartPos = ref
- EndPos = ref
- Author = ref (pass empty buffer)
- authLength = in (size of the input buffer)
- DLL_VERSION = ref (pass empty buffer)

So, your C# import would look something like this:
. [DllImport("mydll.dll", EntryPoint = "FindPositions")]
. public static extern uint FindPositions(void* szInputFilename, ref long StartPos, ref long EndPos, void* Author, long authLength, void* DLL_VERSION);

In your C# code you can convert your szInputFilename like this:
. string filename = @"C:\somefile.txt";
. IntPtr filenamePtr = Marshal.StringToHGlobalAnsi(filename);

to create the buffer for the Author:
. long authLength = 1024; //or some other valid size
. IntPtr AuthPtr = Marshal.AllocHGlobal(authLength);

to create the buffer for the DLL_VERSION:
. IntPtr VersPtr = Marshal.AllocHGlobal(10); //or some other valid length

You can then call your function like this:
. uint result = FindPositions(filenamePtr.ToPointer(), StartPos, EndPos, AuthPtr.ToPointer(), authLength, VersPtr.ToPointer());

To read the Author and DLL_Version:
. string Author = Marshal.PtrToStringAnsi(AuthPtr);
. string Version = Marshal.PtrToStringAnsi(VersPtr);

At the end of the function or when an exception occurs, you must free the used memory in order to avoid memory leaks:
. Marshal.FreeHGlobal(filenamePtr);
. Marshal.FreeHGlobal(AuthPtr);
. Marshal.FreeHGlobal(VersPtr);


If all my assumptions are correct (and I didn't make any typos ;-))
This should do the trick for you.

Friday, November 21, 2008 4:34:51 PM (W. Europe Standard Time, UTC+01:00)
good day

I've a problem with a similar situation. But I think I need example to see and understand how can I access do a c dll file with this .h file. I ned to access to Cima_NT_Disconnect(NTInfo *Connection) function with an C# aplication, can you give me a help.
Sory my English.


#define IDLEN 11
#define N_MAG 8
#define N_MAG_NT12 12
#define N_DIV 150
#define N_PREL 20
#define N_STACKERR 30
#define CASSALEN 6
#define LENPAR 9
#define N_UTENTI 20
#define CURRENCY_LEN 4
#define LOG_PATH_LEN 250
#define LEN_PATH_FILES 250
#define N_IMAGE 2
#define N_FASCE_RITARDI 6
#define MAX_CURR_NAME 50 //Mod.05141
#define COMMTYPELEN 10 //Mod.0821286

typedef struct NTIdentification
{
char Protocol[9];
char Serial_port[9];
char currency[N_DIV][CURRENCY_LEN];
long denomination[N_DIV];
int Stock_number;
} NTInfo;

extern "C" int WINAPI Cima_NT_Disconnect (NTInfo *Connection);
Pedro
Thursday, November 27, 2008 4:16:38 AM (W. Europe Standard Time, UTC+01:00)
Hi All,
Now I am studying how to calling unmanaged C++ DLL from C#.I have a problem with mashalling native Extended MFC DLLs.My native function is:

extern "C" TEST_API HRESULT AddTask(IN TransTaskInfo& sTaskInfo);

"TransTaskInfo" is a complicate struct like this,it includes the enum type,array type:
enum TaskState //任务状态
{
TSReady = 1,
TSRunning = 2,
TSError = 3,
}
struct ReceiverState
{
CString ReceiverName;
TaskState enumState;
}
typedef CArray<SReceiverState, SReceiverState&> CReceiverStateArray;
struct TransTaskBaseInfo
{
CString TaskName;
CTime tExecuteTime;
}
struct TransTaskInfo : public TransTaskBaseInfo
{
CString Sender;
CReceiverStateArray ReceiverList;
}
My question is how to declare the function and the argument in the C# program?Please give me a help ,Thank you very much!
[DllImport("Test.dll", EntryPoint = "AddTask", CharSet = CharSet.Auto)]
public static extern int AddTask(?????);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct TransTaskInfo
{
????????????
}


sunshining
Sunday, December 14, 2008 12:48:32 AM (W. Europe Standard Time, UTC+01:00)
First: I'm not an interop expert :( (otherwise I wouldn't ask your help).

I'm developing a C# client application that uses an rcw of an older COM server. I understand why you need to pin all parameters you're passing to the unmanaged code when the COM server expects pointers. But I don't understand why you don't need to pin strings or objects that are references in C#. Even if you pass a string by value, the string variable is a reference and it is this reference that will be copied, not the object itself.

I came across some examples like this:

Unmanaged function:

SomeFunction(string str, int* pInt)

Managed code:

string str = "something";
IntPtr pInt = IntPtr.Zero;
GCHandle hInt = GCHandle.Alloc(pInt, GCHandleType.Pinned);
SomeFunction (str, hInt.AddrOfPinnedObject());
if (hInt.IsAllocated) hInt.Free();

Why you need to pin down the pointer to the integer (second parameter of SomeFunction), but not the string? The string is a predefined C# reference type and can be moved around by the GC just like the pointer, no?

Please shed some light,
Dave
Dave
Sunday, December 14, 2008 7:03:12 PM (W. Europe Standard Time, UTC+01:00)
I think I've got the answer: pinning ps automatically performed during marshaling for objects such as String, however you can also manually pin memory using the GCHandle class.
Dave
Wednesday, December 17, 2008 10:17:03 AM (W. Europe Standard Time, UTC+01:00)
Hi there, wonder if you may have some suggestions to this

I have a C DLL with the exposed method

extern "C" void FillMatrices(TMatrix** mats, int matcount)
{...
}

The TMatrix structure is
typedef struct tagTMatrix
{
int Id;
int NumColumns;
int NumRows;
double* aData;
} TMatrix;
in C++
and in C# I declare it as

[StructLayout(LayoutKind.Sequential)]
unsafe public struct TMatrix
{
public Int32 id;
public Int32 NumCols;
public Int32 NumRows;
public Int32 NumPlanes;
public IntPtr aData;
};

And I declare the export as
unsafe internal delegate void FillMatrices(IntPtr mats, long num);

And I use this from some place which seems to be a kind of memory defragmenter utility !

[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
static extern void CopyMemory(IntPtr dest, IntPtr[] src, int cb);

IntPtr library = LoadLibrary("TestDLL.dll");
IntPtr procaddr = GetProcAddress(library, "FillMatrices");
FillMatrices fm = (FillMatrices)Marshal.GetDelegateForFunctionPointer(procaddr, typeof(FillMatrices));

TMatrix[] mats = new TMatrix[2];

mats[0]=new TMatrix();
mats[1]=new TMatrix();

mats[0].id=1;
mats[0].NumCols=2;mats[0].NumRows=1;
mats[0].aData = Marshal.AllocHGlobal(sizeof(double) * 2); // uninitialized data
double [] array=new double[2];
array[0]=12.5;array[1]=2.3;
fixed (double* a = array)
{
IntPtr intPtr = new IntPtr((void*)a);
mats[1].aData = intPtr;
mats[1].id = 2;
mats[1].NumCols = 1; mats[1].NumRows = 2;
}

IntPtr[] ptrs = new IntPtr[2];
int total=0;
int matsize=0;
for (int i = 0; i < ptrs.Length; i++)
{
matsize=sizeof(IntPtr) * (4 + mats[i].NumCols * mats[i].NumRows);
ptrs[i] = Marshal.AllocHGlobal(matsize);
total = total + matsize;
}

Marshal.StructureToPtr(mats[0], ptrs[0], false);
Marshal.StructureToPtr(mats[1], ptrs[1], false);


IntPtr pointer=Marshal.AllocHGlobal(total);
CopyMemory(pointer, ptrs, 2 * IntPtr.Size);
fm(pointer,2);


Now this seems to get my array of structures into C++ but I need finally to have my C++ fill in the data and read it back. It seems like quite a mess and I am sure there must be a nice and clean way of doing this... :(

Thanks in advance
Shyamal
Shyamal
Friday, December 19, 2008 9:14:14 AM (W. Europe Standard Time, UTC+01:00)
Hello ...!
I want to import a dll in asp.net, and I have a major problem
First i want to say that this dll works fine in a windows application written in C#, the dll importation works just fine. and this dll works file when I run this code in FileSystem Mode (in ASP.net )
But when I run the this code in Localhost ,I don't get anything back, nothing, not even an error.
Can it be something with the security rights the IIS has? or Web.config? or my Import?

Example Code :

[DllImport("Mydll.dll")]
public static extern int LogIn(int handle);


Please Help me ... Please ....
Tuesday, January 20, 2009 7:38:31 PM (W. Europe Standard Time, UTC+01:00)
Hi,

I am having a problem similar to Marceli, but in my case the c function declaration is quite different.

This is the function that I want to use.

int WINAPI WinStatusPrtCh (char far *lpAppBuff);

In c#, I declared the function this way:

[DllImport("p32prtch.dll",CharSet=CharSet.Ansi)]
public static unsafe extern uint WinStatusPrtCh(IntPtr status);

When I call the WinStatusPrtCh function, it returns 0, it means that the function runned ok. But the status value is always empty (I expect a string whith 10 positions).

Can you help me, please. I'm getting crazy...
Diogo Alves
Sunday, January 25, 2009 3:18:59 PM (W. Europe Standard Time, UTC+01:00)
For all people who have problems writing their native DLL imports for .Net, please read the article "Marshalling Compiler" about an online Marshalling Compiler which takes a C style header as input and converts it into an import of a native DLL in managed C# source code.

http://blog.rednael.com/2009/01/25/MarshallingCompiler.aspx

Monday, February 16, 2009 7:21:59 AM (W. Europe Standard Time, UTC+01:00)
dear sir

have nice day. actually i am developing a plugin for ms-office. in which i have to call a function of a DLL which is made in c++.

for calling i need to pass function pointers from my c# code to the function of the DLL.

following is the c++ function calling details:

long FSDC_API IDefaultPluginInitializedW(
/* [in] */ Byte * pPassPhrase,
/* [in] */ GetActiveDocumentW_type pfGetActiveDocument, ------> this is function pointer
/* [in] */ IsDocumentDirty_type pfIsDocumentDirty, ----------> this is function pointer
/* [in] */ WCHAR * pstrDocPath,
/* [out] */ WCHAR * pstrError);

please can you help me out how i can pass values to those parameters from my c# code.

thanks in advance.

ashish jain
ashish jain
Monday, February 16, 2009 9:44:52 AM (W. Europe Standard Time, UTC+01:00)
Hi Ashish,

I think the problems you're facing is "how to pass a managed function pointer to an unmanaged function?"

You can do this by first creating delegates for your managed functions.
Then get the pointers by calling Marshal.GetFunctionPointerForDelegate(Delegate d). This returns you an IntPtr.
Convert the IntPtr to void* using the ToPointer() function on the returned IntPtr.

Using the Marshalling Compiler (see above), I've converted your function to this:

using System;
using System.Runtime.InteropServices;

public class Imported
{

[DllImport(path_to_dll)]
public static extern int IDefaultPluginInitializedW([MarshalAs(LPStr)] string pPassPhrase, void* pfGetActiveDocument, void* pfIsDocumentDirty, [MarshalAs(LPWStr)] string pstrDocPath, [MarshalAs(LPWStr)] out string pstrError);

}


Tuesday, February 17, 2009 5:29:08 AM (W. Europe Standard Time, UTC+01:00)
but when i type void* it says that void* works only in unmanaged block.
ashish jain
Tuesday, February 17, 2009 9:00:01 AM (W. Europe Standard Time, UTC+01:00)
That's true!
You have found a bug in the Marshalling Compiler.

You need to make the class "unsafe" by declaring the class, like this:


public unsafe class Imported
{


And you could probably also make it an "internal" class, like this:


internal unsafe class Imported
{


That should do the trick.

Tuesday, February 17, 2009 5:15:37 PM (W. Europe Standard Time, UTC+01:00)
typedef long (* GetActiveDocumentW_type)(WCHAR * pstrId); ----> this is having active

typedef bool (* IsDocumentDirty_type)(WCHAR * pstrId);

long FSDC_API IDefaultPluginInitializedW(
/* [in] */ Byte * pPassPhrase,
/* [in] */ GetActiveDocumentW_type pfGetActiveDocument,
/* [in] */ IsDocumentDirty_type pfIsDocumentDirty,
/* [in] */ WCHAR * pstrDocPath,
/* [out] */ WCHAR * pstrError);

this is the over all scenerio in my c++ dll

i need to refere this IDefaultPluginInitializedW function from my c# code
ashish jain
Sunday, March 01, 2009 3:00:31 PM (W. Europe Standard Time, UTC+01:00)
Can you help me with my VB 2005 program plz? I am using a third party DLL which is working perfectly with vb6. Im trying to convert the project into VB 2005 and having some problem getting the desired result.

Working code in vb6 looks something like this
Declare Function some_func Lib "somexx.dll" (ByVal handle As Long, psFirstRecDate As DateTime_struct, ByVal iFirstFindMode As Long, psLastRecDate As DateTime_struct, ByVal iLastFindMode As Long) As Long

where DateTime_struct is this
Type DateTime_struct
lDate As Long
lTime As Long
End Type


Dim sdate As DateTime_struct
Dim edate As DateTime_struct
dim tk as long

tk= 3045678
sdate.lDate = 20092802
sdate.lTime = 0
edate.lDate = 20092802
edate.lTime = 2359999
iErr = some_func(tk, sdate, 1, edate, 0)
This is working fine in vb6.

However I could not get it working in vb 2005.
The dll function is not recognising the inputs. I dont have any details of the DLL except the declaration given above.
I understand this is possibly some marshaling issue. Any help will wille be highly aappreciated.
With regards

Dev

Dev
Monday, March 02, 2009 8:41:44 AM (W. Europe Standard Time, UTC+01:00)
Hi Dev,

I'm sorry, but I don't have much knowledge of VB.

Though, I can tell you this. In VB6 the types were all different than from any other language.
For example, an Integer in VB6 consists of 2 bytes (instead of 4).

Also, in VB6 you would always create a COM functions (using BSTR and such), is this the same in VB2005?
And (although I don't see it in your code) when you would create an Array in VB6, you would actually create a collection. This could also differ from VB2005.

Hope this helps a bit.


Thursday, April 02, 2009 2:16:48 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn

I have just gone through most of your posts.
Looks Great!!! You seems to be an expert in Marshalling.

I want to send the following structure from C++ dll to C# dll.
struct StTest
{
int m_nAge;
char* m_szName;
}

Please help me to resolve this. It will be nice if you can give me an example code snippet.
Hope to get a positive response.

Best Regards
Suyambu
Suyambu
Thursday, April 02, 2009 4:42:37 PM (W. Europe Daylight Time, UTC+02:00)
I've compiled your example:

struct StTest
{
int m_nAge;
char* m_szName;
}; //<<<including the ;


with the marshalling compiler (at http://mc.rednael.com/):

using System;
using System.Runtime.InteropServices;

public class Imported
{

[StructLayout(LayoutKind.Explicit, Size=8)]
public struct StTest
{
[FieldOffset(0)] int m_nAge;
[FieldOffset(4)] [MarshalAs(LPStr)] string m_szName;
}

}
Friday, April 03, 2009 12:05:17 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn

Thanks for your Quick reply.

My requirement is to send an array of structure from VC++ to C#.
eg: Would like to send array of people information to C#.
Am more interested to know about the usage of this both in VC++ and in C# interface function declaration and its definition.
Lets me write a sample code here...

VC++ Code
------------
CSharpSampleDll::ISamplePtr g_SamplePtr;
HRESULT hr = NULL;
::CoInitialize( NULL );
hr = g_SamplePtr.CreateInstance( __uuidof( CSharpSampleDll::Class1 ) );
if ( SUCCEEDED( hr ) )
{
g_SamplePtr->SetData( ... ); // Asking for a SAFEARRAY*, how to send a array of objects.
// Lets say I want to send 3 persion information at one stretch.
}
::CoUninitialize( );


C# Code
------------
public interface ISample
{
void SetData( StTest [ ]obj ); // Do I have to use IntPtr as a parameter instead of STTest [ ]?
// When I specify the array of Structure here, its actually
//asking for SAFEARRAY *, while am using this in VC++.
};

[ClassInterface (ClassInterfaceType.AutoDispatch)]
public class Class1: ISample
{
public void SetData( Test [ ]obj )
{
//How to retrieve the array of objects here in C#?
}
}
}

It will be nice if you can give me an example of sending SAFEARRAY* and accessing the same in VC++.
If this is not the rightway then please let me know the correct method of doing this.

Many Thanks in Advance
Suyambu
Suyambu
Tuesday, April 07, 2009 6:02:25 AM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn

Could you please reply to my last query.
Suyambu
Wednesday, April 22, 2009 7:55:44 AM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn

Have you got my previous question?
I have a submission.
Am in need of a solution very urgently.
Is the above is possible or not?
Please reply.

Best Regards
Suyambu
Suyambu
Friday, April 24, 2009 11:22:02 AM (W. Europe Daylight Time, UTC+02:00)
Hi Suyambu,

I'm not quite sure what the problem is that you have.
If you want to pass COM style arrays like SAFEARRAY, you could probably use the MarshalAs with ELEMENT_TYPE_SZARRAY.
Read more about marshalling of SAFEARRAY types at:
http://msdn.microsoft.com/en-us/library/z6cfh6e6(VS.71).aspx

But most probably if you have COM style arrays, you have a COM style dll (or application)... you don't have to marshal COM dlls yourself!
Just import it with any version of Visual Studio .Net (or higher) and an interop will be automatically created for you.


Friday, April 24, 2009 12:12:41 PM (W. Europe Daylight Time, UTC+02:00)
Hi,

I am using VS 2005. I have a structure in C# as follows.

[StructLayout(LayoutKind.Sequential, Pack=8)]
internal struct MyStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=0x20)]
public string app_name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=15)]
public string version;
[MarshalAs(UnmanagedType.Bool)]
public bool IsRunning;
[MarshalAs(UnmanagedType.U4)]
public int attrib1;
[MarshalAs(UnmanagedType.I8)]
public long attrib2;
[MarshalAs(UnmanagedType.I8)]
public long attrib13;
[MarshalAs(UnmanagedType.I8)]
public long attrib4;
}


I am writing VC++ 6.0 Win32 DLL to fill this structure. what will be the equivalent structure definition in VC++ 6.0. When I have defined one structure in VC++ DLL as follows

struct FeatureInformation
{
char app_name[21];
char version[15];
bool IsRunning;
UINT32 attrib1;
LONG64 attrib2;
LONG64 attrib3;
LONG64 attrib14;
};

when Iam filling this structure in VC DLL Iam unable to send those values to C# Application. There Iam getting garbage values.

I dont want to disturb the existing C# code. Please help me regaridng this.
Lakshman
Friday, April 24, 2009 1:22:55 PM (W. Europe Daylight Time, UTC+02:00)
Hi Laksman,

Have a look at...
1) you have defined your app_name field as char[21] in C++ and defined it as size 32 in your C# code.
2) In C# you've defined attrib1 as int, in C++ you've defined it as unsigned int

Tuesday, April 28, 2009 7:57:50 AM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn

My problem is almost similar to Laksman's problem.
But I want to send in a Structure from VC++ to C#.
Am very new to this, so am not really aware of sending it across.
I tried sending it as a SAFEARRAY*, but while retrieving in C# its crashing.
My very basic doubt is "What would be the parameter type for interface function?"

public interface ISample
{
void SetData( StTest [ ]obj ); // Do I have to use IntPtr as a parameter instead of STTest [ ]?
// When I specify the array of Structure here, its actually
//asking for SAFEARRAY *, while am using this in VC++.
};

But when I typecast my C++ STTest structure to SAFEARRAY* its actually crashing.

Please help me to resolve this.
Suyambu
Tuesday, April 28, 2009 11:12:24 AM (W. Europe Daylight Time, UTC+02:00)
Ok, I'll try it once more...

Concluding this:
1) You don't need to use COM
2) You're building both sides (C and C#)
3) You want to create an array in C and pass it to C#
4) You don't want to reserve memory in C# for the array and pass that to C to fill it

Knowing that:
1) An array in C is a pointer to a block of memory
2) thus, when "int[2] arr", arr is a pointer to a block of memory 2 times the size of an int (which is 4 bytes)

This might be an option for you...

C header code:
---------------------------

//the function creates an array of int:
// &myArrayPointer = new int[size];
extern "C" void createMyArray(int** myArrayPointer, int size);

---------------------------

C# code:
---------------------------
[DllImport(path_to_dll)]
public static extern void createMyArray(void* myArrayPointer, int size);

public int[] createMyArrayWrapper()
{
IntPtr refPtr = IntPtr.Zero;

int arraySize = 10;

try
{
//alloc mem for array pointer
refPtr = Marshal.AllocHGlobal(IntPtr.Size);

//call external method
createMyArray(refPtr.ToPointer(), arraySize);

//unreference pointer (get pointer to array)
IntPtr arrPtr = Marshal.ReadIntPtr(refPtr);

//create the C# array
int[] myArray = new int[arraySize];

//copy data from C array to C# array
Marshal.Copy(arrPtr, myArray, 0, arraySize);
}
finally
{
//clean up memory
if (refPtr != IntPtr.Zero)
Marshal.FreeHGlobal(refPtr);
}
}

---------------------------

This code is from the top of my head and is untested, but it may help you on your way.
Please know that you also MUST free the memory that you've allocated in your C code. If you don't do that, you'll run out-of-memory.
You can do so by creating an other method like freeMyArray(int* myArray); in C, where you do a delete myArray;


Thursday, April 30, 2009 9:25:00 AM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn

Thanks for your detailed reply.

2) You're building both sides (C and C#) - C++ and C#.
3) You want to create an array in C and pass it to C# - Yes but array of structure.

Its the other way round, Actually I want to call a C# function from VC++.
My VC++ dll is loading the C# dll using the following steps.

VC++ Code
------------
CSharpSampleDll::ISamplePtr g_SamplePtr;
HRESULT hr = NULL;
::CoInitialize( NULL );
hr = g_SamplePtr.CreateInstance( __uuidof( CSharpSampleDll::Class1 ) );
if ( SUCCEEDED( hr ) )
{
g_SamplePtr->SetData( ... ); // Asking for a SAFEARRAY*, how to send a array of objects.
// Lets say I want to send 3 persion information at one stretch.
}
::CoUninitialize( );

Here is the C# code...
------------
public interface ISample
{
void SetData( StTest [ ]obj ); // Do I have to use IntPtr as a parameter instead of STTest [ ]?
// When I specify the array of Structure here, its actually
//asking for SAFEARRAY *, while am using this in VC++.
};

[ClassInterface (ClassInterfaceType.AutoDispatch)]
public class Class1: ISample
{
public void SetData( Test [ ]obj )
{
//How to retrieve the array of objects here in C#?
}
}
}

Hope its clear now.
Please guide me to achieve the above.

Suyambu
Monday, May 04, 2009 9:02:05 AM (W. Europe Daylight Time, UTC+02:00)
Hi Suyambu,

So, why don't you just create a C++.Net dll then?
Please read the MSDN library: http://msdn.microsoft.com/en-us/library/68td296t.aspx

And why do you want to code in C# and C++ then? Why not just choose one of them?

Monday, May 04, 2009 10:18:16 AM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn

Well, my C++ dll will be used by different application.
Its a common component, which will act differently for each application. Ofcourse there are some common
features across all these applications. So If am going to change my C++ component to C++.Net, then I may need to change the way that the application loads my dll and so on. I dont want to make any changes to my existing applications.

Moreover the concept which am talking about to send in array of structure to C# dll, is basically a functionality of a particular application. This functionality may not be available in other application. .Net framework is another dependency, that the customer needs to install. So whoever needs uses that specific product, we will ask them to install .Net framework and use the functionality. If I change all my C++ dll to C++.Net dll, then all my application requires .Net framework, which we dont want to make it mandatory for the customers.

Isn't that not possible to send in a array of structure from C++ to .Net dll?
Suyambu
Thursday, May 07, 2009 9:17:32 AM (W. Europe Daylight Time, UTC+02:00)
Hi Martin,

i have a case where i need to pass file pointer (FILE *fp) to native c code (dll) from C# application. how can i achieve this ? could you please point me to some example ?
Shankar
Wednesday, May 27, 2009 9:55:55 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martjin,
I have some legacy DLL library that was written in C++ (VC 6.0). I am trying to write a C# wrapper and everything seems to work relatively well, except one function that has the following prototype: void Foo(__int64* aptr);

According to the documentation, a buffer of (1024* 4 bytes) must be allocated before calling this function. It then fills this buffer with data and returns.

The following blows up? What am I doing wrong?

IntPtr ptr = Marshal.AlloclHGlobal(sizeof(Int32) * 1024);
Foo ((Int64 *)ptr.ToPointer()); //Blows up here with "Attempted to read or write protected memory..."

Int32[] arr = new Int32[1024];
byte[] bytes = new byte[sizeof(Int32)*1024];
Marshal.Copy(ptr, bytes, 0, 1024);

for(int i = 0; i < 1024; i++){
arr[i] = BitConverted.ToInt32(bytes, i * sizeof(Int32));
}

Marshal.FreeHGlobal(ptr);
Kiril
Wednesday, May 27, 2009 10:06:23 PM (W. Europe Daylight Time, UTC+02:00)
Hi Kiril,

So, have you tried to allocate 1024 * 8 bytes?
It could well be that the documentation is flawed. It says in the documentation that you have to pass an array of Int32 (4 bytes), but the function states __int64 (8 bytes).

It would also mean that the C++ function tries to write bytes from 1024*4 until 1024*8. That's in memory that you didn't allocate and such an action could give you the error "Attempted to read or write protected memory..."

Thursday, May 28, 2009 3:42:45 AM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn,
Nice post. Can you also let me know on how to make calls to functions in a native COM DLL?
Thanks,
Prasad
Thursday, May 28, 2009 9:33:51 AM (W. Europe Daylight Time, UTC+02:00)
Hi Prasad,

You don't have to marshal COM DLLs yourself!
Just import it with any version of Visual Studio .Net (or higher) and an interop will be automatically created for you.

If you want to do it more manually, check these out:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.aspx
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comtypes.aspx
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.expando.aspx

Thursday, May 28, 2009 4:10:22 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martjin,

Thank you for the suggestion, I have also tried allocating 8 * 1024 number of bytes and passing that to the function, however I get "StackOverflowException", which does not really make sense to me, as I am allocating memory on the heap and not on the stack. My stack should only contain ptr, bytes, arr addresses pointing to the heap!!! Does Marshal.AllocHGlobal() allocates memory of the heap? And as far as I know it should return you a pointer to contiguous space, correct?!

Also, In documentation it states that "the pointer(xptr) must address a contiguous memory space. The number of bytes copied is equal to four times the length of the buffer (which is 1024). Enough free space must be allocated before this function is called", so I assumed that it returns a buffer of Ints32s not Int64s. In prototype definition it states that xptr is a pointer to integer array, however it does not state which integer array it is(4 bytes or 8 bytes).

Martjin, let me know what can be done/or is there something I am doing wrong?!
Kiril
Sunday, May 31, 2009 8:25:13 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn,

I have the following scenario.

C# application -> Native Wrapper DLL -> Native COM DLL

From the C# application I am able to call Native Wrapper DLL's functionA() and it works fine. But when I try to make a call to functionB() which in turn calls some functionC() in the Native COM DLL, I get a System.NotSupportedException. What could be the potential problem?

I have been using a C++ application before and all the calls to the COM DLL functions were working fine. Now since we wanted to move to C#, I am facing this issue. Any help here is greatly appreciated.
Thanks,
Prasad
Tuesday, June 16, 2009 4:17:59 AM (W. Europe Daylight Time, UTC+02:00)
Hello:

I am writing some graphics funcs in C# and will be packaging them in a DLL but my problem seems to be that when I'm using DLL import that some types seem to be causing problems???

Example: draw_arrow(Graphics g, x, y, Color outline, Color Fill);

I am getting MarshalAs exeception errors on the fill color???
AM I suppost to use the MarshalAs on the Color type and if so then what do you Marshal the Color type as?



Devsupport
Friday, July 17, 2009 4:19:59 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn !

Hopefully You can add in solving a problem with interop.

I am having a really hard time p-invoking a dll call.
The boys pass a referenced pointer to a function (pointered of course) and do an ugly cast.
All I have to do is, call the dll function and throw in the correct pointer.
What I have, is an instance of a T_v24_properties (.Net) structure trying to call RT_QueryProperty in the dll.
But I have no clue ...

Here is the struct
------------------
typedef struct t_hardware {
char* pInitStream; //!< initialization bytestream for overlapping the u_hw_properties
}THardware;

Caller
------
THardware* pHw

iRet = pHw->rt_query (&pHw->pInitStream, pcProperty,pcValue);

Callee
------
int RT_QueryProperty (char** ppDest, const char* pcName, const char* pcValue)
{
((struct t_V24_properties*)*ppDest)->uiProtocol = V24_PROTOCOL_WAKEUP;
...
}


Any Help is greatly apreciated.

Thanks Martin
Martin
Wednesday, July 22, 2009 4:36:12 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martijn,

I am running into the same problem, I have to use C Dll into my VB.net code. but I am not able to figure out how to marshal structures that are passed into the passing.

Is there any way I can email you my my .h file which contains all structure in C format.
Any help would be appreciated.

Thanks,
Yogi
Yogi
Friday, September 25, 2009 3:03:59 PM (W. Europe Daylight Time, UTC+02:00)
Hi Martin,

Bit late to this, but this is a wonderful post that really helped me out. I spent a lot of time reading and just wasn't grasping it until I found this page.

I have a similar problem to Paulo, but instead of structs - which I managed to deal with - I have a problem with enums.

Basically I have a C++ dll that returns me a struct that contains an array of enum values. The struct returned by the function call looks like this:

typedef struct {
WV_PARAMETER_ID WvParameters[WV_MAX_PARAMETERS] ;
} WV_PARAMETER_LIST ;

And the definiton of a WV_PARAMETER_ID looks like this:

typedef enum {
WV_PARAM_INVALID,
WV_PARAM_FIRST,
WV_PARAM_SECOND,
WV_PARAM_THIRD
} WV_PARAMETER_ID

There are about 150 other values, but you get the idea. The C++ function looks like this:

int WINAPI WvListParameters (WV_CONNECT_ID ConnectID, WV_PARAMETER_LIST *pParameterList, int *pNumberOfParameters) ;

Basically, I'm totally lost. If it was an array of structs, based on your original post, I know what I'd do (I do it elsewhere in the code and it works a treat), but I can't get my head round how to convert the enums to a value that C# can use. Following your example with structs, my C# for this looks like this:

[DllImport("WvAPI.dll", EntryPoint = "WvListParameters", CharSet = CharSet.Auto)]
public static extern unsafe int WvListParameters(int iConnID, void* eParameterList, out int iNumberOfParameters);

public static unsafe WV_PARAMETER_LIST WvListParametersWrapper(int iConnID, out int iNumberOfParameters)
{
IntPtr parameterList = IntPtr.Zero;

parameterList = Marshal.AllocHGlobal(IntPtr.Size);

int retVal;
WV_PARAMETER_LIST pl = new WV_PARAMETER_LIST();

try
{
retVal = WvListParameters(iConnID, parameterList.ToPointer(), out iNumberOfParameters);

if (retVal != 0)
{
throw new Exception("Invalid return code: " + retVal.ToString());
}
else
{
pl = (WV_PARAMETER_LIST)Marshal.PtrToStructure(parameterList, typeof(WV_PARAMETER_LIST));
}
}
catch (Exception)
{
throw;
}
finally
{
if (connID != IntPtr.Zero)
{
Marshal.FreeHGlobal(connID);
}
if (parameterList != IntPtr.Zero)
{
Marshal.FreeHGlobal(parameterList);
}
if (numberOfParameters != IntPtr.Zero)
{
Marshal.FreeHGlobal(numberOfParameters);
}
}

return pl;
}

But it doesn't work; the WV_PARAMETER_LIST object I create only ever has one element, and the value changes each time, and iNumberOfParameters comes out with a different number each time, when I know that it should be the same number each time.

Any advice or suggestions gratefully received.
Saturday, September 26, 2009 12:37:09 AM (W. Europe Daylight Time, UTC+02:00)
Hi Tom,

As far as I know is enum in C++ of the type int.

For the parameter list...
I think you're not allocating enough memory. It seems that you alloc enough memory to hold the pointer to the struct, but not enough to hold the struct itself. Because the function WvListParameters takes a pointer to a struct for the pParameterList parameter (and not a pointer to a pointer to a struct), I presume that you have to alloc the whole struct and pass a pointer to that memory as the input parameter.

But hey, it's late right now, and I am quite sleepy, so do check it yourself, before implementing ;-)
But I'm quite sure you can pass the enum as an int. And thus an array of enums to int*.

Monday, October 19, 2009 11:36:44 AM (W. Europe Daylight Time, UTC+02:00)
hello...i'm new in VB.NET and i'm a bit confused....
i have created a .dll in C and i want to use in an application in VB.NET...my dll is a function that takes for input 4 txt files and return (0)...
how to declare it an pass a handle to it??
thanks for your help....
Monday, October 19, 2009 12:53:10 PM (W. Europe Daylight Time, UTC+02:00)
Hi Maria,

Please read the article and the comments above or use the Marshalling Compiler. All should be explained in there...


Tuesday, November 17, 2009 5:14:09 AM (W. Europe Standard Time, UTC+01:00)
Hello Martijn,

Great article.

I have gone through it and found that it mainly covers aspect of calling a function from native dll in different scenarios.

I have been able to do that with my Fortran compiled native dll.

The problem I have is that, this native dll has more than one functions exposed under export list.
I have a C# wrapper class which has interface for these functions and they are called just fine.
Now this wrapper class is a singlton implementation and being used by two-three other classes.

What I am observing is, that if I call function A in native dll through say Class X. This function A sets some variables in native dll which will be used in other function calls.
Now, if I want to call function B through say class Y, it does not seem to remember the value set by function A in native dll.

My understanding is that for each classes, dll is loaded separately in memory and thus it can not remember state set by function A. Is my understanding correct? If yes, is there a solution for it?

Thanks,
Cheers
USMEL
Tuesday, November 17, 2009 8:44:43 AM (W. Europe Standard Time, UTC+01:00)
Hi Usmel,

The thing with native dlls is that they have no state. They're not instantiated or loaded into memory as a static class. Once compiled, they're nothing more than a collection of functions.
That said, your variables in your native dll probably do not exist at all in your process, because they're not occupying any of your process' memory.

Wednesday, February 10, 2010 3:04:29 PM (W. Europe Standard Time, UTC+01:00)
Hello All,

I have the below function in c dll. I want to call this method from .net. Please help me in writing the code. The below function is to read the barcode data from CS1504 scanner.

public static extern long csp2GetPacket([MarshalAs(UnmanagedType.LPArray)] out byte[] stPacketData, long lgBarcodeNumber, long maxLength);
Vaishali
All comments require the approval of the site owner before being displayed.
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2014
Martijn Thie
Sign In
Statistics
Total Posts: 18
This Year: 0
This Month: 0
This Week: 0
Comments: 160
All Content © 2014, Martijn Thie
DasBlog theme adapted from 'Business' (originally by delarou)