While that suggests there are exceptions, WM_KEYDOWN doesn't seem to be one. Without a window handle, who is it going to dispatch the (apparent) keystroke to? On XP SP3, the answer is no one, so nothing happens. It is removed from the message queue with no visible effect that it ever made it to its destination. WM_QUIT works because it causes GetMessage to return 0 which stops the message loop.Quote:
Originally Posted by PostThreadMessage
This is an extended version of yoursQuote:
How about posting a complete working example of using EnumChildWindows as needed in the context of this thread? I'm sure we'll all benefit from it . Especially, the OP.
Code:#undef UNICODE
#undef _UNICODE
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <iostream>
#include <shlwapi.h>
#include <sstream>
#include <iostream>
#pragma comment(lib, "shlwapi.lib")
// our enumerators
BOOL WINAPI ChildEnumerator(HWND hwnd, LPARAM lParam);
BOOL WINAPI ParentEnumerator(HWND hwnd, LPARAM lParam);
// Struct masquerading as a text sink
struct Buffer
{
// constructor sets up where to dump the final buffer, defaults to cout
inline Buffer(std::ostream& out = std::cout) : out(out){}
// destructor dumps it
inline ~Buffer()
{
Dump();
}
// this allows nicer syntax for print operations, similar to printf.
// Less typing required both here and invocation than operator()
// with no real loss IMHO
template<class T>
Buffer& operator,(const T& data)
{
buf << data;
return *this;
}
// this is retained from cout syntax, so we can see where the
// data is being streamed to just by looking at the first output
// it's usage is not necessary
template<class T>
Buffer& operator<<(const T& data)
{
buf << data;
return *this;
}
// dumps the text to the output stream specified in the constructor
inline void Dump()
{
out << buf.str();
out << std::endl;
}
// the ultimate output stream, and our buffer
private:
std::ostream& out;
std::ostringstream buf;
};
void OutputWindowProperties(HWND hwnd, Buffer& printer)
{
char winText[512] = {0};
// Get the text it's displaying
if(SendMessage(hwnd, WM_GETTEXT, 512, reinterpret_cast<LPARAM>(winText)))
{
printer << "\tText: ", winText, '\n';
}
// Find out which file created it
if(GetWindowModuleFileName(hwnd, winText, 512))
{
printer << "\tCreated by: ", PathFindFileName(winText), '\n';
}
// see what thread/process it came from
DWORD procID = 0;
DWORD threadID = GetWindowThreadProcessId(hwnd, &procID);
printer << "\tOwning Process ID: ", procID, " Thread ID: ", threadID, '\n';
// get some misc info
WINDOWINFO wInfo = {sizeof(wInfo), 0};
GetWindowInfo(hwnd, &wInfo);
// se if we can get the class it belongs to
WNDCLASSEX wcl = {sizeof(wcl), 0};
if(GetClassInfoEx(reinterpret_cast<HINSTANCE>(GetWindowLongPtr(hwnd, GWLP_HINSTANCE)),
reinterpret_cast<LPCSTR>(wInfo.atomWindowType), &wcl))
{
printer << "\tClassInfo:\n\t\tName: ";
// try and get the name of the class
if(GetAtomName(wInfo.atomWindowType, winText, 512))
{
printer << winText, '\n';
}
// if we can't, see if the class belongs to the current process
// if it does, we can dereference the string
else if(GetCurrentProcessId() == procID)
{
printer << wcl.lpszClassName, '\n';
}
// otherwise, just print the class id
else
{
printer << wInfo.atomWindowType, '\n';
}
// output the wndproc address in hex
printer << "\t\tWndProc at address: ", std::hex, wcl.lpfnWndProc, std::dec, '\n';
}
// finally the window X/Y location
printer << "\tX Location: ", wInfo.rcWindow.left, ", Y Location: ", wInfo.rcWindow.top, '\n';
}
// called for each top level window
BOOL WINAPI ParentEnumerator(HWND hwnd, LPARAM lParam)
{
// our dumping ground
Buffer printer;
// output window handles in hex, then change the number format back to decimal
printer << "Top-Level Window - ", std::hex, hwnd, std::dec, '\n';
// Get its' properties
OutputWindowProperties(hwnd, printer);
// go through any children and do the same, passing in the text buffer
// so we can have a roughly hierachichal structure to the output
EnumChildWindows(hwnd, ChildEnumerator, reinterpret_cast<LPARAM>(&printer));
// keep calling us for windows we haven't encountered yet
return TRUE;
}
// called for each child window
BOOL WINAPI ChildEnumerator(HWND hwnd, LPARAM lParam)
{
// get the text buffer we passed in
Buffer& printer = *(reinterpret_cast<Buffer*>(lParam));
// everything else is the same as the one above
printer << "\n Child Window ", std::hex, hwnd, std::dec, '\n';
OutputWindowProperties(hwnd, printer);
return TRUE;
}
int main(int argc, char *argv[])
{
// start the chain of window enumeration
// warning, will spew out lots of data
EnumWindows(ParentEnumerator, 0);
}

