开发者

Messaging interop between c# and VB6 mdi applications

开发者 https://www.devze.com 2023-01-28 06:55 出处:网络
I have two mdi applications, both of which retrieve their data from the same database. The two applications need to be able to send messages to each other to keep in synch.

I have two mdi applications, both of which retrieve their data from the same database. The two applications need to be able to send messages to each other to keep in synch. The messages being passed back and forth only contain a string telling the recieving application which piece of data in the database it should be looking at (a job number, and some additional related info). Both applications have a message handler, instantiated when each program starts up.

When a message is sent from the VB6 app to the c# app it sees the message, and acts appropriately, but when I send the same type of message from the c# app to the VB6 app, it seems to see the message event, but when unpacking it, only sees part of the data, and then ignores the message.

I'm thinking I may be formatting something wrong on the c# end. Here is the method that sends the message:

namespace InterProcessMessaging
{
[StructLayout(LayoutKind.Sequential)]
    public struct COPYDATASTRUCT
    {
        public IntPtr dwData;//a pointer to a number use this to identify your message
        public IntPtr lpData;//a pointer to the address of the data
        public IntPtr cbData;//a pointer to the number of bytes to be transferred 

    }
 public class clsMessaging : System.Windows.Forms.NativeWindow, IDisposable
 {
 //API function to send async. message to target application
        [DllImport("user32.dll", CharSet = CharSet.Ansi)]
        public static extern IntPtr SendMessageA(IntPtr hwnd, Int32 wMsg, Int32 wParam, COPYDATASTRUCT lParam);

  public void SendMessageToVB6(string sendMsg, string WindowsAppTitle)
  {
            try
            {

                IntPtr hwndTarget = FindWindow(null, WindowsAppTitle);

                IntPtr pDWData = Marshal.AllocHGlobal(sizeof(Int32));//a pointer to a number used this to identify your message
                Marshal.StructureToPtr(3, pDWData, true);//place the value 3 at this location

                IntPtr pLPData = Marshal.StringToHGlobalAnsi(sendMsg.Trim());//a pointer to t开发者_C百科he address of the data

                IntPtr pCBData = Marshal.AllocHGlobal(sizeof(Int32));//a pointer to the number of bytes to be transferred 
                Marshal.StructureToPtr(sendMsg.Trim().Length+1, pCBData, true);//place the size of the string at this location

                COPYDATASTRUCT cds;//a structure containing the three pointers above
                cds.dwData = pDWData;//a pointer to a number used this to identify your message (3)
                cds.lpData = pLPData;//a pointer to the address of the data
                cds.cbData = pCBData;//a pointer to the number of bytes to be transferred   

                if (!System.IntPtr.Zero.Equals(hwndTarget))
                {
                    SendMessageA(hwndTarget, 74, 0, cds);
                }
            }
            catch (Exception ex)
            {
                Debug.Print(ex.InnerException.ToString());
            }
  }
 }
}


I would recommend to look into Named Pipes. In .NET you can use System.IO.Pipes for this purpose. In VB6 you can easily implement it with Win32API. Named Pipes is better way to make IPC than windows messaging. Also IPC via SendMessage has limitations on Vista and Win7.


You got that pretty wrong. Only COPYDATASTRUCT.lpData is a pointer. dwData indicates the message number. You pick your own, use 0 if you have only one. cbData is the size of the pointed-to data.

More problems, you are leaking the memory. The amount of memory you allocate doesn't match the size you pass. The string conversion is lossy and might not produce as many bytes as string.Length(). FindWindow is notoriously unreliable. Use a socket or a named pipe for this so you don't have to guess a name, WCF is best.

            COPYDATASTRUCT cds;
            cds.dwData = (IntPtr)3;
            cds.lpData = Marshal.StringToHGlobalUni(sendMsg);
            cds.cbData = 2 * (sendMsg.Length + 1);
            SendMessageA(hwndTarget, 74, 0, cds);
            Marshal.FreeHGlobal(cds.lpData);


This works:

public struct COPYDATASTRUCT
{
    public IntPtr dwData;
    public UInt32 cbData;
    [MarshalAs(UnmanagedType.LPStr)]
    public string lpData;
}  

[DllImport("User32.dll", EntryPoint = "SendMessage")]
        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

IntPtr result;

            byte[] sarr = System.Text.Encoding.Default.GetBytes(sendMsg);
            int len = sarr.Length;
            COPYDATASTRUCT cds;

            cds.dwData = (IntPtr)3;
            cds.lpData = sendMsg;
            cds.cbData = (UInt32)len + 1;
            result = SendMessage(hwndTarget, WM_COPYDATA, 0, ref cds);

Credit for this solution goes to Jim Kemp...who is not yet a member. Thanks Jim!


I based the solution off of the example I found here:

http://boycook.wordpress.com/2008/07/29/c-win32-messaging-with-sendmessage-and-wm_copydata/

0

精彩评论

暂无评论...
验证码 换一张
取 消