Can anyone tell me why the child window cannot be created?
I'm using the forgers win32api guide but I cannot figure out what is the problem.
When the program starts running I have all of the controls, but when I click on the 'new' menuitem I get the error message. This is right after the winmain.
Other things like menuitems, the tool and status bars, opening or saving files works.
**HWND CreateNewMDIChild(HWND hMDIClient)
{
MDICREATESTRUCT mcs;
HWND hChild;
mcs.szTitle = "[Untitled]";
mcs.szClass = g_szChildClassName;
mcs.hOwner = GetModuleHandle(NULL);
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = MDIS_ALLCHILDSTYLES;
hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LONG)&mcs);
if(!hChild)
{
MessageBox(hMDIClient, "MDI Child creation failed.", "Oh Oh...",
MB_ICONEXCLAMATION | MB_OK);
}
return hChild;
}**
That's an unfortunate bug in the sample code, that prevents it from running on 64-bit Windows. The final parameter to SendMessage is of type LPARAM (an alias for LONG_PTR). Casting it to LONG truncates it to 4 bytes, not quite sufficient for a 64-bit pointer (see Data Type Ranges).
Change the following line
hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LONG)&mcs);
to
hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs);
and the code should run as expected.
Related
I am currently trying to retrieve the list of icons from my desktop to change their locations and / or hide them as well as display others.
I tried to get the FolderView in the code below but it doesn't even show the number of icons I have on the desktop because count return 0.
HWND hDesktop = GetDesktopWindow();
HWND hDefView = FindWindowEx(hDesktop, NULL, L"SHELLDLL_DefView", NULL);
HWND folderView = FindWindowEx(hShellWnd, NULL, L"SysListView32", NULL);
int count = (int) SendMessage(folderView, LVM_GETITEMCOUNT, 0, 0);
cout << count << endl;
I did tests on the variables and is noticed that hDefView is NULL.
Probably the reason why count return 0.
EDIT : After replace GetDesktopWindow by GetShellWindow the result is always the same, 0
The shell window hierarchy is not documented nor stable. "ProgMan" is usually the parent of "SHELLDLL_DefView" but if you change to slideshow wallpaper it can also be "WorkerW".
It is much better to inspect/manipulate the desktop with the documented shell COM interfaces: IShellWindows, IShellBrowser, IFolderView and IShellFolder.
I'm trying to learn some windows and directX programming and I was messing around trying some different things. When suddently my the windows stopped appearing, even tho it was a successful build. I figured I must have messed something up and I undid everything until i got back to the place where I last managed to get the window to appear, but now when I run (with a successful build) it still doesn't show :( And I'm starting to run out of ideas what the problem could be, it so strange. One of the thing I did since last time I got it to work was add some libs directories but I have a hard time seeing how that would affect the program this way. Have anyone of you run in to this problem before, and if so how did you solve it? Here is the code of the func creating the window (and yes I am aware of the infinite loop, it shouldn't cause this problem tho, right?) :
ps. I have also tried changing between WINDCLASSEX and WINDCLASS, with all the functions that need to be change with it, didn't make any difference ds.
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow){
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
RegisterClass(&wc);
RECT wr = {0, 0, 500, 400}; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"My first window", // Window text
WS_OVERLAPPEDWINDOW, // Window style
CW_USEDEFAULT, CW_USEDEFAULT,//position x,y
wr.right-wr.left, wr.bottom-wr.top,//width, height
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL){
return 0;
}
InitD3D(hwnd);
// Run the message loop.
MSG msg = { };
while (true){
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else{
}
}
return 0;
}
looks like you need a ShowWindow call in there (unless InitD3D does that, you haven't shown the code)
windows are by default created non-visible, so that you can do various initialization without the user seeing what goes on
as an alternative you can create the window already visible, but generally it's a good idea to keep to a single convention
by the way, you can just use a standard int main, no need to use the Microsoft monstrosity
with GNU toolchain that's all, with Microsoft's tools you then have to tell the linker to accept the standard code, if you use the GUI subsystem, via linker option /entry:mainCRTStartup.
also, the call to non-blocking PeekMessage means your message loop will most likely be a CPU hog
instead, use blocking GetMessage
and remember to exit the loop when GetMessage returns 0 (which indicates a WM_QUIT message has been posted)
I am creating a modeless property sheet using the following settings:
PROPSHEETHEADER pshdr = { 0 };
pshdr.dwSize = sizeof(PROPSHEETHEADER);
pshdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE |
PSH_MODELESS | PSH_USECALLBACK;
pshdr.pfnCallback = PropSheetProc;
pshdr.hwndParent = mGlobalState->trayWin;
pshdr.pszCaption = L"My Settings";
pshdr.nPages = mPages.size();
pshdr.ppsp = mWinPages;
In PropSheetProc, I catch the PSCB_PRECREATE message and modify the dialog template so that it gets the DS_CENTER style:
static int CALLBACK
PropSheetProc(HWND hwndDlg, // IN
UINT uMsg, // IN
LPARAM lParam) // IN
{
// Before the dialog is created, bless it with the DS_CENTER style.
if (uMsg == PSCB_PRECREATE) {
DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)lParam;
_ASSERT(dlgTemplate);
dlgTemplate->style |= DS_CENTER;
}
return 0;
}
However this doesn't succeed in centering the dialog. I tried to catch PSCB_INITIALIZED instead and call a CenterWindow method on the hwnd passed to the PropSheetProc:
void
CenterWindow(HWND hwndWindow) // IN
{
int nX, nY, nScreenWidth, nScreenHeight;
RECT rectWindow;
nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
GetWindowRect(hwndWindow, &rectWindow);
nX = (nScreenWidth - (rectWindow.right - rectWindow.left)) / 2;
nY = (nScreenHeight - (rectWindow.bottom - rectWindow.top)) / 2;
SetWindowPos(hwndWindow, 0, nX, nY, 0, 0,
SWP_NOZORDER | SWP_NOSIZE);
}
But that doesn't work either!
Finally, I moved the CenterWindow call to directly after the PropSheet call:
mHwnd = (HWND)PropertySheet(&pshdr);
CenterWindow(mHwnd);
return mHwnd != NULL;
And this DOES work, though on a heavily loaded system, the dialog flashes from its initial position over to its final position, which is suboptimal.
Using the PropSheetProc to modify the DLGTEMPLATE structure seems intuitive. Actually, I can apply other window styles. But DS_CENTER seems to have no effect. So what am I doing wrong? There's many ways I can work around this brokennness but why is it broken in the first place?
Overload the InitialUpdate() of the CPropertySheet, and place the CenterWindow() call there. This happens before the window is drawn on the screen, but after it is created, so it's hwnd will be valid. There is nothing broken. The dialog has to be Created to have a valid HWND. Alternatively, if your working with the resource editor you can set it's property to centered, and it will achieve the same result. Why are you overloading the WinProc for the propertysheet? The whole reason MFC uses message maps was to eliminate the need to even touch WinProc's.
If your using raw win api in a SDK style application ::
Handle WM_CREATE in the WinProc of the property sheet. The LPCREATE struct in the LPARAM will contain a valid HWND from the create call. Just make sure you pass the proper parameters back to WndProcDefault() otherwise window creation will fail.
Trying to get button's handle on window calculator's form.
Spy++ shows the following tree:
("Calculator"; CalcFrame) ->
(""; CalcFrame) ->
(""; #32770 Dialog), ...anather child windows ->
(""; Button) ,... another child windows
// ("window caption"; window class)
// -> next child level
I catch main window and go deeper using FindWindowExA();
#define wndName "Calculator"
...
HWND calcHwnd = ::FindWindowA(0, wndName);
HWND frameHwnd = ::FindWindowExA(calcHwnd, 0, 0, 0);
HWND contentHwnd = ::FindWindowExA(calcHwnd, 0, "#32770 (Dialog)", 0);
DWORD er = GetLastError();
I could use ::FindWindowExA(calcHwnd, 0, 0, 0) several times to get the HWND I need(at that level there are several child windows). but i want to get HWND using condition that the window i need has class "#32770 (Dialog)".
But ::FindWindowExA(calcHwnd, 0, "#32770 (Dialog)", 0) - returns NULL. GetLastError returns 0. What is wrong?
#32770 is actually a class atom. Try:
HWND contentHwnd = ::FindWindowExA(calcHwnd, NULL, MAKEINTRESOURCE(32770), NULL);
I am registering my Class in the following method:
BOOL CNDSClientDlg::InitInstance()
{
//Register Window Updated on 16th Nov 2010, #Subhen
// Register our unique class name that we wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS));
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndcls.lpszMenuName = NULL;
//Class name for using FindWindow later
wndcls.lpszClassName = _T("CNDSClientDlg");
// Register new class and exit if it fails
if(!AfxRegisterClass(&wndcls)) // [C]
{
return FALSE;
}
}
and then calling the InitInstance method and creating the window in constructor of the Class:
CNDSClientDlg::CNDSClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNDSClientDlg::IDD, pParent)
{
InitInstance();
HWND hWnd;
hInst = AfxGetInstanceHandle(); // Store instance handle in our global variable
hWnd = CreateWindow(_T("CNDSClientDlg"), "NDS", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
}
Now in my other application I am finding the window and trying to bring to top:
Edit
Able to bring newlyCreated Windows with below code
CWnd *pWndPrev = NULL;
CWnd *FirstChildhWnd = NULL;
pWndPrev = CWnd::FindWindow(_T("CNDSClientDlg"),NULL);
if(pWndPrev != NULL)
{
//pWndPrev->BringWindowToTop();
WINDOWPLACEMENT wndplacement;
pWndPrev->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
pWndPrev->SetWindowPlacement(&wndplacement);
pWndPrev->SetForegroundWindow();
FirstChildhWnd = pWndPrev->GetLastActivePopup();
if (pWndPrev != FirstChildhWnd)
{
// a pop-up window is active, bring it to the top too
FirstChildhWnd->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
FirstChildhWnd->SetWindowPlacement(&wndplacement);
FirstChildhWnd->SetForegroundWindow();
}
I am able to find the window as pWndPrev is not NULL , but It is not bringing up my application to front. Do I need to register any other class Instead of CNDSClientDlg. I want to bring my MFC application to top.
A few things to look at...
1) Try SetForegroundWindow() instead of BringWindowToTop(). It's been awhile since I've done Win32 programming, but I seem to recall that BringWindowToTop() has some limitations (especially when working with windows in different processes).
2) There are some rules that Microsoft put in place regarding SetForegroundWindow() starting with Windows 2000. The short version is that only the front-most application can change the foreground window. The idea is that an application that is not front-most cannot "jump in front of" the active application. If a background application calls SetForegroundWindow(), Windows will flash the taskbar button for the app, but will not actually bring the app to the front. The user must do that. I'm oversimplifying the rules, but this may be something to look at depending on your specific scenario.
BringWindowToTop() only works if the calling process is the foreground process or if it received the last input event.
Call CWnd::SetForegroundWindow() instead.
You may need to call AllowSetForegroundWindow in your "other" application before calling SetForegroundWindow.
That is assuming your other application is the foreground app and is trying to pass on its foreground status to the application with the window.
If neither app is the foreground app then you're not supposed to be able to bring a window to the front, although there are ways to do it (both accidentally and on purpose).
SetWindowPos(&wndTopMost, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
SetForegroundWindow();