Executing "Show Desktop" from C++ - c++

I am designing a system where the user makes a gesture, then my program captures it (using a web cam) and my program looks in a rule system (based on XML) which are the actions that it has to do.
Ok, once I have explained the background, I'd like to know how I could make my program "execute" the Show Desktop button. I'd like to provide the user the possibility to do a gesture and show the desktop. Is it possible? I have been looking the program (.exe) that executes the Show Desktop button and I am afraid that does not exist.

From this MSDN blog post (dated 2004 but surely still valid), you must call ToggleDesktop().
in C#:
// Create an instance of the shell class
Shell32.ShellClass objShel = new Shell32.ShellClass();
// Show the desktop
((Shell32.IShellDispatch4) objShel).ToggleDesktop();
// Restore the desktop
((Shell32.IShellDispatch4) objShel).ToggleDesktop();
EDIT
C++ version:
#include <Shldisp.h>
CoInitialize(NULL);
// Create an instance of the shell class
IShellDispatch4 *pShellDisp = NULL;
HRESULT sc = CoCreateInstance( CLSID_Shell, NULL, CLSCTX_SERVER, IID_IDispatch, (LPVOID *) &pShellDisp );
// Show the desktop
sc = pShellDisp->ToggleDesktop();
// Restore the desktop
sc = pShellDisp->ToggleDesktop();
pShellDisp->Release();

From http://www.codeguru.com/forum/showthread.php?t=310202:
#define MIN_ALL 419
#define MIN_ALL_UNDO 416
int main(int argc, char* argv[])
{
HWND lHwnd = FindWindow("Shell_TrayWnd",NULL);
SendMessage(lHwnd,WM_COMMAND,MIN_ALL,0); // Minimize all windows
Sleep(2000);
SendMessage(lHwnd,WM_COMMAND,MIN_ALL_UNDO,0); // Bring all back up again.
return 0;
}
Hope it helps. It at least does what it should, minimizes all the windows aka. shows desktop.

You need to call ToggleDesktop.

In Windows you can copy the script:
[Shell]
Command=2
IconFile=explorer.exe,3
[Taskbar]
Command=ToggleDesktop
into a file "somefile.scf" and invoke it from the shell by executing "somefile.scf" by hand. This is also possible with C++.

Related

Name of process for active window in Windows 8/10

The following sample has reliably returned the name of the process that is associated with the active window, but does not work with the newer modern/universal apps because it returns the name of a helper process WWAHost.exe on Windows 8 and ApplicationFrameHost.exe on Windows 10 rather than the name of the app.
HWND active_window = GetForegroundWindow();
GetWindowThreadProcessId(active_window, &active_process_id);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, active_process_id);
GetProcessImageFileName(active_process, image_name, 512);
With Windows 10 the ApplicationFrameHost.exe is the process that creates the window handles and is what gets returned by GetWindowThreadProcessId(), is there another Win32 API that can be used to get the active process of universal app that is active?
Also tried using GetApplicationUserModelId() and GetPackageFullName() with no success as they return APPMODEL_ERROR_NO_APPLICATION and APPMODEL_ERROR_NO_PACKAGE respectively because the active_process handle is just the helper process and not the process of the active application.
Any other APIs to use to get the process name of a Modern/Universal application given the hwnd of the window, or otherwise figure out the process name of the universal app is active.
Thanks in advance!
Be sure to use the Spy++ utility when you want to reverse-engineer something like this. Included with Visual Studio, you need the 64-bit version in Common7\Tools\spyxx_amd64.exe. Use Search > Find Window and drag the bullseye to a UWP app, like Weather.
You'll see the window you'll find with GetForegroundWindow(), it has at least 3 child windows:
ApplicationFrameTitleBarWindow
ApplicationFrameInputSinkWindow
Windows.Core.UI.CoreWindow, that's the host window for the UWP app and the one you are interested in. Right-click it and select Properties, Process tab, click the Process ID. That takes you to the real owner process you want to know.
So you just need to make an extra step from the code you already have, you just have to enumerate the child windows and look for one with a different owner process. Some C code, trying to make it as universal as possible without making too many assumptions and not enough error checking:
#include <stdio.h>
#include <Windows.h>
typedef struct {
DWORD ownerpid;
DWORD childpid;
} windowinfo;
BOOL CALLBACK EnumChildWindowsCallback(HWND hWnd, LPARAM lp) {
windowinfo* info = (windowinfo*)lp;
DWORD pid = 0;
GetWindowThreadProcessId(hWnd, &pid);
if (pid != info->ownerpid) info->childpid = pid;
return TRUE;
}
int main()
{
Sleep(2000);
HWND active_window = GetForegroundWindow();
windowinfo info = { 0 };
GetWindowThreadProcessId(active_window, &info.ownerpid);
info.childpid = info.ownerpid;
EnumChildWindows(active_window, EnumChildWindowsCallback, (LPARAM)&info);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, info.childpid);
WCHAR image_name[MAX_PATH] = { 0 };
DWORD bufsize = MAX_PATH;
QueryFullProcessImageName(active_process, 0, image_name, &bufsize);
wprintf(L"%s\n", image_name);
CloseHandle(active_process);
return 0;
}
Output on the Weather program:
C:\Program Files\WindowsApps\Microsoft.BingWeather_4.5.168.0_x86__8wekyb3d8bbwe\
Microsoft.Msn.Weather.exe
Here is a small console app application that continuously (so you can test it easily selecting different windows on your desktop) display information about the current foreground window process and store process, if any.
Apps can have a window hierarchy that can span multiple processes. What I do here is search the first sub window that has the 'Windows.UI.Core.CoreWindow' class name.
This app uses the UIAutomation API (and also smart pointers, smart BSTRs and smart VARIANTs provided by the #import directive). I suppose you can do the same with standard Windows SDK, but I find the UIAutomation used this way quite elegant.
#include "stdafx.h"
#import "UIAutomationCore.dll"
using namespace UIAutomationClient;
int main()
{
// initialize COM, needed for UIA
CoInitialize(NULL);
// initialize main UIA class
IUIAutomationPtr pUIA(__uuidof(CUIAutomation));
do
{
// get the Automation element for the foreground window
IUIAutomationElementPtr foregroundWindow = pUIA->ElementFromHandle(GetForegroundWindow());
wprintf(L"pid:%i\n", foregroundWindow->CurrentProcessId);
// prepare a [class name = 'Windows.UI.Core.CoreWindow'] condition
_variant_t prop = L"Windows.UI.Core.CoreWindow";
IUIAutomationConditionPtr condition = pUIA->CreatePropertyCondition(UIA_ClassNamePropertyId, prop);
// get the first element (window hopefully) that satisfies this condition
IUIAutomationElementPtr coreWindow = foregroundWindow->FindFirst(TreeScope::TreeScope_Children, condition);
if (coreWindow)
{
// get the process id property for that window
wprintf(L"store pid:%i\n", coreWindow->CurrentProcessId);
}
Sleep(1000);
} while (TRUE);
cleanup:
CoUninitialize();
return 0;
}
Does taking snapshot of running processes and pulling the name out of it by comparing process id not work?
Full reference here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686837(v=vs.85).aspx
But you fix the snapshot with CreateToolhelp32Snapshot().
Or from WTSEnumerateProcesses() and surrounding API?
Pretty sure it worked in Win 8. Is it broken in 10?
Starting from Win10 Anniversary Update ApplicationFrameHost child window return anything but UWP application. It worked only in Tablet mode after relogon.

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.

Using COM methods in console application

i made a win32 console application that imports an ".ocx" file from geovision SDK. I found proper CLSID and interface ID of COM components in generated ".tli" and ".tlh" headers and everything works until i invoke any method(Login2 for example in my code below). Then _com_exception occurs and it gives no detailed info about what exactly happens.
Can anybody give me a hint what should i do next or where should i look for solution? It took me over a week to reach this point of using COM components in console application... I hope its possible to do it.
#include "stdafx.h"
#include "stdio.h"
#import "C:\Windows\GeoOCX\SinglePlayer\20121003\GVSinglePlayer.ocx" \
named_guids no_namespace no_smart_pointers
int _tmain(int argc, _TCHAR* argv[])
{
try
{
CoInitialize(NULL);
_DGVSinglePlayer* pSP = 0;
HRESULT hr = CoCreateInstance(CLSID_GVSinglePlayer ,NULL, CLSCTX_INPROC_SERVER,DIID__DGVSinglePlayer,reinterpret_cast <void**>(&pSP));
_bstr_t lpIPAddress("11.11.11.11");
long iPort=10000;
_bstr_t lpUserID("abcde");
_bstr_t lpPassword("password");
if ( SUCCEEDED ( hr ) )
{
hr = pSP->Login2(lpIPAddress,iPort,lpUserID,lpPassword );
if ( SUCCEEDED ( hr ) )
{
printf("Cool");
}
}else
{
}
pSP->Release();
CoUninitialize();
} catch (_com_error& e)
{
char buf[80];
sprintf(buf, "Error: %S",e.Description());
printf("%s\n",buf);
}
return 0;
}
Since e.Description() prints no info, I attatched visual info about the error.
Many ActiveX controls want to be properly hosted (meaning, the host implements IOleClientSite and related interfaces, and passes the pointer to the control's IOleObject::SetClientSite). Such controls return E_UNEXPECTED for all method calls until the OLE activation dance is performed.
In particular, ActiveX controls developed with MFC usually behave this way; the behavior is baked into MFC framework.
I suspect your control might be one of those. In this case, you wouldn't be able to use it easily in a console app. You would need a windowed application using a framework that implements ActiveX hosting (MFC, ATL, WinForms; others likely exist that I'm not familiar with).

how do I use find window and sendmessage in empty visual c++ project (or console app)

I want to make the most simplest application that can communicate via windows send messages (and parse json). I have found a sample code:
CWnd* pWnd = FindWindow("old title");
pWnd->SendMessage(WM_SETTEXT,0,(LPARAM)"New title");
That works... but only if I use MS Visual Studios "create new MFC form application" wizard. How can I make a console application that sends messages to my program? Or can I? What do I need to include/link if I start an empty project or console application?
The goal in pseudocode:
a = ""
while !EOF
a += read(stdin)
commandArray = jsonToArray(a)
CWnd* pWnd = FindWindow("program");
pWnd->SendMessage(WM_COPYDATASTRUCT,0,commandArrayWrappedInCOPYDATASTRUCT);
exit
The annoyance is that the effective part of the code is roughly 20 lines (above), but the wizard generated part is hundreds of lines. And most of them is stuff that I don't understand. Plus, I get a window that I don't need.
EDIT
Final main.cpp (without the json stuff):
/*
This closes calculator
*/
#include <Windows.h>
#include <atlstr.h>
int main (void)
{
HWND HWnd = FindWindow(NULL, CStringW("Calculator"));
SendMessage(HWnd, WM_CLOSE, 0, 0);
return 0;
}
br,
Juha
If you want something so simple, then I'd just forget all about MFC and start with a basic console app from the New Project Wizard. MFC seems rather heavy duty for something so simple.

PDFCreator will print TIFF instead of PDF

I am trying to convert a RTF document to PDF. I have this code:
// TestCOMPDF.cpp : Defines the entry point for the console application.
//
#include <windows.h>
#include <tchar.h>
#include <objbase.h>
#include <atlbase.h>
#import "MSVBVM60.DLL" rename ( "EOF", "VBEOF" ), rename ( "RGB", "VBRGB" ) //if you don't use this you will be in BIG trouble
#import "PDFCreator.exe"
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
{
CComPtr<PDFCreator::_clsPDFCreator> pdfObject;
HRESULT hr = pdfObject.CoCreateInstance(L"PDFCreator.clsPDFCreator");
pdfObject->cStart("/NoProcessingAtStartup", 1);
PDFCreator::_clsPDFCreatorOptionsPtr opt = pdfObject->GetcOptions();
opt->UseAutosave = 1;
opt->UseAutosaveDirectory = 1;
opt->AutosaveDirectory = "c:\\temp\\";
opt->AutosaveFormat = 0; // for PDF
opt->AutosaveFilename = "gigi13";
pdfObject->PutRefcOptions(opt);
pdfObject->cClearCache();
_bstr_t DefaultPrinter = pdfObject->cDefaultPrinter;
pdfObject->cDefaultPrinter = "PDFCreator";
hr = pdfObject->cPrintFile("c:\\temp\\RTF\\garage.rtf");
pdfObject->cPrinterStop = false;
while(true)
{
printf("sleep\n");
Sleep(1000);
if(pdfObject->cCountOfPrintjobs == 0)
break;
}
printf("done\n");
pdfObject->cPrinterStop = true;
pdfObject->cDefaultPrinter = DefaultPrinter;
}
CoUninitialize();
return 0;
}
When running this code sample instead of creating directly the PDF it prompts me with a Save dialog offering me the option to the output only with the option of choosing a TIFF file (which is not wanted). Can someone point me into the right direction or offer some suggestions?
Thanks,
Iulian
This is only a guess... I had a similar problem -- not when using PDFCreator programmatically (this is beyond my capabilities), but when using it as my standard printer to print to PDFs.
First I used it for a couple of days without any problem. Not I had installed it, but my partner. As I said... it just worked, and created beautiful PDFs.
Then, somehow, someone on our home computer (we are 3 different persons using it) must have changed the setting (maybe inadvertedly) to make it output TIFF instead of PDFs. For me, my default printer was named "PDFcreator" and it confused the hell out of me why it suddenly wanted to create TIFFs.
Meanwhile I've poked a lot in the user interface of all its settings, and learned to know where to look if something goes wrong.
The newest version in its lefthand treeview panel lists an item named "Save". If you select it, you can configure default filename conventions as well as "Standard save format". In my case in the dropdown listview there was "TIFF" selected instead of "PDF".
Looking at your code, you are somehow calling PDFCreator.exe (I don't understand the details, but I can see this string in your code). My bet would go towards this: somehow, the user account which your code uses to run under has his Standard save format set to TIFF. It may be that you look at the printer settings (on my Windows XP, I just type control printers, and rightclick the PDFCreator printername to select Properties...) and find nothing suspicious.
However, PDFcreator stores its settings for each user into a different location, probably in %userprofile%\local settings\temp\pdfcreator\..., or even in the registry...