4

I have recently been trying to develop a simple WPF application in C#, and I need to be able to get the HwndSource of a window so I can add an event handler. Everytime I run the code, I get stopped on handleSource = HwndSource.FromHwnd(handle); and I get the error System.ArgumentException: 'Hwnd of zero is not valid.'. From my understanding, this happens when the window is not fully initialized or there is no window, or it is being destructed. If I have learned correctly, than I have no idea how this is happening.
I have not found anyone else with the same problem from googling, and my code is below.

public partial class MainWindow:Window {

        SimConnect simConnect;
        bool connectedToSim = false;

        /// Window handle
        IntPtr handle;
        HwndSource handleSource;

        const int WM_USER_SIMCONNECT = 0x0402;

        /// <summary>
        /// Constructor and starting for the window
        /// </summary>
        public MainWindow() {
            InitializeComponent();

            handle = new WindowInteropHelper(this).Handle; // Get handle of main WPF Window
            handleSource = HwndSource.FromHwnd(handle); // Get source of handle in order to add event handlers to it
            handleSource.AddHook(HandleSimConnectEvents);

            Thread pollThread = new Thread(PollThread);
        }

        ~MainWindow() {
            if (handleSource != null) {
                handleSource.RemoveHook(HandleSimConnectEvents);
            }
        }

        private IntPtr HandleSimConnectEvents(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool isHandled) {
            isHandled = false;

            switch (message) {
                case WM_USER_SIMCONNECT: {
                        if (simConnect != null) {
                            simConnect.ReceiveMessage();
                            isHandled = true;
                        }
                    }
                    break;

                default:
                    break;
            }

            return IntPtr.Zero;
        }
    }

Any help would be appreciated, Thanks!

Pseudonym Patel
  • 469
  • 7
  • 16
  • My gut feeling is you might want to call `EnsureHandle` at that point in the *life cycle*, ie construction "*If the native window has not yet been created, this method creates the native window, sets the Handle property, and returns the HWND. If the native window has been created already, the handle of the existing native window is returned.*" – TheGeneral Sep 19 '20 at 00:48

2 Answers2

4

You will likely want to make use of EnsureHandle at that point in the window lifecycle (i.e. construction). The call is light and you won't need to wait for the form to show and have a dependency on an event to get access to the handle (if that suits your workflow)

WindowInteropHelper.EnsureHandle Method

Creates the HWND of the window if the HWND has not been created yet.

Remarks

Use the EnsureHandle method when you want to separate window handle (HWND) creation from the actual showing of the managed Window...

If the native window has not yet been created, this method creates the native window, sets the Handle property, and returns the HWND. If the native window has been created already, the handle of the existing native window is returned.

halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
1

Move the code from the constructor of the class to the first invocation of the Shown event as explained in this question: Window shown event in WPF?

The window handle is guaranteed to be there once the window is shown. And you usually don't want to enforce the window handle to be created as early as in the constructor as suggested by Michael Randall's suggestion to use EnsureHandle.

NineBerry
  • 26,306
  • 3
  • 62
  • 93
  • 1
    Maybe this is a stupid question but why wouldn't you want to want to enforce the window handle to be created? ie. What are the downsides to EnsureHandle? – Pseudonym Patel Sep 19 '20 at 11:38
  • The ctor is where the window is being constructed. Before the ctor there is no window to have any handle. During the ctor the window can't have appeared so it won't have a handle. After the window is shown, there has to be a window which will have a handle. Hence, i would think shown seems the obvious choice. – Andy Sep 19 '20 at 12:51
  • @Andy but this seems to be the exact type of circumstance for which EnsureHandle was added to the framework. The (small) disadvantage of using Shown is that it adds complexity which may be unneeded. If there is some other reason to avoid EnsureHandle in the ctor that would be useful to detail in this answer, right now it just reads like an assertion without a rationale. – StayOnTarget Sep 21 '20 at 14:19
  • The circumstance Ensurehandle was added for is explained in the docs. "This is useful when you have an automation client that can accomplish its tasks without the need for showing a window." You should always minimise the code goes in any ctor and this is especially true for mainwindow. If there's any sort of a problem in your code then you get an error in the ctor. If the mainwindow ctor fails then you have no app, – Andy Sep 21 '20 at 14:37