Desktop Elements with Winapi - c++

I'm trying to get the elements in the desktop (icon shortcuts) using winapi, but for some reason I'm getting nothing. Am I doing it wrong? (I'm very new to this)
BOOL CALLBACK EnumChildWindows(HWND hwnd,LPARAM lParam) {
char str[256];
GetWindowTextA(hwnd, str, 200);
OutputDebugStringA(str);
return true;
}
Inside wWinMain:
HWND hDesktop = GetDesktopWindow();
EnumChildWindows(hDesktop, 0);

You used the EnumChildWindows function by mistake:
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {
char str[256]{};
GetWindowTextA(hwnd, str, 200);
OutputDebugStringA(str);
return true;
}
int main(int argc, const char* argv[])
{
HWND hDesktop = GetDesktopWindow();
EnumChildWindows(hDesktop, EnumChildProc, 0);
return 0;
}
You need to set a callback function and call it with EnumChildWindows.
Of course, this cannot get the name of the "desktop shortcut", what you get is the name of all child windows.
If you want to get the name and location of the desktop shortcut, you need to use COM related, here is an example:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <ShlObj.h>
#include <atlbase.h>
int main(int argc, char** argv)
{
CComPtr<IShellWindows> spShellWindows;
CComPtr<IShellBrowser> spBrowser;
CComPtr<IDispatch> spDispatch;
CComPtr<IShellView> spShellView;
CComPtr<IFolderView> spView;
CComPtr<IShellFolder> spFolder;
CComPtr<IEnumIDList> spEnum;
CComHeapPtr<ITEMID_CHILD> spidl;
CComVariant vtLoc(CLSID_ShellWindows);
CComVariant vtEmpty;
STRRET str;
int count = 0;
HRESULT hr;
long lhWnd;
// INITIALIZE COM
CoInitialize(NULL);
// GET ShellWindows INTERFACE
hr = spShellWindows.CoCreateInstance(CLSID_ShellWindows);
// FIND WINDOW
hr = spShellWindows->FindWindowSW(
&vtLoc, &vtEmpty, SWC_DESKTOP, &lhWnd, SWFO_NEEDDISPATCH, &spDispatch);
// GET DISPATCH INTERFACE
CComQIPtr<IServiceProvider>(spDispatch)->
QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&spBrowser));
spBrowser->QueryActiveShellView(&spShellView);
spShellView->QueryInterface(IID_PPV_ARGS(&spView));
hr = spView->GetFolder(IID_PPV_ARGS(&spFolder));
// GET ENUMERATOR
spView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum)); // get enumerator
// ENUMERATE ALL DESKTOP ITEMS
for (; spEnum->Next(1, &spidl, nullptr) == S_OK; spidl.Free()) {
// GET/PRINT ICON NAME AND POSITION
char* name;
POINT pt;
spFolder->GetDisplayNameOf(spidl, SHGDN_NORMAL, &str);
StrRetToStrA(&str, spidl, &name);
spView->GetItemPosition(spidl, &pt);
printf("%5d %5d \"%s\"\n", pt.x, pt.y, name);
}
CoUninitialize(); // release COM
exit(0);
}

Related

Changing the title of uwp process

I want to change the title bar of calc.exe. I read that it's done via SetWindowTextA() but when I used this it only change the title of the preview (1) and I want to change title at (2) as well.
Can anyone explain for me why it change the title at (1) not (2) and how can I change the title at (2)
The Calculator title is Text Control Type retrieved using UI Automation. However according to Text Control Type, the IValueProvider is never supported by text controls. So you can’t.
Edit:
#include <Windows.h>
#include <UIAutomation.h>
#include <wchar.h>
int Element(IUIAutomation* automation)
{
// Get the element under the cursor
// Use GetPhysicalCursorPos to interact properly with
// High DPI
POINT pt;
GetPhysicalCursorPos(&pt);
IUIAutomationElement* pAtMouse;
HRESULT hr = automation->ElementFromPoint(pt, &pAtMouse);
if (FAILED(hr))
return hr;
// Get the element's name and print it
BSTR name;
hr = pAtMouse->get_CurrentName(&name);
if (SUCCEEDED(hr))
{
IUIAutomationTextPattern* pattern;
pAtMouse->GetCurrentPatternAs(UIA_TextPatternId, IID_IUIAutomationTextPattern,(void**)&pattern);
//TODO
wprintf(L"Element's Name: %s \n", name);
SysFreeString(name);
}
// Get the element's Control Type (in the current languange)
// and print it
BSTR controlType;
hr = pAtMouse->get_CurrentLocalizedControlType(&controlType);
if (SUCCEEDED(hr))
{
wprintf(L"Element's Control Type: %s \n", controlType);
SysFreeString(controlType);
}
// Clean up our COM pointers
pAtMouse->Release();
return hr;
}
int main(int argc, TCHAR* argv[])
{
// Initialize COM and create the main Automation object
IUIAutomation* g_pAutomation;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation),
(void**)&g_pAutomation);
if (FAILED(hr))
return (hr);
bool quit = false;
while (!quit)
{
SHORT leftControlMod = GetAsyncKeyState(VK_LCONTROL);
if (leftControlMod != 0)
{
Element(g_pAutomation);
}
quit = GetAsyncKeyState(VK_ESCAPE);
}
g_pAutomation->Release();
CoUninitialize();
return 0;
}

Control path to pinned application to taskbar with Qt

How control path to pinned application to taskbar with Qt
Since I myself have been searching with a lot of effort for a way to customize the program path to an application pinned to the taskbar, I wanted to post here my solution related to Qt.
Problem was, that I link the starter in a set of programs (starter/updater, main) when pinning the main program.
EventFilterPinnable.h
#pragma once
#include <QAbstractNativeEventFilter>
#include <windows.h>
#include <windowsx.h>
#include <shellapi.h>
#include <propsys.h>
#include <propkey.h>
#include <propvarutil.h>
HRESULT PropertyStoreSetStringValue(IPropertyStore* propertyStore, REFPROPERTYKEY pkey, PCWSTR value)
{
PROPVARIANT propVariant;
HRESULT hr = InitPropVariantFromString(value, &propVariant);
if(SUCCEEDED(hr))
{
hr = propertyStore->SetValue(pkey, propVariant);
PropVariantClear(&propVariant);
}
return hr;
}
HRESULT MakeWindowPinnable(HWND hwnd, PCWSTR userModelId, PCWSTR relaunchCommand, PCWSTR relaunchDisplayName, PCWSTR relaunchIcon = NULL)
{
IPropertyStore* propertyStore;
HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&propertyStore));
if(SUCCEEDED(hr))
{
PropertyStoreSetStringValue(propertyStore, PKEY_AppUserModel_ID, userModelId);
PropertyStoreSetStringValue(propertyStore, PKEY_AppUserModel_RelaunchCommand, relaunchCommand);
PropertyStoreSetStringValue(propertyStore, PKEY_AppUserModel_RelaunchDisplayNameResource, relaunchDisplayName);
if(relaunchIcon != NULL)
{
PropertyStoreSetStringValue(propertyStore, PKEY_AppUserModel_RelaunchIconResource, relaunchIcon);
}
propertyStore->Release();
}
return hr;
}
void OnCreate(HWND hwnd)
{
std::wstring sAppId = L"unique.app.id";
std::wstring sAppRelaunchCommand = L"\"C:\\Program Files\\Path with spaces\\Starter.exe\" -a argument1";
std::wstring sAppRelaunchDisplayName = L"Name of progam";
std::wstring sAppRelaunchIcon = L"\"C:\\Program Files\\Path with spaces\\Icon.ico\"";
MakeWindowPinnable(hwnd, sAppId.c_str(), sAppRelaunchCommand.c_str(), sAppRelaunchDisplayName.c_str(), sAppRelaunchIcon.c_str());
}
class EventFilterPinnable : public QAbstractNativeEventFilter
{
public:
EventFilterPinnable() {}
bool nativeEventFilter(const QByteArray& eventType, void* message, long* /*res*/) override
{
if(eventType == "windows_generic_MSG") {
MSG* msg = static_cast<MSG*>(message);
HWND hwnd = msg->hwnd;
if (msg->message==WM_CREATE)
{
OnCreate(hwnd);
}
}
return false;
}
};
in main.cpp simply add
QApplication app(argc, argv);
app.installNativeEventFilter(new EventFilterPinnable());
....
app.exec();

How can DOM elements be retrieved from a C++ program?

I would need to get all elements of webpage displayed in IE from a c++ program.
I tried to see with spy++ but there's only the IEFrame.
So I'm thinking about using the developement tool (F12 in IE), I heard there's a way to automat it, a good idea ?
Thanks
You can get an IHtmlDocument2 reference from an IE's window handle, even out-of-process. This is documented here https://support.microsoft.com/en-us/help/249232/how-to-get-ihtmldocument2-from-a-hwnd, but not really supported by Microsoft.
However it looks like it still works today, I've tested it with a Windows 10 box, and IE is now a frozen app, so not going to change any time soon.
Once you have the proper HWND for Internet Explorer, than you can get the DOM with a code like this. Make sure IE and your program run at the same security level
The DOM is the same as when you're coding IE inprocess (host, activex, etc.), however for security reasons, some things may not work :
void DoSomeDomOperations(HWND hwnd)
{
UINT msg = RegisterWindowMessage(L"WM_HTML_GETOBJECT");
LRESULT result = 0;
SendMessageTimeout(hwnd, msg, NULL, NULL, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&result);
if (!result)
return;
// get main document object
IHTMLDocument2 *doc = NULL;
ObjectFromLresult(result, IID_IHTMLDocument2, NULL, (void**)&doc);
if (!doc)
return;
// get document's url
BSTR url = NULL;
doc->get_URL(&url);
wprintf(L"url:%s\n", url);
SysFreeString(url);
// get body element
IHTMLElement *element = NULL;
doc->get_body(&element);
if (element)
{
BSTR text = NULL;
element->get_innerText(&text);
wprintf(L"text:%s\n", text);
SysFreeString(text);
element->Release();
}
// etc.
// etc.
doc->Release();
}
And here is a full sample console app that scans all current IE processes running:
BOOL CALLBACK GetIEServerWindowProc(HWND hwnd, LPARAM lParam)
{
// enumerate all child windows to find IE's COM server
wchar_t className[100];
GetClassName(hwnd, className, 100);
if (!wcscmp(className, L"Internet Explorer_Server"))
{
*((HWND*)lParam) = hwnd;
return FALSE;
}
return TRUE;
}
HWND GetIEServerWindow(HWND hwnd)
{
HWND serverHwnd = NULL;
EnumChildWindows(hwnd, GetIEServerWindowProc, (LPARAM)&serverHwnd);
return serverHwnd;
}
struct IEServer
{
DWORD processId;
HWND serverHwnd;
};
BOOL CALLBACK GetIEProcessServerWindowProc(HWND hwnd, LPARAM lParam)
{
DWORD processId = ((IEServer*)lParam)->processId;
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
if (pid == processId)
{
HWND serverHwnd = GetIEServerWindow(hwnd);
if (serverHwnd)
{
((IEServer*)lParam)->serverHwnd = serverHwnd;
return FALSE;
}
}
return TRUE;
}
HWND GetIEProcessServerWindow(DWORD processId)
{
IEServer ie = { processId, NULL };
EnumWindows(GetIEProcessServerWindowProc, (LPARAM)&ie);
return ie.serverHwnd;
}
void EnumerateIEProcesses()
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (h == INVALID_HANDLE_VALUE)
return;
PROCESSENTRY32 process;
process.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(h, &process))
{
do
{
// we only consider IE processes
if (!wcscmp(process.szExeFile, L"iexplore.exe"))
{
HWND serverHwnd = GetIEProcessServerWindow(process.th32ProcessID);
if (serverHwnd)
{
DoSomeDomOperations(serverHwnd);
}
}
} while (Process32Next(h, &process));
}
CloseHandle(h);
}
int main()
{
CoInitialize(NULL);
EnumerateIEProcesses();
CoUninitialize();
return 0;
}

UrlToDownloadFile function not downloading

I am using UrlToDownloadFile function, but it doesn't download the file. No error shown in compiler (using VStudio 2012)
Here is the code:
#include <Windows.h>
#include "urlmon.h"
#pragma lib "urlmon.lib"
using namespace std;
void dwFile();
int _tmain(int argc, _TCHAR* argv[])
{
dwFile ();
return 0;
}
void dwFile ()
{
LPCSTR url = ("http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf");
LPCSTR fPath = ("C:\\Users\\Andyy\\Desktop\\test\\n3337.pdf");
HRESULT URLDownloadToFile ((NULL, url, fPath, 0, NULL));
}
Your code is not doing any error handling, and your string handling is wrong. Use this instead:
#include <Windows.h>
#include "urlmon.h"
#pragma lib "urlmon.lib"
using namespace std;
void dwFile();
int _tmain(int argc, _TCHAR* argv[])
{
dwFile ();
return 0;
}
void dwFile ()
{
LPCTSTR url = TEXT("http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf");
LPCTSTR fPath = TEXT("C:\\Users\\Andyy\\Desktop\\test\\n3337.pdf");
HRESULT hr = URLDownloadToFile (NULL, url, fPath, 0, NULL);
if (FAILED(hr))
{
// do something ...
}
/* or more preffered:
LPCWSTR url = L"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf";
LPCWSTR fPath = L"C:\\Users\\Andyy\\Desktop\\test\\n3337.pdf");
HRESULT hr = URLDownloadToFileW (NULL, url, fPath, 0, NULL);
if (FAILED(hr))
{
// do something ...
}
*/
}
Do note the following comment in the documentation:
URLDownloadToFile returns S_OK even if the file cannot be created and the download is canceled. If the szFileName parameter contains a file path, ensure that the destination directory exists before calling URLDownloadToFile. For best control over the download and its progress, an IBindStatusCallback interface is recommended.

Getting the window title from a process name

I am trying to write a program that can get the window title of a process.
Before I describe the problem, here is the code:
#include <Windows.h>
#include <string>
#include <Psapi.h>
#include <algorithm>
std::string window_title;
std::string search_for;
BOOL CALLBACK EnumWindowCallback(HWND hWindow, LPARAM param)
{
if ( IsWindow( hWindow ) == TRUE )
{
DWORD pid = 0;
if ( GetWindowThreadProcessId( hWindow, &pid ) != 0 )
{
HANDLE hProcess;
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid );
if ( hProcess != 0 )
{
std::string path;
CHAR name[MAX_PATH];
GetModuleFileNameExA( hProcess, NULL, name, sizeof(name) / sizeof(CHAR) );
path = name;
unsigned int slash = path.find_last_of('\\');
if ( slash != std::string::npos ){
std::string proc_name = path.substr( slash + 1, path.length() );
std::transform(proc_name.begin(), proc_name.end(), proc_name.begin(), ::tolower);
if ( proc_name == search_for )
{
CHAR finalTitle[MAX_PATH];
ZeroMemory( finalTitle, sizeof(finalTitle) );
SendMessageA( hWindow, WM_GETTEXT, (WPARAM)sizeof(CHAR)/sizeof(MAX_PATH), (LPARAM)finalTitle );
window_title = finalTitle;
return FALSE;
}
}
}
}
}
return TRUE;
};
const char* __stdcall GetWinTitleByProcessName( const char* title )
{
search_for = title;
std::transform(search_for.begin(), search_for.end(), search_for.begin(), ::tolower);
if ( EnumWindows( (WNDENUMPROC)EnumWindowCallback, 0 ) == FALSE )
{
return window_title.c_str();
}
return "NOTFOUND";
}
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
MessageBoxA( NULL, GetWinTitleByProcessName("chrome.exe"), "Test", MB_OK);
}
The program works so far, until I want to get the actual title of the window.
I tried GetWindowText and SendMessage, as shown here.
Both methods return empty strings.
How can I get the window title?
The following code works for a similar problem. In my case I am looking for the windows handle of an application so that I can parent a dll. I identify the app by its caption. Its C++Builder code so some parts may be unfamiliar. I'll comment the differences I spot. The main one is the use of Application, I'm not sure what the non-Embarcadero equivalent is, but each running instance of code has an Application instance that manages the message loop and so on. I set my dll's Application->Handle to the calling apps hWnd to keep it off the taskbar, among other things. This code works on xp, vista 32 and win7 64.
void HideDLL() {
if (Application->Handle == 0) {
SearchObject *so = new SearchObject();
so->Caption = L"MyCallingApp";
so->Handle = 0;
EnumWindows((WNDENUMPROC)EnumWindowsProc, (long)so);
Application->Handle = so->Handle;
delete so;
}
}
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lparam) {
bool result;
SearchObject *so = (SearchObject*)lparam;
wchar_t *caption = new wchar_t[STR_DEFAULT];
GetWindowTextW(hWnd, caption, STR_DEFAULT);
// String is an Embarcadero type representing UnicodeString
String Caption = caption;
// Pos is a wrapper around strstr I think
// the actual caption in my case is decorated with some other stuff
// I only know that it will start with the name of the app
if (Caption.Pos(so->Caption) > 0) {
so->Handle = hWnd;
result = false;
} else {
result = true;
}
delete caption;
return result;
}
Hope this helps.
It seems that (WPARAM)sizeof(CHAR)/sizeof(MAX_PATH) would return you zero, because sizeof(char) will be defenetly smaller then the max path, so you say to WinAPI that your variable has zero length, that's why it returns empty string to you.
Specify there MAX_PATH value instead.