Skip to content

Windows API

SeungAh Hong82min read

windows programming

  • Advantages of Windows

    1. A graphics-based operating system
    • The screen is handled in pixels, the smallest unit of digital representation, rather than in characters, which makes rich screen rendering possible.
    1. Multitasking is possible.
    • It performs several tasks at once.
    1. Device independence.
    • Peripheral devices are controlled and managed by device drivers. When a device changes, you only need to replace the device driver, and the software is not affected by this.
    1. Consistency
    • Because the interface layout is standardized, once you learn it you can use any program in a similar way.
  • When you link a Windows program to create an executable, you must link it against a special "import library" provided by the development environment. The import

    library contains the DLL names as well as reference information for all the Windows function calls the program uses.

  • Checking the import library: available under Project - Setting - Link Tab

  • Based on this information, the linker creates a table inside the executable (.EXE), and when Windows loads the program it patches this table information so that the actual

    Windows functions can be called.

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MessageBox(NULL, TEXT("Hello Windows!"), TEXT("HelloMsg"), 0);

return 0; }

  • Header files (#include <windows.h>)
  1. WINDEF.H : basic type definitions

  2. WINNT.H : type definitions for Unicode support

  3. WINBASE.H : Kernel functions

  4. WINUSER.H : user interface functions

  5. WINGDI.H : graphics device interface functions

  • Program entry point

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

  1. #define WINAPI __stdcall
  • Compile, link, run
  1. In the compile stage, the compiler generates an .OBJ file from the C source code file.

  2. In the link stage, the linker combines the .OBJ file and the .LIB file to produce the .EXE file.

-KERNEL32.LIB, USER32.LIB, and GDI32.LIB are the "import libraries" used to access the Windows subsystems.

  1. In Visual C++ you can compile and link the program using the Debug or Release configuration.

Unicode

  • Difference between Unicode and DBCS
  • Unicode always uses wide characters (16-bit) (8-bit characters are meaningless).

  • DBCS (Double Byte Character Set) still represents 8-bit values.

  • Wide characters and Windows

    1. Windows header file types
    • typedef char CHAR;

    • typedef wchar_t WCHAR;

    1. 8-bit strings

    typedef CHAR *PCHAR; typedef CHAR *LPCH, *PCH;

    typedef CHAR *NPSTR; typedef CHAR *LPSTR, *PSTR;

    typedef CONST CHAR *LPCCH, *PCCH;

    typedef CONST CHAR *LPCSTR, *PCSTR;

    1. 16-bit strings

    typedef WCHAR *PWCHAR; typedef WCHAR *LPWCH, *PWCH; typedef WCHAR *NWPSTR; typedef WCHAR *LPWSTR, *PWSTR;

    typedef CONST WCHAR *LPCWSTR, *PCWSTR;

    typedef CONST WCHAR *LPCWCH, *PCWCH;

  • Windows function calls: depending on whether the UNICODE identifier is defined, a different MessageBox is called.

  1. int WINAPI MessageBox(HWND, LPCSTR, LPCSTR, UINT)

    • WINUSERAPI int WINAPI MessageBoxA(HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType); WINUSERAPI int WINAPI MessageBoxW(HWND hWnd , LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); #ifdef UNICODE #define MessageBox MessageBoxW #else #define MessageBox MessageBoxA #endif // !UNICODE
  • Strings in Windows: depending on whether the UNICODE identifier is defined, a different string function is called.

WINBASEAPI int WINAPI lstrlenA( LPCSTR lpString ); WINBASEAPI int WINAPI lstrlenW( LPCWSTR lpString ); #ifdef UNICODE #define lstrlen lstrlenW #else #define lstrlen lstrlenA #endif // !UNICODE

  • Using printf in Windows

Windows and messages

// hInstance : instance handle, hPrevInstance : kept for compatibility with WIN16,

// lpCmdLine : command-line arguments passed to the program, nCmdShow : how the main window is displayed when it first appears (SW_SHOWNOMAL, etc.)

#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); HINSTANCE g_hInst; LPCTSTR lpszClass=TEXT("First");

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance ,LPSTR lpszCmdParam,int nCmdShow) { HWND hWnd; MSG Message; WNDCLASS WndClass; g_hInst=hInstance;

WndClass.cbClsExtra=0; WndClass.cbWndExtra=0; WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.hCursor=LoadCursor(NULL,IDC_ARROW); WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION); WndClass.hInstance=hInstance; WndClass.lpfnWndProc=WndProc; WndClass.lpszClassName=lpszClass; WndClass.lpszMenuName=NULL; WndClass.style=CS_HREDRAW | CS_VREDRAW; //calls WM_PAINT when the window is resized RegisterClass(&WndClass);

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,(HMENU)NULL,hInstance,NULL); 1st : a pointer to the window class name

2nd : a pointer to the window name

3rd : the window style

  • WS_OVERLAPPEDWINDOW : creates a window that has all of the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX,

    and WS_MAXIMIZEBOX attributes.

  • 4th : the system creates the window at an appropriate default position

ShowWindow(hWnd,nCmdShow);

UpdateWindow(hWnd);

while (GetMessage(&Message,NULL,0,0)) { TranslateMessage(&Message); DispatchMessage(&Message); } return (int)Message.wParam; }

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam) { switch (iMessage) { case WM_DESTROY: PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd,iMessage,wParam,lParam)); }

  • Window : a rectangular region of the screen through which you receive input from the user or produce output in the form of text and graphics.

  • Types of windows

    • Application window : toolbar, scrollbar

    • Dialog box

    • Child window, control window, child window control : push button, radio button, check box, list box, scroll bar

  • Window procedure

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

- Message handler : handles the program's response when a message occurs, and exists separately from the WinMain function under the name WndProc.

- WndProc is not called by WinMain but by Windows.

- The message loop inside WinMain merely forwards messages to the message handler; when a message is input, WndProc is

  called by Windows to process the message.

- A function within an application that is called by the operating system is called a callback (CallBack) function.

- Which messages are delivered directly to the window procedure without being queued in the message queue?
  • Queued messages and non-queued messages

    • Queued messages deliver messages accumulated in the message queue to the window procedure, while non-queued messages are delivered directly to the window procedure by Windows.

    • Queued messages : mainly the result of user actions (WM_KEYDOWN, WM_LBUTTONDOWN, etc.)

    • Non-queued messages : often occur as a result of calling specific Windows functions.

      1. When you call CreateWindow(), it creates a window, and in the process sends a WM_CREATE message to the window procedure.
  • Window function calls

  • GetStockObject() obtains a graphic object.

  • RegisterClass() registers a window class for the program's window.

  • ShowWindow() displays the window on the screen.

  • UpdateWinow() instructs the window to draw itself.

  • GetClientRect() obtains the dimensions of the window's client area.

  • PostQuitMessage() : inserts a quit message into the message queue.

  • DetWindowProc() : handles the default processing for a message.

  • New data types

    • MSG : message structure

    • WNDCLASS : window class structure

    • PAINTSTRUCT : paint structure

    • RECT : rectangle structure

  • Handle ( simply a number (often 32-bit in size) that references an object.

    • HINSTRANCE : instance handle of the program itself

    • HWND : window handle

    • HDC : device context handle.

  • Hungarian notation

  • Registering a window class (RegisterClass(&wndclass) // WNDCLASS wndclass;

  • To create an application window, you must first register a window class by calling RegisterClass().

  • WNDCLASS ASCII version

typedef struct tagWNDCLASSA { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; } WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;

  • Initialize the 10 fields and then call RegisterClass().
  1. 2nd field (lpfnWndProc)

    • Sets WndProc as the window procedure of the window class.

    e.g.) wndclass.lpfnWndProc = WndProc

    • WndProc handles the messages delivered to every window created based on this window class.
if(!RegisterClass(&wndclass))
{
  MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
 
  return 0;
}

//When the program is compiled with the UNICODE identifier defined, it works because RegisterClassW() is implemented on the Windows NT family.

// However, on the Windows 0x family RegisterClassW() is not implemented, so the code above notifies the user and returns 0.

  • Creating a window
  • The difference between a window and a window class

e.g.) The push-button window's common window class and the associated window procedure exist inside Windows.

    The definition of common behavior : the window procedure / characteristics such as the string and changing the screen position are set as part of the window definition.
hwnd = CreateWindow(szAppName, //the string specifying the class of the window to create
  TEXT("The Hello Program"),
  WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  NULL,
  NULL,
  hInstance,
  NULL);

-CreateWindow returns a window handle of type HWND, and programs can reference the window using the handle.

  • Displaying a window

ShowWindow(hwnd, iCmdShow); : makes the window appear on the screen.

  1. hwnd : the window handle just created with CreateWindow()

  2. iCmdShow : determines how the window is initially displayed on screen (one of normal, minimized, or maximized)

  3. The client area of the window is cleared with the background brush specified in the window class

  • Difference between ShowWindow() and UpdateWindow()
  1. In common : they send a WM_PAINT message to the window procedure

  2. The difference : UpdateWindow sends the message directly to the window procedure without storing it in the message queue, so the window is drawn on screen quickly.

            In the past, computers were slow, so with ShowWindow alone there was a problem of slow rendering, which is why UpdateWindow was used;
    
            today, computers are fast enough that it no longer matters much whether you use it.
    
  • Message loop
  1. Windows maintains a "message queue" for each Windows program currently running.

    -When an input event occurs, Windows converts the event into a message and stores it in the program's message queue.

typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time; // the time the message entered the message queue
POINT pt; // the coordinates when the message entered the message queue.
} MSG, *PMSG, NEAR *NPMSG, FAR \*LPMSG;
  1. GetMessage(&msg, NULL, 0, 0) : returns a nonzero value if the message field is not WM_QUIT. If it is, it returns 0 to stop message

                                                reception.
    
  • Passes to Windows a pointer to msg, a variable of type MSG structure.

  • Each time Windows retrieves a message from the message queue, it fills in each field of the message structure.

    ● hwnd : a handle indicating the window the message is destined for.

    ● message : the message identifier, a number that represents the message. e.g.) pressing the left mouse button gives WM_LBUTTONDOWN.

  1. TranslateMessage(&msg)
  • Passes the msg structure to Windows to translate keyboard messages.

  • Checks whether it is a WM_KEYDOWN and whether the pressed key is a character key, and if the conditions are met, creates a WM_CHAR message and appends it to the message queue.

  1. DispatchMessage(&msg)
  • Passes the msg structure to Windows, and Windows sends this message to the appropriate window procedure for processing.

    This means Windows calls the window procedure.

Only when WndProc returns does DispatchMessage return, and after that control moves to GetMessage.

  • Window procedure
  • Determines the content the window displays in its client area and its response to user input.

  • It is the same as the first four fields of the MSG structure.

  • A program can use SendMessage to indirectly call its own window procedure.

  • Processing messages
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch(message)
  {
    case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  }
  return DefWindowProc(hwnd, message, wParam, lParam);
}
  • Every message the window procedure receives can be identified by a number, and this number is passed in the message parameter.

  • Messages that the window procedure chooses not to handle must be passed to the Windows function DefWindowProc so that they are processed by default.

  • WM_PAINT message

    • Notifies the program that part or all of the window's client area has become "invalid" or needs to be "updated".

    • When a window is first created, the program has drawn nothing on screen yet, so the entire client area is invalidated.

    • WinMain() : when ShowWindow and UpdateWindow are called, it instructs the window procedure to draw something in the client area.

    e.g.) hdc = BeginPaint(hwnd, &ps);

      EndPaint(hwnd, &ps);
    
    • When BeginPaint() is called, if the client area has not yet been cleared, Windows clears the background of the client area.

      When clearing the background, it uses the brush specified in the hbrBackground field of the WNDCLASS structure when the window class was registered.

      Currently, wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); so it is painted white.

    • The BeginPaint() call validates the entire client area and returns a device context handle.

    • Device context : a concept representing the physical output device and its associated device driver together; a device context handle is needed

      to output text and graphics to the window's client area.

    • EndPaint() releases the device context handle so that it is no longer valid.

  • WM_DESTROY message

    • Indicates that Windows is in the process of destroying the window at the user's command. (close button, System menu - Close)

    • PostQuitMessage(0) -inserts a WM_QUIT message into the message queue

    • return msg.wParam -contains exactly the value passed to PostQuitMessage() (usually 0).

  • WM_SYSCOMMAND, WM_CLOSE, WM_DESTROY

  1. WM_SYSCOMMAND : the window user (also called the System menu or Control menu) receives this message when a command is selected from the window menu, or

                                when the maximize button, minimize button, restore button, or close button is selected -when SC_CLOSE is passed in the parameter
    
  2. WM_CLOSE : the message is delivered before the window is closed. Since the window has not yet been destroyed, you can intercept the destruction of the window

                     in the middle. -calls DestroyWindow() (window procedure : calls WM_DESTROY)
    
  3. WM_DESTROY : occurs when the window is destroyed in memory. -by calling PostQuitMessage() it puts WM_QUIT into the message queue

  4. WM_QUIT : the message that occurs when the program is ending. -the message loop in WinMain() terminates and the program ends.

Text output

  • WM_PAINT()
  • The UpdateWindow() message notifies the window procedure that the client area needs to be redrawn.
  • The window procedure processes the WM_PAINT message when one of the following events occurs.

    • When a previously hidden window area is revealed because the user moves or uncovers the window.

    • When the user resizes the window (when the CS_HREDRAW, CS_VREDRAW bits are set in the window class style)

    • When the program scrolls part of the client area using ScrollWindow() or ScrollDC()

    • When the program explicitly generates a WM_PAINT message using InvalidateRect() or InvalidateRgn()

  • Cases where the WM_PAINT message is queued

    • When Windows removes a dialog box or message box that was placed over the window

    • When a menu is opened and then closed

    • When a tooltip is displayed

  • GDI overview

  • To draw something in a window's client area, you use the Windows Graphics Device Interface (GDI) functions.
  • Device context
  • A device context handle can be thought of as a kind of permit for a window to use GDI functions.

  • Except for a device context created by calling CreateDC(), you must not save a device context handle obtained while processing one message

    and use it while processing another message.

  • Obtaining a device context handle: method 1
  • BeginPaint(), EndPaint()

    1. BeginPaint prepares for drawing by clearing the background of the invalid region. Its return value is a device context handle.

    2. While processing a WM_PAINT message, you must always call BeginPaint() and EndPaint() as a pair.

  • If you do not process the WM_PAINT() message, you must pass the message to DdfWindowProc().

case WM_PAINT:

 BeginPaint(hwnd, &ps);

 EndPaint(hwnd, &ps);

 return 0;
  • If you invalidate a rectangle of the client area by calling InvalidateRect(), the last argument specifies whether to erase the background.

    TRUE : erase the background / erase the background, FALSE : do not erase the background

  • Obtaining a device context handle : method 2

    • GetDC(), ReleaseDC()

      1. GetDC() and RelaseDC() must also be called as a pair. If GetDC() is called while processing a message, you

        must call ReleaseDC() before exiting the window procedure.

    hdc = GetDC(hwnd);

    ReleaseDC(hwnd, hdc);

  • Difference between GetDC() and GetWindowDC()

    ● GetDC() returns a device context that can output to the window's client area / GetWindowDC() returns a

                    device context handle that can output to the entire window - can output to the window title bar
    
  • Difference between BeginPaint(), EndPaint() and GetDC(), ReleaseDC()

    1. BeginPaint, EndPaint are used when processing a WM_Paint message. / GetDC, ReleaseDC are for processing other than WM_Paint messages,

                                                                                             for drawing a portion of the client area
      
    2. Used only in the WM_PAINT message routine : BeginPaint, EndPaint / General way to obtain a DC handle : GetDC, ReleaseDC

      ( specialized functions for drawing within a message)

    3. Calling BeginPaint, EndPaint validates the invalid region / GetDC, ReleaseDC do not validate the invalid region;

                                                                              to do so you call ValidateRect(hwnd, NULL) to validate the entire region
      
    4. For the device context handle obtained via BeginPaint, EndPaint / for the device context handle obtained via GetDC, the default clipping region is

      the default clipping region is the invalid region, and the client area.

    • Clipping region : the visible region shown on screen
  • TextOut() details <TextOut(hdc, 100, 100, TEXT("HI"), 2);

    1. The first argument is the return value obtained by calling GetDC() or BeginPaint()

    2. 2nd~3rd are the coordinates where the string will be output, 4th is the string, 5th is the length of the string -the TextOut function does not use a null-terminated string.

                                                                                                    Using ASCII control characters (\n, \0, etc.) outputs a box or filled block shape
      
  • Text alignment method - SetTextAlign(HDC hdc, UINT fMode) : e.g.) SetTextAlign(hdc, TA_CENTER);

  • Character size

  • To find the dimensions of text, obtain a device context handle and then call GetTextMetrics().

    TEXTMETRIC tm;

    hdc = GetDC(hwnd);

    GetTextMetrics(hdc, &tm);

    ReleaseDC(hwnd, hdc);

  • The TEXTMETRIC structure provides various information about the font currently selected into the device context.

  • Since the dimensions of the system font do not change until Windows is rebooted, the best place to use GetTextMetrics is when processing the

    WM_CREATE message in the window procedure.

  • GetSystemMetrics

Using the Windows application programming interface (API) function GetSystemMetrics(), you can obtain the width and height of various elements of the window display.

e.g.) int x = GetSystemMetrics(SM_CXSCREEN); Width of screen int y = GetSystemMetrics(SM_CYSCREEN); Height of screen

  • Client area size
  • GetSystemMetrics(), GetClientRect(), using lParam of WM_SIZE

  • WM_SIZE : sends a WM_SIZE message to the window procedure when the window's size changes.

    cxClient = LOWORD(lParam);

    cyClient = HIWORD(lParam);

  • Scroll bar
  • Created by including the window style identifiers WS_VSCROLL and WS_HSCROLL in the third argument of CreateWindow().

  • The space occupied by the scroll bar is not included in the client area

  • The width of a vertical scroll bar and the height of a horizontal scroll bar can be obtained by calling GetSystemMetrics.

  • SetScrollRange : the range of the scroll bar, setScrollPos : the position of the scroll bar

Drawing basics

  • GDI (Graphics Device Interface) : the subsystem responsible for displaying graphics on video displays and printers
  • Windows graphics are mainly handled by the functions that GDI32.DLL exposes externally.
  • Calling GDI functions

    • Device context handle

      1. Processing a WM_PAINT message : BeginPaint, EndPaint / otherwise GetDC, ReleaseDC
    • GetTextMetrics : to obtain dimension information for the currently selected font

    • TextOut : displays text in the client area / changing text color : SetTextColor

    • SetTextAlign : aligns the text starting position

    • CreatePen, CreatePenIndirect, ExtCreatePen : specify various pen attributes.

  • Device context

    • When a program obtains a DC, it means Windows has granted it permission to use the device.

    • The device context contains many attributes, so when TextOut is called it follows the DC's attributes even without setting attribute-related values.

      If you want to change them, you call functions that change the attributes.

  • Obtaining a device context handle

    1. Used to obtain a device context associated with a specific window of the video display (BeginPaint, GetDC, GetWindowDC)
    • BeginPaint, EndPaint have an rcPaint field as the third argument (in the PAINTSTRUCT structure) that defines a rectangle enclosing the invalid region

      in the window's client area.

    • GetDC, ReleaseDC() : applies to the window's client area

    • GetWindowDC, ReleaseDC : lets you obtain a device context handle that applies to the entire window.

      This device context includes the client area, window title bar, menu, scroll bars, and frame.

    1. Other ways to obtain a device context handle
  • CreateDC() : creates a device context for a specific device.

  • CreateIC() : creates an information context for a specific device. This quickly provides information about the device without creating a device context.

  • CreateCompatibleDC(hdc) : creates a memory device context compatible with another device context. Used to prepare an image in memory.

  • CreateMetaFile : GDI calls are not displayed on screen but are saved as part of a metafile.

    -Metafile : a file that contains information describing or defining another file (includes GDI functions, vector-based : no image distortion).

  • Obtaining device context information

    • GetDeviceCaps : used to obtain information about a physical display device (video display, printer, etc.).

      GetDeviceCap(hdc, iIndex) - if hdc is a screen device context handle, the information is the same as GetSystemMetrics

      iIndex - specified in the WINGDI.H file
      
      1. GetDeviceCaps(hdc, HORZRES); GetDeviceCaps(hdc, VERTRES);

      2. This is identical to using the GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) arguments.

  • Learning about color

  • Using GetDeviceCaps you can determine whether a device is capable of handling various kinds of graphics.

    • GetDeviceCaps(hdc, PLANES) : the number of color planes / GetDeviceCaps(hdc, BITSPIXEL) : the number of color bits per pixel

      GetDeviceCaps(hdc, NUMCOLORS) : the number of colors the video card can display simultaneously

  • COLORREF : used to reference a specific color in GDI function calls. #define DWORD COLORREF

    To extract the primary color values of a COLORREF, use the GetRValue, GetGValue, and GetBValue macros.

  • GetNearestColor - uses dithering (mixing) to represent more colors than the actual device can display.

  • Device context attributes

    • Windows uses the device context to store "attributes" that govern how GDI functions operate on the screen.

    • When a program obtains a device context, Windows sets all attributes to their default values.

  • Saving the device context

    • Calling GetDC(), BeginPaint() -returns a DC with all attributes set to default

    • Calling ReleaseDC(), EndPaint() -releases the DC, and all modified attribute values are lost

    • Changing attribute values in advance : include them as a style when registering the window class

    • SaveDC, RestoreDC : used to restore the DC to its previous state after changing DC attributes.

      idSaved = SaveDC(hdc); // SaveDC(hdc);

      RestoreDC(hdc, idSaved); // when the return value is saved // RestoreDC(hdc, -1); // restores the DC to the state most recently saved with SaveDC()

  • Lines

  • Polyline(), PolylineTo() draw a series of connected line segments.

    Difference between Polyline and PolylineTo

    1. Polyline neither uses nor changes the current position.

    2. PolylineTo : uses the current position as the starting position and moves the current position to the endpoint of the last drawn line.

    Polyline, LineTo

    Calling LineTo repeatedly produces output that does not look good on plotters or other drawing modes, and Polyline also lets you easily draw

    lines.

  • MoveToEx(hdc, xBeg, yBeg, NULL) : sets the current position value among the DC's attributes. The last argument stores the previous current position as a POINT.

  • LineTo(hdc, xEnd, yEnd); draws a straight line from the current position to the specified point.

  • GetCurrnetPositionEx(hdc, &pt) : obtains the current position value. (You can change the current position with MoveTo)

  • Bounding box functions : shapes are constructed from a rectangular "bounding box"
  • Rectangle() draws a rectangle

  • Ellipse() : a function that draws an ellipse

  • RoundRect() : a rectangle with rounded corners

  • Arc : an arc is an elliptical curve, not a filled region, Pie : Windows connects the two endpoints of the arc and the center of the ellipse with lines.

  • The interior of the shape drawn with Chord or Pie is filled with the current brush.

  • Curves
  • Bezier(HDC hdc, CONST POINT* lppt, DWORD cPoints);

  • Pass an array consisting of the curve's start point, end point, and two control points as the second argument, and give the number of points in cPoints as the third argument,

    and the curve is drawn.

  • Drawing a single curve requires 4 points, but drawing two or more curves requires as many points as the following formula.

    =required points = number of curves to draw * 3 + 1

  • Using built-in pens
  • To obtain a handle to one of the built-in pens, call GetStockObject().

    hPen = GetStockObject(WHITE_PEN);

  • You must select the pen into the device context.

hPen(previous device context) = SelectObject(hdc, hPen);

=Can be summarized in a single statement SelectObject(hdc, GetStockObject(WHITE_PEN))

  • Creating, selecting, and deleting pens
  • When using GDI objects such as pens, you must follow three rules.
  1. Every GDI object you create must eventually be deleted.

  2. You must not delete a GDI object that is selected into a valid device context.

CreatePen - // hPen = SelectObject // SelectObject(hdc, hPen) // DeleteObject

  1. You must not delete built-in objects.
  • Creating a pen (CreatePen, SelectObject, DeleteObject)

  • CreatePen, CreatePenIndirect (creating a logical pen)

  1. CreatePenIndirect is more effective when you initialize and use several different pens directly. (using the LOGPEN structure)
  • You can obtain the LOGPEN structure values.
  1. GetObject(hPen, sizeof(LOGPEN), (LPVOID)&logpen);
  • If you need the currently selected pen handle, call it as follows.
  1. hPen = GetCurrentObject(hdc, OBJ_PEN);
  • Filling gaps
  • SetBkColor(hdc, crColor) // GetBKMode : used to obtain the background mode

    Used when changing the background color to fill gaps. When the background mode is changed to TRANSPARENT, gaps are not filled and the background color is ignored.

  • Drawing mode

    • When Windows uses a pen to draw a line, it actually performs a bitwise Boolean operation between the pen's pixels and the destination screen's pixels.

      Here the pixels determine the color of the pen and the screen. Performing a bitwise Boolean operation on pixels is called a "raster operation" or "ROP".

  • Drawing in a filled region

  • Windows defines six built-in brushes (WHITE_BRUSH, BLACK_BRUSH, NULL_BRUSH, LTGRAY_BRUSH, DKGRAY_BRUSH,

                                                           GRAY_BRUSH)
    
  • Windows brush handle : HBRUSH

    1. HBRUSH hBrush = GetStockObject(GRAY_BRUSH); //you can obtain a handle.

    2. SelectObject(hdc, hBrush) // select into the device context

    3. SelectObject(hdc, GetStockObject(NULL_PEN)) // a shape without a border

    4. SelectObject(hdc, GetStockObject(NULL_BRUSH)) // if you do not want to draw the shape border or fill the interior

  • Polygon functions and polygon fill mode
  • Polygon(hdc, apt, iCount) : the sixth function that draws a bordered, interior-filled shape

  • PolyPolygon(hdc, apt, aiCounts, iPolycount) draws multiple polygons.

    1. Interior fill method : SetPolyFillMode(hdc, iMode) : iMode (ALTERNATE, WINDING)
  • Filling the interior with a brush

    • Windows provides five functions for creating logical brushes

      1. CreateSolidBrush(COLORREF) : creates a logical brush with a specific solid color.

      2. CreateHatchBrush(fnStyle, COLORREF) : creates a logical brush with a specific hatch pattern and color.

      3. CreatePatternBrush(HBITMAP) : creates a logical brush with a specific bitmap pattern.

      4. CreateDIBPatternBrush(HGLOBAL, UINT) : creates a logical brush with a specific device-independent bitmap.

      5. CreateBrushIndirect(LOGBRUSH) : creates a logical brush with a specific hatch, style, and color.

    typedef struct tagLOGBRUSH { UINT lbStyle; COLORREF lbColor; LONG lbHatch; } LOGBRUSH, *PLOGBRUSH, NEAR *NPLOGBRUSH, FAR *LPLOGBRUSH;

  1. SelectObject() : select into the device context
  • Device coordinate systems

    • In all device coordinate systems, units are expressed in pixels.

    • Screen coordinates : if you use the entire screen, you use screen coordinates.

      If you use the "DISPLAY" argument of CreateDC(), the logical coordinates of GDI functions map by default to screen coordinates.

    • Whole-window coordinates : represent the program's entire application window, including the title bar, scroll bars, borders, etc.

      If you obtain a device context via GetWindowDC(), the logical coordinates of GDI functions map to whole-window coordinates.

    • Device coordinate system : client area coordinates // if you obtain a device context via GetDC(), BeginPaint(), it is converted to client coordinates

    • ClientToScreen() : client area coordinates -screen coordinates // ScreenToClient() : screen coordinates -client area coordinates

  • Viewport and window

  • Mapping mode : defines the mapping from the window (logical coordinates) to the viewport (device coordinates)

  • Viewport specification : uses device coordinates (pixels).

  • Window specification : uses logical coordinates (pixels, millimeters, inches, etc.).

  • Converting device points to logical points - converting logical points to device points

    DPtoLP(hdc, pPoint, iNumber); LPtoDP(hdc, pPoint, iNumber)

    GetClientRect(hwnd, &rect);

    DPtoLP(hdc, (PPOINT)&rect, 2);

  • If you change SetViewportOrgEx(hdc, xViewOrg, yViewOrg, NULL), logical point (0, 0) maps to device point (xViewOrg, yViewOrg).

    If you change SetWindowOrgEx(hdc, xWinOrg, yWinOrg, NULL), logical point (xWinOrg, yWinOrg) maps to device point (0,0).

    GetViewportOrgEx(hdc, &pt); / GetWindowOrgEx(hdc, &pt) // you can obtain the current viewport and window origins.

  • Metric mapping modes

    • The window expresses logical coordinates in physical dimensions (provides five mapping modes)

      1. MM_LOENGLISH/MM_LOMETRIC/MM_HIENGLISH/MM_TWIPS/MM_HIMETRIC
  • User-defined mapping modes

    • MM_ISOTROPIC and MM_ANISOTROPIC are the only mapping modes that allow you to change the viewport extent and window extent.
  • Rectangles, regions, clipping

  • Working with rectangles

    1. FillRect(hdc, &rect, hBrush) : fills the rectangle with the specified brush.

    2. FrameRect(hdc, &rect, hBrush) : draws a rectangle frame using the brush, but does not fill the interior.

    3. InvertRect(hdc, &rect) : inverts all pixels within the rectangle. (1->0 , 0->1)

  • Provides 9 functions for manipulating the RECT structure

    1. SetRect(&rect, xLeft, xTop, xRight, Bottom) : sets the four fields of the RECT structure to specific values

    2. OffsetRect(&rect, x, y) : moves it by a certain amount along the x and y axes.

    3. InflateRect((&rect, x, y) : increases or decreases the size of the rectangle.

    4. SetRectEmpty(&rect) : sets all fields of the rectangle to 0.

    5. CopyRect(&DestRect, &SrcRect) : copies one rectangle into another rectangle.

    6. IntersectRect(&DestRect, &SrcRect1, &SrcRect2) : the intersection of two rectangles

    7. UnionRect(&DestRect, &SrcRect1, &SrcRect2) : the union of two rectangles

    8. bEmtyp = IsRectEmpty(&rect) : tells whether the rectangle is empty

    9. bInRect = PtInRect(&rect, point) : tells whether a point is within the rectangle

  • Creating and drawing regions
  • Region : an area composed of various shapes such as rectangles, ellipses, and polygons

  • CreateRectRgn(xLeft, yTop, xRight, yBottom) or CreateRectRgnIndirect(&rect); // the region describes a rectangle.

  • CreateEllipticRgn(xLeft, yTop, xRight, yBottom) or CreateEllipticRgnIndirect(&rect); // an elliptical region

  • CreatePolyonRgn(&point, iCount, iPolyFillMode) iPolyFillMode : ALTERNATE or WINDING

  • Using CreatePolyPolygonRgn() you can create a region composed of multiple polygons.

  • CombineRgn(hDestRgn, hSrcRgn1, hSrcRgn2, iCombine)

    Combines the two regions hSrcRgn1 and hSrcRgn2 into a new region hDestRgn. iCombine specifies the combination method.

    The return value is one of four (NULLREGION : empty / SIMPLEREGION : a region composed of a single rectangle

                                / COMPLEXREGION : a region composed of multiple rectangles or curves / ERROR : an error occurred)
    
  • With a region handle, FillRgn, FramRgn, InvertRgn, and PaintRgn are used.

  • Clipping with rectangles and regions

    • invalidateRgn(hwnd, hRgn, bErase) : invalidates the client region area.

      validateRgn(hwnd, hRgn) : validates the client region area.

Keyboard

  • Keyboard basics
  • Keyboard input is delivered to the program's window procedure in the form of messages.

  • A specific keyboard event goes to the window that has the input focus. (key events are delivered to the window with the input focus)

  • If the active window has a child window (list box, check box, etc.), the child window has the input focus.

    Keep in mind that the child window is not the active window.

* Queue synchronization

When the user presses and releases a key -hardware scan code (device driver) -system message queue -application message queue

  • system message queue -application message queue

    When the window focus changes, to deliver a message from the system message queue to another window

* Key-press messages

  • WM_KEYDOWN, WM_KEYUP

  • WM_SYSKEYDOWN, WM_SYSKEYUP : keyboard messages pressed together with the Alt key, used when the system uses them for internal purposes

                                                        When you process these messages, you must always send them to DefWindowProc.
    
  • Calling GetMessageTime() lets you obtain the relative time when a key was pressed or released.

  • Virtual key code (check wParam)
  • The virtual key code is stored in the wParam parameter.

  • It is defined in WINUSER.H with names starting with VK_.

  • lParam information (WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP)
  • Contains additional information useful for interpreting the key press.
  1. Repeat count (0~15 : 16 bits) : the number of key presses that the key-press message represents.

  2. OEM scan code (16~23 : 8 bits) : the code generated by the keyboard hardware

  3. Extended key flag (24) : set to 1 when a press occurs on one of the additional keys on the IBM extended keyboard

  4. Context code (29) : set to 1 if the Alt key is pressed

  5. Previous key state (30) : 0 if the key was previously released, 1 if the key was previously pressed. (KeyUp is always set to 1)

  6. Transition state (31) : WM_KEYDOWN : 0, WM_KEYUP : 1 (0 when pressing, 1 when releasing)

  • Shift state (to find out whether the shift keys (Shift, Ctrl, Alt) or toggle keys (Caps Lock, NumLock) are pressed)

    1. Return value (GetKeyState, GetAsyncKeyState)

0x8000 means the key is currently pressed, and 0x0001 means the key has been pressed at some point between the previous call and this call.

e.g.) if( GetAsyncKeyState(VK_RETURN) & 0x8000 ) // the reason for doing this is to check the state of the key at an exact moment

  • SHORT GetKeyState(int nVirtKey)
  1. If the return value of the GetKeyState function is 0x8xxx, the key is pressed, and if it is not 0x8xxx, the key is not pressed.
  • Difference between GetAsyncKeyState and GetKeyState
  1. GetAsyncKeyState : reads and acts immediately at the moment of input, regardless of the message queue.

    GetKeyState : the returned value differs depending on the messages stored in the message queue.

  2. GetKeyState returns a negative value (0xffffff80, 0xffffff82) if the key is pressed, and returns 0 otherwise; if it was previously pressed but not pressed at the moment of the call, it remains 1.

  • Character messages
  1. Character message via GetMessage - TranslateMessage : key-press messages (WM_KEYDOWN, WM_SYSKEYDOWN),

                                                                       Shift key (Shift, Ctrl, Alt), toggle keys (Caps Lock, Num Lock, Scroll Lock)
    

    =Puts WM_CHAR (a character message) into the message queue

  • The four character messages
  • WM_KEYDOWN -WM_CHAR, WM_DEADCHAR

  • WM_SYSKEYDOWN -WM_SYSCHAR, WM_SYSDEADCHAR

  • WM_CHAR : explanation of the wParam, lParam arguments

    1. wParam : TCHAR str = (TCHAR)wParam -ANSI or Unicode character code

    2. lParam : identical to the lParam of the key-press messages (WM_KEYDOWN, WM_SYSKEYDOWN).

  • fUnicode = IsWindowUnicode(hwnd) -the fUnicode variable is TRUE (Unicode message)

  • GetKeyNameText() : used to show the virtual key code and key name for keyboard messages and key-press messages.

  • Message order

    • Character message : WM_KEYDOWN - WM_CHAR - WM_KEYUP

      Since TranslateMessage is called from the WM_KEYDOWN message, WM_CHAR is inserted in between.

  • Handling control characters

  • WM_KEYDOWN : when you need to read Insert, Shift, Ctrl, Alt

  • WM_CHAR : when you need to read keyboard character input

    Backspace, Tab, Escape, Enter : distinguished in WM_CHAR by the predefined ANSI C escapes.

case WM_CHAR:

if(wParam == '\b') // if(wParam == '\t')

  • Dead-character message

    • A dead key is a key that cannot form a character on its own; the dead character it produces combines with the next input character to form a single character.

WM_KEYDOWN WM_DEADCHAR WM_KEYUP WM_KEYDOWN WM_CHAR WM_KEYUP

  • Caret
  • When entering text into a program, a small underscore, vertical bar, or box usually appears to indicate where the next entered character will appear on screen.

    1. Cursor : a small bitmap image that indicates the mouse position - a different meaning from the caret
  • Caret-related functions

  1. BOOL CreateCaret(HWND, HBITMAP, nWidth, nHeight)

  2. BOOL DestroyCatret(VOID)

  3. BOOL ShowCaret(hwnd) // blinks continuously and periodically, waiting for the next insertion position.

  4. BOOL HideCaret(hwnd)

  5. BOOL SetCaretPos(int X, int Y) : specifies the position of the caret (position can be changed even if the caret is hidden)

  6. BOOL GetCaretPos(LPPOINT)

Mouse

  • Mouse basics
  • fMouse = GetSystemMetrics(SM_MOUSEPRESENT) : checks whether a mouse is present (TRUE : installed, FALSE : not installed)

  • cButtons = GetSystemMetrics(SM_CMOUSEBUTTONS) : tells the number of mouse buttons

  • SystemParametersInfo() : used to directly set or obtain various mouse parameters such as double-click speed.

  • Client area mouse messages
  1. Difference between keyboard messages and mouse messages
  • Keyboard message : sends keyboard messages only to the window with the input focus (EditBox)

  • Mouse message : the window procedure receives mouse messages even when the mouse is over a window that is not active and does not have the input focus.

  1. Mouse position value
  • x = LOWARD(lParam) / y = HIWARD(lParam)
  1. wParam : indicates the state of the mouse buttons and the Shift, Ctrl keys.

MK_CONTROL, MK_LBUTTON, MK_RBUTTON, MK_MBUTTON, MK_SHIFT tell the state of the combination keys.

  • What I learned

    int ShowCursor(BOOL bShow);

    The return value is an internal count; when TRUE the internal count is incremented, and when FALSE the internal count is decremented.

    When the internal count is greater than or equal to 0, the cursor is visible on screen.

GetCursorPos(&point) // the point value is in screen coordinates. To convert it to client area coordinates you must use the ScreenToClient function.

SetCursorPos(x, y) //the x, y values are also in screen coordinates, not client coordinates. (If they were client coordinates you would use the ClientToScreen function)

  • Mouse double-click

    • If the window procedure wants to receive double-click mouse messages, include the CS_DBLCLKS identifier when initializing the style field of the window class structure

      before calling RegisterClass().

  • Non-client area mouse messages

    • The window's non-client area : includes the title bar, menu, and window scroll bars.

    • Non-client area mouse messages are passed to DefWindowProc() so that Windows performs the system function.

      wParam : indicates which part of the non-client area the mouse was moved or clicked in.

      lParam : low word (x), high word (y) -these are screen coordinates, not client coordinates.

    e.g.) xPos = GET_X_LPARAM(lParam); yPos = GET_Y_LPARAM(lParam);

Timer

Timer CH8. Timer / Windows programming
2013. 4. 18. 20:33 edit delete copy https://blog.naver.com/ssinga1030/90171478579 view statistics

  • Uses of Windows timers

    1. Multitasking : if many programs must process a large amount of work, you can process each piece whenever a WM_TIMER message is received

    2. Real-time updates : use a timer to update constantly changing information such as a display of system resources.

    3. Auto-save : saves the user's work at a specific interval.

    4. Terminating a "demo" version program : designed to terminate after a certain amount of time has passed since the demo version was distributed.

    5. Controlling animation speed : when automatically showing a sequence of screens, to control the speed.

    6. Using a timer to update visual information about work being done in the background

  • The system and the timer

  • The window sets the count value of the timer set by the user, decrements the count each time a hardware timer tick occurs, and when it reaches 0,

    delivers a WM_TIMER message and resets the count to the original value.

  • Timer messages are not asynchronous.
  • Your program is not interrupted asynchronously to process a WM_TIMER message.

  • Like WM_PAINT, it is stored in the message queue and processed sequentially.

  • Using a timer
  1. First method
  • SetTimer(hwnd, 1, uiMsecInterval, NULL);

    1st argument : window handle, 2nd argument : timer number, 3rd argument : timer interval in 1/1000 second, 4th argument : callback function

    KillTimer(hwnd, 1) : 1st argument : window handle, 2nd argument : timer number

  • WM_TIMER

  1. Second method (callback function)
  • SetTimer(hwnd, 1, uiMsecInterval, TimerProc);

  • This allows Windows to call a function when the timer fires.

  • VOID CALLBACK TimerProc( HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime );

1st argument : window handle / 2nd argument : always WM_TIMER / 3rd argument : timer ID / 4th argument : the elapsed time since Windows started

  1. Third method
  • iTimerID = SetTimer(NULL, 0, wMsecInterval, TimerProc);

    1st parameter : hwnd as NULL / 2nd parameter ignored (0) -the return value of the function becomes the timer ID.

  • KillTimer(NULL, iTimerID)

  • Obtaining the current time

typedef struct _SYSTEMTIME { // st WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME;

  • GetLocalTime(LPSYSTEMTIME) : tells the local time zone. (current time)

  • GetSystemTime(LPSYSTEMTIME) : Coordinated Universal Time (Greenwich time)

Child window controls

  • Child window controls

    • How to obtain the parent window handle from a child window

      hwndParent = GetParent(hwnd)

    • How to send a message to the parent window

      SendMessage(hwndParent, message, wParam, lParam);

    • Child window -parent window

      When there is a change in the child window (control) itself (a Button Click, etc.), it sends a WM_COMMAND notification message to the parent window.

      This message notifies that the child window (control) has been activated.

      LOWORD(wParam) : child window ID, HIWORD(wParam) : notification code, lParam : the handle of the child window

  • Button class

    • Owner Draw

      When it has a bitmap or a shape image, the control cannot output the bitmap itself, so the parent window that owns the control draws the bitmap;

      this approach is called owner draw. In summary, it refers to a form where the parent window that owns the control draws the content.

    • Adding the BS_OWNERDRAW style to the third argument of CreateWindow means "apply the owner-draw style".

      1. WM_MEASUREITEM : specifies the height of the item

      2. WM_DRAWITEM : notifies via a message that it must draw itself.

      lParam : contains a pointer to the DRAWTIEMSTRUCT structure.

  • Reasons for using owner draw

    1. The list box itself is also a window. Therefore, when adding a string, WM_PAINT is called and the output is produced, but in other cases (when it has a bitmap or shape image)

      the control cannot output the bitmap itself, so the parent window has to draw it instead

    2. When displaying information that changes in real time, it is more convenient to implement it with owner draw than to modify the items

  • Creating a child window

CreateWindow { TEXT("button), //class name

         TEXT("PUSHBUTTON);               // window text

                   WS_CHILD|WM_VISIBLE             // window style

                   cxChar                                      // x position

                   cyChar                                      // y position

                   20*cxChar                                 // width

                   70*cyChar/4                             // height

                   hwnd                                       // parent window

                   (HMENU) i                                 // child window ID

                   ((LPCTREATESTRUCT) lParam)->hIstance  // instance handle

                   NULL                                        // extra parameter
  • Three ways to obtain the instance handle

    • On WM_CREATE :

      lParam contains a pointer to a CREATESTRUCT-type structure.

    • Using a global variable

      hInst = hInstance;

    • LONG GetWindowLong(hwnd, GWL_HINSTANCE);

  • Instance handle (HINSTANCE), window identifier (handle - HWND), control ID

    1. Instance : the start address at which the executable is loaded in memory.

      -The instance handle is used as an identifier to distinguish running programs.

      -It is the same as the HMODULE returned when GetProcAddress obtains the address of a function loaded into memory from a different DLL.

    2. Window identifier handle (HWND)

      -An identifier used to distinguish the windows of a given program. (parent window, control window handle, etc.)

    3. Control ID

      -Since a control's ID is used to distinguish between controls, it only needs to be unique among controls under a single parent.

       It is managed as an internal resource.
      
  • How to obtain the ID value

    id = GetWindowLong(hwndChild, GWL_ID);

    id = GetDlgCtrlID(hwndChild);

  • How to obtain the window handle (if you know the ID and the parent window handle)

hwndChild = GetDlgItem(hwndParent, id);

  • Messages a child window sends to the parent window (when the child window is created)
  • BN_CLICKED / BN_PAINT / BN_DISABLE, etc.

  • The child window calls WM_COMMAND (BN_CLICKED) on the parent window - SendMessage(hwndButton, BM_SETSTATE, TRUE, 0)

  • Messages the parent window sends to the child window
  1. BM_GETCHECK, BM_SETCHECK

    • Sent to set the check mark of a check box or radio button.
  2. BM_GETSTATE, BM_SETSTATE

    • Refers to the state when a window is pressed with the mouse or the Space Bar is pressed.
  3. BM_SETSTYLE

    • Allows the style of a button to be changed after the button has been created.
  4. BM_CLICK, BM_GETIMAGE, BM_SETIMAGE

  • Push button

    • Mainly used to start an action immediately without showing an on/off state.

    • When a push button is pressed, it sends a WM_COMMAND message with BN_CLICKED to the parent window.

  • Check box (a square box displayed together with text)

    • To create a check mark in a check box, wParam : 1; to clear the check mark, wParam : 0

      SendMessage(hwndButton, BM_SETCHECK, 1, 0); - create the check mark

      SendMessage(hwndButton, BM_SETCHECK, 0, 0); - clear the check mark

      iCheck = (int)SendMessage(hwndButton, BM_GETCHECK, 0, 0); TRUE if the button is checked, FALSE otherwise

  • Radio button

    SendMessage(hwndButton, BM_SETCHECK, 1, 0); - create the check mark

    SendMessage(hwndButton, BM_SETCHECK, 0, 0); - clear the check mark

  • Group box

    • Unlike other controls, it does not process keyboard or mouse input, and it does not send WM_COMMAND messages to the parent window.
  • Changing button text

    • SetWindowText(hwnd, pszString)

      hwnd : the handle of the target window whose text will be changed, pszString : a pointer to a null-terminated string

    • iLength = GetWindowText(hwnd, pzxBuffer, iMaxLength); //obtains the current text.

    • iLength = GetWindowTextLength(hwnd) : to prepare for a specific text length, allocate a text buffer using the returned length.

  • Visible buttons and enabled buttons

    • For a child window to receive input, it must be displayed on screen and also enabled.

      To hide a child window : ShowWindow(hwndChild, SW_HIDE)

      To check whether a child window is currently visible : IsWindowVisible(hwndChild)

      To enable/disable a child window : EnableWindow(hwndChild, FALSE), EnableWindow(hwndChild, TRUE)

      Whether a child window is enabled : IsWindowEnabled(hwndChild)

  • Buttons and input focus

  1. When moving focus from the parent window to a child window

case WM_KILLFOCUS : ( on KILLFOCUS in the parent -wParam contains the handle of the child window that gained the input focus

for( i=0; i< NUM; i++)

{

    if(hwndChild[i] == (HWND)wParam)

    {

SetFocus(hwnd)

break;

    }

}

  1. When moving focus from a child window to the parent window

      case WM_KILLFOCUS:
    
      if(hwnd == GetParent((HWND)wParam)
    
      {
    
                  SetFocus(hwnd);
    
                  break;
    
       }
    
  • System colors

    • Using GetSysColor() and SetSysColor() you can obtain or set these colors.
  • WM_CTLCOLORBTN message

    • Processing the WM_CTLCOLORBTN message is a way to match button colors to the colors we prefer in the program.

      This message is sent to the window procedure when a child window is about to draw its own client area.

      The parent window can take this opportunity to change the colors the child window procedure uses for drawing.

    1. wParam : a handle to the button's device context

    2. lParam : the button's window handle

    3. Use SetTextColor to set the text color

    4. Use SetBkColor to set the text background.

    5. Return a brush handle to the child window.

  • Problems with WM_CTLCOLORBTN

    Only push buttons and owner-draw buttons can send the WM_CTLCOLORBTN message to the parent window, and if the parent window processes this message

    and returns a brush to paint the background, only owner-draw buttons can respond to it.

LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

switch (msg) {
    case WM_CTLCOLORSTATIC: {
        if ((HWND)lParam == filterNameOff) {
        static HBRUSH hBrushColor;

            if (!hBrushColor) {
                hBrushColor = CreateSolidBrush(RGB(0xFF, 0xFF, 0xFF)); // White background is returned
                SetBkColor((HDC)wParam, RGB(0xFF, 0xFF, 0xFF));          // White background for text
            }

            // Background color that is used to repaint the control (doesn't affect text background)
            return (LRESULT)hBrushColor;
        }
    }
  • Owner-draw button

    1. Add the BS_OWNERDRAW style to the third argument of CreateWindow

    2. A button created with the BS_OWNERDRAW style sends a WM_DRAWITEM message to the parent window whenever it needs to be redrawn.

      WM_DRAWITEM is called when the button is first created, when it is pressed or released, when it loses or gains the input focus, that is, whenever it needs to be redrawn.

    3. lParam is a pointer to the DRAWITEMSTRUCT structure. (contains the information needed to draw the button)

      • hdc = the button's device context

      • rcItem = a RECT structure providing the button's size

      • CtlID = the control window ID

      • itemState = indicates whether the button is pressed or has the input focus

        If the button is pressed, itemState is set to 1 (ODS_SEELECTED), which you check using that constant

  • Static class

    • It does not accept mouse or keyboard input, and it does not send WM_COMMAND messages to the parent window.

    • When the mouse is moved over or clicked on a static child window, the child window intercepts the WM_NCHITTEST message and

      returns HTTRANSPARENT to the window.

    • String alignment including SS_LEFT, SS_RIGHT, SS_CENTER

  • Scroll bar class

    • Instead of sending WM_COMMAND to the parent window, the scroll bar sends WM_VSCROLL, WM_HSCROLL messages.

    • lParam value : the window handle

      i = GetWindowLong((HWND)lParam, GWL_ID)

    • wParam

      nScrollCold = (int)LOWORD(wParam) // SB_PAGEDOWN, SB_LINEDOWN, etc.

      nPos = (Short int)HIWORD(wParam) // when SB_THUMPOSION, SB_THUMTRACK occurs, you can change the Position value.

  • Window subclassing

    • Used to hook into an existing window procedure so that the program processes some messages and passes the rest to the original window procedure.

    • Reason : used to run a program that implements only a few functions and passes the rest to the original procedure.

    e.g.) OldScroll = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (LONG)ScrollProc);

    • After that, you use CallWindowsProc() to call the previous scroll bar window procedure.
  • Painting the background

    • DWORD SetClassLong(HWND, int nIndex, LONG INewVal);

    =Used to change everything registered in the window class, not only the window background color but also the cursor, icon, etc.

    • Return value : on success - the previous value as a specified 32-bit integer, on failure : 0 is returned

e.g.) SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB(color[0], color[1], color[2]));

  • Edit class

    1. Edit class styles

    hwndEdit = CreateWindow(TEXT("edit"), NULL, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|

                                        WS_BORDER|ES_LEFT|ES_MULTILINE|ES_AUTOHSCROLL|ES_AUTOVSCROLL,
    
                                        0, 0, 0, 0, hwnd, (HMENU) 1, ((LPCTREAESTRUCT)lParam)->hInstance, NULL);
    
    1. Alignment : ES_LEFT, ES_RIGHT, ES_CENTER

    2. Lines : default is single line / multi-line MULTILINE

    3. Automatic horizontal/vertical scroll : ES_AUTOHSCROLL, ES_AUTOVSCROLL =automatically scrolls horizontally/vertically when characters are entered to the end

    1. Edit control notifications
    1. LOWORD(wParam) : child window ID

    2. HIWORD(wParam) : notification code

    3. lParam : child window handle

    • Notification codes

      ● EN_ERRSPACE : when the edit control cannot allocate memory

      ● EM_MAXTEXT : when there is not enough space to insert text into the edit control

      =You must handle the above two notification codes.

    1. Messages you can send to an edit control
    1. Cut the selected content : SendMessage(hwndEdit, WM_CUT, 0, 0);

    2. Copy the selected content : SendMessage(hwndEdit, WM_COPY, 0, 0); //paste WM_PASTE

    3. Delete the selected content : SendMessage(hwndEdit, WM_CLEAR, 0, 0);

  • List box class

    1. List box styles

    hwndList = CreateWindow (TEXT ("listbox"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER| WS_VSCROLL | LBS_NOTIFY, 10, 20, 200, 300, hwnd, (HMENU) 2, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL) ;

    1) LBS_NOTIFY : the list box does not send notification messages no matter what happens, so you must add this when you want to use notification messages.
    
                            Reason it was used - it was used to make things a bit faster back when computers were slow (received via WM_COMMAND)
    
    2) LBS_SORT : sorts the items within the list box
    
    3) LBS_MULTIPLESEL, LBS_EXTENDEDSEL : the default selection type of a list box is single-selection, but by adding these two types
    
                                                                     you can add a multiple- or extended-selection list box.
    
    4) LBS_STANDARD -LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER
    

    2. List box strings

    1. List box return values

      • LB_ERRSPACE : SendMessage() returns LB_ERRSPACE when there is not enough memory to store the content.

      • LB_ERROR : when an error occurs for another reason

      • On success, it returns the index value of the position where the string was added.

    2. Inserting a list box string

      • SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)szString);

        =The 4th argument is a pointer to a null-terminated string

          When using LBS_SORT, set the 3rd argument to 0; otherwise you must specify the index value.
        
    3. Deleting a list box string

      • SendMessage(hwndList, LB_DELETESTRING, index, 0)

        SendMessage(hwndList, LB_RESETCONTENT, 0, 0);

        Difference : LB_DELETESTRING deletes the string at the index, while LB_RESETCONTENT removes all items.

    4. Refreshing a list box

      • SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);

        SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);

      =The list box window procedure refreshes the screen when items are added or removed. If there are many strings to add or remove,

       you can temporarily disable the refresh behavior by turning off the control's redraw flag and then turn it back on afterward.
      
       Also, if you add the LBS_NOREDRAW style, you can start with the screen refresh flag turned off.
      
    5. Selecting and deselecting list box items

      • Number of list box items : iCount = SendMessage(hwndList, LB_GETCOUNT, 0, 0);

      • Select an item : SendMessage(hwndList, LB_SETCURSEL, iIndex, 0);

      • Select an item based on its leading characters : iIndex = SendMessage(hwndList, LB_SELECTSTRING, iIndex, (LPARAM)szSearchString);

      • To find out which item is currently selected : iIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0);

      • To find out the length of a string : ILength = SendMessage(hwndList, LB_GETTEXTLEN, iIndex, 0);

      • Store in a text buffer : iLength = SendMessage(hwndList, LB_GETTEXT, iIndex, (LPARAM)szBuffer);

      • Set the selection state of a specific item : SendMessage(hwndList, LB_SETSEL, wParam, iIndex);

      • To find out the selection state of a specific item : iSelect = SendMessage(hwndList, LB_GETSEL, iIndex, 0);

    6. Receiving messages from the list box

      • Child window : LOWORD(wParam)

      • Notification code : HIWORD(wParam)

      • lParam : child window handle

      • WM_COMMAND notification code

        LBN_SELCHANGE : notifies that the current list box selection has changed.

  • APIs I learned about

    GetEnvironmentVariable(lpName, lpBuffer, nSize) : returns the value of an environment variable by name.

    =lpName : the environment variable name / lpBuffer : the buffer where the information held by the environment variable will be returned and stored, nSize : the maximum size that can go into the buffer

  • Icons, cursors, strings, custom resources
  1. Separation of resources
  • In general, a program is divided into code and data

  • Code : the means of processing data / Data : everything that is not code can be referred to as data (bitmaps, menus, icons, etc.)

  • What a resource is : a collection of data unrelated to the logic of the code

  • Advantages of separating resources and the coding process

  1. It is convenient for designers and programmers to divide the work. The programmer diligently builds the program's logic while the designer only

    makes the resources look nice and then combines them.

  2. Even if you modify a resource, you do not have to recompile the entire program every time, so the compile speed becomes significantly faster.

  3. Resources made once can easily be reused in other projects, which is advantageous for resource reuse.

  4. Since resources are replaceable modules, you can use different forms of resources depending on the situation. (multilingual versions, skin features, etc.)

  5. RC file : a file that describes the type, appearance, etc., of the resources you want to use

  6. RES : when you compile the RC file with the resource compiler (RC.exe), a binary file called RES is generated.

-During the linking process, the obj and res files are combined to produce the .exe executable.

  1. Resource.h : uses the Defined values specified in the RC file, and the Resource.h file assigns an ID value to that resource.

    e.g.) *.rc : MENUITEM "&New", ID_MENUITEM40020

      Resource.h  : #define ID_MENUITEM40020                40020
    

● What I learned - DISCARDABLE (indicates that Windows can remove the resource from memory to obtain additional space (if necessary).)

  1. Summary of the process of creating a resource and including it in the project

  2. Adding an icon to the program

  • To add an icon, select Insert/Resource to add an Icon.

  • In the resource editor, specify the FileName and ID value. < added to the *.rc file and resource.h file. >

-*.rc : IDI_ICON<IDICON DISCARDABLE "icondemo.ico"

  *.h :  #define IDI_ICON                        101
  • How to obtain an icon handle

    hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));

    HICON LoadIcon( HINSTANCE, LPCTSTR);

#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))

-Since you cannot assign an integer-type resource ID to a string pointer, MAKEINTRESOURCE is the macro used for casting.

  • How to obtain the icon size (32 x 32 : the icon size generated by Visual C++)

    cxIcon = GetSystemMetrics(SM_CXICON);

    cyIcon = GetSystemMetrics(SM_CYICON);

    To obtain the smaller 16x16 pixel size, XM_CXSMSIZE, SM_CYSMSIZE are used.

  • When drawing an icon : DrawIcon(HDC, x, y, HICON)

● LoadIcon(NULL, IDI_APPLICATION) - since hInstance is NULL, this tells Windows it is a predefined icon.

                                                      IDI_APPLICATION is predefined in WINUSER.H.

                                                      #define IDI_APPLICAION MAKEINTRESOURCE(32512)
  • When switching icons while the program is running

    SetClassLong(hwnd, GCL_HICON, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ALTICON))

  • LoadIcon obtains a handle but there is no need to destroy the handle.

  1. Adding a custom cursor
  • Define the window class

    wndclass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));

    wndclass.hCursor = LoadCursor(hInstance, szCursor); - define the cursor by text name

  1. String resources
  • String resources are mainly used to make it easy to translate a program into another language.

  • Creating a string table

    Insert/Resource - add a String Table

  • LoadString(hInstance, id, szBuffer, iMaxLength)

    2nd argument : the ID value in front of each string

    3rd argument : the address of the buffer that will receive the string, 4th : the maximum number of characters to copy into szBuffer

    Return : returns the number of characters contained in the string.

  • A string resource can have a length of up to 4K.

  • Advantages of string resources

  1. First, because the strings themselves are separated from the code, you can manage the strings separately, which also greatly helps in maintaining the project.
  1. The second benefit of using string resources is that you can easily create multilingual versions

    3) When the strings are separated from the source, you can fix a string without recompiling the source, which speeds up the development period.

  1. Menus

    • Adding a menu

      Insert/Resource - add a Menu item

    • Changing menu properties

      Caption : the name of the menu shown to the user / ID : the name by which the program refers to this menu item.

    • Menu item property : ID_parentMenu_caption : ID_FILE_MENU

    • Define the window class

      wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1)

    • Characteristics of a menu

      1. The 1st characteristic is what is visible on the menu : a text string or a bitmap

      2. The 2nd characteristic is that it passes the ID value of each menu into the low bits of wParam in WM_COMMAND to notify the window procedure of the menu selection

      3. The 3rd characteristic is the menu item's attributes (indicating disabled, enabled, checked, etc.)

● What I learned

  - HMENU GetMenu(hwnd) - obtains the menu handle

  - CheckMenuItem(hMenu, menuID, uCheck)

    e.g.) CheckMenuItem(hMenu, LOWORD (wParam) - ID, MF_CHECKED) ;

  - EnableMenuItem(hMenu, menuID, nEnable)

    e.g.) EnableMenuItem(hMenu, LOWORD (wParam), MF_GRAYED/MF_ENABLED)

8. Keyboard accelerators

  • Advantages of keyboard accelerators

    1. The programmer does not need to duplicate the menu and keyboard accelerator logic.

      Windows sends a WM_COMMAND message to the window procedure of the window specified in TranslateAccelerator().

  • Difference between a mnemonic and a keyboard accelerator

    1. Mnemonic : must be used together with the Alt key and is a quick way to select a menu item by keyboard

    2. Keyboard accelerator : can be used at any time regardless of the menu.

  • Adding an accelerator

    Insert/Resource - add an Accelerator

  • Properties of a keyboard accelerator - ID : the accelerator's ID, KEY : the key the accelerator uses, Modifiers : the combination key pressed together with Key

                                 Type : ASCII code, virtual key code
    
  • Loading the accelerator table

    hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));

    1st argument : the program's instance, 2nd argument : a pointer to the string name of the accelerator table

  • Key-press translation

    TranslateAccelator(HWND, HACCEL, LPMSG)

    1. Changes a keyboard message into a WM_COMMAND message so that the accelerator can operate.

    2. How it works

    KEYDOWN(Ctrl) - TranslateAccelator(FALSE) - TranslateMessage - DispatchMessage - WndProc - processing complete

    KEYDOWN(A) - TranslateAccelator(TRUE) - WndProc - WM_COMMAND is called to be processed.

HACCEL hAccel;

hAccel=LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1)); while(GetMessage(&Message,0,0,0)) { if (!TranslateAccelerator(hWnd,hAccel,&Message)) { TranslateMessage(&Message); DispatchMessage(&Message); } }

Dialog boxes

WndClass.cbClsExtra=0; WndClass.cbWndExtra=0; WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); WndClass.hCursor=LoadCursor(NULL,IDC_ARROW); WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION); WndClass.hInstance=hInstance; WndClass.lpfnWndProc=WndProc; WndClass.lpszClassName=lpszClass; WndClass.lpszMenuName=NULL; WndClass.style=CS_HREDRAW | CS_VREDRAW; RegisterClass(&WndClass);

BOOL CALLBACK AboutDlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam) { switch (iMessage) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: EndDialog(hDlg,IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg,IDCANCEL); return TRUE; } break; } return FALSE; }

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam) { switch (iMessage) { case WM_LBUTTONDOWN: DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),hWnd,AboutDlgProc); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd,iMessage,wParam,lParam)); }

  • Dialog box

    • A special window for dialogue between the program and the user, that is, for conveying commands and information
  • Dialog box template

  • Binary data that defines the appearance of the dialog box

  • It defines not only the properties of the dialog box itself but also the position, size, and properties of the controls created within the dialog box.

  • DialogBoxIndirect(HINSTANCE hInstance, LPCDLGTEMPLATE lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc);

  • The LPCDLGTEMPLATE structure holds position and size properties ( pdt->style = WS_POPUP, pdt->x = 10, pdt->y = 20; )

  • Modal dialog box
  • While the program displays a modal dialog box, the user cannot switch between the dialog box and other windows in the program.
  • Dialog box procedure
  1. Definition of a dialog box procedure

    • Just as a window procedure processes messages occurring in a window, a dialog box procedure processes the messages occurring

      in a dialog box.

  2. Role of the dialog box procedure

    • Initializing child window controls when the dialog box is created, processing messages generated by child window controls, and handling the dialog box's termination

    • Does not process WM_PAINT, keyboard, and mouse messages

  3. Difference between a dialog box procedure and a window procedure

  4. Window : LRESULT / Dialog box : returns a BOOL type ( if the dialog box returns FALSE, the rest of the message is handled by the operating system)

  5. Window : when a specific message is not processed (calls DefWindowProc()) / Dialog box : TRUE if it processes the message, FALSE otherwise

  6. Window : WM_CREATE / Dialog box : WM_INITDIALOG is called < initialization >

                                   -Does not process WM_PAINT, WM_DESTROY messages.
    
  7. WM_COMMAND call

    • The message mainly processed in the dialog box procedure

    • LOWORD(wParam) carries the ID of the control that sent the message, and HIWORD(wParam) carries the notification code.

  • Calling / closing a dialog box

int DialogBox(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc)

  • 1st argument : the instance handle that holds the resource / 2nd argument : the resource ID of the dialog box template

    3rd argument : the parent window that will own the dialog box, 4th argument : the name of the dialog box procedure

    e.g.) DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc) ;

BOOL EndDialog(HWND hDlg, int nResult)

  • 1st argument : the handle passed to the dialog box procedure / 2nd argument : passed as the return value of the DialogBox function that called the dialog box.
  • Communicating with controls
  1. Handle and ID
  1. How to obtain the window handle (when you know the child ID)

HWND GetDlgItem(HWND hDlg, int nIDDlgItem) : the 1st argument is the dialog box's handle, and if you give the control's ID as the second argument you can obtain the handle value.

=The handle value is used to move or hide a control (ShowWindow, MoveWindow)

  1. Used to obtain the ID from a control's window handle

int GetDlgCtrlID(HWND hwndCtl)

id = GetWindowLong(HWND, GWL_ID);

= Used to obtain the ID value from a window handle.

SendDlgItemMessage(HWND, hDlg, int nID, UNIT MSG, WPARAM wParam, LPARAM lPrame)

=Provides an API that combines the two functions SendMessage(GetDlgItem(hDlg, ID) ~

=SendDlgItemMessage(hdlg, id, BM_SETCHECK, 1,0);

  • Reading a control's value
  1. Functions for reading and writing strings
  • UINT GetDlgItemText( HWND hDlg, int nIDDlgItem, LPTSTR lpString, int nMaxCount );
  • BOOL SetDlgItemText( HWND hDlg, int nIDDlgItem, LPCTSTR lpString );
  1. Functions for reading and writing integers
  • UINT GetDlgItemInt( HWND hDlg, int nIDDlgItem, BOOL *lpTranslated, BOOL bSigned );

  • BOOL SetDlgItemInt( HWND hDlg, int nIDDlgItem, UINT uValue, BOOL bSigned ); =If the fourth argument bSigned is TRUE, it reads a signed integer value; if FALSE, it ignores the sign and always reads it as a positive number

    The third argument assigns whether there was an error to the specified BOOL pointer (pass NULL if error checking is not needed)
    
  • Radio Button control usage (all three methods do the same thing) - wParam must be 1 to be checked.
  1. SendMessage(GetDlgItem(hDlg, id), BM_SETCHECK, i == LOWORD(wParam), 0);

for(int I=IDC_BLACK; I<=IDC_WHITE; I++)

SendMessage(GetDlgItem(hDlg, I), BM_SETCHECK, I==LOWORD(wParam), 0);

  1. SendDlgItemMessage(hDlg, id, BM_SETCHECK, i == LOWORD(wParam), 0);

for(int I=IDC_BLACK; I<=IDC_WHITE; I++)

SendDlgItemMessage(hDlg, I, BM_SETCHECK, I==LOWORD(wParam), 0);

  1. CheckRadioButton(hDlg, idFirst, idLast, idCheck)

    -Clears the check mark of all radio button controls from idFirst to idLast, checking only the radio button whose ID is idCheck as an exception.

  • Check box control usage

    1.CheckDlgButton(hDlg, idCheckbox, iCheck);

    -If iCheck is 1 the button is checked, if 0 the check is removed.

  1. iCheck = IsDlgButtonChecked(hDlg, idCheckBox) : you can obtain the state of the check box.
  • Passing arguments to the dialog box procedure
  1. DialogBoxParam(hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam)

e.g.)

typedef struct

{

int iColor, iFigure;

} ABOUTBOX_DATA

static ABOUTBOX_DATA ad = { IDC_BLACK, IDC_RECT };

if(DialogBoxParam(hInstance, TEXT("AboutBox"), hwnd, AboutDlgProc, &ad))

-It is passed as lParam when the WM_INITDIALOG message is received.

pad = (ABOUTBOX_DATA*) lParam;

ad = *pad;

  • Modeless / modal dialog boxes

    1. Differences
    1. Modal : uses the DialogBox() function and returns a value only after the dialog box is destroyed

      Modeless : uses the CreateDialog() function and returns the window handle immediately.

    2. Modeless type usually includes a caption bar and system menu / Modal type does not provide a caption bar and system menu (cannot move to other regions)

    3. For the modeless type, if you omit WS_VISIBLE, you must call ShowWindow() after calling CreateDialog

    e.g.) hDlgModaless = CreateDialog(...);

       ShowWindow(hDlgModaless, SW_SHOW);
    

    2. Modeless implementation details

    hDlgModaless = CreateDialog(hInstance, lpTemplate, hWndParent, lpDialogFunc);

    -The same arguments as DialogBox.

    while(GetMessage(&msg, NULL, 0, 0)){

    if(!IsWindow(hDlgModaless) || !IsDialogMessage(hDlgModaless, &msg)) // when using a modeless dialog box

    {

       if(!TranslateAccelerator(hwnd, hAccel, &msg)) //when using keyboard accelerators
    
       {
    
     TranslateMessage (&msg) ;
     DispatchMessage  (&msg);
    

}

}

BOOL IsWindow(HWND) -checks whether it is a valid window handle

  • Reason : used to prevent creating the dialog box twice.

BOOL IsDialogMessage(hDlg, lpMsg)

  • Reason : after checking the message, if it is a message related to the dialog box, it processes the message and returns TRUE. Otherwise it returns FALSE

DestroyWindow(hDlg) -modal uses EndDialog, but modeless calls DestroyWindow.

You must initialize the handle returned from CreateDialog to NULL.

  • What I learned : why use the WS_CLIPCHILDREN style among the Styles in CreateWindow?

    -It is a Style that lets the program redraw the main window without erasing the dialog box.

  • Common dialog boxes

    • Developed to encourage a single standardized user interface.
  1. Open File dialog box

  2. Color dialog box

  3. Font selection dialog box

  4. Find dialog box

Clipboard

  • Clipboard : a place to temporarily store data to be exchanged between programs or internally

  • Heap allocation (TEXT -clipboard)

    • HGLOBAL GlobalAlloc(UNIT uFlags, DWORD dwByte) : a function that allocates memory on the heap

    • LPVOID GlobalLock(HGLOBAL hMem) : returns a pointer to the actual location of the memory

    • BOOL GlobalUnLock(HGLOBAL hMem)

    • HGLOVAL GlobalFree(HBLOBAL hMem)

  • Bitmap -clipboard

    hBlt = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP));

    After setting CF_BITMAP, you can copy it to the clipboard and read it.

HGLOBAL hmem;

TCHAR *ptr;

hmem=GlobalAlloc(GHND, lstrlen(str)+1); ptr=(TCHAR *)GlobalLock(hmem); memcpy(ptr,str,lstrlen(str)+1); GlobalUnlock(hmem);

if (OpenClipboard(hWnd)) { // take exclusive ownership of the clipboard EmptyClipboard(); SetClipboardData(CF_TEXT,hmem); CloseClipboard();

}

  • Clipboard functions

    BOOL OpenClipboard(HWND hWndNewOwner) // argument : window handle

    BOOL EmptyClipboard(); // clears the clipboard

    HANDLE SetClipboardData(UINT uFormat, HANDLE hMem) // uFormat : CF_BITMAP, CF_TEXT, etc.

    -The hMem data is copied to the clipboard as uFormat. After the call, the user can no longer modify the hMem memory (managed by the system : clipboard)

    -SetClipboardData(CF_TEXT, hmem);

    BOOL CloseClipBoard(); // closes the clipboard (if omitted, other users cannot use the clipboard)

    BOOL IsClipboardFormatAvailable(UINT format) // uFormat : checks whether CF_BITMAT, CF_TEXT, etc., are on the clipboard

    HANDLE GetClipBoardData(UINT format)

    -hmem = GetClipBoardData(CF_TEXT);

    -HBITMAP hBit = (HBITMAP)GetClipBoardData(CF_BITMAP)

  • Registering a new clipboard format

    UINT RegisterClipboardFormat(LPCTSTR lpszFormat)

    e.g.)

    MyFormat = RegisterClipboardFormat("MOVIE");

    SetClipboardData(MyFormat, hmem);

  • Functions for managing clipboard formats

int CountClipboardFormats(void) // the number of registered formats

UINT EnumClipboardFormats(UINT format); // enumerates each format

int GetClipboardFormatName(UINT format, LPTSTR lpszFomatName, int cchMaxCount); // obtains the registered name of a format.

  • Clipboard viewer

    • A program that is notified of changes in the clipboard content

    • Viewers are connected to each other in a chain, so the most recently installed viewer is at the front and passes changes or state to the viewers behind it through the chain.

    • Change in clipboard content : SetClipboardViewer(CF_TEXT, hmem) -Windows calls WM_DRAWCLIPBOARD -> notifies all viewers of the addition

    • Removing a clipboard viewer : ChangeClipboadChain(hWnd, hNext) -WM_CHANGECBCHAIN -notifies all viewers of the removal

Printer

  • Printing process

Program - GDI - spooler - device driver - printer

  1. Spooler : loads the appropriate printer device driver into memory - converts high-level output commands into journal records - saves them as a file on disk

    • Prints in the background based on the saved output commands - journal records (converted to DDI (Device Driver Interface) so that the device driver can understand them)
  • Printer DC

    1. Function that calls the print dialog box

      • BOOL PrintDlg(LPPRINTDLG lppd);

pd.lStructSize = sizeof(PRINTDLG); //structure size pd.Flags = PD_RETURNDC; // obtain the printer DC pd.hwndOwner = hWndMain; // window handle pd.nFromPage = 1; pd.nToPage = 1; pd.nMinPage = 1; pd.nMaxPage = 1; pd.nCopies = 1; PrintDlg(&pd); hPrtdc = pd.hDC; // assign to HDC to use the print DC

  1. HDC CreateDC(LPCTSRT lpszDriver, LPCTSTR lpszDevice, LPCTSTR lpszOutput, CONST DEVMODE *lpInitData)

      1. driver name, 2. device name, 3. NULL 4. device-specific initialization data for the device driver
    • Used to obtain the DC of a device with a specific name.

PRINTER_INFO_4 *pi4;

EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &cbNeed, &cbReturn); pi4=(PRINTER_INFO_4 *)malloc(cbNeed); EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE)pi4, cbNeed, &cbNeed, &cbReturn);

hdc = CreateDC(NULL, pi4->pPrinterName, NULL, NULL);

  1. Starting the print job

    • int StartDoc(HDC hdc, Const DOCINFO *lpdi);

doc.cbSize = sizeof(DOCINFO); doc.lpszDocName = TEXT("TEST Document"); doc.lpszOutput = NULL; // the output file name, if NULL it outputs to the printer DC doc.lpszDatatype = NULL; StartDoc(hPrtdc, &doc);

  1. Prepares the printer driver to accept data (starts a new page)
  • int StartPage(HDC hdc)

     StartPage(hPrtdc);
    
  1. After completing the output of one page, loads a new sheet
  • int EndPage(HDC hdc);

EndPage(hPrtdc);

  1. Finishing the print job
  • int EndDoc(HDC hdc)

EndDoc(hPrtdc);

DeleteDC(hPrtdc);

  • Changing the font

xpage = GetDeviceCaps(hPrtdc, HORZRES); // the number of pixels of the device size ypage = GetDeviceCaps(hPrtdc, VERTRES); Rectangle(hPrtdc,0,0,xpage,ypage);

dpiY = GetDeviceCaps(hPrtdc, LOGPIXELSY); // the number of pixels per inch

// Because the screen resolution and the printer resolution are high, the calculation below is needed.

// 1 inch = 72 point = the number of pixels per inch obtained (pixel)

 point = n*1/72*dpiY

MyFont = CreateFont(20*dpiY/72, 0,0,0,FW_NORMAL, FALSE,FALSE,FALSE,HANGEUL_CHARSET,3,2,1, VARIABLE_PITCH|FF_ROMAN,TEXT("궁서"));

  • Bitmap output

Result=GetDeviceCaps(hPrtdc, RASTERCAPS) & RC_BITBLT; if (!Result) goto end; hbit=(HBITMAP)LoadImage(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION); .. MemDC=CreateCompatibleDC(hPrtdc); OldBitmap=(HBITMAP)SelectObject(MemDC, hbit); StretchBlt(hPrtdc,dpiX,dpiY,4dpiX,4by/bx*dpiY,MemDC,0,0,bx,by,SRCCOPY);

  • Precautions

    1. When outputting a bitmap to the printer, you must output it with the StretchBlt function (if you output with BitBlt as is, it prints smaller than what appears on screen)

    2. You must check whether bitmap output is possible.

      GetDeviceCaps(hPrtdc, RASTERCAPS) -checks whether raster output is possible

      RC_BITBLT -supports bitmap transfer

    3. You must read it with the LoadImage function. - because the screen color format and the printer color format do not match (since it is loaded as a DDB)

    LR_CREATEDIBSECTION - after reading it as a DIB section, when output it converts the bitmap format to match the printer.

  • Printing multiple pages

    1. Calculating the document length

      • You must find out the length of the document the user selected.

        PD_ALLPAGES, PD_PAGENUMS, PD_SELECTION

if (pd.Flags & PD_PAGENUMS) { nFirstPage=pd.nFromPage; nFinalPage=pd.nToPage; } else { nFirstPage=pd.nMinPage; nFinalPage=pd.nMaxPage; }

  1. Printing from the start page to the end page (must loop with a for statement to print)

for(nPage = nFirstPage; nPage <= nFinalPage; nPage++)

 {

      StartPage()

      EndPage()

  }

  EndDoc();
  • Cancel procedure (when canceling printing)
  1. A cancel procedure and a cancel dialog box are needed.

// cancel dialog box

g_hDlgCancel=CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWndMain, (DLGPROC)AbortDlgProc); // create the dialog box as modeless

LRESULT CALLBACK AbortDlgProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: g_bPrint=FALSE; // set to FALSE when the cancel button is pressed EnableWindow(hWndMain, TRUE); DestroyWindow(g_hDlgCancel); g_hDlgCancel=NULL; return TRUE; } return FALSE; }

// Abort procedure. Returning TRUE from this function continues printing, while returning FALSE cancels printing.

SetAbortProc(hPrtdc, (ABORTPROC)AbortProc); // add the cancel procedure

EnableWindow(hWndMain, FALSE); // to prevent closing the program or doing other work while printing

BOOL CALLBACK AbortProc(HDC hPrtdc, int iError) { MSG msg; while (g_bPrint && PeekMessage(&msg, NULL,0,0,PM_REMOVE)) { // printing is canceled when g_bPrint becomes FALSE. if (!IsDialogMessage(g_hDlgCancel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); }

return g_bPrint;

}

  • Enumerating printers
  1. Enumerating printers
  • Enumerates the printers and print servers installed on the system.

  • BOOL EnumPrint(DWORD Flags, LPTSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded,

                       LPDWORD pcReturnd);
    
    1. Flags : specifies the kind of object to examine (PRINTER_ENUM_LOCAL, PRINTER_ENUM_SHARED)

    2. Name : additional information about the target to examine (mostly set to NULL) - you can specify a domain name when examining the printer list within a specific domain.

    3. Level, pPrinterEnum : Level 2 -PRINTER_INFO_2 // used to obtain the desired information about the printer, ranging from 1 to 5

    4. cbBuf : the size of the array

    5. pcbNeeded : the amount of memory required

    6. pcReturned : returns the size of the structure array

typedef struct _PRINTER_INFO_4A { LPSTR pPrinterName; LPSTR pServerName; DWORD Attributes; } PRINTER_INFO_4A, *PPRINTER_INFO_4A, *LPPRINTER_INFO_4A;

PRINTER_INFO_4 *pi4;

EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &cbNeed, &cbReturn); pi4=(PRINTER_INFO_4 *)malloc(cbNeed); EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, (PBYTE)pi4, cbNeed, &cbNeed, &cbReturn); for (i=0;i<cbReturn;i++) { wsprintf(Mes,"프린터 이름: %s, 종류:%s ", pi4[i].pPrinterName, pi4[i].Attributes==PRINTER_ATTRIBUTE_LOCAL ? "로컬":"네트워크"); TextOut(hdc,10,y++*20,Mes,lstrlen(Mes)); } free(pi4);

  • Examining attributes

    1. Resolution, size (pixels), size (dimensions)

      GetDeviceCaps(HDC, HORZRES/HORZSIZE/LOGPIXELSX);

    2. Checking attributes based on the printer name (collated printing, duplex printing)

      DeviceCapabilities(szPrinter, szPrinter, DC_COLLATE/DC_DUPLEX, NULL, NULL); //collated printing, duplex printing

    3. OpenPrinter, GetPrinter, ClosePrinter : obtain a handle value from the printer name to get and set the PRINTER_INFO value

      GetPrinter and EnumPrinters can obtain the size of PRINTER_INFO in the same way.

Bitmaps and the Bitblt function

  • Reason for using a memory DC (bitmaps)

    • In the case of bitmaps, since they are large data, outputting them directly has the disadvantage of slow output speed.

      (bitmaps cannot be output directly to the screen)

    -Used to draw into a memory DC and then quickly copy it to the screen DC for display.

  • Fast-copy functions from memory DC to screen DC

    1. BOOL BitBlt(hdcDest, xDest, xDest, nWidth, nHeight, hdcSrc, nXsrc, nYSrc, dwRop) - raster operations : 256 kinds

    dwRop : specifies the raster operation method

    -SRCCOPY : copies the source region to the destination region.

    1. Enlargement and reduction possible during bitmap transfer

      BOOL StretchBlt(hdcDest, xOriginDest, YOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc,

                         nHeightSrc, dwRop) - raster operations : 256 kinds
      
      • StretchBlt(hdc, 0,0,246,320,MemDc,0,0,123,160,SRCCOPY)

      • SetStretchBltMode can change the mode.

  1. BOOL PatBlt(HDC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, DWORD dwRop) - raster operations : 16 kinds

    • Fills the specified rectangular region with the brush currently selected into the DC

    • FillRect fills a rectangular region with a brush, but PatBlt can vary depending on dwRop. (when filling with black or white)

  • GDI bitmap objects
  1. DDB bitmap creation functions
  • CreateBitmap(cx, cy, cPlanes, cBitsPixel, bits);

  • CreateCompatibleBitmap(hdc, cx, cy) -uses hdc to obtain GetDeviceCaps(PLANES(number of color planes), BITPIXEL(bits per pixel)) information

    -internally calls CreateBitmap.

  • CreateCompatibleBitmap(&bitmap) -sets the address in the BITMAP structure

    ● GetObject(hBitmap, sizeof (BITMAP), &bitmap) -you can obtain the structure's values

  • Memory device context

    hdcMem = CreateCompatibleDC(hdc);

    1. Specifying NULL as the argument creates a memory device context compatible with the video display

    2. Destroyed by calling DeleteDC

  • Loading a bitmap resource

    hBitmap = LoadBitmap(hInstance, szBitmapName);

    1. Loading a system bitmap : hinstance = NULL

    2. Deleted with DeleteObject

  • Monochrome bitmap format (creating a monochrome bitmap from a color array without creating a resource)

    static BYTE bits[] = {0x51, ~~};

    1. bitmap.bmBits = (PSTR)bits;

      hBitmap = CreateBitmapIndirect(&bitmap);

    2. hBitmap = CreateBitmapIndirect(&bitmap);

      SetBitmapBits(hBitmap, sizeof(bits), bits);

    3. hBitmap = CreateBitmap(20, 5, 1, 1, bits); //width, height,planes,bitsPixel,color data array

      -You must release it by calling the DeleteObject function.

Device-independent bitmaps

  • Difference between DIB & DDB
  • DDB (Device Dependent Bitmap) : a bitmap that is output according to the device settings (32bit -32bit, monochrome -monochrome)

                                                Advantage : since the information matches, images are output at high speed
    
                                                Disadvantage : since it depends on the device, it is not output correctly on other devices.
    
  • DIB (Device Independent Bitmap) : a bitmap that is output according to the settings in the header regardless of the device

                                                 Advantage : outputs the same image information on any device with any settings
    
                                                 Disadvantage : bitmap output speed may drop (conversion work is needed if the bitmap configuration differs)
    
  • DIB structure
  1. BITMAPFILEHEADER structure

    • Holds information about the bitmap file itself.

typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

  1. BITMAPINFOHEADER structure

    • A structure that is located right after the BITMAPFILEHEADER structure and holds information about the DIB's size (width, height) and color format.

typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

  1. RGBQUAD structure
  • Defines the color table used in the bitmap

typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD;

  1. DIB output

    1. SetDIBitsToDevice

BYTE* pRaster;

int SetDIBitsToDevice(HDC hdc,int xDest,int yDest,DWORD dwWidth,DWORD dwHeight,int xSrc,int ySrc,UINT uStartScan

                           UINT cScanLines,CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT fuColorUse);
  • Return : the number of scan lines

  • 9th argument (cScanLines) : the number of scan lines = the height of the bitmap

                   < bitmap >
    

    BITMAPFILEHEADER *fh = NULL;

    fh = (BITMAPFILEHEADER*)malloc(GetFileSize(hFile, NULL));

    BYTE* lpvBits = (PBYTE)fh+fh->bfOffBits;

  • lpvBits : a pointer to the raster data, which is the actual appearance of the bitmap (BITMAPFILEHEADER+BITMAPINFOHEADER == bfOffBits(FILEHEADER))

  • fuColorUse : DIB_RGB_COLORS - color values / DIB_PAL_COLORS - palette indices

    1. StretchDIBits ( when outputting enlarged )

int StretchDIBits(HDC hdc,int XDest,int YDest,int nDestWidth,int nDestHeight,int XSrc, int YSrc,int nSrcWidth,int nSrcHeight

                   CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi,UINT iUsage,DWORD dwRop);
  • Return : the number of scan lines

  • iUsage : DIB_RGB_COLOR (color table color values), DIB_PAL_COLORS (palette indices)

  • dwRop : raster operation

  1. DDB conversion

HBITMAP CreateBitmap(HDC hdc, CONST BITMAPINFOHEADER *lpbmih, DWORD fdwInit, CONST VOID *lpbInit

                               CONST BITMAPINFO* lpbmi, UINT fuUsage)'

{

if(hdc)

hBitmap = CreateCompatibleBitmap(hdc, cx, cy);

else

hBitmap = CreateBitmap(cx,cy,1,1,NULL);

if(fdwInit)

{

hdcMem = CreateCompatibleDC(hdc);

SelectObject(hdcMem, hBitmap);

SetDIBitsToDevice(hdcMem,0,0,cx,cy,0,0,0,cy,lpbInit,lpbmi,fuUsage);

DeleteDC(hdcMem);

}

return hBitmap;

}

  • Internally it creates a memory DC and outputs the DIB to a compatible bitmap. (outputs with BitBlt)
  1. DIB section
  • Advantages : you can directly manipulate the raster data, and it is convenient to handle large files (file mapping object)

  • HBITMAP CreateDIBSection(HDC hdc, CONST BITMAPINFO *pbmi, UINT iUsage, VOID **ppvBits,

                                        HANDLE hSection, DWORD dwOffset);
    
  1. Converting to a DIB
  • CreateBitmap and CreateCompatibleBitmap are fast because they depend on the device, but to save as a DIB the API below must be called.

  • int GetDIbits(HDC hdc,HBITMAP hBitmap,UINT uStartScan,UINT uScanLines,LPVOID lpvBits,LPBITMAPINFO lpbi, UINT uUsage);

Text and fonts

  • Text drawing functions

    1. SetTextAlign(HDC hdc, UINT fMode)

      ● fMode : sets the specified alignment Mode.

      TA_UPDATECP : ignores the x, y coordinates specified in TextOut and uses the current CP (current position).

      TA_NOUPDATECP : uses the specified coordinates instead of the CP and does not change the CP.

    2. TabbedTextOut(hdc, xStart, yStart, pString, iCount, iNumTabs, piTabStops, xTabOrigin)

      • If the text string contains a tab character ('\t', 0x09), TabbedTextOut() expands the tabs into spaces based on the integer array passed as an argument.

e.g.) int tabstop[4] = {8,16,24,32}

  wsprintf(temp, "tabbedTextOut\t를\t이용한\t출력");

  1) TabbedTextOut(hdc,0,20,temp,strlen(temp),4,tabstop,0);

  =iNumTabs : the number of tabs, piTabStops : an array holding the tab positions

  =At the first tab, it spaces by 8 times the average width of the configured string; at the second tab, by 16 times.

  2) TabbedTextOut(hdc,0,20,temp,strlen(temp),1,tabstop,0);

  =Each time a tab key is encountered, it spaces uniformly by the first value of tabstop, that is, 8.

3. ExtTextOut(hdc, x, y,

                 fuOptions, - text output options

                 &rect  - the rectangular region

lpString,

                   cbCount,

                   lpDx ) - a pointer to an array of spacing values between characters (int pDx[]={5,6~~} pDx[i] is the spacing between a character and the character to its right

 - Draws the string using the currently selected font, background color, and text color.

 - When both &rect and lpDx are NULL, it functions the same as TextOut. (internally, TextOut calls ExtTextOut.)

1) fuOptions : specifies how the application-defined rectangle is used.

  ● ETO_CLIPPED : the text is clipped to the given rectangle. The string is output only inside the region.

  ● ETO_OPAQUE : a background rectangle to be filled with the current background color

4. DrawText(hdc, pString, iCount, &rect, iFormat);

- Setting iFormat to 0 : Windows interprets the text as a series of lines separated by carriage return characters ('\r') and line feeds ('\n')

                                  DT_WORDBREAK : automatically wraps at the right edge of the rectangular region.

                                  DT_NOCLIP : outputs the string as is without truncating it even if it goes beyond the boundaries of the rectangular region

- DrawTextEx(hdc, pString, iCount, &rect, iFormat, &drawtextparams)

typedef struct tagDRAWTEXTPARAMS { UINT cbSize; // the size of the structure int iTabLength; // the size of each tab stop int iLeftMargin; //left margin int iRightMargin; //right margin UINT uiLengthDrawn; // receives the number of characters processed. } DRAWTEXTPARAMS, FAR *LPDRAWTEXTPARAMS;

  • DWORD GetSysColor(nIndex) : nIndex - obtains the specified system color. (COLOR_MENU, COLOR_WINDOW)

  • Current character spacing

    • SetTextCharacterExtra(hdc, iExtra) - iExtra is in logical units, which the window converts to pixels (changes the spacing between characters)

    • GetTextCharacterExtra(hdc)

  • Creating a font

typedef struct tagLOGFONTW { LONG lfHeight; LONG lfWidth; LONG lfEscapement; // the angle of the string LONG lfOrientation; // the angle of individual characters LONG lfWeight; // the thickness of the characters BYTE lfItalic; // italic BYTE lfUnderline; // underline BYTE lfStrikeOut; // strikethrough BYTE lfCharSet; // character set BYTE lfOutPrecision; // output precision (specifies whether to find a font close in height, width, pitch, etc.) BYTE lfClipPrecision; //how to handle when it goes outside the clipping region BYTE lfQuality; // output quality (emphasizes the appearance of the typeface/font) BYTE lfPitchAndFamily; // pitch : the width of individual characters, and the font family WCHAR lfFaceName[LF_FACESIZE]; //typeface : the name of the font } LOGFONTW, *PLOGFONTW, NEAR *NPLOGFONTW, FAR *LPLOGFONTW;

-Same as the argument values of CreateFont. The LOGFONT structure is used as an argument to CreateFontIndirect.

  • Logical font : a font created by the CreateFont function

    Physical font : a font that actually exists on the operating system or device

    Stock font : a font provided by the operating system (GetStockObject)

  • Enumerating fonts

  1. Font enumeration functions
  1. int EnumFontFamilies(HDC hdc, LPCTSTR lpszFamily, FONTENUMPROC lpEnumFontFamProc, LPARAM lParam)

    lpszFamily : specifies the font family to examine (if the value is NULL, it examines all families).

    lpEnumFontFamProc : reports the characteristics of the found fonts

  2. int CALLBACK EnumFontFamProc(ENUMLOGFONT FAR *lpelf, NEWTEXTMETRIC FAR *lpntm, int FontType, LPARAM lParam)

    ENUMLOGFONT - the LOGFONT structure, ElFullName - the font type string,

    NEWTEXTMETRIC : holds various characteristic values of the font.

    FontType : the type of font (device, raster, TrueType)

  • Physical fonts

    1. BOOL GetTextMetrics(HDC hdc, LPTEXTMETRIC lptm) : used when you want to obtain information about the width or height of individual characters and then space them appropriately.

                                                                                  ( various information about the physical font currently selected into the hdc)
      
      • e.g.) GetTextMetrics(hdc, &tm)

        TextOut(hdc, 0, i*(tm.tmHeight), str, lstrlen(str));

  • BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int cbString, LPSIZE lpSize) : used to obtain the size of a string.

     - "ijl" and "BMW" are both three characters but their overall widths differ. This is used in that case.
    
     - e.g.) GetTextExtentPoint32(hdc, str, lstrlen(str), &sz)
    
             x += sz.cx;
    
             TextOut(hdc, x,0, str, lstrlen(str));
    
  • Installing a font

    • lpszFilename : passes the path of the font to add/remove. (Windows\Font)

    • int AddFontRsource( LPCTSTR lpszFilename)

      ● Installation process

      1. Copy the font file to the Font folder
      
      2. Register the font : AddFontResource
      
      3. Broadcast WM_FONTCHANGE
      
         SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
      
      4. Record the font name in the registry
      
  • Removing a font

    • BOOL RemoveFontResource(LPCTSTR lpFileName)

      ● Process

      Cancel the registered font : RemoveFontResource - broadcast WM_FONTCHANGE - remove the font name from the registry - delete the font file
      
  • BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInformation)

    • An API that provides version information about the currently running OS
    1. OSVERSIONINFO

       typedef struct _OSVERSIONINFOW {
      DWORD dwOSVersionInfoSize; //Version Info size
      DWORD dwMajorVersion;        // OS Version 2.1 -2
      DWORD dwMinorVersion;        //OS Version 2.1 -1
      DWORD dwBuildNumber;
      DWORD dwPlatformId;            // OS platformID -VER_PLATFORM_NT, VER_PLATFORM_WIN32_C3, etc.
      WCHAR  szCSDVersion[ 128 ];     // additional information about the OS
      

      } OSVERSIONINFOW, *POSVERSIONINFOW, *LPOSVERSIONINFOW;

  • Path

    • The shape of a figure drawn by GDI functions

    • A path is drawn without a handle, which means you cannot create multiple paths and swap between them for use.

    • The region between BeginPath(HDC) and EndPath(hWnd) is called the path bracket, and during this the GDI functions do not produce output but record into the path.

    StrokePath(HDC): the outline, FillPath(HDC) : the interior of the path, StrokeAndFillPath(HDC) : the outline and the interior of the path

    • Clip path
    1. SelectClipPath(HDC, iMode)
    • SelectClipPath(hdc, RGN_COPY); //RGN_COPY : the current path is selected as the new clipping region
    1. PathToRegion(hdc) - used to convert a path into a region (e.g. hRgn = PathToRegion(hdc) )
  • Extended pen

  • ExtCreatePen(dwPenStyle, dwWidth, LOGBRUSH, dwStyleCount, lpStyle)
  1. PenStyle : specify styles such as PS_SOLID, PS_JOIN_ROUND, etc.

  2. dwWidth : the thickness of the line

  3. LOGBRUSH : specify the line's pattern and style within the structure

  4. dwStyleCount, lpStyle : specify PS_USERSTYLE (used when drawing a user-defined line - if unused : set the two arguments to 0 and NULL)

    • dwStyleCount : the size of the lpStyle array

    • lpStyle : draw 5 pixels, skip the next 5 pixels.

    e.g.) DWORD Style[] = {5,5,4,4,3,3,2,2,1,1};

     hGeo = ExtCreatePen(PS_USERSTYLE|PS_GEOMETRIC, 1, &logBrush, 10, Style)
    

Multiple document interface

  • Multiple-Document Interface (MDI)

    • Difference between a client window and a regular window

      1. The client window is fixed as MDICLIENT.

        CreateWindow("MDICLIENT"~~) is predefined by the operating system, so there is no need to register a window class.

      2. The client window must pass a pointer to a CLIENTCREATESTRUCT structure in the last argument lParam of CreateWindow.

  • TranslateMDISysAccel(hWndClient, lpMsg)

    • Responsible for sending WM_KEYDOWN, WM_SYSCOMMAND messages to the MDI child windows.
  • Frame window message processing / window message processing

    1. Argument difference
    • DefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)

    • DefFrameProc(HWND hWnd,HWND hWndMDIClient,UINT Msg, WPARAM wParam, LPARAM lParam)

      =The client window handle is added.

    1. Message processing

      • After processing frame window messages, you must use a break statement instead of return 0. (focus errors)
  • Client window

    1. GetSubMenu(GetMenu(), 1)

      Based on the menu

      Submenu 0 (File)

      Submenu 1 (Window)

    2. CLIENTCREATESTRUCT explanation

    • hWindowMenu : the menu ID used for managing the child list

    • idFirstChild : the menu item where the list of the first child window will be output (up to 9 can be output)

    ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), WINDOWMENU) ccs.idFirstChild = IDM_WINDOWCHILD; // 9 consecutive IDs after the first child item in the menu must be empty.

                                                              So you must #define them as a range of consecutive values.
    
  1. Style in CreateWindow

    • WS_CLIPCHILDREN is set to prevent sending a WM_PAINT message to child windows when the client window is redrawn.
  • Client window, MDI-related structures
  • When an application creates an MDI client window, it must specify a CLIENTCREATESTRUCT structure.

  • When the MDI client window creates an MDI child window, it must specify an MDICREATESTRUCT structure.

  • Child window

    1. Precautions for child windows

      • Since child windows cannot have a menu, lpszMenuName must be NULL.

      • It is good to specify a separate icon. (to distinguish minimize and system menus)

      • You must leave spare memory. (the child window's file name or serial number is stored)

    2. Creating a child window

    • Fill in the MDICREATESTRUCT properties

      1. mcs.style = MDIS_ALLCHIDSTYLES

        =MDIS_ALLCHILDSTYLES : WS_MINIMIZE | WS_MAXMIZE | WS_HSCROLL | WS_VSCROLL

      2. Sending WM_MDICREATE via SendMessage creates a child window (passes a pointer to the MDICREATESTRUCT structure in lParam)

      typedef struct tagMDICREATESTRUCT { LPCTSTR szClass; LPCTSTR szTitle; HANDLE hOwner; int x; int y; int cx; int cy; DWORD style; LPARAM lParam;

    } MDICREATESTRUCT, *LPMDICREATESTRUCT;

     3) HWND CreateMDIWindow(LPTSTR lpClassName, LPTSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth,
    
         int nHeight, HWND hWndParent, HINSTANCE hInstacne, LPARAM lParam);
    
  1. Tiling child windows
  • Sending WM_MDITILE via SendMessage creates a child window arrangement

  • MDITILE_HORIZONTAL horizontal alignment, MDITILE_VERTICAL vertical alignment

  1. Cascading child windows
  • Sending WM_MDICASCADE via SendMessage creates a child window arrangement

  • If you pass the MDITILE_SKIPDISABLED flag in wParam, disabled children are excluded from the arrangement.

  1. Arranging child window icons
  • Sending WM_MDIICONARRANGE via SendMessage creates a child window arrangement

  • Arranges the minimized icons.

  1. Finally, you must handle it by calling DefMDIChildProc (the same arguments as DefWindowProc).
  • In WndClass, cbWndExtra = sizeof(int) -you can specify spare memory.

  • SetWindowLong(hWnd, 0, ChildNum) - stores values through a pointer that references the memory block.

index : if the window has spare memory, you can also specify the offset of the spare memory. This value must be positive and less than cbWndExtra-4. For example, if 32 bytes of spare memory are specified, nIndex can be specified from 0 to 28.

=You can check the stored value through GetWindowLong(hWnd, 0).

Multitasking, multithreading & synchronization

  • Multitasking : an environment where multiple processes run simultaneously on a single operating system

  • Multithreading : an environment where multiple threads run simultaneously within a single process

  • Thread : a path that executes instructions within a process, a sequence of execution code

    1. Creating a thread
    • HANDLE CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreateFlags, lpThreadID)

1st argument : specifies the thread security attributes (set to NULL unless handles interfere with each other)

2nd argument : the size of the thread's stack (defaults to 1M)

3rd argument : the thread's start address

4th argument : the work content passed to the thread

5th argument : specifies thread characteristics (when the CREATE_SUSPENDED flag is specified, the thread is created but does not run - you must call the ResumeThread function)

6th argument : the thread ID

2 Thread characteristics

- Threads within the same process share the address space, global variables, and code.

3. Checking thread status

  • BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)

    1st argument : the target thread handle

    2nd argument : examines and returns the thread's exit code

  1. Terminating a thread

    1. Difference between Return & ExitThread and the problem with ExitThread

      • Difference :
  2. Problem : if a C++ object exists in functions A and B, and you terminate with the ExitThread function in function C, the destructors of functions A and B are not called, so a memory leak occurs; therefore you should avoid using it as much as possible and return instead.

  3. Difference between ExitThread & TerminateThread

    • VOID ExitThread(DWORD dwExitCode) / BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)

      1. ExitThread : terminates the thread at a specific point in the running thread

        TerminateThread is used to forcibly terminate the thread passed as an argument.

  • Suspending/resuming a thread

    • SuspendThread(HANDLE hThread) : increments the suspend count

    • ResumeThread(HANDLE hThread) : decrements the suspend count (resumes when it reaches 0)

  • UI thread

    • Worker thread : a thread that is invisible to the user, does only internal computation, and then disappears

    • UI thread : a thread that creates windows and has a message queue and message loop

e.g.)

RegisterClass(~)

DWORD WINAPI ThreadFunc(LPVOID temp)

{

  CreateWindow(~);

while(GetMessage(~))

{

TranslateMessage

DispatchMessage

}

}

LRESULT CALLBACK DeCompProc(~)

{

...

}

  • Thread priority

    • A thread's priority is determined by the combination of two values : the priority class and the priority level.
    1. Priority class (process) CreateProcess (set in the 6th argument)

      DWORD GetPriorityClass(HANDLE hProcess);

      BOOL SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass);

    2. Priority thread (thread)

      int GetThreadPriority(HANDLE hThread);

      BOOL SeThreadPriority(HAND hThread, int nPriority)

  • C runtime library

  • When writing in C/C++ code, using the CreateThread provided by WINAPI can cause problems, so you should use _beginThreadex, _endthreadex.
  1. Difference between _beginthread and _beginthreadex

    _beingthread creates a new thread and then internally calls the CloseHandle function to remove the created thread handle

    _beingthreadex returns a handle (which must be cast), and since it does not internally call the CloseHandle function, you must call the function explicitly.

e.g.)

unsigned __stdcall SecondThreadFunc(void *pArg)

{

~

_endthreadex(0);

}

void main()

{

HANDLE hThread;

hThread = (HANDLE)_beginthreadex(NULL, 0, SecondThreadFunc, null, 0, &threadID);

CloseHandle(hThread);

}

  • TLS (Thread Local Storage)
  1. TLS (Thread Local Storage)
  • Came about to solve the problem of threads sharing global variables or static variables
  1. TLS functions
  • Obtaining an index value (allocating a slot) / freeing a slot

    TlsIndex= TlsAlloc(); TlsFree(TlsIndex);

  • Setting a value in a slot / obtaining a slot value

    TlsSetValue(TlsIndex, (LPVOID)0); tcount=(int)TlsGetValue(TlsIndex)+1;

  • Synchronization

    • Making multiple threads execute in coordination so as to resolve race conditions or deadlocks
  1. Deadlock - an abnormal state where the wait never ends and it waits indefinitely

ThreadFunc1

EnterCriticalSection(&crit1); - 1

EnterCriticalSection(&crit2); - 3

LeaveCriticalSection(&crit2);

LeaveCriticalSection(&crit1);

ThreadFunc2

EnterCriticalSection(&crit2);

EnterCriticalSection(&crit1); - 2

LeaveCriticalSection(&crit1);

LeaveCriticalSection(&crit2);

  1. Difference between critical section / mutex / semaphore

    1. Critical section : a user-mode object, lightweight and fast.

                         Supports thread synchronization within the same process
      
    2. Mutex, semaphore : kernel-mode objects, relatively heavy and slow

                             Support synchronization between threads of multiple processes
      
    3. Difference between mutex and semaphore : a mutex allows only one thread to access the critical region

                                       a semaphore controls the number of threads accessing the critical region
      
  2. Critical section

    • A block of code that must not be interrupted

    • CRITICAL_SECTION functions

      1. InitializeCriticalSection, DeleteCriticalSection - initialize / destroy

      2. EnterCriticalSection, LeaveCriticalSection - marks the start of the section / the section to exit

  3. Mutex

    • WaitForSingleObject, WaitForMultiIObject

    • CreateMutex, OpenMutex, ReleaseMutex

  4. Semaphore

  • CreateSemaphore, OpenSemaphore, ReleaseSemaphore CreateSemaphore 2nd argument : the number of critical regions, 3rd argument : the number of critical region accesses
  1. Event
  • CreateEvent, OpenEvent, SetEvent, ResetEvent
    1. 2nd argument TRUE : manual-reset event, FALSE : auto-reset event
    2. 3rd argument TRUE : creates the event and simultaneously puts it in the signaled state.
  • Static linking & dynamic linking

  • Advantages of using DLLs

  1. Saves memory because multiple programs use it simultaneously

  2. Programs that use a DLL are small in size. (statically linked executables become large.)

  3. It is easy to improve the program's performance by replacing the DLL. (only the DLL needs to be replaced)

  4. Resources can be replaced (multilingual versions)

  5. Easy debugging (assuming the DLL has no bugs)

  6. Mixed programming is possible (compatible with any development tool)

  7. It is easy for programmers to divide the work, and reusability is excellent

  • Disadvantages of using DLLs
  1. If the DLL is missing or corrupted, execution is impossible

  2. If the DLL version changes, program incompatibility can occur

  • Functions exported from a DLL / functions imported into a DLL
  1. extern "C" __declspec(dllexport) function prototype -__declspec : provides information about the function

    extern "C" __declspec(dllimport) function prototype

  • Import library : has no actual code and stores only location information about the functions.
  • Order in which DLL files are searched

    =1. The directory containing the client program

     2. The program's current directory
    
     3. The Windows system directory
    
     4. The Windows directory
    
     5. All directories specified by the PATH environment variable
    
  • Specifying the import library : #pragma comment(lib, "MyDll.lib")

  • Explicit linking (explicitly loading and using the DLL)

    1. HINSTANCE LoadLibrary(LPCTSTR lpLibFileName)

    2. FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName)

    hInst = LoadLibrary(TEXT("MyDll.dll"));

    pFunc = (int (*)(int, int))GetProcAddress(hInst,"AddInteger");

  • Advantages/disadvantages of explicit linking

    1. Memory and resources are saved because the DLL is loaded and used only when needed.

    2. You can replace the DLL to use (just replace the DLL name according to the situation)

    3. The program can run even when the required DLL is missing

    4. The client program starts quickly.

    Disadvantage : function call speed becomes slower.

  • DllMain function

    BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpRes);

    -The above function is called when the DLL is first loaded into memory and when it is removed.

    fdwReason : the reason the function was called
    
    1) DLL_PROCESS_ATTACH / DLL_PROCESS_DETACH
    
        DLL_THREAD_ATTACH / DLL_THREAD_DETACH
    

Memory

  • C runtime functions ( consume physical memory)

    • void *malloc(size_t size);

      void *calloc(size_t num, size_t size); // logically expresses the amount of memory needed

      void *realloc (void *memblock, size_t size); // when reallocating already-allocated memory larger or shrinking it

      void free(void* memblock);

  • Virtual memory allocation

    1. Advantages
    • Reserved memory allocation is possible ( can be allocated without consuming physical memory)

    • You can set the access permissions of the allocated memory

  LPVOID VirtualAlloc(LPVOID lpAdress, DWORD dwSize, DWORD flallocationType, DWORD flProtect);
 
  BOOL VirtualFree(LPVOID lpAddress, DOWRD dwSize, DWORD dwFreeType);
 
  ptr = (int*)VirtualAlloc(NULL, sizeof(int)*10, MEM_RESERVE|MEM_COMMT, PAGE_REDWRITE);
 
  wsprintf(str "%d", ptr[i]*i*2);
 
  TextOut(hdc, 10, i\*20, str, lstrlen(str));
 
  VirtualFree(ptr, sizeof(int)\*10, MEM_DECOMMIT);
 
  VirtualFree(ptr, 0, MEM_RELEASE);

Synchronization

  1. The need for synchronization
  • In a preemptive multithreading system using a single processor, multiple threads appear to run simultaneously, but only one thread actually runs. At that time, synchronization becomes necessary to resolve the problems that arise from thread preemption of shared resources.
  1. Synchronization functions
  1. Critical section : user-level synchronization (not a kernel object), usable only within the same process, high speed

  2. Mutex : uses a kernel object (CreateMutex, OpenMutex, ReleaseMutex, CloseHandle), protects a single shared resource

    • Abandoned mutex : when you use TerminateThread or ExitThread to kill a thread while it holds a mutex -the return value of WaitForSingleObject returns WAIT_ABANDONED.
  3. Semaphore : a synchronization object that counts the number of available resources ( CreateSemaphore, OpenSemaphore, ReleaseSemaphore)

  1. Event
  1. Coordinates the work order or timing between threads, and sends signals

  2. CreateEvent(. bManualReset,,) bManualReset = True manual (must use ResetEvent, SetEvent) False automatic