|
IsWindow(m_hwnd) returns 0.
Hi, guys:
I've met a problem that a new thread tests the window handle m_hwnd through IsWindow() but reurns 0.
below is related code:
/////////////////////////////////////////////
class MyClass
{
public:
HWND m_hwnd;
......
int run();
void * run_undetached();
};
void mainfunc()
{
......
MyClass a;
a.run();
}
int MyClass::run()
{
......
m_hwnd = CreateWindow(......);
//start the run_undetached() in a new thread here.
......
}
void * MyClass::run_undetached()
{
......
if ( !IsWindow(m_hwnd))
outputmsg("m_hwnd is not a window!");
}
/////////////////////////////////////////////
any comments?
TIA
|
|
|
|
|
The remarks in MSDN for IsWindow() actually say that a thread should not call IsWindow() for a window that it did not create because the window could be destroyed after the function is called - so that's not a promising start...
Anyway, here's a couple of likely reasons for your problem:
1) Does the call to CreateWindow() succeed? If not, then obviously IsWindow() will not succeed either.
2) When does the window get destroyed? If it is destroyed in the MyClass destructor, then this will be called at the end of the scope of the MyClass object (since it is created on the stack). From the code snippet above, that means that it will be called when mainfunc() terminates, which, unless you have some sort of syncrhonisation, will be before your thread function terminates. Consequently, the window will be destroyed before the thread gets around to using it.
Dave
http://www.cloudsofheaven.org
|
|
|
|
|
thanks for your reply !
1) CreateWindow succeeds clearly!
2) the window will be available till mainfunc() terminates.
more help ?
|
|
|
|
|
Well that's your problem then. When mainfunc() terminates, your class will be destroyed, and so will the window. Then your other thread will be calling IsWindow() on a random piece of memory (the HWND has been destroyed, and so now is just a random number), so it will not work. You need to ensure that your class is not destroyed for the lifetime of the other thread.
Dave
http://www.cloudsofheaven.org
|
|
|
|
|
Greets,
Yes, a comment I have is that there is not enough context; you can't see what run_undetached returns and it's not clear as to whether or not CreateWindow() returned null. What are you trying to do that I may have missed from your code?
Regards,
Joe
|
|
|
|
|
MFC does not support access of CWnd's from threads other than the ui thread, which I think is what you are doing.
There are two approaches you can take:
1. Pass the HWND only to the other thread, and have it use the Windows api directly.
2. Use ::PostMessage() from the other thread on that window handle and trap the message in you main ui thread, and process it there. (I would strongly recommend this approach, as you really shouldn't be accessing windows from threads other than the main ui thread (except to post window messages)).
Cheers,
Swine
[b]yte your digital photos with [ae]phid [p]hotokeeper - www.aephid.com.
|
|
|
|
|
Hi all,
Anyone could please suggest me were to find some info on how to change the background of a Dialog Bar?
I've been desperately trying to accomplish this, but I think now I am lost.
I tried to derive a class from CDialogBar to override the OnCtlColor function, but now I think this is the hard way, and there might be an easier way.
Any suggestions will be greatly appreciated!
Alfredo
|
|
|
|
|
I may have programmed myself into a corner, anyways here is my situation.
I have a full screen dialog based application that serves as a menu.
Note: The main application and the plugins are all drawn using GDI+ so
I am not forced to use a dialog base application, but it happens
to be the direction I choose.
The menu has buttons which can:
a) start a dialog based dll b) Run an executable c) Execute a command
My intension was that this application would:
1) Act as a menu.
2) Watch for keyboard presses and send a message to plugins stating which key was pressed.
3) Watch for UIR (remote control) commands and send a message to the plugins stating commands
received.
4) It was not my intention to have each dll do #2 nor #3
Problem:
1) When I start a plugin from the menu application it no longer does anything. I placed a timer which fired every 4 seconds calling the MessageBeep(..) function and it was not called while the plugins dialog was active. So, it seems that there is no persistance when using dialogs the way I am using them.
Question:
How do I get around this problem? I want the main application to work as I have described above.
I am open to complete redesign or whatever options or opinions anyone might have.
Thanks,
Steve
|
|
|
|
|
I'll try to approach this problem from a perspective more closer to mine.
So, let's formulate that you have a standard Windows application, with a dialog as a main window. Okay, your application now loads two DLLs into it's address space. After these DLLs are loaded, you need to use GetProcAddress to get an address of an exported function, which you can then call from your application.. Correct ? No ?
Are your plugins supposed to act as little programs of their own ? Then you need to create a new thread and post the function to execute on that thread for the thread creator. For example, the Kernel creates a thread and specifies your 'WinMain' function to execute there. You can do the same: get the exported (worker) function from the DLL, and use it's address to start a new thread. Your function, then, can do anything it wants from just returning 'SUCCESS' to starting a message pump and creating a window. This is called multi-threading application, and is something I don't know much of. I've never needed it so far
You said that the plugins are represented as dialogs. So, let's assume you define a class for this dialog, a derived CDialog, for example. Then, you declare a global object in the 'DllMain', and use 'GetProcAddress' to get the address of an exported function, which does nothing more than return the address of this global object.
Here's the general flow chart:
Application XYZ starts -> App maps a DLL using LoadLibrary -> The DLLs DllMain routine creates a dynamic/static CMyDialog object -> The app uses GetProcAddress to get an exported function from the DLL and calls it -> This function returns the address of this object
App can now, in combination with the header file of the object, call dialog's member functions (Create / DoModal) and start it. Make it modal, specify your application window as parent, and vot, you got yourself an ordinary dialog
I believe using MFC classes this way requires a bit more thought, though, but this is the general idea. I am unsure how it works, look up MSDN for more help.
On the alternative, you can use the multi-threaded solution to create seperate threads for your plugin dialogs (Like, small applications with dialog as main window), then use SendMessage to send messages to these windows.
If this is not the idea you're after, then could you clarify more of your ideas. What is it that your plugins need to do ? Why are they placed in external DLL plugins ? Why just not objects inside your main application class ?
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Antti Keskinen wrote:
So, let's formulate that you have a standard Windows application, with a dialog as a main window. Okay, your application now loads two DLLs into it's address space. After these DLLs are loaded, you need to use GetProcAddress to get an address of an exported function, which you can then call from your application.. Correct ? No ?
Correct.
Antti Keskinen wrote:
Are your plugins supposed to act as little programs of their own ?
Well, yes they are intended to act as their own little program as well as receive messages from the parent application. ( like I mentioned key presses and remote control presses )
Antti Keskinen wrote:
Then you need to create a new thread and post the function to execute on that thread for the thread creator. For example, the Kernel creates a thread and specifies your 'WinMain' function to execute there. You can do the same: get the exported (worker) function from the DLL, and use it's address to start a new thread. Your function, then, can do anything it wants from just returning 'SUCCESS' to starting a message pump and creating a window.
What if I where to use a modeless dialog with a callback function. I could process messages that way or I could use the SendMessage interface I added to my plugin interface. My problem is that when the dialog in the dll comes up Modal then it stops any processing from the parent application.
Antti Keskinen wrote:
If this is not the idea you're after, then could you clarify more of your ideas. What is it that your plugins need to do ?
The plugins can do anything. The plugin I am currently testing with gets the current weather from the internet and displays it. The dialog has buttons for refreshing and returning to the main application. This would be done by remote control. You select for example the back button which would cause the main application to send an ENTER command to the plugin. Well, this is my intention anyways.
Antti Keskinen wrote:
Why are they placed in external DLL plugins ? Why just not objects inside your main application class ?
They are external because I want people to be able to write their own plugins given a dll template project. I want to application to be completely customizible and I don't want to give out all my source code just so someone can add desired functionality.
Hope that all makes sense. Thanks for your response.
Steve
|
|
|
|
|
smesser wrote:
What if I where to use a modeless dialog with a callback function. I could process messages that way or I could use the SendMessage interface I added to my plugin interface. My problem is that when the dialog in the dll comes up Modal then it stops any processing from the parent application.
The plugins can do anything. The plugin I am currently testing with gets the current weather from the internet and displays it. The dialog has buttons for refreshing and returning to the main application. This would be done by remote control. You select for example the back button which would cause the main application to send an ENTER command to the plugin. Well, this is my intention anyways.
Upon reviewing your original post again I saw a possible problem in your implementation: did you remember to start the message pump for the dialog when you created it ? A thread without a message pump can create a dialog, but the dialog won't do anything.
If you use MFC for the dialogs (CDialog derivance), see AfxLoadLibrary MSDN entry for an easy example on how to create the main application's portion of the code. There is an example (In MSDN Library April 2003), which loads a DLL, gets a CView-derived class's runtime info using an exported function, and creates a new document template based on the value returned by the function.
The Dll side would consist of your class definition (.h), and an implementation file. This implementation file has two requisities: it creates an object of the class on it's global level, that is, NOT inside DllMain. Also, it must export a function to return the address of the object.
Or if you would like to use the AfxLoadLibrary example straight on, the exported function would result a RUNTIME_CLASS( Your class name here )
You can use the same approach to pass out any type of class information, even a ready object, if you so please. I am not sure whether the AfxLoadLibrary creates a new thread upon which DllMain of the loaded library executes. In that case, you must be very careful when specifying the main application window as the parent, as inter-thread information may easily become corrupted :I
And yeah, use AfxLoadLibrary instead of LoadLibrary. The MFC version makes sure that main application data is not corrupted.
If you can't get it to work, you can download a small MFC application I made. It uses a DLL to create a dialog and then runs that dialog. See it's source file 'CLoaderApp' for a full description of it's soul life.
Here's a link: www.tpu.fi/~t1akeski/MFC_goes_DLL.zip[^]
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible., for example.
|
|
|
|
|
Thanks for the example but I am not sure how much it relates to my project in VC++ 6.
Antti Keskinen wrote:
Upon reviewing your original post again I saw a possible problem in your implementation: did you remember to start the message pump for the dialog when you created it ? A thread without a message pump can create a dialog, but the dialog won't do anything.
In my project the Loader as in your example has a dialog and is a full application.
So, I am not sure I see the relevance of starting the message pump manually. In my project
the main application starts the dll and has a function for sending messages. I can also
override the DefWindowProc() to catch messages that maybe sent to it's window.
The dialog in my dll does not have problems doing anything. It works fine,
it just is blocking the main application from telling it anything.
My original problem was not getting the dialog in the dll to work it was getting it to not block the processing of the main application. It was doing so because the dialog in the dll was Modal.
In the mean time I have changed the dialog in my dll to a modeless dialog and it is no longer blocking the processing of the main application.
I either don't understand your answer or we are not trying to solve the same problem.
Are you saying that the thread in my dll needs a message pump? I am not using any threads.
Sorry for being so dense.
Steve
|
|
|
|
|
It seems there has been a misunderstanding when I readed your first message. My apologies.
When you use AfxLoadLibrary to map a DLL to the address space, it's DllMain (Or if you use MFC, it's CWinApp-derived object's InitInstance) gets executed on a seperate thread. This is a feature of AfxLoadLibrary, but I don't believe it will pose a problem.
It, however, means that you cannot pass C++ CWnd or CDialog objects (or their addresses) from the DLL to the main application. This will cause an assertion in the debug version of MFC, and most obviously, a crash in the release version.
You CAN pass the HWND of the dialog, if you need to post messages to it, or alternatively, create an exported function (from the DLL) to send the messages. Afterall, the function you export gets called within the DLL's thread, as you use GetProcAddress to get a POINTER to that function, which you then call from the main application.
Like said, if you export a function from the DLL which returns the HWND of the dialog, you can use this HWND to pass messages to the dialog. However, you can not return the address of the CWnd/CDialog object from the DLL. This violates the above-mentioned object sharing aspect.
The reason why I used custom message pumping in my application was because my application did not have a main window at all. MFC is designed to shut the thread down if, after the execution of InitInstance returning TRUE, the m_pMainWnd member of CWinApp is NULL.
I could've created my own dialog for the example application: I just didn't feel it necessary. Otherwise, your and my app work similarly. Both load a DLL, both create a dialog in that DLL. My case just is that I am force-running the thread to prevent framework from shutting it down before I want it to.
But, like you said, the problem is solved after you changed the plugin dialog to modeless. Good luck for the future development of the app, and feel free to ask if you run into any more problems
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
No apologies necessary. I learned from our discussion and appreciate your time and effort and your example. After all you were the only one to respond so again I say thanks. This does not seem to be an area that most people have a lot of experience with. I know that it has been eye opening experience for me.
One final question though, you mentioned that:
Antti Keskinen wrote:
It, however, means that you cannot pass C++ CWnd or CDialog objects (or their addresses) from the DLL to the main application. This will cause an assertion in the debug version of MFC, and most obviously, a crash in the release version.
Since I am not currently using AfxLoadLibrary could I if I wanted pass a CWnd handle of my dll back to the main application? I am not clear on that point.
- Steve Messer
|
|
|
|
|
In short, you can pass the HWND of the Windows object bound to a CWnd from the DLL back to the main application. This is legal. Now for some explanation:
I ran into a strange problem while creating the example app, and when debugging, my application fired an assertion as I created the CDialog in the DLL and then passed the active C++ object's address to the main application. Here, the term "active" refers to an MFC object means that is bound to an existing Windows window/GDI/whatever object. An "inactive" object would be one that has not had it's 'Create' method (or any other initialization method) called.
Here is an exerpt from wincore.cpp, a MFC source file which defines the behaviour of CWnd::AssertValid, among other things.
ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); <DIV>
</DIV>
So, like you see on the commented lines, passing the addresses of created C++ objects from one thread to another is a dangerous business, especially if the object is bound to a Windows GDI object already.
The reasons for this are in the core functionality of the MFC. Like you might already know, MFC is just a (huge) collection C++-based classes, which encapsulate the functionality of the major Windows base services (Windows, pens, brushes, DCs, sockets and so on). This is why it is so difficult for most people to make the difference between MFC and the Windows API.
Building on this theory, you now understand why the passing of an active CWnd object's address is dangerous: the object itself is created on a seperate thread, and if you call it's methods, they are executed in the context of the seperate thread as well. The Windows window object bound to the CWnd exists on the seperate thread as well. So, if you were to use the DLL's existing, active CWnd object's address or a reference to it in order to construct a new CWnd object in the main application, you would most likely be greeted by an access violation. Cross-thread communication is very vulnerable to causing those. However, you can store the object's address and call it's methods through a pointer. This is completely fine and legal
Alternatively, you can always use a simple HWND variable in the main application, and use Windows API's SendMessage to post messages to that HWND.
Just create an exported function to the DLL which returns the HWND of the Windows window bound to the CDialog/CWnd object in question. Then call this function through a pointer from the main thread, and vot, you have the HWND.
MFC Reference, however, cautions us from binding two CWnd objects to a same HWND handle, as this may result in serious implications if one of the object is destroyed while the other is still attached to the Windows window object. The destructor of CWnd, by default, attempts to destroy the underlying Windows window object as well. So, if you pass the HWND, use the API's SendMessage to send your message to the window. Do not wrap the HWND into a new CWnd object.
The most safest way is to use pointers. Cross-thread pointers are a very safe way to exchange information between two (or more) threads.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Very informative I am sure your information will save me hours of headaches in the future.
Thanks,
-Steve Messer
|
|
|
|
|
I'm throwing up a message box inside the OnGridEndEdit function of a CGridCtrl object. I want to inform the user that a duplicate name has been entered and a unique one must be supplied. However, after the message box is clicked on, the cursor highlights cells in the grid control and its a wierd side effect. Any suggestions?
Here is the code:
<br />
void RDialogForEditingCanalObjects::OnGridEndEdit(NMHDR *pNotifyStruct,LRESULT* pResult)<br />
{<br />
bool bAcceptChange = false;<br />
CGridCellBase* pRow = NULL;<br />
<br />
NM_GRIDVIEW* pItem = (NM_GRIDVIEW*) pNotifyStruct;<br />
<br />
if (this->m_eCanalObjectType != CO_SSFC) <br />
{<br />
<br />
if (pItem->iRow == 1 && pItem->iColumn == 1)<br />
{<br />
<br />
pRow = this->m_PrimaryGrid.GetCell(pItem->iRow,pItem->iColumn);<br />
<br />
if (pRow) <br />
{<br />
switch(this->m_pCanMan->IsNameUnique(pRow->GetText())) {<br />
case 0:<br />
Beep(999,189);<br />
Beep(999,189);<br />
MessageBox("Please enter a unique name for this object",<br />
"Duplicate Naming Error!",MB_OK);<br />
bAcceptChange = FALSE;<br />
<br />
break;<br />
case 1:<br />
bAcceptChange = TRUE;<br />
break;<br />
} <br />
<br />
}<br />
}<br />
} <br />
}<br />
|
|
|
|
|
All,
I am trying to compile some code that uses the FILETIME structure. When I try and compile it I get the following error message:
c:\Documents and Settings\Me\My Documents\my projects\CPP Projects\First Project\Hello World Proj\Form1.h(27) : error C2872: 'FILETIME' : ambiguous symbol
could be 'C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\WinDef.h(354) : _FILETIME FILETIME'
or 'stdafx.cpp(0) : System::Runtime::InteropServices::FILETIME'
It appears that there are two different declarations for FILETIME. When you search the MSDN Library for just "FILETIME" it tells you to just include windows.h. If you search the MSDN Library for "about FILETIME structure" it says that it is located in the namespace system.runtime.interopservices. I should mention that I have both an include of windows.h and a line for:
using namespace System::Runtime::InteropServices
If I comment out the using namespace line in order to fix the error I get a profusion of different errors because I use message boxes and apparently they need that namespace definition.
c:\Documents and Settings\me\My Documents\my projects\CPP Projects\First Project\Hello World Proj\Form1.h(208) : error C2653: 'MessageBoxA' : is not a class or namespace name
Thanks in advance for any ideas,
Robert
|
|
|
|
|
Here's two options:
1) Qualify FILETIME as being in the global namespace as: ::FILETIME, so that the compiler knows you are not refering to the one in System::Runtime::InteropServices.
2) Instead of importing the entire InteropServices namespace, either qualify them explicitly, or just include the classes that you actually need (e.g. using System::Runtime::InteropServices::Blah).
Dave
http://www.cloudsofheaven.org
|
|
|
|
|
I want to change a toolbar bitmap image Inbox to a different bitmap (or a bitmap with a very different color background) when there are messages in the Inbox. Or some way to give the user an alert that there are new messages in the Inbox. Can this be done?
Elizabeth
|
|
|
|
|
One quick method would be to have two cpies of the same toolbar in your resources which have the same buttons, but one has a different image. When you need to switch bitmaps, you just call pToolbar->LoadToolbar() with the correct resource id for the correct images you want.
I do somehing similar in an app of mine to switch between small/large icons and it works fine.
Roger Allen
Sonork 100.10016
Death come early, death come late,
It takes us all, there is no reason.
For every purpose under heaven,
To each a turn, to each a season.
A time to weep and a time to sigh,
A time to laugh and a time to cry,
A time to be born and a time to die.
Dust to dust and ashes to ashes,
And so I end my song.
|
|
|
|
|
I tried out your method. However, the toolbar flashes whenever the mouse is over it. I had LoadToolBar() at ON_UPDATE_COMMAND_UI(ID_INBOX, OnUpdateInbox). The flashing is very annoying.
Elizabeth
|
|
|
|
|
It sounds like you just need to add a small amount of extra processing that only calls LoadToolbar() when a change in the button state is required. That should remove the flashing in the ON_UPADTE() handler.
Roger Allen - Sonork 100.10016
If your dead and reading this, then you have no life!
|
|
|
|
|
I added some lines to set state of the toolbar, but once it gets out of ON_UPDATE_COMMAND_UI, the state is reset. What I am trying to do is to set the toolbar button ID_INBOX to TBSTATE_PRESSED when there is new mail and TBSTATE_ENABLED when there is no new mail. But the toolbar keeps flashing when I move the mouse over it. Here is some code:
if (pDoc->NewMail())
{
if (m_wndToolBarCtrl.GetState(ID_INBOX) != TBSTATE_PRESSED)
{
m_wndToolBar.LoadToolBar(IDR_MAINFRAME_NEWMAIL);
m_wndToolBar.GetToolBarCtrl().SetState(ID_INBOX, TBSTATE_PRESSED);
}
}
else
{
if (m_wndToolBar.GetToolBarCtrl().GetState(ID_INBOX) != TBSTATE_ENABLED)
{
m_wndToolBar.LoadToolBar(IDR_MAINFRAME);
m_wndToolBar.GetToolBarCtrl().SetState(ID_INBOX, TBSTATE_ENABLED);
}
}
Elizabeth
|
|
|
|
|
hi, im tryin to find some simple code for a water effect in opengl. basically something i can use for an ocean effect. any ideas?
bik
|
|
|
|
|