MFC 模块状态的实现

C++模块化编程 C++程序模块化编程1、在.h文件中定义类(对成员函数只包括声明部分),对应的.cpp文件主要是对类的成员函数的定义。2、在main函数中定义对象,然后通过对象引用类的成员以实现某功能。3、将头文件添加到.cpp文件比添加到.h文件的好处是可以避免重复包含,如果不是头文件要用到某文件的内容的话,还是把.h文件放到.cpp中更好4、也可以某个类在自己的cpp文件中定义全局对象(变量),然后在对应.h... 阅读详情

本技术备忘录介绍MFC “模块状态”结构的实现。充分理解模块状态这个概念对于在DLL中使用MFC的共享动态库是十分重要的。

MFC的状态信息分为三种:全局模块状态数据、进程局部状态数据和线程局部状态数据。有时这些数据类型之间没有严格界限,例如MFC的句柄表既是全局模块状态数据也属于线程局部状态数据。

进程局部状态数据和线程局部状态数据差不多。早先这些数据是全局的,但是为了更好的支持Win32和多线程,现在设计成进程或者线程相关的。模块状态数据既可以包含真正的全局状态数据,也可以指向进程或者线程相关的数据。


一、什么是模块状态?

模块状态实际上是指可执行模块运行所需的一个数据结构。首先要说明,这里的"模块"指的是一个MFC可执行程序,或者使用共享版本MFC动态库的DLL或者ActiveX控件。没有使用MFC的程序或者DLL等不在讨论范围之内。

正如下图"单个模块的状态数据"所描述的,使用MFC的每个模块都有一套状态数据。这些数据包括包括:窗口进程句柄(用于加载资源),指向当前程序的CWinApp和CWinThread对象的指针,OLE模块引用次数,以及很多关于Windows对象和其对应句柄的映射表等等。

                 单个模块(程序)的状态数据
              
             +-------------MFC程序
             |
            //
       +--------------------------------------------+
       |                                            |
       |    +--------------------------------+      |
       |    |                                |      |
       |    |   线程对象                     |      |
       |    |                                |      |
       |    +--------------------------------+      |
       |    |  m_pModuleState                +---+  |
       |    +--------------------------------+   |  |
       |                                        //  |
       +--------------------------------------------+
       |    状态数据                                |
       +--------------------------------------------+

(注意,因为采用的字符画图,如果图形显示有问题,请复制到记事本中看)

一个模块的所有状态数据包含在一个结构中,这个结构在MFC中被打包成一个类 AFX_MODULE_STATE, 它派生自 CNoTrackObject。关于这个类后面会谈到。AFX_MODULE_STATE类的定义位于AfxStat_.H中。内容如下所示:

// AFX_MODULE_STATE (模块的全局数据)
class AFX_MODULE_STATE : public CNoTrackObject
{
public: //构造函数
#ifdef _AFXDLL
 AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion);
 AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,
  BOOL bSystem);
#else
 AFX_MODULE_STATE(BOOL bDLL);
#endif
 ~AFX_MODULE_STATE();    //析构函数

 CWinApp* m_pCurrentWinApp;  //指向CWinApp对象的指针
 HINSTANCE m_hCurrentInstanceHandle; //当前进程句柄
 HINSTANCE m_hCurrentResourceHandle; //当前资源句柄
 LPCTSTR m_lpszCurrentAppName;  //当前程序的文件名
 BYTE m_bDLL;       //TRUE表示模块是 DLL,否则是EXE
 BYTE m_bSystem;    //TRUE表示模块是系统模块。
 BYTE m_bReserved[2];    //字节对齐

 DWORD m_fRegisteredClasses;   //窗口类注册标记

 。。。//很多其它运行态数据
};

二、为什么需要切换模块状态

模块状态数据是十分重要的。因为很多MFC函数都要使用这些状态数据。如果一个MFC程序使用多模块,比如一个MFC程序需要调用多个DLL或者OLE控件的情况,则每个模块都拥有自己的一套MFC状态数据。

MFC程序运行过程中,每个线程都包含一个指向“当前”或者“有效”模块状态的指针(自然,这个指针是MFC的线程局部状态数据的一部分)。当线程执行代码流跨越模块边界,转入一个特定的模块的时候,就要改变这个指针的值,如下图所示,m_pModuleState必须设置成指向有效的模块状态数据。这一点是非常重要的,否则将导致无法预知的程序错误。

多模块下的状态数据

 MFC程序
   /
    /                                             +--------------+
 +--------------------------------------+         |   DLL模块1   |
 |                                      |         |              |
 |   +----------------+      转向模块1  |         +--------------+
 |   |   线程对象     |     +-----------+-------->|  状态数据    |
 |   |                |     |           |         +--------------+
 |   +----------------+     |           |
 |   | m_pModuleState +-----+           |         +--------------+
 |   |                |      转向模块2  |         |   DLL模块2   | 
 |   |                +-----------------+----+    |              | 
 |   +----------------+                 |    |    +--------------+
 |                                      |    +--->|  状态数据    |
 +--------------------------------------+         +--------------+
 |   状态数据                           |
 +--------------------------------------+

(注意,因为采用的字符画图,如果图形显示有问题,请复制到记事本中看)

比如说,如果你在DLL中导出了一个函数,该函数要创建一个对话框,而这个对话框的模板资源位于DLL中。缺省情况下,MFC是使用主程序中的资源句柄来加载资源的,但现在这个对话框的资源位于DLL中,所以,必须设置m_pModuleState指向DLL模块的状态数据,否则,就会导致加载资源失败。

因此,每个模块要负责在它的所有入口点进行状态数据的切换。所谓"入口点" 就是任何执行代码流可以进入模块的地方,包括:
1、DLL中导出的函数;
2、COM接口函数
3、窗口过程

首先谈dll中的导出函数。一般来说,如果从一个DLL中导出了一个函数,应该使用AFX_MANAGE_STATE 宏维护正确的全局状态。

调用这个宏的时候,它设置pModuleState指向有效的模块状态数据,从而该函数后面的代码就可以通过该指针得到有效的状态数据。当函数执行完毕,即将返回时,该宏将自动恢复指针原来的值。

这个自动切换是这样完成的,在栈空间上创建一个AFX_MODULE_STATE类的实例,并把当前的模块状态指针保存在一个成员变量里面,然后把pModuleState设置成有效的模块状态,在这个实例对象的析构函数中,对象恢复以前保存的指针。

所以,对于上面所说的DLL导出函数,可以在该函数的开始加入如下预句:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

这个代码将当前的模块状态设置成AfxGetStaticModuleState返回的值。离开当前作用域之后恢复原来的模块状态。

但是,不是任何DLL中导出的函数都需要使用AFX_MANAGE_STATE。例如InitInstance函数,MFC在调用这个函数的时候是自动切换模块状态的。对于MFC常规动态库中的所有消息处理函数来说也不需要使用这个宏。因为常规DLL会链接一个特殊的主窗口过程,里面会自动切换模块状态。对于其它导出函数,如果没有用到模块状态中的数据,也可以不使用这个宏。

对于COM接口的成员函数来说,一般使用METHOD_PROLOGUE宏来维护正确的模块状态数据。这个宏实际上也使用了AFX_MANAGE_STATE。详细信息可以参考技术备忘录38:"MFC/OLE IUnknown的实现"。

对于窗口过程,如果模块使用了MFC,则该模块会静态链接一个特殊的窗口过程实现函数,首先用AFX_MANAGE_STATE宏设置有效的模块状态,然后调用AfxWndProc,这个函数接着调用某窗口具体的WindowProc函数。具体可以参考WINCORE.CPP。

三、模块状态是如何切换的

一般来说,设置当前的模块状态数据可以通过函数AfxSetModuleState。但是大多数情况下,无需直接使用这个API函数,MFC知道应该如何正确设置模块状态数据,它会替你调用它,比如在WinMain函数、OLE入口、AfxWndProc中等等。这是通过静态链接一个特殊的WndProc和WinMain (或者DllMain)实现的。可以参考 DLLMODUL.CPP或者APPMODUL.CPP,找到这些实现代码。

设置当前的模块状态,而又不把它设置回去的情况是十分少见的,一般来讲,在改变了模块状态后,都要进行恢复。可以通过AFX_MANAGE_STATE宏和AFX_MAINTAIN_STATE类来实现。我们看看这个宏的定义:

#ifdef _AFXDLL //定义了这个符号表示动态链接MFC
struct AFX_MAINTAIN_STATE
{
 AFX_MAINTAIN_STATE(AFX_MODULE_STATE* pModuleState);//参数是AFX_MODULE_STATE类对象指针
 ~AFX_MAINTAIN_STATE();

protected:
 AFX_MODULE_STATE* m_pPrevModuleState;  //保存在这个私有变量中
};

class _AFX_THREAD_STATE; //线程局部状态数据,这个类也是派生自CNoTrackObject
struct AFX_MAINTAIN_STATE2    //多线程版本
{
 AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pModuleState);
 ~AFX_MAINTAIN_STATE2();

protected:
 AFX_MODULE_STATE* m_pPrevModuleState;  //用来保存模块状态数据的指针
 _AFX_THREAD_STATE* m_pThreadState;  //指向线程局部状态数据的指针
};
#define AFX_MANAGE_STATE(p) AFX_MAINTAIN_STATE2 _ctlState(p); //定义AFX_MANAGE_STATE宏
#else  // _AFXDLL
#define AFX_MANAGE_STATE(p) //否则,这个宏没有意义。
#endif //!_AFXDLL

我们再来看看AFX_MAINTAIN_STATE2的构造函数,很简单的代码:

AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pNewState)
{
 m_pThreadState = _afxThreadState;  //首先保存线程局部状态数据指针
 m_pPrevModuleState = m_pThreadState->m_pModuleState; //保存全局模块状态数据指针
 m_pThreadState->m_pModuleState = pNewState; //设置全局模块状态数据指针,指向pNewState。
}

由此可见,线程局部状态数据里面包含一个指向全局模块状态数据的指针。


四、进程局部数据

对于Win32 DLL,在每个关联它的进程中都有一份独立的数据拷贝。考虑如下代码:

static CString strGlobal; // at file scope

__declspec(dllexport)
void SetGlobalString(LPCTSTR lpsz)
{
   strGlobal = lpsz;
}

__declspec(dllexport)
void GetGlobalString(LPCTSTR lpsz, int cb)
{
   lstrcpyn(lpsz, strGlobal, cb);
}

如果上述代码位于一个DLL中,并且该DLL被两个进程A和B加载(或者同一个程序的两个实例),那么将会发生什么事情呢? A调用SetGlobalString("Hello from A"),结果,在进程A的上下文中为该CString对象分配内存空间,现在B 调用GetGlobalString(sz, sizeof(sz))。那么B是否可以访问到A 设置的数据呢?

在WIN3.1中是可以的,因为Win32s没有提供象Win32那样的进程间的保护措施。显然这是有问题的,为了解决这个问题。MFC 3.x 是采用线程局部存储(TLS)技术解决这个问题,和Win32下保存线程局部数据的方法类似。但是每个MFC DLL都要在每个进程中使用两个TLS索引,如果加载过多DLL,会很快消耗完TLS索引(只有64个)。除此以外,还有其它问题。所以在MFC 4.x的版本中,采用了一套模板类,来包装这些进程相关的数据。例如下面的方法:

struct CMyGlobalData : public CNoTrackObject
{
   CString strGlobal;
};
CProcessLocal<CMyGlobalData> globalData;

__declspec(dllexport)
void SetGlobalString(LPCTSTR lpsz)
{
   globalData->strGlobal = lpsz;
}

__declspec(dllexport)
void GetGlobalString(LPCTSTR lpsz, int cb)
{
   lstrcpyn(lpsz, globalData->strGlobal, cb);
}

MFC采用两个步骤实现该方法。首先,在Win32 Tls* API (包括TlsAlloc, TlsSetValue, TlsGetValue等)之上实现一个接口层,无论进程加载多少DLL,每个进程仅需使用两个TLS索引。其次,通过CProcessLocal模板访问数据,它重载了->操作符。所有打包进CProcessLocal的对象必须派生自CNoTrackObject。而 CNoTrackObject提供一个底层的内存分配函数(LocalAlloc/LocalFree)以及一个虚析构函数,保证进程终止的时候,MFC可以自动销毁该进程局部数据。这些CNoTrackObject派生类对象可以有自己的析构函数,用于其它必要的清除操作。上面的例子里面没有,因为编译器会自动产生一个,并销毁内嵌的 CString 对象。CNoTrackObject类的定义位于Afxtls_.h中,主要是重载new 和 delete操作符,它的实现位于Afxtls.cpp中。


五、线程局部数据

和进程局部数据类似,线程局部数据是指必须和指定线程相关的局部数据,也就是说,不同线程访问同一个数据的时候,要为每个线程准备一份数据的实例。假设有一个CString对象,可以通过把它嵌入 CThreadLocal模板,使它成为线程局部数据:

struct CMyThreadData : public CNoTrackObject
{
   CString strThread;
};
CThreadLocal<CMyThreadData> threadData;

void MakeRandomString()
{
   // 一种洗牌方式,52张牌,效率很低,不实用
   CString& str = threadData->strThread;
   str.Empty();
   while (str.GetLength() != 52)
   {
      TCHAR ch = rand() % 52 + 1;
      if (str.Find(ch) < 0)
         str += ch;
   }
}

如果从两个不同的线程调用 MakeRandomString ,则每个线程都会打乱字符串的顺序,而且相互之间没有影响。这是因为每个线程都有一个strThread实例对象,而不是只有一个全局对象。

上述代码中使用了一个引用,而不是在循环中使用 threadData->strThread,避免循环调用->操作符,这样可以提高代码的效率。

-------------------
End. iwaswzq 2005/5/23

AFX_MAINTAIN_STATE2::~AFX_MAINTAIN_STATE2() AFX_MAINTAIN_STATE2::~AFX_MAINTAIN_STATE2()  Add:       afxAmbientActCtx = FALSE; To:       CWinApp::InitInstance(); 阅读详情

相关推荐

MFC的状态 模块状态、进程状态、线程状态。

MFC 定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如 MFC 句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。

MFC和模块状态

什么是模块状态?       在每个使用了Microsoft   Foundation   Classes   (MFC)的模块(EXE,DLL)中,都存在一种“全局”数据,MFC正是依靠这种全局数据才能执行正确的操作。这种全局数据就叫做MFC   模块状态。       例如,MFC应用程序经常使用下面的代码从资源文件中加载字符串:           CString   str;      

jia_xiaoxin的专栏 5020

U3d WebGL使用ToLua

首先我们在编辑器模式下加入Tolua插件,然后配置修改到在编辑器模式下能够正常的运行。 同个U3d 插件Build出WebGL的工程,运行的时候你会发现(有些需要把这个WebGL工程放在一个HttpServer下面,直接本地访问index.html会被拒绝,让你使用http的格式)。 当要加载完的时候会出现 To use dlopen, you need to use Emscripten'...

qq_35267906的博客 2946

MFC全局函数开局——AfxGetApp解剖

AfxGetApp( )这个函数可以得到当前应用进程的指针,是CWinApp*类型的,通过这个指针可以访问到这个进程中的对象。 函数原型: CWinApp*AFXAPI AfxGetApp(); 返回值: A pointer to the single CWinApp object for the application. 返回指向应用程序的单一的CWinApp对象的指针。 注

thanklife的专栏 1484

Matlab信号处理——基于BP神经网络的调制信号分类与识别

如果你想要进一步了解更多的相关知识,可以关注下面公众号联系~会不定期发布相关设计内容包括但不限于如下内容:信号处理、通信仿真、算法设计、matlab appdesigner,gui设计、simulink仿真......希望能帮到你!对信号进行采样和处理,得到了一系列特征参数,包括幅度均值、频率峰值、频率平方均值以及相位标准差、修正后的相位标准差。

小嘤熊的博客 1308

ROS探索篇(一)在Gazebo中实现移动机器人仿真与环境搭建

$x+y=z$

weixin_52029211的博客 4619

AFX_MODULE_STATE作用

MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。 模块状态 这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DLL,比如一个OLE控件就是一个模块。 一个应用程序的每一个模块都有一个状态,模块状态包括这样一些信息:用来加载资源的 Windows实例句柄、指向当前CW...

guniwi的博客 2297

Upload Symbols Failed:The archive did not include a dSYM for the LiveKitWebRTC.framework with the UU

你需要从源码构建 LiveKitWebRTC,而不是使用 CocoaPods 安装的预编译 .xcframework。Step 2: 修改 Podfile 使用本地路径引用(不是从源下载的 xcframework)方法 :强制从源码构建 LiveKitWebRTC.framework(推荐)这样它就会编译 WebRTC 并带上正确 UUID 的 dSYM。替换路径为你 clone 下来的 LiveKit 源码位置。Step 1: 克隆源码仓库。

baidu_40537062的博客 2135

MFC模块状态实现

本技术备忘录介绍MFC “模块状态”结构的实现。充分理解模块状态这个概念对于在DLL中使用MFC的共享动态库是十分重要的。 MFC的状态信息分为三种:全局模块状态数据、进程局部状态数据和线程局部状态数据。有时这些数据类型之间没有严格界限,例如MFC的句柄表既是全局模块状态数据也属于线程局部状态数据。 进程局部状态数据和线程局部状态数据差不多。早先这些数据是全局的,但是为了更好的支持Win32和

ylwdi的专栏 818

(八)基于MuJoCo的LeRobot SO100仿真操控实战指南(操作优化)

本文详细介绍了如何在MuJoCo仿真环境中搭建并优化LeRobot SO100机械臂的操控。通过两种核心模式(纯键盘仿真与实机镜像同步)的实战演示,重点讲解了关键的参数标定方法,以实现虚拟模型与真实硬件的精准同步。文章还提供了性能优化技巧,旨在帮助开发者构建高效、安全的机器人算法开发与测试流程。

weixin_29083649的博客 317

STM32+FreeRTOS环境下LwIP协议栈移植详解

本文详细介绍了在STM32F407ZGT6平台上移植轻量级TCP/IP协议栈LwIP的过程。使用FreeRTOS操作系统和LAN8720A以太网PHY芯片,通过STM32CubeMX生成基础工程配置。重点包括LwIP源码的获取与工程集成、关键配置文件的编写(如lwipopts.h)、操作系统适配层sys_arch.c的实现,以及以太网接口驱动ethernetif.c的移植。文章特别强调内存管理、中断优先级、硬件校验和等关键配置项的注意事项,为基于STM32和LwIP的嵌入式网络开发提供了实用参考。

电脑管家 753

MFC模块讲解

MFC的状态   MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。 模块状态   这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DL

benny5609的专栏 3528

手势识别器:实现手部动作识别器

在本篇文章中,我们将使用Python来实现一个简单的手部动作识别器。然后,我们通过循环从摄像头获取每一帧图像,并对每一帧图像进行处理。我们提取手部关键点并计算手势的特征向量,然后将其添加到特征列表和标签列表中。接下来,我们再次从摄像头获取每一帧图像,并进行手势识别。我们提取手部关键点并计算手势的特征向量,然后使用训练好的分类器来预测手势,并在图像上显示出来。在这个实现中,我们将使用MediaPipe库来检测和跟踪手部关键点,然后使用K最近邻(K-Nearest Neighbors)算法对手势进行分类。

BitSlinger的博客 238

MFC的状态

MFC的状态   MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。 模块状态   这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DL

1059

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

MFC 的模块状态

MFC应用程序包括三种状态:进程状态,线程状态,模块状态(物理划分),详见 http://blog.youkuaiyun.com/jia_xiaoxin/archive/2009/01/16/3795431.aspxTN058: MFC Module State Implementation

jenus1的专栏 765

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

第九讲 MFC的状态

第九讲 MFC的状态 MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。 模块状态 这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DLL,比如一个OLE控件就是一个模块。 一个应用程序的每一个模块都有一个状态,模块状态包括这样一些信息:用来加载

mitesi的专栏 1197

MFC 教程【9_MFC的状态】

 MFC的状态 MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。模块状态 这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DLL,比如一个OLE控件就是一个模块。一个应用程序的每一个模块都有一个状态,模块状态包括这样一些信息

优秀技术文章收录 1693

9.MFC的状态

  MFC的状态   MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。   模块状态   这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DL

雨声的专栏 2127

MFC教程-9

 MFC的状态 MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。模块状态 这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DLL,比如一个OLE控件就是一个模块。一个应用程序的每一个模块都有一个状态,模块状态包括这样一些信息:用来加载资

JidanIt的专栏 1025

9_MFC的状态

MFC的状态 MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。 模块状态 这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DLL,比如一个OLE控件就是一个模块。一个应用程序的每一个模块都有

刘磊的专栏 845

mfc宏状态介绍

MFC的状态   (2011-07-15 09:51:39) 转载▼ 标签:  杂谈 分类: MFC学习 MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。   模块状态   这里模

tangyanzhi1111的专栏 1387

MFC教程(9)MFC的状态

MFC的状态 MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。模块状态 这里模块的含义是:一个可执行的程序或者一个使用MFC DLL的DLL,比如一个OLE控件就是一个模块。一个应用程序的每一个模块都有一个状态,模块状态包括这样一些信息:用来加载资源的 Windows实例句柄、指向

2294

MFC的模块状态:从AfxGetApp()和AFX_MANAGE_STATE()看MFC的模块状态

 MFC的模块状态:从AfxGetApp()和AFX_MANAGE_STATE()看MFC的模块状态收藏 新一篇: Mac OS X Programming读书笔记4 - Windows | 旧一篇: Mac OS X Programming读书笔记3 - 事件处理 function StorePage(){d=document;t=d.selection?(d.selec

skyremember的专栏 1296
上一篇: 解决CentOS语言更改成简体中文出现的乱码问题
下一篇: CString LPCTSTR
playStudy
博客等级 码龄19年 275粉丝 60原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值