Message Loop and WM_INPUT
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 19/12/2010 at 12:01, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 12
Platform: Windows ;
Language(s) : C++ ;---------
Hello;hopefully someone can explain away the following problem once and for all. There are a few threads on the forum that point into the same direction but as far as I can see, none addresses the core issue (or maybe I'm just too dumb...)
Situation: I want to get system messages (here: Windows) but for obvious reasons not through busy loops, active polls, secondary libraries or parallel threads, but through the clean and safe system methods.
Under Windows, I normally derive my window class, add a message map, and use a callback that will be called when the desired message is present.
Unfortunately, GeDialog is not derived from the proper Windows class, and thus I cannot derive it and overload/expand the message map. I assume that isn't possible with other means since GeDialog is system independent.
GeDialog does provide a method that returns the handle of the window, but I'm not sure whether this is the real Windows handle or some other descriptor, and anyway, by the time I can access the handle, the window has already been created. I would need to inject the message map and callback handler after the window has been created already, not sure whether there is a clean way to do this.
The standard messaging system in C4D is not equivalent to the Windows messaging, so I can't really expect to get WM_xxx messages here, can I?
I could probably open a normal Windows window to receive the messages - provided the messages are routed through an inactive window's message map at all -, but I am pretty sure that this is not necessary.
The built-in 3Dconnexion SpaceMouse dialog does something like this. Even more, since R12 you don't even have to have the dialog open any more to make the SpaceMouse work. How? (Incidentally, it's precisely the SpaceMouse I want to poll - the provided example from the 3Dconnexion website does use WM_INPUT messages through the standard Windows class system though, and I'm missing the proper join to the C4D system.)
Currently, I don't even know what direction I should think in. Any pointers, so I won't waste my time with testing stuff that cannot work anyway?
Thanks.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/12/2010 at 02:20, xxxxxxxx wrote:
I will look into it.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/12/2010 at 09:17, xxxxxxxx wrote:
Thank you.
And since it's a necessary prerequisite, how can Windows and MFC libraries be included at all? I was sure there had been a guide for that problem once, but my memory seems to mislead me. Including Windows headers with separate files is no problem, but to achieve any useful results at all, I need to access both Windows and C4D headers. This leads to doubled #defines (which I can #undefine, but that's rude) and/or to doubled link functions (new and delete are the most prominent culprits).
What's the recommended way inside of a C4D C++ plugin to include Windows/MFC functionality?
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/12/2010 at 13:23, xxxxxxxx wrote:
I'm afraid an answer has to wait for after the Christmas and New Year holidays as most people at MAXON are taking a break between the holidays. Sorry for the inconvenience.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 22/12/2010 at 23:35, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Thank you.
And since it's a necessary prerequisite, how can Windows and MFC libraries be included at all? I was sure there had been a guide for that problem once, but my memory seems to mislead me. Including Windows headers with separate files is no problem, but to achieve any useful results at all, I need to access both Windows and C4D headers. This leads to doubled #defines (which I can #undefine, but that's rude) and/or to doubled link functions (new and delete are the most prominent culprits).
What's the recommended way inside of a C4D C++ plugin to include Windows/MFC functionality?
hello,
have you seen melange library... there is an example that use mfc tu render using cinema4d inside a native mfc windows.all the best
Franz -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 23/12/2010 at 01:47, xxxxxxxx wrote:
Ah, interesting. I had a late R12 update, so I haven't looked into Melange yet, but now I certainly will! Thanks for the tip!
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/12/2010 at 05:03, xxxxxxxx wrote:
Had a look into Melange, but it seems to do things in the opposite way: you define a Windows window and then call C4D functionality - or more correct: Melange library functionality - inside of it. What I'd need is the opposite: the plugin code runs inside a window that C4D already has generated (and therefore has control over).
But Melange at least helped me to access Windows: While it still causes errors to access MFC through an import of afxwin.h and afxext.h, it is easily possible to include the non-MFC basic Windows libraries:
#include <tchar.h> #include <windows.h> #include <vfw.h> #include <stdio.h>
Since - for all of my purposes - MFC is just a OO class wrapper around the Windows function calls, this will suffice for my current needs to access the window.
And the handle that is returned by GetWindowHandle() in GeDialog is indeed the Windows HWND, so you can write:
void* handle = GetWindowHandle(); char mytitle[500]; GetWindowText((HWND)handle,mytitle,499); GePrint (mytitle);
This does not solve the original question, though: Windows does not permit changes to the event procedure as far as I can see - a sensible limitation for an OS, but it would force me to go through a self-defined window as child of my dialog to receive messages at all. Maybe not quite a hack, but I still believe the C4D programmers did it differently...
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/12/2010 at 04:37, xxxxxxxx wrote:
Okay, just in case somebody wants to follow my little quest, here's what I came up with so far:
Since I cannot currently access messages from the original C4D windows system, since I don't control their message loops or inject any callbacks, I need to open my own Windows window to provide the message loop.
Since the message loop will Wait for messages to arrive (in GetMessage()), I cannot implement the loop in the main thread. This would either take over control from C4D (by receiving all messages), or block the C4D system (by receiving only my own window's messages). The first method does not work; C4D does a lot of idle processing that my loop wouldn't cover (believe me, I tried...); the second method is obvious bulls**t since the window would be application modal.
Okay, so I need my own thread. This thread includes basic Windows libraries. It defines a class derived from C4DThread. Its Main() function first opens a window, then registers raw input device messages with that window, then goes into the message loop of this window and stays there (GetMessage/TranslateMessage/DispatchMessage).
And lo! the window is receiving messages from the SpaceNavigator!
Now the crappy thing is that a Windows message loop does not look for the TestBreak() method that a C4D thread uses to check for termination. It cannot, because it is stuck in GetMessage(). TestBreak() does only work for a busy thread, where the execution loop passes this call every now and then.
I just don't want to change the message loop behavior. GetMessage() ensures that the thread will only consume processing time when actual messages are present. Using a busy loop just to make sure the thread can be terminated at any time is really wasteful.
So, the thread is controlled in the following way: One (global, public) method creates the thread object and starts the thread. The other first calls End(FALSE) on the thread (asynchronously) to set the thread-termination flag. Then it sends a dummy message to the window, so the message loop wakes up from the GetMessage() sleep. The loop then polls the termination flag and calls DestroyWindow(). [Just for the record, the outside method cannot simply Destroy the window because that function works only with windows belonging to the same thread!] The outside function meanwhile waits for the thread to end, and finally deletes the thread object.
There are a few other details to make sure termination stuff is not called twice and whatnot, but this seems to work. The Windows window can even be switched to SW_HIDE to be invisible; the SpaceMouse input is still read. C4D terminates; the thread is deleted correctly at the end of the program; memory is freed, and there are no object corpses left after the application ends.
... This is, of course, not what I wanted to do - using an invisible main window certainly feels like a hack to me -, and it's Windows only, no Mac allowed... but if I don't get a cleaner solution by the developers, at least it's a way to capture these pesky raw system messages that I want.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 29/12/2010 at 09:33, xxxxxxxx wrote:
Originally posted by xxxxxxxx
This does not solve the original question, though: Windows does not permit changes to the event procedure as far as I can see - a sensible limitation for an OS, but it would force me to go through a self-defined window as child of my dialog to receive messages at all. Maybe not quite a hack, but I still believe the C4D programmers did it differently...
Did you try SetWindowLong(GWL_WNDPROC, YourWndproc)?
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 29/12/2010 at 12:51, xxxxxxxx wrote:
Interesting idea... it would chain my handling into the existing window's handling; however, would this break the message loop of a C4D window? I'm not sure since I don't have any code from the original C4D app.
Also, this would need to change the main window's loop itself since changes in the layout lead to the creation and destruction of the Windows window framework... e.g. a dialog that becomes embedded in a layout will not have a window of its own but returns the HWND of the embedding window, and so on. The main window does apparently things in the idle loop or even concurrently during message processing, so any change in the loops may disrupt C4D functionality somewhere.
I may try this when I have time... or perhaps the programmers will tell me whether it's the correct approach...
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 03/01/2011 at 02:21, xxxxxxxx wrote:
I got the answer from our developers that it is currently not possible for plugins to receive Windows messages.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 03/01/2011 at 05:15, xxxxxxxx wrote:
Well, not through an official way, and not for C4D-owned windows. The one I described above does work, at least for the WM_INPUT raw messages I need.
I do wonder, however, how C4D's own 3dconnexion SpaceMouse plugin does it. Using undocumented classes and/or functions? Private overrides? Somewhere there is a whole Windows dependency hidden...