WM_COPYDATA with .net and c

WM_COPYDATA with .net and c

WM_COPYDATA is a window message that you can use as a very simple ipc(Inter Process Communication) mechanism. There are some small issues to overcome when using this with .net, the least of which is the need to use the user32.dll in .net.

WM_COPYDATA with .net and c Details

So you are still reading which means either you are really interested in what I have to say or possibly you can’t get the issue solved yourself.

To help you along:

The Copy Data Structure

The copy data struct layout in c# and vb.net can be found here

The SendMessage function

The SendMessage import information can be found here

The PostMessage function

The PostMessage import information can be found here

The FindWindow function

The FindWindow import information can be found here

The Principles

The basic principle behind using WM_COPYDATA is to find the window handle for the window you want to send data to using FindWindow, checking the result, then Calling either PostMessage or SendMessage with the window handle and a CopyDataStruct filled in.

Some hurdles for sending the data include marshaling the data properly, and formatting the data properly. To properly Marshal, you need to first import System.Runtime.Interop namespace, then make sure that you use the pair of memory functions that suit allocating and deallocating memory. You can use CoTaskAlloc, or GlobalAlloc variants. You may also use string or structure specific functions.

Once these hurdles are out of the way, you are usually presented with some issues in terms of windows 7 and UIPI. There is some background information on UIPI(User Interface Privilege Isolation) here and here. The workaround is to use the ChangeWindowMessageFilter function found here or the extended version here

The final missing piece depends on if you are using any processor, x86 or x64. The details using these different functions requires specific handling for the structure. Essentially if you are using the any processor or x64 you may have to use IntPtr or long, but for x86 you can use int for the dwData.

using System;
using System.Runtime.InteropServices;

namespace SendWindowMessage
{
    class Program
    {
        const int WM_COPYDATA = 0x004A;
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll")]
        static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [System.Runtime.InteropServices.DllImport("user32.dll",CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hwnd, int msg,IntPtr wparam, IntPtr lparam);
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
        [StructLayout(LayoutKind.Sequential)]
        struct COPYDATASTRUCT
        {
            public uint dwData;
            public int cbData;
            public IntPtr lpData;
        }
        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;
        }

        static void Main(string[] args)
        {

            string message = "This is a test" ;
            IntPtr hWnd = FindWindow("Example", "" );
            if ( hWnd == IntPtr.Zero){

            }else{

                COPYDATASTRUCT cds ;
                cds.dwData = 1;
                cds.cbData = message.Length + 1;
                cds.lpData = Marshal.StringToHGlobalAnsi(message);
                IntPtr cdsBuffer = IntPtrAlloc ( cds ) ;
                PostMessage(hWnd, WM_COPYDATA, IntPtr.Zero, cdsBuffer);
                IntPtrFree(cds.lpData);
                IntPtrFree(cdsBuffer);
            }
        }
    }
}
#include <tchar.h>
#include <windows.h>

#define WND_CLASS_NAME _T ( "Example" )

LRESULT CALLBACK WndProc (  HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) ;

int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ){
	WNDCLASSEX ex ;
	MSG msg ;
	ex.cbClsExtra = 0 ;
	ex.cbSize = sizeof ( WNDCLASSEX ) ;
	ex.cbWndExtra = 0 ;
	ex.hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
	ex.hCursor = LoadCursor ( NULL, _T ( "IDC_ARROW" ) ) ;
	ex.hIcon = LoadIcon ( NULL, _T ( "IDI_APPLICATION" ) ) ;
	ex.hIconSm = LoadIcon ( NULL, _T( "IDI_APPLICATION" ) ) ;
	ex.hInstance = hInstance ;
	ex.lpfnWndProc = (WNDPROC )WndProc ;
	ex.lpszClassName = WND_CLASS_NAME ;
	ex.lpszMenuName = NULL ;
	ex.style = 0 ;
	if ( !RegisterClassEx ( &ex ) ){
		return 0 ;
	}
	HWND hWnd = CreateWindow ( WND_CLASS_NAME, _T ( "" ), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ) ;
	if ( !hWnd ){
		UnregisterClass ( WND_CLASS_NAME, hInstance ) ;
		return 0 ;
	}

	ShowWindow(hWnd, SW_HIDE ) ;
	UpdateWindow ( hWnd ) ;
	if ( !ChangeWindowMessageFilter ( WM_COPYDATA, MSGFLT_ADD ) ){
		MessageBox ( HWND_DESKTOP, _T("Failed to change message filter"),_T("STATUS"), MB_OK ) ;
	}
	while ( TRUE ) {
		UINT res = GetMessage ( &msg, hWnd, 0, 0 ) ;
		if ( res == 0 ){
			break ;
		}else if ( res <0){

		}else{
			DispatchMessage ( &msg ) ;
		}
	}

	return 0 ;
}

LRESULT CALLBACK WndProc (  HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ){
	PCOPYDATASTRUCT pcds;
	switch ( uMsg ){
		case WM_CREATE :
		break ;
		case WM_COPYDATA :
			pcds=(PCOPYDATASTRUCT)lParam;
			if ( pcds->cbData > 0 && pcds->cbData < 512 ){
				if ( pcds->dwData == 1 ){
					((CHAR*)pcds->lpData)[pcds->cbData-1] = '\0' ;
					MessageBoxA ( HWND_DESKTOP, (LPCSTR)pcds->lpData, "STATUS", MB_OK ) ;
				}else if ( pcds->dwData == -1 ){
					((CHAR*)pcds->lpData)[pcds->cbData-1]= L'\0' ;
					MessageBoxW ( HWND_DESKTOP, (LPCWSTR)pcds->lpData, L"STATUS", MB_OK ) ;
				}
			}

		break ;
		case WM_DESTROY :
			PostQuitMessage(0);
		default :
			return DefWindowProc ( hWnd, uMsg, wParam, lParam ) ;
	}
	return 0L ;

}
ttessier

About ttessier

Professional Developer and Operator of SwhistleSoft
This entry was posted in Applications Development, C Programming, C#.net. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *