PInvoke GlobalGetAtomName

P

PLS

I'm having problem calling the Win32 function GlobalGetAtomName from C#.
I'm getting a debugger popup telling me that the called function has
unbalanced the stack.

I'm hoping someone here can see what I'm doing wrong.

Here is the function declaration, in a class call DDEFunctions:

[DllImport("kernel32.dll", SetLastError=true,
CharSet=CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
EntryPoint = "GlobalGetAtomNameW")]
public static extern int GlobalGetAtomName(ushort nAtom,
out String lpBuffer, int nSize);

And here is the code that calls it

public static String GetAtomString(ushort Atom)
{
if (Atom == 0)
return null;

int BufferLen;
String Buffer;

BufferLen = 514;
Buffer = new String('\0', BufferLen);

BufferLen = DDEFunctions.GlobalGetAtomName
( Atom, out Buffer, BufferLen);

if (BufferLen == 0)
{
System.Diagnostics.Trace.WriteLine("GetAtomString failed
with DLL error number " + Marshal.GetLastWin32Error().ToString());
return null;
}
else
{
Buffer = Buffer.Substring(1, BufferLen);
return Buffer;
}
}


Does anyone see the problem?

Thanks very much,
++PLS
 
N

Nicholas Paldino [.NET/C# MVP]

Yes, the second parameter needs to be a StringBuilder instance in order
to receive the return value. Make sure that you allocate the buffer in the
StringBuilder before passing it to the function.
 
P

PLS

Yes, the second parameter needs to be a StringBuilder instance in order
to receive the return value. Make sure that you allocate the buffer in the
StringBuilder before passing it to the function.
I've already tried that, with exactly the same result: unbalanced stack.

++PLS
 
N

Nicholas Paldino [.NET/C# MVP]

What is the declaration of the function with the StringBuilder? It
shouldn't be "out", as the P/Invoke layer will know that the buffer has to
be marshaled in and out when the StringBuilder is in place.
 
P

PLS

It was out, but changing it to ref did not change anything.

The definition is now
[DllImport("kernel32.dll", SetLastError=true,
CharSet=CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
EntryPoint = "GlobalGetAtomNameW")]
public static extern int GlobalGetAtomName(ushort nAtom,
ref StringBuilder lpBuffer, long nSize);
 
P

Peter Duniho

It was out, but changing it to ref did not change anything.

I think he means to make the parameter not "out" _or_ "ref". Just make
it a regular by-value parameter. P/invoke will handle the rest.

Pete
 
W

Willy Denoyette [MVP]

PLS said:
It was out, but changing it to ref did not change anything.

The definition is now
[DllImport("kernel32.dll", SetLastError=true,
CharSet=CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
EntryPoint = "GlobalGetAtomNameW")]
public static extern int GlobalGetAtomName(ushort nAtom,
ref StringBuilder lpBuffer, long nSize);


What is the declaration of the function with the StringBuilder? It
shouldn't be "out", as the P/Invoke layer will know that the buffer has
to
be marshaled in and out when the StringBuilder is in place.



Why did you change the nSize into a long? it should be an int.
lpBuffer should be a "StringBuilder" not a "ref StringBuilder".


Willy.
 
P

PLS

PLS said:
It was out, but changing it to ref did not change anything.

The definition is now
[DllImport("kernel32.dll", SetLastError=true,
CharSet=CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
EntryPoint = "GlobalGetAtomNameW")]
public static extern int GlobalGetAtomName(ushort nAtom,
ref StringBuilder lpBuffer, long nSize);


What is the declaration of the function with the StringBuilder? It
shouldn't be "out", as the P/Invoke layer will know that the buffer has
to
be marshaled in and out when the StringBuilder is in place.



Why did you change the nSize into a long? it should be an int.
lpBuffer should be a "StringBuilder" not a "ref StringBuilder".


Willy.
I was trying various things to get something to work. I ended up with
StringBuilder and int.

I've also corrected this function signature on pinvoke.net
 

Ask a Question

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

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

Ask a Question

Top