c++ ui automation - click a button programmatically - c++

I need to click on the "I Agree" button in the below code programmatically, could you please help? is this possible to use SendMessage(hButton, BM_CLICK, 0, 0); ?
typedef HRESULT STDAPICALLTYPE AcquireDeveloperLicense(
_In_opt_ HWND hwndParent,
_Out_ FILETIME *pExpiration
);
HINSTANCE hDll = LoadLibrary(TEXT("WSClient.dll"));
AcquireDeveloperLicense *acquire_license = (AcquireDeveloperLicense*)GetProcAddress(hDll, "AcquireDeveloperLicense");
FILETIME pExpiration = {};
HWND hwnd = GetConsoleWindow();
HRESULT result = acquire_license(hwnd, &pExpiration);

Related

Shell_NotifyIcon creates blank, unresponsive icon in system tray

I am trying to make a simple system tray icon app. Here is the heart of the code.
WNDCLASSEX wx = {};
wx.cbSize = sizeof( WNDCLASSEX );
wx.lpfnWndProc = WndProc; // function which will handle messages
wx.hInstance = hInstance;
wx.lpszClassName = szWindowClass;
if ( RegisterClassEx( &wx ) == 0 ) {
fileLogger->critical("Failed to register class");
return 0;
}
HWND hWnd = CreateWindowEx(
0, // _In_ DWORD dwExStyle,
szWindowClass, // _In_opt_ LPCTSTR lpClassName,
szTitle, // _In_opt_ LPCTSTR lpWindowName,
0, // _In_ DWORD dwStyle,
0, // _In_ int x,
0, // _In_ int y,
0, // _In_ int nWidth,
0, // _In_ int nHeight,
HWND_MESSAGE, // _In_opt_ HWND hWndParent,
NULL, // _In_opt_ HMENU hMenu,
hInstance, // _In_opt_ HINSTANCE hInstance,
NULL // _In_opt_ LPVOID lpParam
);
if ( hWnd == NULL )
{
fileLogger->critical("Failed to create window. Error code "+std::to_string(GetLastError()));
return 0;
}
NOTIFYICONDATA nid = {};
nid.uVersion = NOTIFYICON_VERSION_4;
nid.cbSize = sizeof( nid );
nid.hWnd = hWnd;
nid.guidItem = myGUID;
nid.uCallbackMessage = ICON_MESSAGE;
StringCchCopy( nid.szTip, sizeof( nid.szTip )/sizeof( nid.szTip[0] ), "Starting Client" );
// Loading a windows system icon for testing
LoadIconMetric( NULL, (PCWSTR)MAKEINTRESOURCE( IDI_ASTERISK ), LIM_LARGE, &(nid.hIcon) );
if ( ! Shell_NotifyIcon( NIM_ADD, &nid ) ) {
fileLogger->critical("Shell_NotifyIcon failure.");
return 0;
}
...
When I compile and run the executable from the command prompt, it creates a blank space in the system tray. I also returns immediately (maybe normal) even though the process is still running. I see no tooltip when I hover over the blank icon, and the blank spot persists until I manually terminate the program. The icon does not seem to be passing messages to WndProc when I click it.
Possible clue: According to every piece of documentation I've seen, this line
LoadIconMetric( NULL, (PCWSTR)MAKEINTRESOURCE( IDI_ASTERISK ), LIM_LARGE, &(nid.hIcon) );
Should be
LoadIconMetric( NULL, MAKEINTRESOURCE( IDI_ASTERISK ), LIM_LARGE, &(nid.hIcon) );
Why would I have to typecast it when apparently nobody else does?
That may or may not be related to my problem, but is definitely suspicious.
The first thing is that you don't set flags to indicate which fields are supplied:
nid.uFlags = NIF_ICON | NIF_TIP | NIF_GUID | NIF_MESSAGE;
I also suspect that you may have mixed Unicode / ASCII code. You should explicitly use wide char versions of functions.

Winrt Message Dialog not showing

I am trying to display a Message Dialog in C++ (winrt) from a Desktop Windows App targeting Win 10 x64. The following code executes but the dialog is not shown. Return code from ShowAsync is good
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
Microsoft::WRL::Wrappers::RoInitializeWrapper init(RO_INIT_SINGLETHREADED);
Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IMessageDialogFactory> messageDialogFactory;
Microsoft::WRL::Wrappers::HStringReference messageDialogFactoryId(RuntimeClass_Windows_UI_Popups_MessageDialog);
Windows::Foundation::GetActivationFactory(messageDialogFactoryId.Get(), messageDialogFactory.GetAddressOf());
Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IMessageDialog> messageDialog;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Popups::IUICommand*>> uiCommands;
messageDialogFactory->CreateWithTitle(Microsoft::WRL::Wrappers::HStringReference(L"XXX").Get(), Microsoft::WRL::Wrappers::HStringReference(L"YYY").Get(), messageDialog.GetAddressOf());
messageDialog->get_Commands(uiCommands.GetAddressOf());
Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IUICommandFactory> uiCommandFactory;
Microsoft::WRL::Wrappers::HStringReference commandFactoryId(RuntimeClass_Windows_UI_Popups_UICommand);
Windows::Foundation::GetActivationFactory(commandFactoryId.Get(), uiCommandFactory.GetAddressOf());
w::ComPtr<pu::IUICommand> button;
uiCommandFactory->CreateWithHandler(Microsoft::WRL::Wrappers::HStringReference(L"ZZZ").Get(), new ButtonHandler(), button.GetAddressOf());
uiCommands->Append(button.Get());
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand*>> showOperation;
HRESULT hr = messageDialog->ShowAsync(showOperation.GetAddressOf());
MSG msg;
while( ::GetMessage(&msg, 0, 0, 0) > 0 )
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return 0;
}
Should have read documentation - API doesn't have the DualApiPartitionAttribute

C++ run a function in async and not block the ui

I have a small app that checks the dotnet framework, if it is not installed it will install it
Now when the application starts i want to popup a gif image with something like loading and in background check the framework and install.
the catch here is that it can not have any prerequisite to run the application
here is what i have till now
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
int exitCode = -1;
showPic(hInstance);
MessageBox(0L, L"Dotnet will installed", L"Alert", 0);
auto fut = std::async(std::launch::async, DoWork, hInstance, lpCmdLine);
fut.wait();
exitCode = fut.get();
return exitCode;
}
showPic()
void showPic(HINSTANCE hInstance)
{
loadImage(hInstance);
// create window
wnd = createWindow(hInstance);
SetWindowLong(wnd, GWL_STYLE, 0);
ShowWindow(wnd, SW_SHOW);
}
loadImage(HINSTANCE hInstance)
void loadImage(HINSTANCE hInstance)
{
imageDC = CreateCompatibleDC(NULL);
imageBmp = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
imageBmpOld = (HBITMAP)SelectObject(imageDC, imageBmp);
}
Now what is happening here is that the if i dont show the messagebox the picture does not load in the window, and still the window goes into not responding mode also i could not get it work with gif, only with bmp images
any help is appriciated
now since i wait for fut it is obvious that it will block the ui until it has the value, what is the workaround for that
This should be simple. Create the window, show it, call the thread, go to main message loop. When thread is done it will destroy the window.
struct T_data {
HWND hWnd;
HINSTANCE hInstance;
LPTSTR cmdline;
int exitCode;
};
DWORD WINAPI taking_too_long(LPVOID p) {
Sleep(2000); //wait at least 2 seconds!
T_data* data = reinterpret_cast<T_data*>(p);
auto fut = std::async(std::launch::async, DoWork, data->hInstance, data->lpCmdLine);
fut.wait();
data->exitCode = fut.get();
//make sure the window handles IDM_EXIT to close itself
PostMessage(data->hWnd, WM_COMMAND, IDM_EXIT, 0);
}
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR lpCmdLine, int) {
T_data data;
data.exitCode = -1;
data.hWnd = hWnd;
data.hInstance = hInstance;
data.cmdline = lpCmdLine;
data.hWnd = showPic(hInstance);
CreateThread(NULL, 0, taking_too_long, &data, 0, NULL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return data.exitCode;
}

How to set the window's default position?

I'm using Dev C++. After I created a windows application, it generated some code which creates a window. I understand the code broadly. I've found the code to set the size, title, and background color but how do I set up the default position of the new window? I want to start it at the center of the screen.
You should have CreateWindow function, its definition is as follows:
HWND WINAPI CreateWindow(
__in_opt LPCTSTR lpClassName,
__in_opt LPCTSTR lpWindowName,
__in DWORD dwStyle,
__in int x,
__in int y,
__in int nWidth,
__in int nHeight,
__in_opt HWND hWndParent,
__in_opt HMENU hMenu,
__in_opt HINSTANCE hInstance,
__in_opt LPVOID lpParam
);
The x and y parameters specify the location of the newly-created window. These are the ones you need to set.

How to explicitly set taskbar icon?

In Visual Studio I generated a plain old Win32 application and stripped all the resources and generated code so that my application consists of this:
#include "stdafx.h"
#include "IcoTest.h"
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
::MessageBox( NULL, L"Testing", L"Test", MB_OK );
}
When I run the application, this is what I see:
So the question is can I change that default application icon in the taskbar? If so, what code needs to be added to do it?
Edit:
Here's what I did, and this kind of works but it isn't ideal. The new icon shows up alright, but the taskbar preview window in Vista doesn't work and the system menu doesn't work so I'm just going to leave it alone for now.
HWND CreateDummyWindow(HINSTANCE hInstance, int iconId, LPCTSTR taskbarTitle)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DefWindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(iconId));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = taskbarTitle,
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(iconId));
ATOM atom = RegisterClassEx(&wcex);
HWND wnd = ::CreateWindow(
wcex.lpszClassName, taskbarTitle, WS_ICONIC | WS_DISABLED,
-1000, -1000, 1, 1, NULL, NULL, hInstance, NULL);
return wnd;
}
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
HWND wnd = CreateDummyWindow(hInstance, IDI_ICON1, _T("Test") );
::MessageBox( wnd, _T("Testing"), _T("Test"), MB_OK );
::DestroyWindow( wnd );
}
The icon shown on the task bar is taken from the window itself. If the only window is the standard Windows MesssageBox, then you'll get some sort of OS default. You have to create your own window and give it an icon, then Windows will use that.
This looks like just sample code. If the real code is a non-console Windows application, you can do this:
Give your application's main window a task bar icon by calling SetIcon(). Then when you call MessageBox(), set the first parameter to the HWND of your application's main window.
For this particular case (one MessageBox call in the WinMain function) you could hook the message box dialog creation and set an icon there. Like this:
HHOOK g_hMsgBoxHook;
HINSTANCE g_hInstance;
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode == HC_ACTION)
{
CWPSTRUCT* pcwp = (CWPSTRUCT*)lParam;
if(pcwp->message == WM_INITDIALOG)
{
HICON hIcon = NULL;
HICON hIconBig = NULL;
// Small icon.
hIcon = (HICON)LoadImage(g_hInstance,
MAKEINTRESOURCE(IDI_MYICON),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0);
if(hIcon)
{
SendMessage(pcwp->hwnd, WM_SETICON,
ICON_SMALL, (LPARAM)hIcon);
}
// Big icon.
hIconBig = (HICON)LoadImage(g_hInstance,
MAKEINTRESOURCE(IDI_MYICON),
IMAGE_ICON,
GetSystemMetrics(SM_CXICON),
GetSystemMetrics(SM_CXICON),
0);
if(hIconBig)
{
SendMessage(pcwp->hwnd, WM_SETICON,
ICON_BIG, (LPARAM)hIconBig);
}
}
}
return CallNextHookEx(g_hMsgBoxHook, nCode, wParam, lParam);
}
int CALLBACK wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow
)
{
g_hInstance = hInstance;
g_hMsgBoxHook = SetWindowsHookEx(WH_CALLWNDPROC,
CallWndProc, NULL, GetCurrentThreadId());
MessageBoxW(NULL, L"Testing", L"Test", MB_OK);
// ...
UnhookWindowsHookEx(g_hMsgBoxHook);
}
Where IDI_MYICON is the ID of your icon resource.
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(wndclass);
// ..
wndclass.hIconSm = ExtractIconEx( ... );
RegisterClassEx(&wndclass);
HWDN wnd = CreateWindow(...)
Why not just add an icon resource to the EXE? I'm pretty sure Windows will try that before falling back to the "generic" icons.
Create a form but never show it then assign it an icon and use that as the parent of your message box.
This hides the icon:
using (var f = new Form())
{
MessageBox.Show(f,"my message");
}
This will create an icon:
using (var f = new Form())
{
f.Icon = Resources.IconUpload;
f.Location=new Point(-1000,-1000);
f.StartPosition = FormStartPosition.Manual;
f.Show();
MessageBox.Show(f,"my message");
}