COM+ app not continuing until some unknown condition - mfc

I have a COM+ application which I instantiate with
CoCreateInstance(CLSID_TheComponent, NULL, CLSCTX_ALL, IID_ITheComponent, &m_TheComponent);
This is followed by event initialization
CoCreateInstance(CLSID_TransientSubscription,NULL,CLSCTX_ALL,IID_ITransinetSubscription,&Trans);
...some more code that eventually registers some CLSID_Events, IID__IEvents.
I have an MFC application with following:
OnBtn1Clicked()
{
m_TheComponent->DoSomething();
}
also in the Dialog class there is
class CMFCMyDialog : public CDialogEx, _IEvents
{
...
virtual HRESULT STDMETHODCALLTYPE OnSomething(); // abstract in _IEvents
When running, after clicking Btn1 two things happen: 1.OnSomething() is fired, and 2. the COM+ does a bunch of other stuff it should do. So far so good.
The interesting thing is that 1 & 2 happen only after OnBtn1Clicked() is exited. Even if i put a sleep() after DoSomething() or if I attempt to call DoSomething() within a different thread, 1 + 2 don't happen only after OnBtn1Clicked() is cleared.
From The COM component log I see it reaches and enters it's OnSomething() call but does not exist it (and of course does not reach the client side sink) until OnBtn1Clicked() is cleared. Once cleared, the sink is reached and the COM component continues execution.
All this would not be a problem since I can wait for after the button is clicked, but I need to implement this in a console application client. When implementing in a console application I was not able to make 1 and/or 2 happen. Only after I kill the client process (!) 2 happens (the COM+ continues processing) but of course client side OnSomething() does not since the process is dead.
Any idea what happens when OnBtn1Clicked() is cleared that affects the COM+?

MyConsoleClass::MyConsoleClass()
{
new thread(&MyConsoleClass::Run, this);
}
void MyConsoleClass::Run()
{
m_ThreadId = GetCurrentThreadId();
m_IsActive = true;
MSG msg;
BOOL bRet;
while (m_IsActive)
{
if (bRet = GetMessage(&msg, NULL, 0, 0) != 0)
{
if (bRet == -1)
// error
else if (msg.message == WM_QUIT)
m_IsActive = false;
else if (msg.message == DO_SOMETHING)
DoSomething(msg.wParam);
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
void MyConsoleClass::Invoke(const actionEnum action, const void *params)
{
PostThreadMessage(m_ThreadId, action, (WPARAM)params, NULL);
}

Related

Is it safe to manually handle custom message sent from another thread

I'm trying to post message from one thread to a window in another thread via PostThreadMessage:
auto result = PostThreadMessage(mainThreadId, UserMessage::DestroyWindowRequest, 0, 0);
The MSDN says that
Messages sent by PostThreadMessage are not associated with a window. As a general rule, messages that are not associated with a window cannot be dispatched by the DispatchMessage function.
So I cann't just receive my message. Is it safe to handle a message manually in a message loop as in code below?
INT_PTR AbstractWindow::TranslateMessageLoop()
{
MSG msg{0};
BOOL gotMessage = FALSE;
static const BOOL hasError = -1;
PostMessage(windowHandle, UserMessage::MessageLoopTranslated, 0, 0);
while ((gotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && gotMessage != hasError) {
// Here I process a message. I assume that the message is always destined for my main window,
// so I use it's handle - windowHandle.
if (!msg.hwnd && msg.message == UserMessage::DestroyWindowRequest) {
DestroyWindow(windowHandle);
}
else {
if (PreTranslateMessage(&msg) == FALSE) {
if (IsDialogMessage(windowHandle, &msg) == FALSE) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
return msg.wParam;
}
I know, MSDN suggest to use custom hooks, but it's a little bit overkill for me now.

MFC executing thread problems

I have a CDialog that allow users to navigate, listing and showing files preview in the hard disk. In some cases there might be a lot of heavy files and these cases require a lot of time, so we moved the loading operations in a separate thread.
Now, I expect that moving disk accesses in a separate thread would have let me to use the CDialog normally, but this does not happen so I can't scroll or move the window.
Am I missing something in the process? Here's the code:
void CMyDialog::LoadFiles()
{
// …
std::thread load_file(LoadingRoutine, reinterpret_cast<void *>(&data));
load_file.detach();
// same happens if I use Afx functions
// AfxBeginThread(&CMyDialog::LoadingRoutine, reinterpret_cast<void *>(&data));
// …
}
Problem partially fixed: it seems that using threads prevents the window to consume messages regularly even if it's a non-blocking call.
My workaround consisted in giving the control back to window to let it to consume messages:
// … thread stuff
for (auto nI = 0; nI < nCount; nI++)
{
// Heavy computing
nSleepStep = 5;
nSleepTime = 200;
while (nSleepTime > nSleepStep)
{
while(PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
{
switch( msg.message )
{
case WM_TIMER :
case WM_PAINT :
TranslateMessage( &msg );
DispatchMessage( &msg );
break;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(nSleepStep));
nSleepTime -= nSleepStep;
}
}
The correct way is to use AfxBeginThread or std::thread::detach. You will be able to use the dialog in the main UI thread normally.
Alternatively you can do this in a single thread, assuming your function can be interrupted and broken in to different parts. For example, lets say you have function that takes 3 seconds to complete:
Sleep(3000);
It can be broken in to 30 parts and simulated as
for (int i = 0; i < 30; i++)
Sleep(100);
You can update paint after each move. Note that other dialog messages must be ignored, because this is a single thread and you can only do one thing at a time. You should disable the controls to let the user know the dialog is busy. Example:
void update_paint()
{
MSG msg;
while(PeekMessage(&msg, m_hWnd, 0, 0, PM_REMOVE))
{
if(msg.message == WM_COMMAND && msg.wParam == IDCANCEL) { }//cancel reuested
if(msg.message == WM_PAINT ||
(msg.message >= WM_NCCALCSIZE && msg.message <= WM_NCACTIVATE) ||
(msg.message >= WM_NCMOUSEMOVE && msg.message <= WM_NCMBUTTONDBLCLK))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
void CMyDialog::single_thread()
{
MessageBox(L"start");
//disable child controls to let user know the dialog is busy
for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
p->EnableWindow(FALSE);
for(int i = 0; i < 30; i++)
{
Sleep(100);
update_paint();
}
//enable child controls
for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
p->EnableWindow(TRUE);
MessageBox(L"done");
}
If the function cannot be interrupted then launching a second thread is necessary.

What is the proper use of WTL CIdleHandler?

I'm trying to learn WTL / Win32 programming, and I don't quite understand the design of the CIdleHandler mixin class.
For WTL 9.1, The CMessageLoop code is as follows (from atlapp.h):
for(;;)
{
while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!OnIdle(nIdleCount++))
bDoIdle = FALSE;
}
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
{
ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
continue; // error, don't process
}
else if(!bRet)
{
ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
break; // WM_QUIT, exit message loop
}
if(!PreTranslateMessage(&m_msg))
{
::TranslateMessage(&m_msg);
::DispatchMessage(&m_msg);
}
if(IsIdleMessage(&m_msg))
{
bDoIdle = TRUE;
nIdleCount = 0;
}
}
The actual call to idle handlers is very straightforward.
// override to change idle processing
virtual BOOL OnIdle(int /*nIdleCount*/)
{
for(int i = 0; i < m_aIdleHandler.GetSize(); i++)
{
CIdleHandler* pIdleHandler = m_aIdleHandler[i];
if(pIdleHandler != NULL)
pIdleHandler->OnIdle();
}
return FALSE; // don't continue
}
As is the call to IsIdleMessage
static BOOL IsIdleMessage(MSG* pMsg)
{
// These messages should NOT cause idle processing
switch(pMsg->message)
{
case WM_MOUSEMOVE:
#ifndef _WIN32_WCE
case WM_NCMOUSEMOVE:
#endif // !_WIN32_WCE
case WM_PAINT:
case 0x0118: // WM_SYSTIMER (caret blink)
return FALSE;
}
return TRUE;
}
My analysis is as follows: it seems like once per "PeekMessage Drought" (a period of time where no messages are sent to the Win32 Application), the OnIdle handlers are called.
But why just once? Wouldn't you want background idle tasks to continuously be called over and over again in the case when PeekMessage ? Furthermore, it seems strange to me that WM_LBUTTONDOWN (User has left-clicked something on the Window) would activate idle processing (bDoIdle = True), but WM_MOUSEMOVE is explicitly called out to prevent reactivation of idle processing.
Can anyone give me the "proper" use scenario of WTL Idle Loops (or more specifically: CIdleHandler)? I guess my expectation was that Idle-processing functions would be small, incremental tasks that take no more than say... 100ms to complete. And then they'd be called repeatedly in the background.
But it seems like this is not the case in WTL. Or maybe I'm not fully understanding Idle loops? Because if I had an incremental background task registered as a CIdleHandler... then if the user stepped away from the window, the task would get run only once! Without any messages pumped into the system (such as WM_LBUTTONDOWN), the bDoIdle variable would remain false for all time!
Does anyone have a good explanation for all this?
As said in the comments, OnIdle handler is supposed to be called when idling starts after certain activity, esp. in order to update UI. This explains "once" calling of the handlers: something happened and then you have a chance to once update the UI elements. If you need ongoing background processing, you are supposed to use timers or worker threads.
WTL samples suggest the use of idle handlers, e.g. in \Samples\Alpha\mainfrm.h.
Window class picks up message loop of the thread and requests idleness updates:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// ...
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
Later on after message processing and user interaction, the idleness handler updates toolbar to reflect possible state changes:
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}

After sending ctrl-c to a child proc., how do I re-attach handling to parent without ctrl-c being automatically handled (windows)?

EDIT: Related post and possible .Net solution: related question (I would like a non-.Net solution)
I have a need to shut-down a child process with a given process ID. My first attempt was to use this code:
bool shutDown(int const processID)
{
// detach handler from 'this', parent process
SetConsoldeCtrlHandler(NULL, TRUE);
// send ctrl-c event to processID
bool success = false;
FreeConsole();
AttachConsole(processID);
success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
while(waitUntilSomething()) {}
return success;
}
Now this works fine, however, I would like to return console ctrl to the 'this' process so that if I want to, I can break out of the while loop. With this in mind, I tried this:
bool shutDown(int const processID)
{
// detach handler from 'this' process
SetConsoldeCtrlHandler(NULL, TRUE);
// send ctrl-c event to processID
bool success = false;
FreeConsole();
AttachConsole(processID);
success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
SetConsoleCtrlHandler(NULL, FALSE); // <--- I added this bit
while(waitUntilSomething()) {}
return success;
}
But this doesn't work, because the ctrl-c signal then falls through to the parent process and the while loop is never executed.
I also tried the following, using a custom handler to ignore ctrl-c events from 'this':
BOOL WINAPI handler(DWORD eventType)
{
switch(eventType) {
case CTRL_EVENT:
case CTRL_BREAK_EVENT:
return TRUE;
default:
return FALSE;
}
}
bool shutDown(int const processID)
{
// attach custom handler to i
SetConsoldeCtrlHandler(handler, TRUE);
// send ctrl-c event to processID
bool success = false;
FreeConsole();
AttachConsole(processID);
success = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
SetConsoleCtrlHandler(handler, FALSE);
while(waitUntilSomething()) {}
return success;
}
...but in a similar way to the second example, the ctrl-c then passes straight through to the parent process and the while loop is never executed, because of the second SetConsoleCtrlHandler(handler, FALSE); call.
Is there a way that I can return ctrl-c handling to the parent process after generating a ctrl-c event for a child process, without that event being automatically handled?
Thanks,
Ben.

Game loop in Win32 API

I'm creating game mario like in win32 GDI . I've implemented the new loop for game :
PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
while (msg.message!=WM_QUIT)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else // No message to do
{
gGameMain->GameLoop();
}
}
But my game just running until I press Ctrl + Alt + Del ( mouse cursor is rolling ).
I've always been using something like that:
MSG msg;
while (running){
if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
try{
onIdle();
}
catch(std::exception& e){
onError(e.what());
close();
}
}
onIdle is actual game lopp implementation, onError() is an error handler (takes error description as argument), and "running" is either a global bool variable or a class member. Setting "running" to false shuts down the game.
I think this really depends on your context. Windows will only send a WM_QUIT in response to your application calling PostQuitMessage. A common (if not great) solution here is to use a bool to exit the message loop when your program wants to end.
I guess the program may ask user for continue or exit, inside GameLoop function call. On exit Post WM_QUIT message to the window.
PostMessage(hWnd, WM_QUIT, 0, 0 );
hWnd-> The handle of the game window
else make a call to
DestroyWindow(hWnd);
This will send a WM_DESTROY to your window procedure. There you can call
PostQuitMessage(0);