Sunday, February 26, 2006

Creating a Tray Icon

#undef UNICODE
#undef _UNICODE
#include

//
// TRAY ICON
//

NOTIFYICONDATA nid;


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case 10101:
if (lParam == WM_LBUTTONDBLCLK) {
MessageBoxA(NULL, "Hello", "Hi", MB_OK);
}
break;
case WM_CREATE:
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}

return 0;
}

int __stdcall WinMain(HINSTANCE hPrevInstance, HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
int ret;
MSG msg;
HWND hwnd;

wc.cbClsExtra=0;
wc.cbSize=sizeof(WNDCLASSEX);
wc.cbWndExtra=0;
wc.hbrBackground=(HBRUSH) (COLOR_WINDOW+1);
wc.hCursor=LoadCursor(NULL, IDC_ARROW);
wc.hIcon=wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance=hInstance;
wc.lpfnWndProc=WndProc;
wc.lpszClassName="Cyto";
wc.lpszMenuName=NULL;
wc.style=0;

ret = RegisterClassEx(&wc);
if (ret==NULL) {
MessageBoxA(NULL, "Could not register window", "Error", MB_OK);
ExitProcess(-1);
}

hwnd = CreateWindowEx(NULL, "Cyto", "The League", WS_OVERLAPPEDWINDOW, 10, 10, 320, 200, NULL, NULL, hInstance, NULL);
if (hwnd==NULL) {
MessageBoxA(NULL, "Could not create window", "Error", MB_OK);
ExitProcess(-1);
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

nid.cbSize=sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
nid.szTip[0] = 'T'; nid.szTip[1] = 'V'; nid.szTip[2] = '\0';
nid.uID = 1;
nid.uCallbackMessage = 10101;
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;

Shell_NotifyIcon(NIM_ADD, &nid);


while (GetMessage(&msg, hwnd, 0, 0)>0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

Shell_NotifyIcon(NIM_DELETE, &nid);

return (int) msg.wParam;
}

Window with Controls

Controls are just like windows - You create them with CreateWindowEx and get an HWND on creation.

#undef UNICODE
#undef _UNICODE
#include

//
// SIMPLE CONTROLS
//

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_COMMAND:
if (wParam==2) {
HWND target_hwnd = FindWindowEx(NULL, NULL, NULL, "My Computer");
if (target_hwnd==NULL) {
MessageBoxA(NULL, "FindWindow error", "Error", MB_OK);
} else {

// MoveWindow(target_hwnd, 50, 50, 320, 200, TRUE);
}
}
break;
case WM_CREATE:
//Use "edit" for textbox and "button" for command button; the hmenu value will appear as wParam with a WM_COMMAND message on clicking
CreateWindowEx(NULL, "button", "Click", WS_VISIBLE|WS_CHILD|WS_BORDER, 30, 30, 75, 30, hwnd, (HMENU) 2, NULL, NULL);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

int __stdcall WinMain(HINSTANCE hPrevInstance, HINSTANCE hInstance, LPSTR CmdLine, int nCmdShow) {
WNDCLASSEX wc;
int ret=0;
HWND hwnd;
MSG msg;

wc.cbClsExtra=0;
wc.cbSize=sizeof(WNDCLASSEX);
wc.cbWndExtra=0;
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.hCursor=LoadCursor(NULL, IDC_ARROW);
wc.hIcon=(wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION));
wc.hInstance=hInstance;
wc.lpfnWndProc=WndProc;
wc.lpszClassName="Mariott";
wc.lpszMenuName=NULL;
wc.style=0;

if ((ret=RegisterClassExA(&wc))==0) ExitProcess(-1);

if ((hwnd = CreateWindowEx(0, "Mariott", "White Wine", WS_OVERLAPPEDWINDOW, 10, 10, 320, 200, NULL, NULL, hInstance, NULL))==NULL) ExitProcess(-1);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

while (GetMessage(&msg, hwnd, 0, 0)>0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return (int) msg.wParam;
}

Simple Win32 Window

#undef UNICODE
#undef _UNICODE
#include

//
// SIMPLE WINDOW
//

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}


int __stdcall WinMain(HINSTANCE hPrevInstance, HINSTANCE hInstance, LPSTR CmdLine, int nCmdShow) {

WNDCLASSEX wc;
int ret=0;

wc.cbClsExtra=0;
wc.cbSize=sizeof(WNDCLASSEX);
wc.cbWndExtra=0;
wc.hbrBackground=(HBRUSH) (COLOR_WINDOW+1);
wc.hCursor=LoadCursor(NULL, IDC_ARROW);
wc.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance=hInstance;
wc.lpfnWndProc=WndProc;
wc.lpszClassName="Marshal";
wc.lpszMenuName=NULL;
wc.style=0;

ret = RegisterClassExA(&wc);
if (ret==0) {
MessageBoxA(NULL, "Could not register window class", "Error", MB_OK);
ExitProcess(-1);
}


HWND hwnd;
hwnd = CreateWindowEx(0, "Marshal", "Video Game", WS_OVERLAPPEDWINDOW, 10, 10, 320, 200, NULL, NULL, hInstance, NULL);

if (hwnd==NULL) {
MessageBoxA(NULL, "Could not instantiate window class", "Error", MB_OK);
ExitProcess(-1);
}


ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);


MSG msg;
while (GetMessage(&msg, NULL, 0, 0)>0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return (int) msg.wParam;

}

Single Instance Application

Mutexes (Mutual Exclusion Locks; I believe it is also known as a spin-lock) are used to control access to shared resources. They can also be used in Windows Applications to ensure that only one instance of an application runs at any given time.

The following is an example of using a mutex in a simple Win32 application:

#undef UNICODE
#undef _UNICODE
#include

//
// SINGLE INSTANCE USING MUTEX
//

int __stdcall WinMain(HINSTANCE hPrevInstance, HINSTANCE hInstance, LPSTR CmdLine, int nCmdShow) {
HANDLE hMutex;
hMutex = CreateMutexA(NULL, FALSE, "VoilaApp");

if (GetLastError()==ERROR_ALREADY_EXISTS) {
MessageBoxA (NULL, "Error", "Already running", MB_OK);
ExitProcess(-1);
}
MessageBoxA (NULL, "Voila", "It's working", MB_OK);
return 0;
}

Introduction

This blog is an attempt to put together little articles & snippets of Win32 C++ code that can be used as examples for beginners. In the process, I hope to become more proficient in Win32 as well since, at the moment, I'm just a novice.

With Visual C++ .NET, writing Win32 applications is easier than ever. You can write all of your logic in a higher language such as VB.NET, C# or J#; all the Windows low-level stuff can be written in C++ libraries. It'll also ensure that you don't have to throw away your C++ code anytime in the near future as Microsoft intends to keep C++ developers employed for many more years to come.