|
Here are your options
1. Change to array
struct BBG_SECURITIES {
long nRecords; // Number of Entries
CStringArray* entries; // Security Name
BBG_SECURITIES()
{
entries = new CStringArray[13];
}
};
Looping then would be straight forward.
2. Unstructured and unsafe method
BBG_SECURITIES sec;
int nItems = (sizeof(BBG_SECURITIES) - sizeof(long))/sizeof(CStringArray);
CStringArray* pIter = (CStringArray*)&sec.sName;
for(int i = 0; i < nItems; i++)
{
pIter->SetSize(0);
pIter++;
}
|
|
|
|
|
Thanks for your reply:
* Wouldn't this fail if the structure is NOT empty (e.g., I have 5 elements in each CStringArray):
int nItems = (sizeof(BBG_SECURITIES) - sizeof(long))/sizeof(CStringArray);
* I am not quite sure what you are doing here:
CStringArray* pIter = (char*)&sec.sName;
sName is supoposed to be unknown.
* Any other reasons for calling this an unsafe method?
Thanks
|
|
|
|
|
Anton A. Loukine wrote:
CStringArray* pIter = (char*)&sec.sName;
Sorry a typo it should be,
CStringArray* pIter = &sec.sName;
|
|
|
|
|
Actually best thing for you would be to write a devstudio macro.
|
|
|
|
|
Can you elaborate on this a little bit. I am not familiar with macros and how they affect performance
|
|
|
|
|
Although others have posted very smart ways to have the task you're asking for accomplisedh automatically, please let me warn you'd better stay away of nifty tricks and stick to the boring sequence of resettings. If you ever add another item to your struct, you'd probably have to remember all the places scattered in your code where you put that. Instead, add a method to your struct like this:
struct BBG_SECURITIES {
...
void Reset()
{
nRecords = 0;
sName.SetSize(0);
...
}
}; and use it accordingly. You can do it even better: as CString s are constructed to the empty string by default, you can have it like:
struct BBG_SECURITIES {
...
BBG_SECURITIES()
{
nRecords = 0;
}
void Reset()
{
BBG_SECURITIES clean_struct;
(*this)=clean_struct;
}
}; The ability to inspect the contents of a class (its members, methods, etc.) is called reflection and alas is lacking in C++ (altough Java and C# do have it and it's magical for some uses.)
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
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
|
|
|
|