GetWindowThreadProcessId can not find my window handle, even though its process ID exists on Window - c++

I have a setup application that if user clicks the same setup twice, they would get the pop up message "Another setup instance already running". Upon clicking OK on that message I want to put focus back on the existing installation window which has been running. I currently have the following codes:
if("setup.exe" == CString(buffer))
EnumWindows(EnumWindowsProc,(LPARAM)processID);
BOOL CALLBACK EnumWindowsProc(HWND windowHandle,LPARAM lParam)
{
DWORD searchedProcessId = (DWORD)lParam;
DWORD windowProcessId = 0;
GetWindowThreadProcessId(windowHandle,&windowProcessId);
if(searchedProcessId == windowProcessId)
{
//Set focus when detects the right window.
SetForegroundWindow(windowHandle);
return FALSE;
}
return TRUE;
}
The above code works if I stay on the first screen/step on the installation wizard (install shield).
When I move to the next screen on the installation wizard, this focus logic no longer works. Upon debugging I found that the function GetWindowThreadProcessId could not find any windowProcessID that match searchedProcessId. I also confirmed the following:
the searchProcessId value remains the same whether I am on the 1st or 2nd installation screen.
I confirmed I see the searchProcessID value exists when I view in in the window task manager.
I read up on GetWindowThreadProcessId and see the following note: "The return value is the identifier of the thread that created the window." In my own interpretation, was this because the 2nd step/screen on the wizard is generated by its own thread?
I tried to play around with EnumChildWindow() function but that did not help. I'd be very appricated if anyone able to point me in the right direction of trying to get this to work?

I would use Spy++ which comes with Visual Studio or a similar system monitoring tool to show you all the windows/threads so you can try to confirm exactly what the install wizard is doing. Chances are EnumWindows() is working just fine and it is a problem with your code or your assumptions of how things work.

Related

C++ Global Hotkeys with platform APIs

I'm working on an application for taking screenshots on Windows, OSX and Linux in C++/Qt. Now I need to set global hotkeys, so the user can take screenshots when the application is running in the background. I tried with Qxt and UGlobalHotkey, which are both Qt libraries, but neither of them seemed to work.
I tried to implement it for OSX with Carbon (tutorial), but I need to call a class member function, which just doesn't work. Could someone provide me with an example? You can find my code here. The function i need to call is new_screenshot().
Or is there any other way to achieve something like this? I really need my application to take a screenshot from the background, otherwise it's pretty useless (yes, I should probably have implemented it at the very beginning to see if it even works). Would it maybe be better to have a separate client for every platform (Cocoa Swift for OSX, GTK for Linux, C# client for Windows)? I have often thought about this the past few days.
Do I understand correctly that you want to call new_screenshot from the hot key event handler? If so, InstallApplicationEventHandler lets you pass a pointer to user data in 4th argument. Pass a pointer to your MainWindow instance (based on code from the tutorial):
MainWindow *mainWindow = ... // get main window somehow
InstallApplicationEventHandler(&MyHotKeyHandler,1,&eventType,mainWindow,NULL);
Then you can use it in the event handler.
OSStatus MyHotKeyHandler(EventHandlerCallRef nextHandler,EventRef theEvent, void *userData)
{
//Do something once the key is pressed
static_cast<MainWindow*>(userData)->new_screenshot();
return noErr;
}
I did something in the past with MFC and WIN32 API....so it only works on Windows...but pressing ALT+F10 was able to hide/show a window...
void CWinHideDlg::OnButtonActive()
{
CString tmp;
GetDlgItemText(IDC_BUTTON_ACTIVE,tmp);
if(0 == strcmp(tmp.GetBuffer(tmp.GetLength()),"Activate"))
{
m_myAtom=GlobalAddAtom("MY_GLOBAL_HOT_HIDE_KEY");
int err=RegisterHotKey(this->GetSafeHwnd(),m_myAtom,MOD_ALT,VK_F10);
SetDlgItemText(IDC_BUTTON_ACTIVE,"Stop");
CButton *pBtn = (CButton *)GetDlgItem(IDC_BUTTON_UNHIDE);
pBtn->EnableWindow(TRUE);
SetDlgItemText(IDC_STATIC_INFO,"Set the mouse over the window \nand press ALT + F10 to hide it...");
}
else
{
UnregisterHotKey(this->GetSafeHwnd(),m_myAtom);
GlobalDeleteAtom(m_myAtom);
CButton *pBtn = (CButton *)GetDlgItem(IDC_BUTTON_UNHIDE);
pBtn->EnableWindow(FALSE);
SetDlgItemText(IDC_BUTTON_ACTIVE,"Activate");
}
}
Basically this code activates/deactivates the hot key ALT+F10, once it activates you can hide/unhide a running window on the system by setting the mouse pointer over the window and press ALT+F10...
This is from the WindowProc function:
if(message == WM_HOTKEY)
{
CString tmp;
POINT pc;
GetCursorPos(&pc);
if(GetAsyncKeyState(VK_F10))
{
HWND hwnd=::WindowFromPoint(pc);
if(hwnd)
{
tmp.Format("%08Xh",hwnd);
m_HideWins.InsertString(m_HideWins.GetCount(),tmp);
::ShowWindow(hwnd,SW_HIDE);
}
}
}
You can use the code to register your own HOT Key and use it to take a screenshot...
Hope it helps...

C++ Windows System Tray wont display message

I have been stuck here for 4 days. I made a function that puts a program in the system tray but the problem here is that it wont show balloon title and message. What Am I doing Wrong? I even made a separate function to determine what windows os we are running on and initialize cbSize based on the Os detected. Any help will be appreciated. Bellow is the function.
EDIT: I am using Windows 7 and the Icon shows up in the system tray but wont show the message or title. I am also doing this Console Application right now as this will be used as a plugin in Unity3D. I want a solution that uses windows api but not windows form as I don't want any new window to open from this.
void createSystemTray()
{
HWND wHandler = GetDesktopWindow();
NOTIFYICONDATA iData;
ZeroMemory(&iData,sizeof(iData));
if(getOsVersion()=="Windows Vista" || getOsVersion()=="Windows 7" || getOsVersion()=="Windows 8" || getOsVersion()=="Windows 8.1")
{
iData.cbSize = sizeof(NOTIFYICONDATA);
}
else if (getOsVersion()=="Windows XP"||getOsVersion()=="Windows XP Professional x64 Edition")
{
iData.cbSize = NOTIFYICONDATA_V3_SIZE;
}
else if (getOsVersion()=="Windows 2000")
{
iData.cbSize = NOTIFYICONDATA_V2_SIZE;
}
else if (getOsVersion()=="UNKNOWN OS")
{
//Assume we have old Windows Os such as Me,95....
iData.cbSize = NOTIFYICONDATA_V1_SIZE;
}
iData.hWnd = wHandler;
iData.uID = 100;
iData.uVersion = NOTIFYICON_VERSION_4;
iData.uCallbackMessage = WM_MESSAGE;
iData.hIcon = LoadIcon(NULL,(LPCTSTR)IDI_WARNING);
lstrcpy(iData.szTip,"My First Tray Icon");
lstrcpy(iData.szInfo,"My App Info");
lstrcpy(iData.szInfoTitle,"My Info Title");
iData.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
Shell_NotifyIcon(NIM_SETVERSION,&iData); //called only when usingNIM_ADD
Shell_NotifyIcon(NIM_ADD,&iData);
}
I added NIF_INFO to the uFlags and the problem is gone. Now it displays everything including text, title and info title.
The code below is what solved it.
iData.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP|NIF_SHOWTIP|NIF_INFO;
Your biggest problem with the code in the question is that you pass the wrong window handle. You have to pass one of your window handles. But instead you pass the window handle of the desktop.
You will need to create a window and use its handle. The window does not need to be visible. I believe that you can use a message only window.
You must also call NIM_SETVERSION after NIM_ADD.
I'm very sceptical of your version switching being based on string equality testing. Your code will break on Windows 9 for instance. Use the version helper functions.
You also perform no error checking. This isn't the easiest function to call but your failure to check for errors makes things even harder than they need to be. Please read the documentation and add error checking code.

Getting ActiveX window handle

I have followed this link to get the window handle of a ActiveX control
Sample Code from microsoft's site
// The following code should return the actual parent window of the ActiveX control.
HWND CMyOleControl::GetActualParent()
{
HWND hwndParent = 0;
// Get the window associated with the in-place site object,
// which is connected to this ActiveX control.
if (m_pInPlaceSite != NULL)
m_pInPlaceSite->GetWindow(&hwndParent);
return hwndParent; // Return the in-place site window handle.
}
But in my case I keep finding that "m_pInPlaceSite" is always NULL. I'm trying to run this code in my controls FinalConstruct. Is there something else I need to implement for the m_pInPlaceSite to be given a value? Or do I need to Query to get the value.
Thanks
FinalConstruct is way too early. In FinalConstruct your class is just being created and is not yet initialized. There is no "in place" site, there is no yet site at all.
Your control will be called by its owner, it will be given its site, then activated - only then you will possibly have m_pInPlaceSite available.

Passing Data to Windows Console Control Handler

I am working on writing a simple game engine and I am having trouble handling Windows console events; specifically, I cannot figure out how to pass custom data to the callback handler.
I first call this code to specify my callback function:
SetConsoleCtrlHandler((PHANDLER_ROUTINE)WindowsSystemManager::ConsoleControlHandler, true);
My static-member callback function is defined as:
bool WINAPI WindowsSystemManager::ConsoleControlHandler(DWORD controlType){
if(controlType == CTRL_CLOSE_EVENT){
MessageBox(NULL, L"Close Event Captured", L"Close Event Captured", NULL);
}
return true;
}
Everything works fine - when I click on the close button in the console, this MessageBox pops up. Only problem is, I need to call code that flushes a logging buffer to a log file on this type of shutdown (as well as other clean-up), and the Logger instance is a member in my WindowsSystemManager.
I have dealt with a similar problem of passing custom data to window handles by using SetWindowLongPtr and GetWindowLongPtr successfully, but I can't find any information on how to do this type of thing with console control handlers. Any thoughts?
EDIT: I got this functionality working based on MSalters' suggestions. The final code for the console control handler is here:
bool WINAPI WindowsSystemManager::ConsoleControlHandler(DWORD controlType){
BerserkEngine* engine = (BerserkEngine*)GetWindowLongPtr(GetConsoleWindow(), GWLP_USERDATA);
if(controlType == CTRL_CLOSE_EVENT){
engine->~BerserkEngine();
PostQuitMessage(0);
}
return true;
}
Where I set this custom data pointer in the WindowsSystemManager constructor:
SetWindowLongPtr(GetConsoleWindow(), GWL_USERDATA, (LONG_PTR)this->engine);
I'm not sure why you'd need this. You can have multiple windows, but only one console.
However, GetConsoleWindow will give you the console HWND, on which you might call SetWindowLongPtr. Not very clean (you're not supposed to do this on windows that you don't manage), but it might just work.

Maximized Window Restores to Full Screen

Using CWnd::ShowWindow(SW_SHOWMAXIMIZED) maximizes my app window as expected.
However, when clicking the restore button on the app (or double clicking the title-bar), the restored size is the same size as the maximized window, which is confusing for the user.
Using this alternative code has the same problem:
WINDOWPLACEMENT wndpl;
GetWindowPlacement(&wndpl);
wndpl.showCmd = SW_SHOWMAXIMIZED;
SetWindowPlacement(&wndpl);
How can I keep the default un-maximized size when restoring.
I've solved my problem, and the solution might solve yours too. My problem was that even though I called SetWindowPlacement(&wndpl) within CMainFrame::OnCreate the window was not properly restored if it was maximized. I added two lines of code before SetWindowPlacement, and now it works as expected.
CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
// Obtain wndpl, maybe from registry
AfxGetApp()->m_nCmdShow = wndpl.showCmd;
wndpl.showCmd = SW_SHOW;
SetWindowPlacement(&wndpl);
}
These two lines helps underlying code not to mess things up when calling ActivateFrame, which calls ShowWindow with parameter obtained from CWinApp::m_nCmdShow.
All information are in the file with extension .RC. I never used a Maximize/Restore procedures though you should look for a 'DIALOGEX' for the same window. You can change it using any editor (notepad, ultraedit etc.)