1

Имеется программа, рассылающая сообщения на c++.

Сообщение

В WPF принимаю следующим образом:

public static void RegisterWindowMessage(this Window window, string lpString, Action<string> action)
{
    _action = action;
    _msg = RegisterWindowMessage(lpString);
    var source = HwndSource.FromHwnd(new WindowInteropHelper(window).Handle);
    source?.AddHook(WndProc);
}

И обработка Hook:

private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == _msg)
    {
        _action(lParam.ToString());
    }
return IntPtr.Zero;

}

Возникла задача перенести проект на MAUI. Соответственно решил сделать тоже самое через WinApi:

[DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, IntPtr dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName);

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern uint RegisterWindowMessage(string lpString);

[DllImport("kernel32.dll")] private static extern IntPtr GetCurrentThreadId();

public static void RegisterWindowMessage(string lpString, Action<string> action) { _action = action; _msg = RegisterWindowMessage(lpString.ToString()); //49824

  HoockProc = new HookProc(HookCallback);

  ProcessModule module = Process.GetCurrentProcess().MainModule;
  IntPtr hModule = GetModuleHandle(module.ModuleName);

  IntPtr hwnd = ((MauiWinUIWindow)App.Current.Windows[0].Handler.PlatformView).WindowHandle;

  MainThread.BeginInvokeOnMainThread(() =&gt;
  {
      var WH_MSGFILTER = SetHook(HookTypes.WH_MSGFILTER, HoockProc);
      var WH_MSGFILTERErrorCode = Marshal.GetLastWin32Error();

      var WH_CALLWNDPROC = SetHook(HookTypes.WH_CALLWNDPROC, HoockProc);
      var WH_CALLWNDPROCErrorCode = Marshal.GetLastWin32Error();

      var WH_CALLWNDPROCRET = SetHook(HookTypes.WH_CALLWNDPROCRET, HoockProc);
      var WH_CALLWNDPROCRETErrorCode = Marshal.GetLastWin32Error();

      var WH_KEYBOARD = SetHook(HookTypes.WH_KEYBOARD, HoockProc);
      var WH_KEYBOARDErrorCode = Marshal.GetLastWin32Error();

      var WH_KEYBOARD_LL = SetHook(HookTypes.WH_KEYBOARD_LL, HoockProc, false);
      var WH_KEYBOARD_LLErrorCode = Marshal.GetLastWin32Error();

      var WH_MOUSE = SetHook(HookTypes.WH_MOUSE, HoockProc);
      var WH_MOUSE_ErrorCode = Marshal.GetLastWin32Error();

      var WH_MOUSE_LL = SetHook(HookTypes.WH_MOUSE_LL, HoockProc, false);
      var WH_MOUSE_LLErrorCode = Marshal.GetLastWin32Error();

      var WH_JOURNALRECORD = SetHook(HookTypes.WH_JOURNALRECORD, HoockProc, false);//
      var WH_JOURNALRECORDErrorCode = Marshal.GetLastWin32Error();

      var WH_JOURNALPLAYBACK = SetHook(HookTypes.WH_JOURNALPLAYBACK, HoockProc, false);//
      var WH_JOURNALPLAYBACKErrorCode = Marshal.GetLastWin32Error();

      var WH_FOREGROUNDIDLE = SetHook(HookTypes.WH_FOREGROUNDIDLE, HoockProc);
      var WH_FOREGROUNDIDLEKErrorCode = Marshal.GetLastWin32Error();

      var WH_SYSMSGFILTER = SetHook(HookTypes.WH_SYSMSGFILTER, HoockProc, false, false);//
      var WH_SYSMSGFILTERErrorCode = Marshal.GetLastWin32Error();

      var WH_GETMESSAGE = SetHook(HookTypes.WH_GETMESSAGE, HoockProc);
      var WH_GETMESSAGEErrorCode = Marshal.GetLastWin32Error();

      var WH_CBT = SetHook(HookTypes.WH_CBT, HoockProc);
      var WH_CBTErrorCode = Marshal.GetLastWin32Error();

      var WH_HARDWARE = SetHook(HookTypes.WH_HARDWARE, HoockProc);
      var WH_HARDWAREErrorCode = Marshal.GetLastWin32Error();

      var WH_DEBUG = SetHook(HookTypes.WH_DEBUG, HoockProc);
      var WH_DEBUGErrorCode = Marshal.GetLastWin32Error();

      var WH_SHELL = SetHook(HookTypes.WH_SHELL, HoockProc);
      var WH_SHELLErrorCode = Marshal.GetLastWin32Error();
  });


  //_hookId = SetWindowsHookEx((int)HookTypes.WH_GETMESSAGE, HoockProc, nint.Zero, GetCurrentThreadId());

}

    #endregion

private static IntPtr SetHook(HookTypes typeOfHook, HookProc callBack, bool onThread = true, bool onDescriptor = false)
    {
        IntPtr hwnd = ((MauiWinUIWindow)App.Current.Windows[0].Handler.PlatformView).WindowHandle;

        var descriptor = onDescriptor ? hwnd : IntPtr.Zero;
        var thread = onThread ? GetCurrentThreadId() : nint.Zero;

        return SetWindowsHookEx((int)typeOfHook, callBack, descriptor, thread);

        //IntPtr hInstance = LoadLibrary(&quot;User32&quot;);
        using (Process currentProcess = Process.GetCurrentProcess())
        using (ProcessModule currentModule = currentProcess.MainModule)
        {
            if (onThread)
                return SetWindowsHookEx((int)typeOfHook, callBack, IntPtr.Zero, GetCurrentThreadId());
            else
                return SetWindowsHookEx((int)typeOfHook, callBack, 0, 0);
                //return SetWindowsHookEx((int)typeOfHook, callBack, GetModuleHandle(currentModule.ModuleName), 0);
}

}

private static IntPtr HookCallback(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam) { // Ваш обработчик сообщений

Debug.WriteLine($&quot;{hwnd} - {message} - {lParam} - {wParam}&quot;);

//_action?.Invoke(message);

return IntPtr.Zero; }

Вывод в debug:

введите сюда описание изображения

Обрабатывает сообщения мыши, клавиатуры, работу с окном, но не видит этих сообщений.

Как можно изменить код, чтобы прилетели сообщения?

Denis
  • 867
  • Проблема в отправке, а не в приёме. Не туда отправляете. А вообще можно WM не использовать в принципе, это громоздско и неудобно. Используйте например Named Pipe для обмена данными между приложениями. – aepot Mar 30 '23 at 12:55
  • Кстати, в WPF оно как-то проще делалось https://ru.stackoverflow.com/a/1442172/373567, в смысле навешивание своего обработчика на WM. – aepot Mar 30 '23 at 13:34

1 Answers1

0

Я сделал это с помощью WinAPI, создав пустое невидимое окно внутри Maui Blazor.

internal class Win32
{
    public const uint WM_DESTROY = 0x0002;
    public const uint WM_CREATE = 0x0001;
    public const uint WM_PAINT = 0x000F;
public const uint WS_OVERLAPPED = 0x00000000;
public const uint WS_MAXIMIZEBOX = 0x00010000;
public const uint WS_MINIMIZEBOX = 0x00020000;
public const uint WS_THICKFRAME = 0x00040000;
public const uint WS_SYSMENU = 0x00080000;
public const uint WS_CAPTION = 0x00C00000;
public const uint WS_VISIBLE = 0x10000000;
public const uint WS_OVERLAPPEDWINDOW =
    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU 

| WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;

public const uint IDI_APPLICATION = 32512;

public const uint IDC_ARROW = 32512;

public const uint COLOR_WINDOW = 5;

public const uint MB_OK = 0x00000000;
public const uint MB_ICONEXCLAMATION = 0x00000030;
public const uint MB_SETFOREGROUND = 0x00010000;

//public const uint CW_USEDEFAULT = 0x80000000;

public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

/*
public enum GetWindowLongConst
{
    GWL_WNDPROC = (-4),
    GWL_HINSTANCE = (-6),
    GWL_HWNDPARENT = (-8),
    GWL_STYLE = (-16),
    GWL_EXSTYLE = (-20),
    GWL_USERDATA = (-21),
    GWL_ID = (-12)
}
 * */

[Flags]
public enum ClassStyles : uint
{
    ByteAlignClient = 0x1000,
    ByteAlignWindow = 0x2000,
    ClassDC = 0x40,
    DoubleClicks = 0x8,
    DropShadow = 0x20000,
    GlobalClass = 0x4000,
    HorizontalRedraw = 0x2,
    NoClose = 0x200,
    OwnDC = 0x20,
    ParentDC = 0x80,
    SaveBits = 0x800,
    VerticalRedraw = 0x1
}

public enum MessageBoxResult : uint
{
    Ok = 1,
    Cancel,
    Abort,
    Retry,
    Ignore,
    Yes,
    No,
    Close,
    Help,
    TryAgain,
    Continue,
    Timeout = 32000
}

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int X;
    public int Y;

    public POINT(int x, int y)
    {
        X = x;
        Y = y;
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
    public int cx;
    public int cy;

    public SIZE(int cx, int cy)
    {
        this.cx = cx;
        this.cy = cy;
    }
}

public struct MSG
{
    public IntPtr hwnd;
    public uint message;
    public IntPtr wParam;
    public IntPtr lParam;
    public uint time;
    public POINT pt;
}

[StructLayout(LayoutKind.Sequential)]
public struct PAINTSTRUCT
{
    public IntPtr hdc;
    public bool fErase;
    public RECT rcPaint;
    public bool fRestore;
    public bool fIncUpdate;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public byte[] rgbReserved;
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int left, top, right, bottom;
}

[StructLayout(LayoutKind.Sequential)]
public struct WNDCLASSEX
{
    public uint cbSize;
    public ClassStyles style;
    [MarshalAs(UnmanagedType.FunctionPtr)]
    public WndProc lpfnWndProc;
    public int cbClsExtra;
    public int cbWndExtra;
    public IntPtr hInstance;
    public IntPtr hIcon;
    public IntPtr hCursor;
    public IntPtr hbrBackground;
    public string lpszMenuName;
    public string lpszClassName;
    public IntPtr hIconSm;
}

[DllImport(&quot;user32.dll&quot;)]
public static extern sbyte GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin,
   uint wMsgFilterMax);

[DllImport(&quot;user32.dll&quot;)]
public static extern IntPtr DispatchMessage(ref MSG lpmsg);

[DllImport(&quot;user32.dll&quot;)]
public static extern bool TranslateMessage(ref MSG lpMsg);

//[DllImport(&quot;user32.dll&quot;, EntryPoint = &quot;GetWindowLong&quot;)]       // 32 bits only
//public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);

[DllImport(&quot;user32.dll&quot;)]
public static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint);

[DllImport(&quot;user32.dll&quot;)]
public static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint);

[DllImport(&quot;user32.dll&quot;)]
public static extern void PostQuitMessage(int nExitCode);

[DllImport(&quot;user32.dll&quot;)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);

[DllImport(&quot;user32.dll&quot;, SetLastError = true)]
public static extern IntPtr GetDC(IntPtr hWnd);

[DllImport(&quot;user32.dll&quot;)]
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

[DllImport(&quot;user32.dll&quot;)]
public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);

[DllImport(&quot;user32.dll&quot;)]
public static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);


[DllImport(&quot;user32.dll&quot;, CharSet = CharSet.Unicode)]
public static extern MessageBoxResult MessageBox(IntPtr hWnd, string text, string caption, int options);

[DllImport(&quot;user32.dll&quot;, SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateWindowEx(
   uint dwExStyle,
   string lpClassName,
   string lpWindowName,
   uint dwStyle,
   int x,
   int y,
   int nWidth,
   int nHeight,
   IntPtr hWndParent,
   IntPtr hMenu,
   IntPtr hInstance,
   IntPtr lpParam);

[DllImport(&quot;user32.dll&quot;, SetLastError = true)]
public static extern short RegisterClassEx(ref WNDCLASSEX lpwcx);

//[DllImport(&quot;gdi.dll&quot;)]
//public static extern bool GetTextExtentPoint(IntPtr hdc, string lpString, int cbString, out SIZE lpSize);

[DllImport(&quot;user32.dll&quot;, SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint RegisterWindowMessage(string lpString);

[DllImport(&quot;gdi32.dll&quot;, CharSet = CharSet.Unicode)]
public static extern bool TextOut(IntPtr hdc, int nXStart, int nYStart,
   string lpString, int cbString);

//[DllImport(&quot;gdi32.dll&quot;, CharSet = CharSet.Auto)]
//public static extern bool GetTextMetrics(IntPtr hdc, out TEXTMETRIC lptm);

}

internal static class WindowExtensions {

#region Private static fields

private static Action&lt;nint&gt; _action;
private static uint _msgId;

#endregion

private static readonly string AppName = &quot;DrawHello Program&quot;;
private static readonly string ClassName = &quot;DrawHelloClass&quot;;
private static IntPtr hWnd;

#region Public methods

public static void RegisterWindowMessage(string lpString, Action&lt;nint&gt; action)
{
    _action = action;
    _msgId = Win32.RegisterWindowMessage(lpString.ToString());

    WNDCLASSEX wcex = new()
    {
        style = ClassStyles.DoubleClicks
    };
    wcex.cbSize = (uint)Marshal.SizeOf(wcex);
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    //wcex.hIcon = Win32.LoadIcon(IntPtr.Zero, (IntPtr)Win32.IDI_APPLICATION);
    //wcex.hCursor = Win32.LoadCursor(IntPtr.Zero, (int)Win32.IDC_ARROW);
    wcex.hIconSm = IntPtr.Zero;
    //wcex.hbrBackground = (IntPtr)(Win32.COLOR_WINDOW + 1);
    wcex.lpszMenuName = null;
    wcex.lpszClassName = ClassName;

    if (RegisterClassEx(ref wcex) == 0)
    {
        _ = MessageBox(IntPtr.Zero, &quot;RegisterClassEx failed&quot;, AppName,
            (int)(MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND));
        return;
    }

    //uint visible = Win32.WS_OVERLAPPEDWINDOW | Win32.WS_VISIBLE;
    uint invisible = 0;

    var x = 0; // 250;
    var y = 0; // 250;
    var w = 0; // 250;
    var h = 0; // 250;
    hWnd = CreateWindowEx(0, ClassName, AppName, invisible,
        x, y, w, h, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

    if (hWnd == IntPtr.Zero)
    {
        _ = MessageBox(
            IntPtr.Zero, &quot;CreateWindow failed&quot;, AppName, 
            (int)(Win32.MB_OK | Win32.MB_ICONEXCLAMATION | Win32.MB_SETFOREGROUND));
        return;
    }

    // Main message loop:
    /*int rv;
    while ((rv = GetMessage(out MSG Msg, IntPtr.Zero, 0, 0)) &gt; 0)
    {
        _ = Win32.TranslateMessage(ref Msg);
        _ = Win32.DispatchMessage(ref Msg);
    }*/
}

private static IntPtr WndProc(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam)
{
    if (message == _msgId)
    {
        _action?.Invoke(lParam);
    }
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            return IntPtr.Zero;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

#endregion

}

0xdb
  • 51,614
Denis
  • 867