A call to PInvoke function 'WindowsApplication2!WindowsApplication2.Form1::SendMessage' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Sounds like my parameter datatypes are incorrect. What am i doing wrong? here is my code:
public partial class Form1 : Form
{
String data = "my message";
public const int WM_COPYDATA = 0x4A;
int iHandle;
COPYDATASTRUCT cds;
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
public int lpData;
}
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll",CharSet=CharSet.Auto)]
private static extern int SendMessage(int hWnd, int wMsg, int wParam, COPYDATASTRUCT lParam);
[DllImport("kernel32.dll")]
public static extern void CopyMemory(byte dst, string src, int len);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
iHandle = FindWindow(null, "window_name");
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = data.Length;
cds.lpData = VarPtr(data);
}
public static byte[] StrToByteArray(string str)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
return encoding.GetBytes(str);
}
public int VarPtr(object e)
{
GCHandle GC = GCHandle.Alloc(e, GCHandleType.Pinned);
//int gc = GC.AddrOfPinnedObject().ToInt32();
int gc = GC.AddrOfPinnedObject().ToInt32();
GC.Free();
return gc;
}
private void button1_Click(object sender, EventArgs e)
{
SendMessage(iHandle, WM_COPYDATA, 0, cds);
}
}
AlanPosted Sep 30, 2007, 10:44 AM
As a general rule it's best to always look at the original C function declarations to see what's defined as a pointer and what isn't. However, it doesn't normally matter whether you use 'int' or IntPtr which are both 4 bytes long on a 32-bit system, provided you don't pass a value when a pointer is required and vice versa.
There are a couple of problems in your code which jump out at me.
(1) In the SendMessage declaration, lParam is a pointer so you need to pass the COPYDATASTRUCT by reference rather than by value (this is probably what's unbalancing the stack).
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, int wMsg, int wParam, ref COPYDATASTRUCT lParam); // CharSet not needed as no string parameters
// call with
SendMessage(iHandle, WM_COPYDATA, 0, ref cds);
(2) Although you aren't actually using it in your code snippet, the CopyMemory function (commonly used in VB6) is in fact an alias for the Win32 API function RtlMoveMemory so you need to specify this as the EntryPoint in the DllImport attribute. Also the first two parameters should be of type IntPtr.
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
public static extern void CopyMemory(IntPtr dst, IntPtr src, int len);