building a win32api application raw access to the api
Post on 21-Dec-2015
232 Views
Preview:
TRANSCRIPT
Building a Win32API Application
Raw access to the API
Resources• The resource script (.rc file):
– separate from code and dynamic data– compiled by a separate "Resource Compiler”
• Resources determine the app’s “look and feel”
• Examples: – Keyboard Accelerators, Bitmaps, Cursors, Dialog Box values,
Fonts, Icons, Menus, String Tables
• Separation of resources and program code– separates tasks of programmer & designer– can change user interface without touching code
Message Processing
WndProc:Evaluate msg, take action
Msg loop:GetMsgDispatchMsg
User input(mouse,
keyboard) OSinterrupt
msg
Message queue
msg
Basic program flow– RegisterClassEx()
(you provide a pointer to a function (usually called WndProc) which handles windows messages such as WM_CREATE, WM_COMMAND, etc.
– CreateWindowEx()• returns a handle (pointer) to that control.
– When the user clicks on a control you receive the WM_COMMAND message with the ID of that control.
– Now handle that event. SetWindowText() and GetWindowText() allow you to set/get the text of any control.
– ShowWindow() – displays the window– UpdateWindow() – updates the buffer– Start the message loop– OS then calls WndProc() - Process O/S's messages
Message loop
MSG msg; // probably a global vblwhile (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg); // tell OS to call my WndProc}Notes: 1. the name of the window processor does NOT have
to be "WndProc"2. The two 0's are filter max/min values
About msg loops• O/S only creates a message queue for threads that
perform operations which require one.• Must create a window before entering loop• GetMessage blocks until a filter-matching msg arrives
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx for a discussion of filter max/minvalues
Windows Messages
• Two 32-bit integer values (DWORDs)– WPARAM – 2 16-bit WORDs inside a DWORD– LPARAM – a 32-bit DWORD
• High-order and low order 16 bit WORDs• Extract each WORD with C macros
– HIWORD(msg) gets high order– LOWORD(msg) gets low order
• Meanings of HI and LO depend on the message
Win32API Programs
• WinMain (replaces "main")– Primary entry point from OS
• Procedure definition• Init• Message processing loop
• WinProc (the "callback" function)– Performs actions to process messages
• Switch statement based on msg#• Reentered once for each message
– Pixel-by-pixel mouse move– Mouse-click, etc.
LPARAM & WPARAM• LPARAM & WPARAM are datatypes• window message design:
– if the message takes a pointer, • the pointer is usually passed in the LPARAM,
– if the message takes a handle or an integer, • it is passed in the WPARAM
– if a message takes both, • the pointer goes in the LPARAM• the integer goes in the WPARAM
wParam & lParam
• Not every message uses these WParam values • Each message uses them differently. • WM_CLOSE message doesn't use either, so ignore both. • WM_COMMAND message uses both,
– WParam contains two values, • HIWORD (WParam) - notification message (if
applicable) • LOWORD (WParam) - control or menu id that sent
the message.
• LParam - HWND (window handle) of control which sent the message – NULL if the message isn't from a control.
example
• Given, some function "fn", extract the string from the parameter (which is a pointer)
LRESULT class::fn (WPARAM wParam, LPARAM lParam) { //two steps required
LPTSTR lpMessage = (LPTSTR) lParam; // get ptr to stringCString s = lpMessage; // put string into needed type
}
Caution
• Important For WM_LBUTTONDOWNDo not use the LOWORD or HIWORD macros to extract the x- and y- coordinates of the cursor position because these macros return incorrect results on systems with multiple monitors. Systems with multiple monitors can have negative x- and y- coordinates, and LOWORD and HIWORD treat the coordinates as unsigned quantities.
Sending messages
• Two ways to inform a handler– PostMessage
• Enqueues message for handler• Retrieved with GetMsg• Immediate return to caller (it's a non-blocking call)
– SendMessage• Sends message to handler (NO queueing)• BLOCKS until message received!!
WndProc Processes System Messages
LRESULT CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
Typical operations:• If msg is WM_CREATE, call CreateWindow(). • If msg is WM_QUIT, terminate• If msg is WM_PAINT, then redraw the window
Menus
When a menu item is selected• Windows sends WM_COMMAND msg• low word of wParam will be the item ID• extract with LOWORD(wParam)• then do
– switch/case using LOWORD(wParam) value
Menus-1
• Double-click your resource file's name (.rc)• Click on menu/menu-name• Enter names as needed
Menus-2
• Double-click on "Resource.h"• Scroll down to your menu items• Change the numeric values
– Increment to the next available integer
Misc– Msg class specifies what kind of 'control' this
window ise.g.; "edit" is a text box and "button" is a button.
– Each control (a window) must have a unique ID– Use CString vs. STL string– Remainder of STL is OK in all apps– Note use of new datatypes, "_T", LPSTR
• Recommended: use _T() macro vs. char or wchar_t• Use LPTSTR vs. char* or wchar_t*.• Then set MBCS or _UNICODE & rebuild w/o code
changes.
Character strings
• Unicode– 16 bit characters– Allows for international alphabets/symbols
• ANSI (Windows-1252 = ASCII, ISO-8859)• String declaration types
– "mystring" will use ANSI characters only– L"mystring" will use Unicode characters only– _T("mystring")
• Unicode if #define _UNICODE• ANSI if not
Pointers to strings
• DO NOT use char* or wchar*• Do use TCHAR* or LPTSTR• LPCTSTR is for usage like: const char*• Replace strcpy with _tcscpy• To convert a byte-buffer to character-size
buffer, use: bufflen/sizeof(TCHAR)• pWnd->GetWIndowText(buffer, sizeof(buffer)
/ sizeof(TCHAR))
Callback skeleton for Win32API (for writing text)LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ PAINTSTRUCT ps; HDC hDC; TCHAR greeting[ ] = _T ("DJ says, 'Hello World!'");
TCHAR click_greeting[] = _T ("Saw your click"); RECT rect;switch (message){case WM_PAINT:
hDC = BeginPaint (…, &ps);nHeight = -MulDiv (PointSize, GetDeviceCaps (…, LOGPIXELSY), 72); GetClientRect (…, &rect);/* set_font and color where his comment is */TextOut (…, 5, y_position, greeting, _tcslen (greeting));EndPaint (…, &ps);DeleteObject (SelectObject (…, hTmp)); break;
case WM_LBUTTONDOWN:InvalidateRect (…, NULL, FALSE); // TRUE => erase current contenthDC = BeginPaint (…, &ps);increment_line_num (…);set_font (hDC);TextOut (hDC, 5, y_position, click_greeting, _tcslen (click_greeting));EndPaint (…, &ps); break;
case WM_DESTROY: PostQuitMessage (0); break;default: return DefWindowProc (…, message, wParam, lParam); break;}return 0; // return to the OS from the callback function
}
subroutinesvoid increment_line_num (HDC hDC){
line_num++;y_position = (-1)*nHeight * line_num; // allow some space to avoid clipping
// Remember that y-positions are more negative as you go DOWN the screen!!// i.e.; the top left corner is 0,0};Void SetFont (){if (line_num==0)
hFont = CreateFont(nHeight, closest_match, escapement, orientation, FW_DONTCARE,no_italic, no_ul, no_xout, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH, TEXT("Times")); // TEXT ≡ _T
}
Callback skeleton (for drawing)LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){PAINTSTRUCT ps; RECT rect;
switch (message){case WM_LBUTTONDOWN:
iPrevX = LOWORD(lParam); iPrevY = HIWORD(lParam); return 0;case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON){ hdc = GetDC (hwnd);
MoveToEx (…, …, …, …); // update current position. Get old position back in parm 4
LineTo(…, …, …); iPrevX = LOWORD(lParam); iPrevY = HIWORD(lParam);
ReleaseDC (hwnd, hdc);}
return 0;case WM_LBUTTONUP:
InvalidateRect (…, …, …); return 0;case WM_PAINT:
GetClientRect (hwnd, &rect);hdc = BeginPaint (hwnd, &ps);InvalidateRect (…, …, …);EndPaint (hwnd, &ps); return 0;
case WM_DESTROY:PostQuitMessage(0); return 0;
}return DefWindowProc(hwnd, message, wParam, lParam);}
Draw a Circlecase ID_DRAW_CIRCLE:/* draw a blue-bordered magenta-crosshatched circle */hDC = GetDC(hWnd); /* get a DC for painting */hPen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255)); /* blue pen */hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 0, 255));hOldPen = (HPEN)SelectObject(hDC, hPen); /* select into DC & */hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); /* save old object */Ellipse(hDC, 100, 30, 180, 110); /* draw circle */SelectObject(hDC, hOldBrush); /* displace brush */DeleteObject(hBrush); /* delete brush */SelectObject(hDC, hOldPen); /* same for pen */DeleteObject(hPen);ReleaseDC(hWnd, hDC); /* release the DC to end painting */break;
Draw a Rectanglecase ID_DRAW_RECTANGLE:/* draw a red-bordered, cyan-filled rectangle */hDC = GetDC(hWnd); /* get a DC for painting */hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0)); /* red pen */hBrush = CreateSolidBrush(RGB(0, 255, 255)); /* cyan brush */hOldPen = (HPEN)SelectObject(hDC, hPen); /* select into DC & */hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); /* save old object */Rectangle(hDC, 15, 15, 80, 60); /* draw rectangle */SelectObject(hDC, hOldBrush); /* displace new brush */DeleteObject(hBrush); /* delete it from DC */SelectObject(hDC, hOldPen); /* same for pen */DeleteObject(hPen);ReleaseDC(hWnd, hDC); /* get rid of DC */break;
top related