锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 开源技术 / C++开源英语 / Win32++:MFC代替框架
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

Win32++:MFC代替框架

Introduction

Win32++ is a simple and easy to understand library for creating windows applications.  It runs on the commonly available free compilers, making it a free alternative to MFC.

Win32++ has been designed to make life a little easier for those learning to use C++ to program using the Windows API directly. Win32++ doesn't attempt to hide the Windows API. On the contrary, it exposes the Windows API, allowing it to be more easily learnt and understood. Win32++ is also a good choice for those professional programmers looking for a simple, robust and efficient framework.

Win32 ++是一个简单易懂的库,用于创建Windows应用程序。它运行在常用的免费编译器上,使其成为MFC的免费替代品。

Win32 ++旨在让那些学习使用C ++直接使用Windows API进行编程的人们的生活更轻松。Win32 ++不会尝试隐藏Windows API。相反,它暴露了Windows API,使其更容易学习和理解。对于那些寻求简单,强大和高效框架的专业程序员来说,Win32 ++也是一个不错的选择。

The code has been designed to run on a wide range of C++ compilers, including those from Microsoft, Borland and the free MinGW compiler from GNU. Win32++ supports all Windows operating systems, from Windows 95 through to Windows 7. It can be used to create both 32 bit and 64 bit applications.

Win32++ also directly supports the Windows CE operating system. Windows CE is the operating system which runs on the various Pocket PCs, Smartphones, as well as industrial devices and embedded systems. The Windows CE API is a subset of the Windows API. It also includes some new common controls tailored for the smaller computers and devices it runs on.

Win32++ brings an object oriented approach to programming directly with the Windows API. Each window created is a C++ class object capable of having its own window procedure for routing messages.

该代码被设计为在各种C ++编译器上运行,包括来自Microsoft,Borland和GNU的免费MinGW编译器。Win32 ++支持从Windows 95到Windows 7的所有Windows操作系统。它可用于创建32位和64位应用程序。

Win32 ++还直接支持Windows CE操作系统。Windows CE是在各种Pocket PC,智能手机以及工业设备和嵌入式系统上运行的操作系统。Windows CE API是Windows API的子集。它还包括一些新的通用控件,适用于运行的小型计算机和设备。

Win32 ++带来了一种面向对象的方法,可以直接使用Windows API进行编程。创建的每个窗口都是一个C ++类对象,它有自己的窗口过程来路由消息。

Background

When I first approached the task of teaching myself to program Windows using C++, I took a brief look at some of the Win32 tutorials on the Web and then jumped straight into using MFC. I hoped that using MFC might make the task of learning Windows programming easier.

With the benefit of hindsight, I now realize that this approach was a mistake. I should have taken the time to study the Windows API more thoroughly before moving on to MFC. It would have been far easier (and faster) to approach these two topics one at a time, instead of trying to learn both of them at once. In a sense, I should have learned to walk before trying to run. The two main challenges I faced when writing Win32 applications were:

  • Bringing an object-oriented approach to Win32 programs
  • Building Windows API programs with a professional-looking user interface

With this in mind, I decided to revisit my Windows API programming and develop a generic Framework for my applications that could be used as an alternative to MFC. My goal was to produce a Framework that was robust, object-oriented and that produced professional-looking results.

当我第一次接受教我自己使用C ++编程Windows的任务时,我简要地看了一下Web上的一些Win32教程,然后直接使用MFC。我希望使用MFC可以使学习Windows编程的任务更容易。

事后看来,我现在意识到这种方法是错误的。在继续使用MFC之前,我应该花时间更全面地研究Windows API。一次一个地处理这两个主题会更容易(也更快),而不是试图同时学习这两个主题。从某种意义上说,我应该在尝试跑步之前学会走路。编写Win32应用程序时遇到的两个主要挑战是:

  • 为Win32程序引入面向对象的方法
  • 使用具有专业外观的用户界面构建Windows API程序

考虑到这一点,我决定重新接触我的Windows API编程并为我的应用程序开发一个通用框架,可以用作MFC的替代方案。我的目标是生成一个强大的,面向对象的框架,并产生具有专业外观的结果。

Framework Overview框架概述

The following diagram illustrates the classes used in Win32++:下图说明了Win32 ++中使用的类

win32++类图

The classes which define the Framework itself are contained within the Win32xx namespace. These classes are as follows:

  • CBitmapInfoPt: A class used to simplify the creation and use if the BITMAPINFO structure for use with GDI graphics.
  • CCmdbar: A class used on Windows CE to provide a CommandBar. It is used by CFrame on Windows CE.
  • CContainer: A specialised view window for dockers. It has tabs and an optional toolbar.
  • CCriticalSection: This class provides for thread synchronization for multi-threaded applications.
  • CDC: A class which represents a Device Context. It simplifies working the Windows GDI.
  • CDialog: The class responsible for creating modal and modeless dialogs. It is used by CFrame, and can also be used to create dialog applications.
  • CDocker: A class which provides support for docking and splitter windows.
  • CFrame: This class produces a frame window which has a rebar, menubar, toolbar, and a status bar. The client area of the frame window should be occupied by a separate CWnd object.
  • CListView: A class used to create a list-view control.
  • CMDIApp: This class is inherited from CWinApp. You should inherit from this class to start an MDI frame application.
  • CMDIChild: This is the class to be used for MDI children. Each MDI child should be inherited from this class.
  • CMDIClient: This is a class used internally by Win32++ as the view window for the MDI frame.
  • CMDIFrame: This class is responsible for creating the MDI frame window. It is inherited from CFrame.
  • CMenubar: This class is responsible for creating the menubar. A menubar is a menu housed inside a rebar control.
  • CPoint: This class can be used in place of a POINT structure.
  • CPropertyPage: This class adds support for property pages to Win32++. A property page has one or more property sheets.
  • CPropertySheet: This class represents a property page. It is used by CPropertySheet.
  • CRebar: This class is responsible for creating the rebar. It is used by CFrame.
  • CRect: This class can be used in place of a RECT structure.
  • CSize: This class can be used in place of a SIZE structure.
  • CSocket: This class adds network support to Win32++.
  • CStatusBar: The class responsible for creating the status bar. It is used by CFrame.
  • CTab: A class used to create a tab control.
  • CToolBar: The class responsible for creating the toolbar. It is used by CFrame.
  • CTreeView: A class used to create a tree-view control.
  • CWceFrame: A class which provides a simple frame for Pocket PCs. It utilises a Commandbar to display the menu and toolbar buttons.
  • CWinApp: The class responsible for initializing the Framework, and also provides our message loop. You should inherit from this class to start the Framework.
  • CWinException: A class which handles exceptions.
  • CWnd: The class responsible for the window objects. It is the base class for the more specialized window objects such as CDialog, CFrame, CToolbar etc.
  • 定义框架本身的类包含在Win32xx命名空间中。这些类如下:

    • CBitmapInfoPt:用于简化创建和使用的类,如果BITMAPINFO结构用于GDI图形。
    • CCmdbar:Windows CE上用于提供的类CommandBar。它CFrame在Windows CE上使用。
    • CContainer:拖靠子窗口的专用视图窗口。它有标签和可选的工具栏。
    • CCriticalSection:此类为多线程应用程序提供线程同步。
    • CDC:表示设备上下文的类。它简化了Windows GDI的工作。
    • CDialog:负责创建模态和无模式对话框的类。它由CFrame,也可用于创建对话框应用程序。
    • CDocker:为对接和分割窗口提供支持的类。
    • CFrame:此类生成一个框架窗口,其中包含钢筋,菜单栏,工具栏和状态栏。框架窗口的客户区域应由单独的CWnd对象占用。
    • CListView:用于创建列表视图控件的类。
    • CMDIApp:这个类继承自CWinApp。您应该从此类继承以启动MDI框架应用程序。
    • CMDIChild:这是用于MDI子项的类。每个MDI子项都应该从此类继承。
    • CMDIClient:这是Win32 ++内部使用的类,作为MDI框架的视图窗口。
    • CMDIFrame:该类负责创建MDI框架窗口。它是继承自CFrame。
    • CMenubar:这个类负责创建菜单栏。菜单栏是一个装在钢筋控制器内的菜单。
    • CPoint:此类可用于代替POINT结构。
    • CPropertyPage:此类将属性页的支持添加到Win32 ++。属性页面包含一个或多个属性表。
    • CPropertySheet:此类表示属性页。它被使用CPropertySheet。
    • CRebar:这个班负责创建钢筋。它被使用CFrame。
    • CRect:此类可用于代替RECT结构。
    • CSize:此类可用于代替SIZE结构。
    • CSocket:此类为Win32 ++添加了网络支持。
    • CStatusBar:负责创建状态栏的类。它被使用CFrame。
    • CTab:用于创建选项卡控件的类。
    • CToolBar:负责创建工具栏的类。它被使用CFrame。
    • CTreeView:用于创建树视图控件的类。
    • CWceFrame:为Pocket PC提供简单框架的类。它利用a Commandbar 来显示菜单和工具栏按钮。
    • CWinApp:负责初始化Framework的类,还提供了我们的消息循环。您应该从此类继承以启动Framework。
    • CWinException:处理异常的类。
    • CWnd:负责窗口对象的类。它是为更专门的窗口的基类对象,例如CDialog,CFrame,CToolbar等。

About the File Downloads关于文件下载

The file download from Sourceforge includes the following:

  • The Win32++ library itself
  • Help for the library
  • A set of tutorials
  • A collection of sample applications
  • Sourceforge的文件下载包括以下内容:

    • Win32 ++库本身
    • 帮助图书馆
    • 一套教程
    • 一组示例应用程序

The sample applications include:

  • Browser - An Internet browser application based on ActiveX controls.
  • Dialog - An example of a simple dialog application.
  • DialogDemo - An interative dialog application demonstrating slider controls and progress bars.
  • DialogTab - A dialog application with a tab control.
  • DirectX - A simple DirectX application.
  • Dock - An example of a simple docking application.
  • DockContainer - An example of a docking application which incorporates containers.
  • DockTabbedMDI - An example of a docking application with containers and a tabbed MDI.
  • Explorer - A Windows Explorer-like application.
  • FastGDI - An application which demonstrates direct manipulation of a bitmap's colour.
  • FormDemo - An example of a modeless dialog within a frame.
  • MDIFrame - A simple MDI frame applications
  • MDIFrameDemo - Demonstrates some additional features of MDI frames.
  • Networking - Demonstrates the use of networking.
  • Notepad - A simple text editor with printing.
  • Performance - Measures Win32++'s message handling speed.
  • Picture - A simple picture rendering application.
  • PropertySheets - A demonstration of property sheets.
  • Scribble - A simple drawing application.
  • Simple - Creates a simple window.
  • Splitter - A demo of the CSplitter class.
  • StaticLibrary - Builds the Win32++ framework into a static library.
  • TabDemo - Demonstrates the use of a CTab control in a frame.
  • Themes - Demonstrates how to customise the colours for rebar and toolbar controls.
  • Threads - Demonstrates multi-threaded Windows.
  • WinCE samples - A small collection of samples for Windows CE
  • 示例应用程序包括:

    • Browser - 基于ActiveX控件的Internet浏览器应用程序。
    • Dialog - 简单对话框应用程序的示例。
    • DialogDemo - 演示滑块控件和进度条的交互式对话框应用程序。
    • DialogTab - 带有选项卡控件的对话框应用程序。
    • DirectX - 一个简单的DirectX应用程序。
    • Dock - 简单对接应用程序的示例。
    • DockContainer - 包含容器的对接应用程序的示例。
    • DockTabbedMDI - 带有容器和选项卡式MDI的对接应用程序示例。
    • Explorer - 类似Windows资源管理器的应用程序。
    • FastGDI - 演示直接操作位图颜色的应用程序。
    • FormDemo - 帧内无模式对话框的示例。
    • MDIFrame - 简单的MDI框架应用程序
    • MDIFrameDemo - 演示MDI帧的一些附加功能。
    • Networking - 演示网络的使用。
    • Notepad - 带打印的简单文本编辑器。
    • Performance - 测量Win32 ++的消息处理速度。
    • Picture - 简单的图片呈现应用程序。
    • PropertySheets - 演示财产表。
    • Scribble - 简单的绘图应用程序。
    • Simple - 创建一个简单的窗口。
    • Splitter - CSplitter课堂演示。
    • StaticLibrary - 将Win32 ++框架构建到静态库中。
    • TabDemo - 演示在框架中使用CTab控件。
    • Themes - 演示如何自定义钢筋和工具栏控件的颜色。
    • Threads - 演示多线程Windows。
    • WinCE samples - Windows CE的一小部分示例

Using the Framework使用框架

The code which forms the basis of the Framework is located in the Win32++ directory. You shouldn't need to modify these files, but rather inherit from Win32++ and add any additional code in your derived classes. To use the Framework to create an SDI frame window, for example, you would typically derive your own class from CFrame and place any modifications to the standard frame there. You can override the WndProc member function to include any additional messages you would like to handle.

A separate view window is placed over the client area of the frame window. Typically, this view window is created by inheriting a class from CWnd. The CFrame::SetView function is used to assign the view window to the frame. For MDI frames however, the CMDIFrame already uses CMDIClient as the view window, and you would use CMDIFrame::AddMDIChild to create a new instance of an MDI child window.

One of the important advantages of programming directly with the Windows API is that the code produced is portable, which is to say that it can be compiled on different compilers. The code in this Framework has been checked for compatibility with Visual C++ 6.0, Visual Studio .NET 2003, Visual C++ 2008 Express Edition, and also Dev-C++ version 4.9.9.2. Dev-C++ is a free C++ compiler and Integrated Development Environment available for download from here. The Framework is also compatible with Visual C++ Toolkit 2003 (a free compiler from Microsoft) and Borland's free Turbo C++ 2006.

A tutorial which provides step by step instructions for using the Framework is included with the framework.

构成Framework基础的代码位于Win32 ++目录中。您不需要修改这些文件,而是从Win32 ++继承并在派生类中添加任何其他代码。例如,要使用框架创建SDI框架窗口,通常可以从CFrame派生自己的类,在派生类里对标准框架进行任何修改。您可以覆盖WndProc成员函数以包含您要处理的任何其他消息。

在框架窗口的客户区域上放置单独的视图窗口。通常,此视图窗口是通过继承CWnd类来创建。该CFrame::SetView功能用于将视图窗口分配给框架。但是,对于MDI框架窗口,CMDIFrame已经把CMDIClient用作视图窗口,您将用CMDIFrame::AddMDIChild 创建MDI子窗口的新实例。

直接使用Windows API编程的一个重要优点是生成的代码是可移植的,也就是说它可以在不同的编译器上编译。已检查此框架中的代码是否与Visual C ++ 6.0,Visual Studio .NET 2003,Visual C ++ 2008 Express Edition以及Dev-C ++版本4.9.9.2兼容。Dev-C ++是一个免费的C ++编译器和集成开发环境,可从此处下载。该框架还兼容Visual C ++ Toolkit 2003(来自Microsoft的免费编译器)和Borland的免费Turbo C ++ 2006。

框架中包含一个教程,该教程提供了使用框架的分步说明。

Object-oriented Approach面向对象的方法

The key to bringing an object-oriented approach to programming directly with the Windows API is to have a C++ class that can create a window and which includes its own window procedure as a member function. Once we have this class, we can inherit from it and override the window procedure member function to handle messages the way we want for each derived window type.

Creating a class like this is not trivial and I suspect that's one of the reasons why MFC was created in the first place. The problem stems from the way a "window class" is registered before the window can be created. The term "class" here refers to the Windows API "window class," which is not the same thing as a C++ class. The following code snippet shows how a window class might be registered using the API:

使用Windows API直接引入面向对象方法的关键是拥有一个可以创建窗口的C ++类,它包含自己的窗口过程作为成员函数。一旦我们有了这个类,我们就可以从它继承并重写窗口过程成员函数来按照我们想要的方式处理每个派生窗口类型的消息。

创建这样的类并非易事,我怀疑这是MFC首先创建的原因之一。问题源于在创建窗口之前注册“窗口类”的方式。这里的术语“类”是指Windows API“窗口类”,它与C ++类不同。以下代码段显示了如何使用API​​注册窗口类:

WNDCLASSEX wc = {0};

wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WindowProc; //Window procedure function

wc.hInstance = hInstance;
wc.lpszClassName = "TEST";
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

//Register the window class
::RegisterClassEx(&wc);

Note that we need to supply the function name of our window procedure. The window procedure is where we control what is to be done when a window message is received. This function must conform precisely to the predefined standards required by the Windows API. A typical declaration of the callback function looks like this:请注意,我们需要提供窗口过程的函数名称。窗口过程是我们控制接收窗口消息时要执行的操作的位置。此功能必须严格符合Windows API所需的预定义标准。回调函数的典型声明如下所示:

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg,      WPARAM wParam, LPARAM lParam);

We might be tempted to set the WindowProc function as a member of the class. Unfortunately, each class member function has an implicit this pointer as one of its arguments and therefore cannot be used as the callback function for a window. If we did this, our WindowProc function would no longer conform to the predefined standards and the program would fail to compile.

We can make the WindowProc function a static member function of the class. There is no implicit this in a static function and this will compile correctly. Unfortunately, a static member function doesn't have access to the class object (i.e. it doesn't have a this pointer) and it cannot access other members of the class. It is this that prevents the static member function from being used in an object-oriented way. The following code demonstrates the limitations of a static member function approach:

我们可能想要将WindowProc函数设置为类的成员。不幸的是,每个类成员函数都有一个隐式this指针作为其参数之一,因此不能用作窗口的回调函数。如果我们这样做,我们的WindowProc函数将不再符合预定义的标准,并且程序将无法编译。

我们可以使WindowProc函数成为static类的成员函数。没有隐含的this一个static功能,这将正确编译。不幸的是,static 成员函数无法访问类对象(即它没有this指针),也无法访问类的其他成员。这是为了防止static 成员函数以面向对象的方式使用。以下代码演示了static 成员函数方法的局限性:

class TestStatic
{
public:
int member;

void NormalFunction()
{
//We can access member variables in a normal
//member function
member = 5;

//The following line is equivalent to the one above
this->member = 5;
}

void static StaticFunction()
{
//We cannot access member variables
//in a static member function

//The following line will give a compile error
member = 5;

//This will give an error too
this->member = 5;
}
};

A static member function for the window procedure would be useful if we could just get our hands on a pointer to the window class object (our this pointer). There are a number of techniques that we can use to get access to our pointer as the window is being created. The one I have chosen takes advantage of Thread Local Storage to store our pointer, which is later inserted into an STL map. This is how it's done:

Step 1: Set up the Thread Local Storage to store our this pointer. This is done in the CWinApp class:

如果我们能够拿到窗口类对象指针(this指针),一个窗口过程的static成员函数将是有益的。在创建窗口时,我们可以使用许多技术来访问指针。我选择的那个利用线程本地存储来存储我们的指针,稍后将其插入到STL映射中。这就是它的完成方式:

步骤1:设置线程本地存储以存储我们的this指针。这是在CWinApp课堂上完成的:

CWinApp::CWinApp(HINSTANCE hInstance) : m_hInstance(hInstance)
{
if (GetApp() == 0)
{
st_dwTlsIndex = ::TlsAlloc();

//snip
}
}

Step 2: Store our this pointer in the Thread Local Storage when we use CreateEx to create the window:第2步:this当我们CreateEx用来创建窗口时,将指针存储在线程本地存储中:

// Ensure this thread has the TLS index set
TLSData* pTLSData = GetApp()->SetTlsIndex();

// Store the CWnd pointer in thread local storage
pTLSData->pCWnd = this;

Step 3: Extract the pointer from Thread Local Storage and add it to the STL map during the initial creation of the window:步骤3:从线程本地存储中提取指针,并在初始创建窗口期间将其添加到STL映射:

// Retrieve the pointer to the TLS Data
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());

// Retrieve pointer to CWnd object from Thread Local Storage TLS
w = pTLSData->pCWnd;

// Store the CWnd pointer in the HWND map
GetApp()->AddToMap(hWnd, w);

return w->WndProc(hWnd, uMsg, wParam, lParam);

Step 4: For each subsequent window message, we extract the pointer from the STL map and use it to redirect the message handling to the appropriate WndProc function:步骤4:对于每个后续窗口消息,我们从STL映射中提取指针并使用它将消息处理重定向到适当的WndProc函数:

CWnd* w = GetApp()->GetCWndFromMap(hWnd);
return w->WndProc(hWnd, uMsg, wParam, lParam);

Window Creation in Detail窗口创建细节

Now that we've had a look at thread local storage and the window procedure, it is time to see how these fit together as we create the window. This is the code that creates the window:现在我们已经了解了线程本地存储和窗口过程,现在是时候看看它们在创建窗口时如何组合在一起了。这是创建窗口的代码:

HWND CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hParent,
HMENU hMenu, LPVOID lpParam /*= NULL*/)
{
try
{
// Test if Win32++ has been started
if (0 == GetApp())
throw CWinException(_T("Win32++ has not been initialised properly.\n
Start the Win32++ by inheriting from CWinApp."));

// Only one window per CWnd instance allowed
if (::IsWindow(m_hWnd))
throw CWinException(_T("CWnd::CreateEx ... Window already exists"));

// Ensure a window class is registered
TCHAR ClassName[MAX_STRING_SIZE] = _T("");
if (0 == lstrlen(lpszClassName) )
lstrcpyn (ClassName, _T("Win32++ Window"), MAX_STRING_SIZE);
else
// Create our own local copy of szClassName.
lstrcpyn(ClassName, lpszClassName, MAX_STRING_SIZE);

WNDCLASS wc = {0};
wc.lpszClassName = ClassName;
wc.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
if (!RegisterClass(wc)) // Register the window class (if not already registered)
throw CWinException(_T("CWnd::CreateEx Failed to register window class"));

// Ensure this thread has the TLS index set
TLSData* pTLSData = GetApp()->SetTlsIndex();

// Store the CWnd pointer in thread local storage
pTLSData->pCWnd = this;

// Create window
m_hWnd = ::CreateWindowEx
(dwExStyle, ClassName, lpszWindowName, dwStyle, x, y, nWidth,
nHeight, hParent, hMenu, GetApp()->GetInstanceHandle(), lpParam);

// Now handle window creation failure
if (!m_hWnd)
throw CWinException(_T("CWnd::CreateEx ... Failed to Create Window"));

m_hWndParent = hParent;

// Automatically subclass predefined window class types
::GetClassInfo(GetApp()->GetInstanceHandle(), lpszClassName, &wc);
if (wc.lpfnWndProc != st_pfnWndProc)
{
Subclass();

// Send a message to force the HWND to be added to the map
::SendMessage(m_hWnd, WM_NULL, 0, 0);

OnCreate(); // We missed the WM_CREATE message, so call OnCreate now
}

// Clear the CWnd pointer from TLS
pTLSData->pCWnd = NULL;

// Window creation is complete. Now call OnInitialUpdate
OnInitialUpdate();
}

catch (const CWinException &e)
{
e.MessageBox();
}

return m_hWnd;

} // HWND CWnd::CreateEx()

The next code segment handles the window procedure which first receives the messages. We extract the pointer to the CWnd object from the map, and use it to redirect the handling of the window messages to the appropriate WndProc function:下一个代码段处理首先接收消息的窗口过程。我们从地图中提取CWnd对象的指针,并使用它将窗口消息的处理重定向到适当的WndProc函数:

LRESULT CALLBACK CWnd::StaticWindowProc
(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
try
{
CWnd* w = GetApp()->GetCWndFromMap(hWnd);
if (0 != w)
{
// CWnd pointer found, so call the CWnd's WndProc
return w->WndProc(hWnd, uMsg, wParam, lParam);
}
else
{
// The CWnd pointer wasn't found in the map, so add it now

// Retrieve the pointer to the TLS Data
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
if (NULL == pTLSData)
throw CWinException(_T("CWnd::StaticCBTProc ... Unable to get TLS"));

// Retrieve pointer to CWnd object from Thread Local Storage TLS
w = pTLSData->pCWnd;
if (NULL == w)
throw CWinException(_T("CWnd::StaticWindowProc .. Failed to route message"));

pTLSData->pCWnd = NULL;

// Store the CWnd pointer in the HWND map
GetApp()->AddToMap(hWnd, w);

// Store the HWND in the CWnd object early
w->m_hWnd = hWnd;

return w->WndProc(hWnd, uMsg, wParam, lParam);
}
}
//snip

Finally, the next code segment shows the function called by StaticWindowProc. Typically, when we derive a new class from CWnd, we would override this function to control the way various window messages are handled:最后,下一个代码段显示了被调用的函数StaticWindowProc。通常,当我们从中派生一个新类时CWnd,我们将覆盖此函数以控制处理各种窗口消息的方式:

LRESULT CWnd::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Override this function in your class derived from CWnd to handle
// window messages. A typical function might look like this:

// switch (uMsg)
// {
// case MESSAGE1: // Some Windows API message
// OnMessage1(); // A user defined function
// break; // Also do default processing
// case MESSAGE2:
// OnMessage2();
// return x; // Don't do default processing, but instead return
// // a value recommended by the Windows API documentation
// }

// Always pass unhandled messages on to WndProcDefault
return WndProcDefault(hWnd, uMsg, wParam, lParam);
}

The method described here uses a global map to associate a windows handle (HWND) with a CWnd object. This map uses Thread Local Storage (TLS) to ensure that the creation of the windows thread safe. If TLS wasn't used, attempts to create multiple windows simultaneously in different threads could fail.  Using a map to associate a windows handle (HWND) with a CWnd object also allows every message for the window to be processed.  There is no need, for example, to discard window messages prior to WM_NCCREATE when using this method.此处描述的方法使用全局映射将窗口句柄(HWND)与CWnd对象相关联。此映射使用线程本地存储(TLS)来确保创建Windows线程安全。如果未使用TLS,则尝试在不同线程中同时创建多个窗口可能会失败。使用映射将窗口句柄(HWND)与CWnd对象相关联也允许处理窗口的每条消息。例如,在使用此方法时,不需要在WM_NCCREATE之前丢弃窗口消息。

友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内