[Last Call] Learn how to a build a cloud-first strategyRegister Now


Interfacing C# and C Dll Files using pointers that are sometimes required null with const TCHAR*   500pts

Posted on 2006-05-02
Medium Priority
Last Modified: 2010-05-18
I have a C dll that I am writing a .NET wrapper for. Other functions that don't involve string-like types work. If i try to pass it as a string back to the C dll, then it gives me a Stack Imbalance error. Same goes for uint, IntPtr, and char[]. Anyway, Here is the function declaration in the API manual:
HENTRY Open2(const TCHAR *pszPort)

And here is my DllImport & function (APILIB is a constant declared earlier)
[DllImport(APILIB, PreserveSig = true)]
private static extern HWKBENTRY Open2(ref char pszPort);

public static HWKBENTRY WkbOpen(string pszPort)
            byte[] arg2 = System.Text.Encoding.Default.GetBytes(pszPort);
            return Open2(ref arg2[0]);
This works... except for one problem. I need to be able to pass a null pointer. Passing a null does not work. Passing a ref to a 0 byte does not work. I'm pretty lost on this one,
Question by:wibuus
  • 3

Accepted Solution

Daeljan earned 2000 total points
ID: 16595760
Change the import to use:

IntPtr pPort

instead of

char pszPort

Then, to pass the string to the function:

string testString = "TextBeforeCall";

IntPtr pTestString = Marshal.StringToCoTaskMemAnsi("testString");

Look at alternatives to StringToCoTaskMemAnsi() if this gives you problems.

To retrieve text returned from an IntPtr:

string textAfterFunctionCall = Marshal.PtrToStringAnsi(pTestString);

Marshal.FreeCoTaskMem(pTestString); // Dont forget to do this!!

To specify null, use IntPtr.Zero

Be carefull of HWKBENTRY. I don't know what it is, but if you get the type wrong, your stack will go out of line.

Expert Comment

ID: 16595855
Ahh, hold on.

That is correct as far as correctly passing a string in is concerned (always free the memory afterwards). If you want to receive the string back, then thats a different story I think.

The way I do it is to allocate a buffer to hold the returned string:

string message = string.Empty;
byte[] messageBuffer = new byte[MESSAGE_SIZE];
GCHandle hMessageBuffer = GCHandle.Alloc(messageBuffer, GCHandleType.Pinned);
IntPtr pMessageBuffer = hMessageBuffer.AddrOfPinnedObject();

MarshalledFunctionCall(pMessageBuffer); // This is the unmanaged call

message = Marshal.PtrToStringAnsi(pMessageBuffer);

// message now holds a normal .NET string

There are other ways of doing this I'm sure, but this works fine for me.

If you want to pass a string into a function, have it modified and then read it back as an out parameter, then the solution is somewhere near to my first post, but exactly what it is I can't say - I never had that situation. Maybe you can write another C function in the lib to get around that situation and use 2 pointers instead of 1.

Good luck!

Author Comment

ID: 16597133
Thanks a lot... that worked perfectly!

Expert Comment

ID: 16597852
Glad to have been of help!

Featured Post

New feature and membership benefit!

New feature! Upgrade and increase expert visibility of your issues with Priority Questions.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
When you discover the power of the R programming language, you are going to wonder how you ever lived without it! Learn why the language merits a place in your programming arsenal.
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…
Starting up a Project

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question