CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 4 of 4
  1. #1
    Join Date
    Aug 2010
    Posts
    50

    Unhappy Another WM_COPYDATA issue

    Hi. Here is some code, i'll write the explanations after:

    Code:
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
        Public Structure MsgSTR
            Public code As String
            Public index1 As Integer
            Public index2 As Integer
            Public arr() As Integer
        End Structure
    
    <StructLayout(LayoutKind.Sequential)> _
        Public Structure CopyData
            Public dwData As IntPtr
            Public cbData As Integer
            Public lpData As MsgSTR
        End Structure
    
    Private Declare Auto Function SendMessage Lib "user32" _
         (ByVal hWnd As IntPtr, _
          ByVal Msg As Integer, _
          ByVal wParam As IntPtr, _
          ByVal lParam As CopyData) As Boolean
    
        Private Declare Auto Function FindWindow Lib "user32" _
         (ByVal lpClassName As String, _
          ByVal lpWindowName As String) As IntPtr
    
        Private Const WM_COPYDATA As Integer = &H4A
    
    Private Function mesajSMSSTR(ByVal msg As MsgSTR) As Boolean
            Dim ClientWindow As IntPtr
            Dim a() As System.Diagnostics.Process = System.Diagnostics.Process.GetProcesses
    
            For Each p In a
                If UCase(p.ProcessName) = "SOMEPROCESS" Then
                    ClientWindow = p.MainWindowHandle
                    Exit For
                End If
            Next
           
            If Not ClientWindow.Equals(IntPtr.Zero) Then
    
                Dim message As MsgSTR = msg
                Dim data As CopyData
    
                data.lpData = message
                data.cbData = Marshal.SizeOf(message)
    
                frmTest.SendMessage(ClientWindow, frmTest.WM_COPYDATA, Me.Handle, data)
                Return True
            Else
                Return False
            End If
    End Function
    
    Private Sub cmdSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSend.Click
           
                Dim msg As MsgSTR
                msg.code = Trim(txtCode.Text)
                msg.index1 = CInt(Trim(txtI1.Text))
                msg.index2 = CInt(Trim(txtI2.Text))
                ReDim msg.arr(40)
                For i = 0 To Trim(txtArr.Text).Split(" ").Length - 1
                    msg.arr(i) = CInt(Trim(txtArr.Text).Split(" ")(i))
                Next
    
    
    
                If mesajSMSSTR(msg) Then
                    MsgBox("Message sent")
                Else
                    MsgBox("Message not sent. Process not running.")
                End If
           
    End Sub
    Basically i have a structure with a string, two 32bit integers and an array of 32bit integers. I need to send this structure using WM_COPYDATA to an application made in VC++ 6.0, from my VB .NET 2008 framework 3.5.

    When i execute the code above, only the (first) string is sent. If i comment the lines related to Arr() (both in the structure and in the _click event), only the first 16 characters of my string are being sent.

    For testing purposes, the receiving application uses memcopy to get any data that is sent to it and displays it in a messagebox.

    I have searched google and these forums a lot for similar problems but everything i tried yielded the same result - the integer values are not sent at all.

    If i put 3 strings in my structure instead, only the first is sent. Adding a vbNullString to the end of the first string (MSGSTR.code) results in an empty message box in the receiving application.

    Any help is appreciated, thanks.
    Last edited by Crusader2010; November 16th, 2011 at 05:33 AM.

  2. #2
    Join Date
    Feb 2000
    Location
    OH - USA
    Posts
    1,892

    Arrow Re: Another WM_COPYDATA issue

    What immediately pops in to my head is that you should change the way that you're declaring the lpData member of CopyData, and then change the way that you pass the data along.

    Declare the lpData member as an IntPtr.

    Then pin your custom struct to memory so that it's available in it's entirety to your native application.

    You can see an example of this here:
    http://pinvoke.net/default.aspx/Stru...ATASTRUCT.html
    Code:
     public static IntPtr IntPtrAlloc<T>(T param)
          {
         IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
         Marshal.StructureToPtr(param, retval, false);
         return (retval);
          }
    
          public static void IntPtrFree(IntPtr preAllocated)
          {
         if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home"));
        Marshal.FreeHGlobal(preAllocated); preAllocated = IntPtr.Zero;
          }
    
          [StructLayout(LayoutKind.Sequential)]
          struct COPYDATASTRUCT
          {
         public UInt32 dwData;
         public int cbData;
         public IntPtr lpData;
          }
    
         IntPtr buffer = IntPtrAlloc(txStruct);
         COPYDATASTRUCT copyData = new COPYDATASTRUCT();
         copyData.dwData = 0xC0b1;
         copyData.lpData = buffer;
         copyData.cbData = Marshal.SizeOf(txStruct);
         IntPtr copyDataBuff= IntPtrAlloc(copyData);
         SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, copyDataBuff);
         IntPtrFree(copyDataBuff); copyDataBuff = IntPtr.Zero;
         IntPtrFree(buffer); buffer = IntPtr.Zero;
    It's not entirely clear, but in the example, your struct would go where the "txStruct" value is used.

    Here is some more light reading:
    http://msdn.microsoft.com/en-us/library/awbckfbz.aspx

    If none of this helps, my next guess would be to double back and make sure that you're treating your structure the same on both ends.
    Good Luck,
    Craig - CRG IT Solutions - Microsoft Gold Partner

    -My posts after 08/2015 = .NET 4.x and Visual Studio 2015
    -My posts after 11/2011 = .NET 4.x and Visual Studio 2012
    -My posts after 02/2010 = .NET 4.0 and Visual Studio 2010
    -My posts after 12/2007 = .NET 3.5 and Visual Studio 2008
    -My posts after 04/2007 = .NET 3.0 and Visual Studio 2005
    -My posts before 04/2007 = .NET 1.1/2.0

    *I do not follow all threads, so if you have a secondary question, message me.

  3. #3
    Join Date
    Aug 2010
    Posts
    50

    Re: Another WM_COPYDATA issue

    Thanks for the reply. I did try before to allocate memory for my structure and send it as a pointer and got the same result(no integers were sent), but i didn't try to also send the copyData structure as one. I'll get in touch with the other application's designer and see if we can work something out, after which i'll post here about the results.

    EDIT: i've made these changes(removed the array for now), but now the message is not sent at all:

    Code:
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
        Public Structure MsgSTR
            <MarshalAs(UnmanagedType.LPStr, sizeconst:=200)> Public code As String
            <MarshalAs(UnmanagedType.I4)> Public index1 As Integer
            <MarshalAs(UnmanagedType.I4)> Public index2 As Integer
            'Public arr() As Integer
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure CopyData
            Public dwData As IntPtr
            Public cbData As Integer
            Public lpData As IntPtr
        End Structure
    
        Private Declare Auto Function SendMessage Lib "user32" _
         (ByVal hWnd As IntPtr, _
          ByVal Msg As Integer, _
          ByVal wParam As IntPtr, _
          ByRef lparam As IntPtr) As Boolean
    
        Private Shared Function pALLOC(Of tip)(ByRef st As tip) As IntPtr
            Dim retval As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(st))
            Marshal.StructureToPtr(st, retval, False)
            Return retval
        End Function
    
        Private Shared Sub pFREE(ByRef p As IntPtr)
            If p <> IntPtr.Zero Then
                Marshal.FreeHGlobal(p)
                p = IntPtr.Zero
            End If
        End Sub
    
        Private Function mesajSMS(ByVal msg As MsgSTR) As Boolean
            Dim ClientWindow As IntPtr
            Dim a() As System.Diagnostics.Process = System.Diagnostics.Process.GetProcesses
    
            For Each p In a
                If UCase(p.ProcessName) = "PROCESSTEST" Then
                    ClientWindow = p.MainWindowHandle
                    Exit For
                End If
            Next
            ' make sure we found an active client window
            If Not ClientWindow.Equals(IntPtr.Zero) Then
                Dim data As New CopyData
                Dim buffer As IntPtr = pALLOC(Of MsgSTR)(msg)
    
                data.dwData = ClientWindow
                data.lpData = buffer
                data.cbData = Marshal.SizeOf(msg)
    
                Dim dataBuff As IntPtr = pALLOC(Of CopyData)(data)
    
                If frmTest.SendMessage(ClientWindow, frmTest.WM_COPYDATA, Me.Handle, dataBuff) Then
                    pFREE(dataBuff) : pFREE(buffer)
                    Return True
                Else
                    pFREE(dataBuff) : pFREE(buffer)
                    Return False
                End If
            Else
                Return False
            End If
        End Function
    
        Private Sub cmdTrimite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdTrimite.Click
    
                Dim msg As New MsgSTR
                msg.code = Trim(txtCode.Text)
                msg.index1 = CInt(Trim(txtIndex1.Text))
                msg.index2 = CInt(Trim(txtIndex2.Text))
    
                If mesajSMS(msg) Then
                    MsgBox("Sent")
                Else
                    MsgBox("Not Sent")
                End If
             
           End Sub
    The process window is found correctly but the SendMessage function returns false for some reason. Any ideas? thank you.
    Last edited by Crusader2010; November 21st, 2011 at 09:56 AM.

  4. #4
    Join Date
    Feb 2000
    Location
    OH - USA
    Posts
    1,892

    Arrow Re: Another WM_COPYDATA issue

    I am able to get this to run. Are you absolutely certain that the target hwnd is correct and that the struct definition is identical on the native side?

    At the very least, you should be seeing the WM_COPYDATA message at the target (whether the payload is well-formed or not is another question).
    Good Luck,
    Craig - CRG IT Solutions - Microsoft Gold Partner

    -My posts after 08/2015 = .NET 4.x and Visual Studio 2015
    -My posts after 11/2011 = .NET 4.x and Visual Studio 2012
    -My posts after 02/2010 = .NET 4.0 and Visual Studio 2010
    -My posts after 12/2007 = .NET 3.5 and Visual Studio 2008
    -My posts after 04/2007 = .NET 3.0 and Visual Studio 2005
    -My posts before 04/2007 = .NET 1.1/2.0

    *I do not follow all threads, so if you have a secondary question, message me.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured