• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 708
  • Last Modified:

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

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,
  • 3
1 Solution
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.
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!
wibuusAuthor Commented:
Thanks a lot... that worked perfectly!
Glad to have been of help!
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now