|
Write a Reset() function that does all those calls. Then you can write:
m_strCurrentUniverse.Reset();
--Mike--
Just released - RightClick-Encrypt - Adds fast & easy file encryption to Explorer
Like the Google toolbar? Then check out UltraBar, with more features & customizable search engines!
My really out-of-date homepage
Sonork - 100.10414 AcidHelm
|
|
|
|
|
I'm experimenting with threads and I've found an example article here on codeproject.
The example I've found:
UINT CMyClass::threading(LPVOID p)
{
CMyClass * me = (CMyClass *)p;
me->threading();
return 0;
}
void CMyClass::threading()
{
}
I assume I've to add the functionality in threading() . It works fine.
But! this thread is inside CMyDialog. When I call UpdateData(TRUE/FALSE) the app crashes (calling ShowWindow for example, doesn't crash the app...)
Is there something I've overlooked? I'm new to c++threads.
[VISUAL STUDIO 6.0] [MFC] [WIN98/2]
Bluute tette!
|
|
|
|
|
frisco wrote:
UpdateData(TRUE/FALSE)
UpdateData should not be called from a different thread.
|
|
|
|
|
Should I change the controls directly then? And a ValidateWindow() afterwards?
Or is there another standard procedure for this?
[VISUAL STUDIO 6.0] [MFC] [WIN98/2]
Bluute tette!
|
|
|
|
|
Don't try UI stuff from a thread that does not own the window. Instead post or send a message to the main thread for the window and handle the message in that thread and do your stuff.
Nish
Regards,
Nish
Native CPian.
Born and brought up on CP.
With the CP blood in him.
|
|
|
|
|
Of course...
tnx, that should work fine
[VISUAL STUDIO 6.0] [MFC] [WIN98/2]
Bluute tette!
|
|
|
|
|
I have a list control in my dialog, call m_listctrl
How can I scroll it down 20 lines ?
How about this: ScrollWindow(0,20) ?
Hung Son
A student
i-g.hypermart.net
dlhson2001@yahoo.com
|
|
|
|
|
Use EnsureVisible( int nItem, BOOL bPartialOK );
|
|
|
|
|
Hi,
when you create a modal dialog, it looks like this:
<br />
CAboutDialog dlg;<br />
dlg.DoModal();<br />
Somewhere in the MFC code of the dialog there is a RunModalLoop() which looks like a PumpMessage loop. When I start a modal dialog with DoModal() , does this mean:
a) it will block in the RunModalLoop() loop until modal dialog is done,
b) and it will keep the message handling for the thread alive, b/c the modal dialog does take the role of the message pump?
I try to understand how it works, thx for help.
|
|
|
|
|
Both a) and b) are correct.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
the message loop will also reflect ( or send back ) some messages to the parent windows so the redraw can be done. ( i think )
max.
|
|
|
|
|
Yep, that's it. For instance, timer messages ar also fed to the main app even if it is blocked.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Thx Joaquín.
I tried to do something similar as a modal dialog.
What works so far: Instead of a modal dialog I started a (Win32 based) window which has a message pump. It's a OpenGL window which blocks also in a message pumping mainloop Run() until it receives WM_QUIT. I can stop the OpenGl window by posting a PostQuitMessage(0) with my Stop() member function. The calling code looks something like this:
void CMainFrame::OnAppToggle3DDialog()
{
if(!m_pEngine)
{
m_pEngine = new CPiserver3DEngine("Piserver 3D Output");
TRACE("start modal\n");
m_pEngine->Run();
TRACE("stop modal\n");
delete m_pEngine;
m_pEngine = NULL;
} else {
m_pEngine->Stop();
}
}
Constructor, just to give some more overview...
CMainFrame::CMainFrame()
{
m_pSystrayIcon = new CSystemTray();
m_pEngine = NULL;
}
CMainFrame:: ~CMainFrame()
{
delete m_pSystrayIcon;
if(m_pEngine) delete m_pEngine;
}
Well, as I told the window runs fine. I can start and stop the OpenGL window, other dialogs handled by my mainframe remain unaffected (no side effects). But... if I close my mainframe, an existing openGL window will not be closed, eeks!
I debugged a while and found out the OpenGL mainloop m_pEngine->Run() is never left ("stop modal" point is never reached). It looks like the mainframe is closing, calls the destructor and so the destructor of my OpenGL class (see delete m_pEngine above). The destructor of my OpenGL class posts a quit message, but the mainloop never ever stops.
Is there something magically I should know? I know my win32 knowledge is poor. However, I'd like to understand what is going on. Sorry for this long post & thx for ideas to fix my problem!
|
|
|
|
|
You're having some kinf of reentrancy problem. Could you post the code for the destructor of your OpenGl class, as well as the Stop method and the message pump?
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Hi!
I added verbose debug output. It looks like the mainframe "takes over" the message pump activity, and never give control back to my OpenGL mainloop. So it does not get the chance to continue it's work to quit.
1. Here is a log from what happens when I toggle the OpenGL dialog. Everything runs fine:
<br />
[MainFrame] start modal<br />
\Mainloop running<br />
\PumpMessage<br />
/PumpMessage<br />
/Mainloop running<br />
....<br />
\Mainloop running<br />
\PumpMessage<br />
PumpMessage message 0x0200<br />
PumpMessage message 0x0202<br />
[MainFrame] post stop<br />
PumpMessage message 0x0012 WM_QUIT<br />
/PumpMessage WM_QUIT<br />
Mainloop leaving..<br />
MessageHandler message 0x0046<br />
MessageHandler message 0x0047<br />
MessageHandler message 0x0002 WM_DESTROY<br />
[MainFrame] stop modal<br />
2. Here is log from what happens when I close my mainframe, while the OpenGL dialog still runs. You will see the problems at the end.
<br />
[MainFrame] start modal<br />
\Mainloop running<br />
\PumpMessage<br />
/PumpMessage<br />
/Mainloop running<br />
....<br />
\Mainloop running<br />
\PumpMessage<br />
MessageHandler message 0x001c WM_ACTIVATEAPP<br />
PumpMessage message 0x0111 WM_COMMAND (wParam = ID_APP_EXIT)<br />
[MainFrame] OnClose <br />
[MainFrame] post stop<br />
MessageHandler message 0x0085<br />
MessageHandler message 0x000d<br />
MessageHandler message 0x0014<br />
MessageHandler message 0x001c<br />
MessageHandler message 0x001f<br />
MessageHandler message 0x000a<br />
MessageHandler message 0x001c<br />
MessageHandler message 0x001c<br />
Explanation: Everything runs fine... until I choose to quit my application. That's the WM_COMMAND from above, which is from my systray menu. Immediately the MainFrame::OnClose() is called and therr I post a QuitMessage to my OpenGL window.
But the control is never given back to my OpenGL message pump, so it can't receive the WM_QUIT and leave the mainloop.
Where do I have my concept failure? Thx for help...
PS: I can post all the code, if the debug output isn't enough (just ask). I thought this way it is easier to see what happens.
|
|
|
|
|
Moak wrote:
I added verbose debug output. It looks like the mainframe "takes over" the message pump activity, and never give control back to my OpenGL mainloop. So it does not get the chance to continue it's work to quit.
After a night of debugging, spending time in Petzold and MFC wincore.cpp it looks like only CWnd derived classes can provide an own messagepump within MFC.
Well, I'm not sure and honestly I'm not much less confused as I was before. I found no way to mix MFC messagepump with a Win32 messagepump. It looks possible in CWnd::RunModalLoop() to have more then one message pump (only one active at one time), but this seems not to be possible when mixing MFC (CWnd) with Win32 (homebrew).
Are there workarounds?
I can start my OpenGL window in a own thread, but I don't want to leave the thread context. How about calling my MainRender() method as often as possible? Any ideas how to achieve this, using OnIdle or set a windows hook for GetMessage(), etc?
Thx, Moak
|
|
|
|
|
PPS: Here are the requested code snippets, perhaps it helps to trace the problem.
BOOL CBlueSharkEngine::Run()
{
if(!ShowWindow()) return FALSE;
m_bEngineRunning=TRUE;
m_timer.Init();
for (;; )
{
TRACE("\\Mainloop running\n");
if(!m_pWindow->PumpMessage()) break;
TRACE("/Mainloop running\n");
}
TRACE("Mainloop leaving..\n");
DestroyWindow();
m_bEngineRunning=FALSE;
return TRUE;
}
void CBlueSharkEngine::Stop()
{
if(m_bEngineRunning) PostQuitMessage(0);
}
BOOL CBlueSharkEngineWindow::PumpMessage()
{
MSG msg;
TRACE(" \\PumpMessage\n");
while (::PeekMessage (&msg,NULL,0,0,PM_NOREMOVE))
{
TRACE(" PumpMessage message 0x%04x\n",msg.message);
if (!::GetMessage (&msg, NULL, 0, 0))
{
TRACE(" /PumpMessage WM_QUIT\n");
return FALSE;
}
::TranslateMessage (&msg);
::DispatchMessage (&msg);
}
TRACE(" /PumpMessage\n");
return TRUE;
}
CBlueSharkEngine:: ~CBlueSharkEngine()
{
Stop();
assert(!m_bEngineRunning);
DestroyWindow();
if(m_pWindow) delete m_pWindow;
if(m_pTexture) delete m_pTexture;
if(m_pFont) delete m_pFont;
if(m_pInterface) delete m_pInterface;
}
CBlueSharkEngineWindow:: ~CBlueSharkEngineWindow() {}
|
|
|
|
|
OK, try that: I don't think you need any extra message pump (since the main frame is active even when the OpenGL window shows). So, remove the pump out of CBlueSharkEngine::Run , move DestroyWindow to the handling code for WM_CLOSE , and elminate the post-run portion in CMainFrame::OnAppToggle3DDialog . Now replace your CBlueSharkEngine::Stop with a call to CloseWindow (i.e. send a WM_CLOSE to yout OpenGL window.) There are some more details to be adjusted, but I think the general scheme should work.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Thx, Joaquín.
Oops, the main important line in CBlueSharkEngine::Run() is what I commented out previously:
EngineMain(m_timer.GetElapsedSeconds());
This method will render the OpenGL scene (depending from elapsed time). Right now I called it from inside my message loop CBlueSharkEngine::Run() . I need to call this method regular (and as fast as possible to get a high frame rate). Hmm, I think I found a possible replacement, when couldn't start my main message loop. With some structure changes:
LRESULT CALLBACK Wnd_ProcMessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
if(pEngine->m_bEngineRunning)
pEngine->EngineMain(pEngine->m_timer->GetElapsedSeconds());
break;
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
return 0;
}
The "trick" above is to get repeated WM_PAINT messages to render my frames with EngineMain() . The rendering starts, when I set m_bEngineRunning=TRUE (and Invalidate() ). It works in a test project, I will do more testings soon.
Some questions:
* How efficient is it to request repeated WM_PAINT messages generally, don't I loose CPU performance compared to my direct calling message loop? In a game engine or a 3D visualisation you want to reach highest frame rate.
* There is one negative side effect with this new type of message handling. The handling of the system menu became very "blocky", anything else negative that could happen?
Thx again, Moak
|
|
|
|
|
First of all, have you finally solved the message pump mess following my proposal? (just curious, you know.)
As for how to get repainting in your OpenGL window, you have various options:- The most simple way is to set a Windows timer (see
SetTimer ), which sends a message at a given rate. This is not very accurate, but should suffice for say up to 10 fps. - If you need more frames per second, probably your best bet is multimedia timers. These call a user-defined callback with much finer temporal resolution than Windows timers. This callback is executed in a thread different from your app's, so beware of concurrency problems. Probably the best way to avoid them is sending a user message to the OpenGL window from the multimedia timer callback and doing the reapaint there.
For much more info on different timers, read Nemanja Trifunovic's Timers tutorial.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Joaquín M López Muñoz wrote:
First of all, have you finally solved the message pump mess following my proposal?
Yes, your ideas was helpfull! I think it didn't solve the problem yet how to keep the rendering of the OpenGL scene alive? I was thinking about suggestion 1. + 2. too; what do you think about my solution 3. with the repeated WM_PAINT (see my last post)?
Briefly explanation: The trick was letting Windows sending you WM_PAINTs as often as possible, so you do not need an additional timer, multimedia or high resultion timer triggering the rendering. When rendering the OpenGL scene (just imagine a game with at least 30 FPS) you mainly don't need very regular redraws (which usually is an illusion in a multitasking environment). But you want them as often/fast as possible!
The trick with the WM_PAINT is working because you do not validate the update region with DefWindowProc function, Windows will send another WM_PAINT soon. As far as I understood from one Codeproject tutorial, WM_PAINT is a virtual message that is generated on the fly, whenever nothing else is happening. Idea sounds good and testing software showed it works.
I still prefer to use my own message pump and direct triggering of the rendering in a game, but the WM_PAINT trick seems to be a nice way to mix a MFC application with OpenGL.
Well, I need to do some profiling (evaluating FPS). Basically the WM_PAINT thing works... I wonder how efficient it is? What do you think?
Btw, befor you wonder about the timer in pEngine->EngineMain(pEngine->m_timer->GetElapsedSeconds()) . I use this timer to tell the rendering how many time has elapsed since last drawing. The EngineMain() function should update the object depending on time. I allready used this technique before to gain a CPU independent rendering.
Greets, Moak
|
|
|
|
|
I don't really think having your own message pump (unless it is an a separate thread) is a good idea at all. Depending on the host program, the message pump can do a lot of things you don't have the slightest idea about (as indeed does MFC), so replacing it with your own is bound to problems.
As for the WM_PAINT message, well if it works and you're satisfied with it, I guess it's OK. Nevertheless, multimedia timers are probably best fit for this kind of purposes (thery're are designed for this), and they allow for more flexibility to set the framerate desired (as it stands now, I guess the WM_PAINT method causes your app to choke a bit, doesn't it.)
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
A and B are correct.
Just for your knowledges as well, the modal dialog in MFC is different than the modal dialog that you will get with the Win32 API. That is because of that function that you found, RunModalLoop(), MFC creates its own message pump to handle all of the messages, which allows the rest of the app to intervene if necessary, MFC is able to accomplish this because it always creates its dialogs with CreateDialog rather than DialogBox. If you call DialogBox in the Win32 API, windows will create their own modal message pump for you.
Coincidentally this is how the processing for menus works as well, there is a modal message pump involved.
Build a man a fire, and he will be warm for a day Light a man on fire, and he will be warm for the rest of his life!
|
|
|
|
|
Is there anyway in code to create a file association. i.e. I want to associate a file type of .log with notepad. I know how to do this via Windows explorer, can I do this at runtime?
Thanks in advance,
Bob
|
|
|
|
|
You can create registry keys at HKEY_CLASSES_ROOT.
Create one for the file extesion (Ex.: .log) and put as default value a mime type (Ex.: text/plain). If the mime doesn´t exists you can create another key at HKEY_CLASSES_ROOT with a subkey shell\open and put the command to open the file there.
Mauricio Ritter - Brazil
Sonorking now: 100.13560 Trank
The alcohol is one of the greatest enemys of man, but a man who flee from his enemys is a coward.
|
|
|
|
|