2
\$\begingroup\$

I'm trying to render my game (SDL2, C++) in a Windows Form application (C#) using C++/CLI to interface with my underlying C++ code. The purpose of the form is to create an editor which can monitor/adjust/interact with the game, however the game is also executable without the form.

To do this I'm using the SDL_CreateWindowFrom function (which takes the handle to the form panel). This works fine for actually rendering to the panel, however I'm not receiving any events when calling SDL_PollEvents. When I use SDL_WaitEvent instead I do receive SDL_SYSWMEVENT's but this isn't ideal (as this means my renderer will be stalled while waiting for events AND I would have to process raw windows message events (e.g. WM_KEYDOWN)).

Is there a way to allow SDL to receive (particularly important: input) events from an external window? Is there a way to override the WndProcHandler that SDL uses? Or is there an entirely different approach I should be taking?

Thanks a lot!

\$\endgroup\$
2
\$\begingroup\$

This is probably not the approach you want to take. Normally this kind of "render my engine into a HWND" technique accomplishes input handling by having the other HWND's process (the C# application in this case) send the relevant events back to your engine process via some kind of backchannel, such as a socket connection. It's generally an easier-to-deal-with technique.


That said, if you're set on monitoring the events directly, look into SetWindowsHookEx. That function allows you to inject a hook function that is called with before (WH_CALLWNDPROC) or after (WH_CALLWNDPROCRET) they have been processed by the target windows WNDPROC. You need to give the function a hook type (one of the two previous constants) and a hook function, which must look like:

LRESULT CALLBACK HookFunction(int code, WPARAM wparam, LPARAM lparam);

Your hook function will be called with the appropriate window message and parameters as given in the hook function signature. Be aware that your placement of the hook before or after the target window procedure impacts how you must handle the resulting messages, as the window may or may not have done things to reflect state differently based on whatever its own WNDPROC wants to do. You also may not be permitted to take action when your hook is called (if the code is negative, you must immediately invoke and return the value of CallNextHookEx.

Also, you'll need to put your hook code into shared memory since you're not hooking something in your own thread, and you'll need to be aware of the bitness (32 or 64) of both processes, because they have to match.

Overall it can be a bit tricky to deal with. There are some good posts on StackOverflow about using SetWindowsHookEx in various ways, such as this one dealing with the shared memory issue.


Since you control all the code involved here (as I understand it), I think you should avoid the trouble of SetWindowsHookEx and go with a socket-based approach. Alternatively you can create a control in the C++/CLI interop layer that talks directly to your engine code and manually pumps events for it using a variant of an Application.Idle event listener. That may require some rejiggering of how your engine's core loop is coupled to SDL_PollEvents though, so it's hard to say for sure how much work is involved without seeing more of your code.

\$\endgroup\$
  • \$\begingroup\$ Could you explain to me what the difference is between the socket based approach and the C++/CLI interface approach? (By the latter I suppose you mean I create a list where it stores the unhandled events in the form, then forward it on a custom 'poll' it using a self written method that queries this list in the C++/CLI code?) Most of the code I've written for this so far is pretty trivial, in the C# I creating a custom 'GamePanel' control which contains an instance of Engine (C++/CLI), then on Application.Idle I simply call engine.Step(deltaTime) and gpanel_main.Invalidate() \$\endgroup\$ – PhilipMR Jun 9 '16 at 18:09
  • \$\begingroup\$ I mean "socket" as in a networking socket; you communicate between the two processes as if you were talking over a network (although in practice you just connect via localhost). The C++/CLI approach, as you noted, all basically stays in-process and doesn't use networking. \$\endgroup\$ – Josh Jun 9 '16 at 18:24
  • \$\begingroup\$ Thanks! This has been helpful, I went with the C++/CLI approach as it seems faster/easier to implement. I made it so that when a key down event occurs, the C# code will execute engine.RegisterKeyDown((int)e.Keys); Then from the C++/CLI code all I have to do is build the SDL_Event and call SDL_PushEvent, works like a charm! \$\endgroup\$ – PhilipMR Jun 9 '16 at 18:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.