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

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;
}

Related

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++ windows]capturing mouse click event from a window that isn't mine

I want to detect when the mouse is pressed on my wallpaper.
So I got the wallpaper handle and now I'm trying to add a message loop to it, but its not working for some reason.
Here's my code so far:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND hWallPaper = getWallPaperHWND();
if (hWallPaper != NULL)
{
MSG msg;
while (GetMessage(&msg, hWallPaper, 0, 0))
{
MessageBox(NULL, "msg", "got message", MB_OK);
}
}
else
MessageBox(NULL,"Window wasn't found","window not found",MB_OK);
return 0;
}
Why isn't it showing a message box when I fire an even on the wallpaper, like when I click on it or even just move the mouse?

Why is WinAPI not creating the window with the configured size?

I am fairly new to C++ coding so this could be a really easy fix. I have recently created a basic WinMain window. When I run the program from either the IDE or .exe file the application doesn't open at the proper size.
I can resize the window but I'm not sure why it isn't opening at that size set.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// Function prototypes
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
bool CreateMainWindow(HINSTANCE, int);
LRESULT WINAPI WinProc(HWND, UINT, WPARAM, LPARAM);
// global variable
HINSTANCE hinst;
// Constants
const char CLASS_NAME[] = "WinMain";
const char APP_TITLE[] = "Hello World";
const char WINDOW_WIDTH = 400;
const char WINDOW_HEIGHT = 400;
//==================================
// Starting point for the windows application
// Parameters are
// hInstance. Handle to the current instance of the application
// hPrevInstance. Always NULL, obsolete parameter
// lpCmdLine. Pointer to null-terminated string of command arguements
// nCmdShow. Specifies how the window is to be shown
//=================================
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
MSG msg;
// Create thw window
if (!CreateMainWindow(hInstance, nCmdShow))
return false;
// Main message loop
int done = 0;
while (!done)
{
// PeekMessage is a non blocking message for Windows messages
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Look for quit message
if (msg.message == WM_QUIT)
done = 1;
// Decode and pass messages on to WinProc
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
// Window event callback function
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
//Tell windows to kill this program
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// Create the window, returns False on error
bool CreateMainWindow(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASSEX wcx;
HWND hwnd;
// Fill in the window class structure with parameters
// That describe the main window
wcx.cbSize = sizeof(wcx); // Size of the structure
wcx.style = CS_HREDRAW | CS_VREDRAW; // Redraw if the size changes
wcx.lpfnWndProc = WinProc; // Points to windows procedure
wcx.cbClsExtra = 0; // No extra class memory
wcx.cbWndExtra = 0; // No extra window memory
wcx.hInstance = hInstance;
wcx.hIcon = NULL;
wcx.hCursor = LoadCursor(NULL, IDC_ARROW); // Predifined arrow
// Background brush
wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcx.lpszMenuName = NULL; // Name of menu resource
wcx.lpszClassName = CLASS_NAME; // Name of window class
wcx.hIconSm = NULL;
// Register the window class
// RegisterClassEx return 0 on error
if (RegisterClassEx(&wcx) == 0) // if error
return false;
// Create Window
hwnd = CreateWindow(
CLASS_NAME, // Name of window class
APP_TITLE, // Title bar text
WS_OVERLAPPEDWINDOW, // Window style
CW_USEDEFAULT, // Default horizontal postion of window
CW_USEDEFAULT, // Default vertical postion of window
WINDOW_WIDTH, // Width of window
WINDOW_HEIGHT, // Height of window
(HWND) NULL, // No parent window
(HMENU) NULL, // No menu
hInstance, // Handle to application window
(LPVOID) NULL); // No window parameters
// If there was an error the window
if (!hwnd)
return false;
// Show the window
ShowWindow(hwnd, nCmdShow);
// Send a WM_PAINT message to the window procedure
UpdateWindow(hwnd);
return true;
}
Change the two constant definitions from char to int:
const int WINDOW_WIDTH = 400;
const int WINDOW_HEIGHT = 400;
Assuming a signed character is 8-bits then char x = 400 actually sets x to 16.

Access Violation in DirectX9

Easiest way to put this: My code is throwing an access violation error whenever I run it. I have concluded it is the fault of calling this->d3ddev.(whatever) inside of the function System::renderFrame(). This function starts on line 112. If anyone could help me out here, that'd be great.
(by the way, I've gotten this working, but I wanted to put this code into classes, and that's where I started having my troubles. Also, I was told before to make sure to initialize all pointers. They are initialized, through d3d->createDevice())
system.h
#ifndef SYSTEM_H
#define SYSTEM_H
#include "stdinc.h"
class System {
private:
void initD3D (void);
void cleanD3D (void);
void setUpHWND (HINSTANCE, LPSTR, int);
static LRESULT CALLBACK StaticWindowProc(HWND, UINT, WPARAM, LPARAM);
LRESULT WindowProc(HWND, UINT, WPARAM, LPARAM);
HWND window;
WNDCLASSEX windowClass;
LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;
D3DPRESENT_PARAMETERS d3dpp;
HINSTANCE hInstance;
LPSTR lpCmdLine;
int nCmdShow;
public:
System (void);
System (HINSTANCE, LPSTR, int);
System (const System&);
~System (void);
void renderFrame (void);
};
#endif
system.cpp
#include "system.h"
//////////////////////////////////////////////////
// Class: System
// Private
//////////////////////////////////////////////////
void System::initD3D (void) {
this->d3d = Direct3DCreate9(D3D_SDK_VERSION);
ZeroMemory(&(this->d3dpp), sizeof(d3dpp));
this->d3dpp.Windowed = WINDOWED;
this->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
this->d3dpp.hDeviceWindow = this->window;
this->d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
this->d3dpp.BackBufferWidth = SCREEN_WIDTH;
this->d3dpp.BackBufferHeight = SCREEN_HEIGHT;
this->d3dpp.EnableAutoDepthStencil = TRUE;
this->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
this->d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
this->window,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&(this->d3dpp),
&(this->d3ddev));
this->d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
this->d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
this->d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);
};
void System::cleanD3D (void) {
this->d3d->Release();
this->d3ddev->Release();
};
void System::setUpHWND (
HINSTANCE hInstance,
LPSTR lpCmdLine,
int nCmdShow) {
this->hInstance = hInstance;
this->lpCmdLine = lpCmdLine;
this->nCmdShow = nCmdShow;
ZeroMemory(&(this->windowClass), sizeof(WNDCLASSEX));
this->windowClass.cbSize = sizeof(WNDCLASSEX);
this->windowClass.style = CS_HREDRAW | CS_VREDRAW;
this->windowClass.lpfnWndProc = System::StaticWindowProc;
this->windowClass.hInstance = this->hInstance;
this->windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
this->windowClass.lpszClassName = "WindowClass";
RegisterClassEx(&(this->windowClass));
this->window = CreateWindowEx(NULL, "WindowClass", "The Direct3D Program",
WS_OVERLAPPEDWINDOW, SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, this->hInstance, NULL);
};
LRESULT CALLBACK System::StaticWindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
System *SystemPtr = (System*)GetWindowLong(hWnd, GWLP_USERDATA);
if(SystemPtr)
{
return SystemPtr->WindowProc(hWnd, message, wParam, lParam);
}
else
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
};
LRESULT System::WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
};
//////////////////////////////////////////////////
// Class: System
// Public
//////////////////////////////////////////////////
System::System (void) {
};
System::System (
HINSTANCE hInstance,
LPSTR lpCmdLine,
int nCmdShow) {
this->setUpHWND(hInstance, lpCmdLine, nCmdShow);
ShowWindow(this->window, this->nCmdShow);
this->initD3D();
};
System::System (const System &) {
};
System::~System (void) {
this->cleanD3D();
};
void System::renderFrame (void) {
// Update the camera here
// Update objects
// Clear objects
// FOR SOME REASON THERE IS AN ERROR HERE
this->d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0);
this->d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
this->d3ddev->BeginScene();
// Draw objects
// Finish up
this->d3ddev->EndScene();
this->d3ddev->Present(NULL, NULL, NULL, NULL);
};
main.cpp
#include "system.h"
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow) {
System MainSys;
MainSys = System(hInstance, lpCmdLine, nCmdShow);
// Enter the main loop
MSG msg;
while (TRUE)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
break;
MainSys.renderFrame();
}
// Clean up DirectX and the COM
//delete MainSys;
return msg.wParam;
};
I tried to compile your code and changed the following lines:
System MainSys;
MainSys = System(hInstance, lpCmdLine, nCmdShow);
into
System MainSys(hInstance, lpCmdLine, nCmdShow);
and it worked.
I admit I don't know exactly why it fails, but there's a lot of stuff in your System class and you are constructing two instances of it (once in both lines) and then assign one to the other. This is not a good idea in any case and unnecessary. I guess it has somethinig to do with Direct3D reference counting and you are not honoring it when the class gets copied to MainSys in the second line.
EDIT
I just noticed that the destructor of MainSys gets called after the class is constructed with System(hInstance, lpCmdLine, nCmdShow); So the just obtained device is Released() again.
I don't see anything imeediately wrong here but its easy to miss something.
I suggest checking the HRESULTS from every d3d api call to make sure something didn't fail, and assing assert(pointer != NULL) all over to try to catch the problem. Or step through with a debugger and look at the variables to determine when it starts to fail.
Also, if you've not done so, turn on the d3d9 debug version and look at the log. It often tells you what you've missed.

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");
}