Search

Categories

On this page

Statistics

Total Posts: 9
This Year: 0
This Month: 0
This Week: 0
Comments: 42

Feeds

RSS 2.0 | Atom 1.0 | CDF

Contact

Send mail to the author(s) E-mail

 

Sign In

# Friday, 29 August 2008
Friday, 29 August 2008 13:25:57 (W. Europe Standard Time, UTC+01:00) ( .Net )

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.

 

Monday, 01 September 2008 04:47:50 (W. Europe Standard Time, UTC+01: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, 01 September 2008 15:21:21 (W. Europe Standard Time, UTC+01: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, 18 October 2008 11:02:56 (W. Europe Standard Time, UTC+01: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, 20 October 2008 08:25:30 (W. Europe Standard Time, UTC+01: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, 20 October 2008 08:52:53 (W. Europe Standard Time, UTC+01: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, 30 October 2008 19:19:29 (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, 31 October 2008 05:17:05 (W. Europe Standard Time, UTC+01:00)
Hi Roman,

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

Thursday, 06 November 2008 19:42:16 (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, 07 November 2008 09:33:28 (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, 10 November 2008 10:55:43 (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, 10 November 2008 10:56:20 (W. Europe Standard Time, UTC+01:00)
i mean bye ... sry :D
Martin
Monday, 10 November 2008 19:39:24 (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, 14 November 2008 12:04:02 (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, 14 November 2008 16:12:54 (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, 14 November 2008 21:18:30 (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, 18 November 2008 16:07:25 (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, 18 November 2008 16:44:08 (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, 19 November 2008 09:04:34 (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, 19 November 2008 10:38:49 (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, 21 November 2008 16:34:51 (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, 27 November 2008 04:16:38 (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, 14 December 2008 00:48:32 (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, 14 December 2008 19:03:12 (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, 17 December 2008 10:17:03 (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, 19 December 2008 09:14:14 (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 ....
Name
E-mail
Home page

Comment (Some html is allowed: i, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview