Win32 SDK Closed Example - Ordinary Windows Program (Translation)

zhaozj2021-02-08  209

Ordinary Windows program

This program encapsulates the Windows API using classes.

The Controller - the bridge between the window process and the object. View - The output package of the Windows program. Canvas - encapsulates different equipment descriptors and events, you can use them. Model - workers, the brain of your program. Never processed the window.

Note: This is a Win32 program - it will run under Windows 95 and Windows. Note: _SET_NEW_HANDLER is Microsoft Specific. If you use other compilers, just remove this line of code. According to the current C standard, the New operator should abandon anyway. Note: The old compiler may have problems in templates. You can call GET / SETWINDOWLON directly instead of WIN [Get / Set] long template. Example, call the following instead of controller * pctrl = WinGetlong

(hwnd);

You can call Controller * pctrl = reinterpret_cast (:: getWindowlong (hwnd, gwl_userdata);

Let us start from Winmain, we build a window class and our top window. I encapsulated these actions in two classes: WinClass and WinMaker. If we have run an instance where our program has already run, WinClass can tell us. When such a thing occurs, our example will end the simple activation program after the previous instance. When you just want your program to run an instance at the same time, you should do this. Once the top window is successfully established, we start the message loop. At this time we process shortcuts by calling TranslateMessage. This is because our program's menu entry can be accessed using a combination of Alt keys. In addition, this program is interesting that we can't use a long string to name our resources - we use digital identity. Even the API calls, like window type names, or titles, we are stored in string resources, access through identifiers. Most of your Windows development environment has a resource editor to set up icons, menus, and string resources, assign them the appropriate numeric identifier. The symbolic names of these identifiers are stored in an episode of the header file - we call it resource.h. Constants, ID_main is an icon introduced for the main program of the instance (there is a large one in the same resource), the main menu, and the string of the window type sentence. ID_caption is a window title string.

Int WinApi Winmain

Hinstance Hinst, Hinstance Hprevinst,

Char * cmdparam, int cmdshow)

{

_SET_NEW_HANDLER (& NewHandler);

// Use exception help to debug your program

/ / Prevent anomalous event

Try

{

// Establish a top window class

TopwinClass TopwinClass (ID_main, hinst, mainwndproc);

/ Is the instance of this program?

HWND HWNDOTHER = TopwinClass.GetrunningWindow ();

IF (hwndother! = 0)

{

:: setForegroundWindow (HWndother);

IF (: isiconic (hwndother))

:: ShowWindow (hwndother, sw_restore;

Return 0;

}

TopwinClass.register ();

// Establish a top window

Resstring caption (hinst, id_caption);

TopwinMaker Topwin (TopwinClass, CAPTION); Topwin.create ();

Topwin.show (cmdshow);

// Principal Message Cycle

MSG msg;

Int status;

While (status = :: getMessage (& msg, 0, 0, 0))! = 0)

{

IF (status == -1)

Return -1;

:: TranslateMessage (& MSG);

:: DispatchMessage (& MSG);

}

Return msg.wparam;

}

Catch (Winexception E)

{

Char buf [50];

WSPrintf (BUF, "% s, error D", E.GETMESSAGE (), E.GETERROR ());

:: MessageBox (0, BUF, "Exception", MB_ICONEXCLAMATION | MB_OK);

}

Catch (...)

{

:: MessageBox (0, "Unknown", "Exception", MB_ICONEXCLAMATION | MB_OK);

}

Return 0;

}

Let's take a look at the WinClass class. It encapsulates the window definition structure called by WndClassex, providing a reasonable default value for all of its fields. It comes from a WINSIMPLECLASS template class, you can use some fixed window types (icon buttons, lists) I have a method, if there is a method, you can not consider the default. For example, setbgsyscolor can change the background color of the client area of ​​the default window. Methods SetresICons are loaded from the resources into the appropriate icon and attach them on the window class. These icons will be displayed in the main window and the taskbar of the main window and Windows. TopwinClass is used for use by WinClass. It also assigns the menu to the top window class.

Class WinsImpleClass

{

PUBLIC:

WinsImpleClass (Char const * name, hinstance hinst)

: _Name (Name), _HINSTANCE (HINST)

{}

WinsimpleClass (int Resid, hinstance hinst);

CHAR const * getname () const {return_name.c_str ();

Hinstance getInstance () const {return_HINSTANCE;

HWnd getRunningWindow ();

protected:

Hinstance_HINSTANCE;

Std :: string _name;

}

WinsimpleClass :: WinsImpleClass (int Resid, hinstance hinst)

_HINSTANCE (HINST)

{

RESSTRING RESSTR (HINST, Resid);

_name = relasstr;

}

HWND WinsimpleClass :: getRunningWindow ()

{

HWND HWND = :: FindWindow (getName (), 0);

IF (: iswindow (hwnd))

{

HWND HWNDPOPUP = :: getLastactivePopup (hwnd);

IF (: iswindow (hwndpopup))

HWnd = hwndpopup;

}

Else

HWND = 0;

Return hwnd;

}

Class Winclass: Public WinsImpleClass {

PUBLIC:

WinClass (Char Const * Classname, Hinstance Hinst, WndProc WndProc);

WinClass (int Resid, Hinstance Hinst, WndProc WndProc);

Void setbgsyscolor (int syscolor)

{

_class.hbrbackground = reinterpret_cast (syscolor 1);

}

Void SetResicons (int Resid);

Void register ();

protected:

Void setDefaults ();

WNDCLASSEX _CLASS;

}

WinClass :: Winclass (Char const * ClassName, Hinstance Hinst, WndProc Wndproc)

: WinsimpleClass (Classname, Hinst)

{

_CLASS.LPFNWNDPROC = WNDPROC;

SetDefaults ();

}

WinClass :: WinClass (int Resid, Hinstance Hinst, WndProc WndProc)

: WinsImpleClass (Resid, Hinst)

{

_CLASS.LPFNWNDPROC = WNDPROC;

SetDefaults ();

}

Void Winclass :: setDefaults ()

{

/ / Provide reasonable default values

_class.cbsize = sizeof (wndclassex);

_class.style = 0;

_class.lpszclassname = getName ();

_class.hinstance = getInstance ();

_class.hicon = 0;

_class.hiconsm = 0;

_CLASS.LPSZMENUNAME = 0;

_class.cbclsextra = 0;

_class.cbwndextra = 0;

_class.hbrbackground = reinterpret_cast (Color_Window 1);

_class.hcursor = :: loadcursor (0, IDC_ARROW);

}

Void WinClass :: SetResicons (int Resid)

{

_class.hicon = :: loadicon (_class.hinstance, makeintresource (resid));

/ / You can use LoadImage from the same resource to load small icons

_class.hiconsm = reinterpret_cast

:: LoadImage

_class.hinstance,

MakeintResource (Resid),

Image_icon,

:: getSystemMetrics (SM_CXSMICON),

:: getSystemMetrics (SM_CYSMICON),

Lr_shared));

}

Void WinClass :: register ()

{

IF (: registerclassex (& _class) == 0)

Throw Winexception ("Internal Error: RegisterClassex Failed.");

}

Class TopwinClass: Public Winclass {

PUBLIC:

TopwinClass (int Resid, Hinstance Hinst, WndProc WndProc);

}

Topwinclass :: TopwinClass (int Resid,

Hinstance Hinst, WndProc WndProc

: WinClass (Resid, Hinst, WndProc)

{

SetResicons (Resid);

_Class.lpsz GeneNuname = makeintResource (resid);

}

Once the window class is registered in the system, you can build any window you want. They will, of course, they will enjoy this class registration process. We will learn about the difference between the different instances of the window in the process. WenMaker class work is very like WinClass. Its constructor provides the actual default value, which can be overwritten by calling the detail method. Once anything is set, you call the CREATE method to create a window, and call the show method to display it. Note that your window will be called by the WM_CREATE message when calling CREATE. The top window is established using the TopwinMaker class, providing the appropriate style and title.

Class WinMaker

{

PUBLIC:

WinMaker (WinClass & WinClass);

Operator hwnd () {return_hwnd;}

Void AddCaption (Char const * caption)

{

_Windowname = CAPTION;

}

Void addsysmenu () {_Style | = ws_sysmenu;

Void addvscrollbar () {_style | = ws_vscroll;

Void addhscrollbar () {_Style | = ws_hscroll;

Void crete ();

Void show (int ncmdshow = sw_shownormal);

protected:

Winclass & _class;

HWND_HWND;

DWORD _EXSTYLE; / / Extension window style

Char const * _windowname; / / Pointer Point Pointer P

DWORD _Style; // Window style

INT _X; // Window horizontal position

INT _Y; // Route position

INT _WIDTH; / / window wide

INT _HEIGHT; / / window high

HWND _HWNDPARENT; / / Parent window or owner's handle

HMENU _HMENU; // Handle of the menu, or the identifier of the child window

void * _data; // Point to the window creates data

}

WinMaker :: WinMaker (Winclass & Winclass)

: _hWnd (0),

_class (winclass),

_exStyle (0), // extended window style

_windowname (0), // Point to the name of the window

_Style (WS_OVERLAPPED), // Window Style

_X (cw_usedefault), // Horizontal position

_y (0), // The rise position of the window

_width (cw_usedefault), // window width _height (0), // high window

_hWndparent (0), // parent window or handle of the owner

_hmenu (0), // Point to menu, or sub-window identifier

_DATA (0) // Pointing the window to create data

{

}

Void WinMaker :: Create ()

{

_hWnd = :: CreateWindowex

_exstyle,

_class.getname (),

_Windowname,

_Style,

_x,

_y,

_WIDTH,

_height,

_hwndparent,

_HMenu,

_Class.GetInstance (),

_DATA);

IF (_hWnd == 0)

Throw WinException ("Internal Error: Window Creation Faled.");

}

Void WinMaker :: Show (int ncmdshow)

{

:: ShowWindow (_HWND, NCMDSHOW);

:: UpdateWindow (_HWND);

}

// Manufacture the window of the top overlapping tape title

TopwinMaker :: TopwinMaker (Winclass & Winclass, Char const * caption)

: WinMaker (WinClass)

{

_Style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;

_Windowname = CAPTION;

}

This has a small class before we start the next step. WinException throws the failure of the Windows API at any time. It needs to retrieve the Windows error code. (By the way, using FormatMessage is easy to convert error code to string.) The RESSTRING class is a simple package for strings stored in string resources of your application.

// EXCEPTION class: Storage message and error code

Class Winexception

{

PUBLIC:

WinException (char * msg)

: _ERR (:: getLastError ()), _MSG (MSG)

{}

DWORD getError () const {return_err;}

CHAR const * getMESSAGE () Const {Return_MSG;}

Private:

DWORD_ERR;

Char * _msg;

}

// Memory overflow: Throw an exception

INT NewHandler (size_t size)

{

Throw Winexception ("Out of Memory");

Return 0;

}

Class relasstring

{

ENUM {MAX_RESSTRING = 255};

PUBLIC:

Resstring (Hinstance Hinst, Int Resid);

Operator char const * () {return_buf;

Private:

Char _buf [MAX_RESSTRING 1];

}

Resstring :: relasworth (Hinstance Hinst, Int Resid)

{

IF (! :: loadstring (hinst, resid, _buf, max_resstring 1)))

Throw Winexception ("Load String Failed");

}

Controller is a strong system of a special window instance. It built a window and stored it and destroyed it at the end. In its control you can place some description information for a particular window instance. In general, the controller has a view (interacting through the surface of the window) and it has the right to use Model. It is equivalent to the brain of your app (in this, MVC or Model-View-Controller is called through the SmallTalk program). If, this often occurs, your application has only one top window, you can insert Model in its control. This monolithic resource management, which is closely related to Model. This connection should be avoided in large projects - preferred in the controller to use a pointer to Model. More Controller methods require a handle that points to the window for their operation. This handle is a handle through each window message, but it is just a simple and simple storage to the Controller object, you can use it at any time. Remember - there is one-to-one communication between the window instance (because the handle of the window) and the Controller object. Class Controller

{

PUBLIC:

Controller (HWND HWND, CREATESTRUCT * PCREATE);

~ Controller ();

Void size (int X, int y);

Void paint ();

Void Command (INT CMD);

Private:

HWND_HWND;

Model_model;

View _View;

}

The window process is a main switch for a window application. You can't call it in your program window! Whenever something meaningful event occurs, Windows sends a bar message to your program. This message is passed by your window. You can handle it or deliver it to the default window process. The window is called by a given message. This handle is an unique internal window data of a coordinated window instance. When it happens, we can access these data structures, and use it to store some instance specified. This is a typical way to access the structure. Incident, the GWL_USERDATA member of this structure is given for all windows. Contains message boxes, dialogs, and smoothing buttons.

Template

Inline T WingeTlong (HWND HWND, INT Which = GWL_USERDATA)

{

Return Reinterpret_cast (:: getWindowlong (hwnd, heich));

}

Template

Inline void winsetlong (hwnd hwnd, t value, int which = gwl_userdata)

{

:: Setwindowlong (hwnd, which, reinterpret_cast );

}

Whenever Windows calls our window procedure, we should first retrieve its control objects. Remember, this may share the same window procedure in this case, we should control each window. How do we know which control to use after we are called? We find the handle of the window. In this handle we store the controller to this particular window, use WIN [SET / GET] long skill. The window process is first called by the WM_CREATE message. At that time we established a controller object and initialize it with a window handle and specified the data structure by calling CreateStruct. Once we have a controller, we store the data structure of the corresponding internal windows pointing to the label of the current HWND. The next window process is called, with a different message with WM_CREATE, as long as we simply retrieve the pointer to our controller, use hwnd. This support is easy. Window process interpret message parameters and appropriate modules of calling the controller. LResult Callback WndProc

(HWND HWND, UINT MESSAGE, WPARAM WPARAM, LPARAM LPARAM)

{

Controller * PCTRL = WinGetlong (hwnd);

Switch (Message)

{

Case WM_CREATE:

// Have to capture the extra error!

Try

{

PCTRL = New Controller (hwnd,

Reinterpret_cast (lparam);

Winsetlong (HWND, PCTR);

}

Catch (Winexception E)

{

:: MessageBox (hWnd, E.GetMessage (), "Initialization",

MB_ICONEXCLAMATION | MB_OK);

Return -1;

}

Catch (...)

{

:: MessageBox (HWnd, "Unknown Error", "Initialization",

MB_ICONEXCLAMATION | MB_OK);

Return -1;

}

Return 0;

Case WM_SIZE:

PCTRL-> SIZE (Loword (LPARAM), HiWord (LPARAM);

Return 0;

Case WM_Paint:

PCTRL-> PAINT ();

Return 0;

Case WM_COMMAND:

PCTRL-> Command (Loword (WPARAM));

Return 0;

Case WM_DESTROY:

Winsetlong (hwnd, 0);

Delete PCTRL;

Return 0;

}

Return :: DefWindowProc (Hwnd, Message, WParam, Lparam);

}

A little controller method is performed in this simple example. The constructor has to remember the handle of the window. The destructor has to send a left message, and the size method passes its parameters to View, and so on, we will discuss the depiction window. Currently, notice that the controller is ready to be drawn with the View.

Controller :: Controller (HWND HWND, CREATESTRUCT * PCREATE)

: _hWnd (hwnd),

_Model ("generic")

{

}

Controller :: ~ Controller ()

{

:: PostquitMessage (0);

}

Void Controller :: Size (int Cx, Int Cy)

{

_View.setsize (cx, cy);

Void Controller :: Paint ()

{

// prepare the canvas and let View do the rest

PainTcanvas Canvas (_HWND);

_View.paint (canvas, _model);

// NOTICE: The Destructor of PainTcanvas Called Automatically!

}

When the user selects one of the menu entry, the WM_COMMAND message window process is called. The appropriate control method is saving the command ID assignment command. When you use your resource editor to establish your menu, you select these identifier IDs for each menu entry. They are stored in the appropriate header file (possibly in resource.h), have to be included in the source file of the controller. Our menu only contains three entries, their identification IDs are IDM_EXIT, IDM_HELP, and IDM_ABOUT. The dialog box is displayed when the IDM_about is displayed, and it is also established by the resource editor, the given identification ID is IDD_ABOUT. Its dialog process is AboutDLGPROC. Finally, in order to display a dialog, we need to specify the handle of the application instance. The standard approach is to retrieve it with the application's HWND access to the internal window data structure.

// Menu command processing

Void Controller :: Command (INT CMD)

{

Switch (cmd)

{

Case idm_exit:

:: SendMessage (_HWND, WM_CLOSE, 0, 0L);

Break;

Case idm_help:

:: MessageBox (_hwnd, "Go figure!",

"Generic", MB_ICONITIONFORMATION | MB_OK);

Break;

Case IDM_About:

{

// obtain an instance handle via hwnd

Hinstance hinst = wingeTlong (_hwnd, gwl_hinstance);

:: Dialogbox (Hinst,

MakeintResource (IDD_ABOUT),

_hwnd,

AboutDLGProc);

}

Break;

}

}

Apply objects usually store the size of the client. They update with the WM_SIZE message of the controller process. First, the WM_SIZE message is sent before the window creation and the WM_PAINT message, so we can renderate the size of the known customer range when depicting the call. The graphic output to the window is done by the appropriate CANVAS object. If the text we print is the prototype is a vertical line of 10 pixels from the edge of the customer's range.

Class view

{

PUBLIC:

Void Setsize (int Cxnew, int CYNEW)

{

_CX = CXNEW;

_CY = cynew;

}

Void Paint (Canvas & Canvas, Model & Model);

protected:

INT_CX;

INT_CY;

}

Void View :: Paint (Canvas & Canvas, Model & Model)

{

Canvas.Text (12, 1, model.gettext (), model.getlen ());

Canvas.Line (10, 0, 10, _cy);

}

The Canvas object encapsulates the so-called device descriptor of Windows. Our Canvas is very simple, we just know how to print the text and draw a line, but your Canvas can have a lot of ways to do creative things. We will tell more about Canvas in the next guide.

Class Canvas

{

PUBLIC:

Operator hdc () {return_hdc;} void line (int X1, int y1, int x2, int y2)

{

:: MoveToex (_HDC, X1, Y1, 0);

:: LINETO (_HDC, X2, Y2);

}

Void text (int X, int y, char const * buf, int CBUF)

{

:: Textout (_HDC, X, Y, BUF, CBUF);

}

Void char (int X, int y, char c)

{

:: Textout (_HDC, X, Y, & C, 1);

}

protected:

// Protective constructor: You can't build

// A Canvas object, but you can

// construct the object from its source.

Canvas (HDC HDC): _HDC (HDC) {}

HDC_HDC;

}

The Canvas you built is used to respond to the WM_PAINT message to a specific type. They release the device descriptor by calling BeginPaint and released by calling EndPaint. Paintstruct contains additional information about which part of the user should be written, and when we ignore this detailed information, if you seriously pay attention, you should learn more about it.

// CANVAS specific examples.

// established this object after the WM_Paint message.

Class PainTcanvas: Public Canvas

{

PUBLIC:

// Constructor Obtains the DC

PainTcanvas (HWND HWND)

: Canvas (:: beginpaint (hwnd ,&paint)),

_hwnd (hwnd)

{}

// Destructor Release DC

~ PainTcanvas ()

{

:: endpaint (_HWND, & _PAINT);

}

protected:

Paintstruct_paint;

HWND_HWND;

}

Copyright by vCroad © 2000-2001 All Right Reserve

转载请注明原文地址:https://www.9cbs.com/read-3414.html

New Post(0)