MFC common skills



1. How to get the window handle in MFC

Get the handle of the main window

There is a member variable in the window class of VC: m_hWnd, which represents the handle of this window. Therefore, through some functions that get the window pointer in VC, and then access the member variable of this, you should be able to get the desired handle.
For example, use this function to get the window pointer, and then access its m_hWnd;
for example, in the window class: this->m_hWndor this-》GetSafeHwnd().
Therefore, whether in the main window class or in the sub-window class, the method of obtaining the handle of the main window:
AfxGetMainWnd()->m_hWnd;

Get the handle of the child window

With FindWindow, you only need to know the name of the child window, for example:
HANDLE h返回找到的窗口的句柄 = ::FindWindow(NULL/*窗口的类名*/, lpszWindowName/*窗口的标题*/);

For example, in the MFC program, find out whether the program window named "Qingzhi - Check Machine" is running:
CWnd* pWnd=FindWindow(NULL,_T(“清芝--支票机“));

FindWindowEx has two more handle parameters than FindWindow:
HWND WINAPI FindWindowEx(
In_opt HWND hWndParent, //To find the handle of the parent window of the child window
In_opt HWND hWndChildAfter, //The handle of the child window
In_opt LPCTSTR lpszClass,
In_opt LPCTSTR lpszWindow);

When obtaining the handle (HWND) of a pointer to a window object (a CWnd-derived object), the safest way is to use the GetSafeHwnd() function.
Let’s see why with the following example:

CWnd *pWnd = FindWindow(“ExploreWClass”,NULL); //希望找到资源管理器
HWND hWnd = pwnd->m_hwnd;	//得到它的HWND

When executing such code, when the obtained pwnd is empty, a "General protection error" will appear, and the application will be closed, because it is generally not possible to access its members for a NULL pointer.
If you use the following code, there will be no problems (warning pop-up window, program abort), because even when pWnd is NULL, GetSafeHwnd can still be used, just return NULL.

CWnd *pwnd = FindWindow(“ExploreWClass”,NULL);	//希望找到资源管理器
HWND hwnd = pwnd->GetSafeHwnd(); //得到它的HWND

Get the handle of the control in the window

Use the GetDlgItem function, the syntax is: GetDlgItem(IDC_COMBO3)->m_hWnd;
the parameter is the ID of the control, and the return value is: CWnd* type, but it is a function in the CWnd class, so first obtain the pointer of the window where the control is located, for example:

CString str(_T(“ddoutput“));
//在指定控件上绘制文字
::SendMessage(AfxGetMainWnd()->GetDlgItem(IDC_COMBO3)->m_hWnd, WM_SETTEXT , 0 , (LPARAM)str.GetBuffer(0));

get pointer from handle

Use the FromHandle function.
grammar:CWnd* pWnd = CWnd::FromHandle(hWnd);

Summary: Get window handle (full collection) vc&MFC

this->m_hwnd
HWND GetForegroundWindow(VOID);
GetSafehWnd //Get the handle of the window class where your program is located
GetActiveWindow //Get the handle of the current active window
AfxGetMainWnd //Get the handle of the main window
GetForegroundWindow //Get the handle of the foreground window
FindWindow
EnumWindow

Reference: http://www.ekangw.net/news/2022/0924/194873.html


2. String

CString to char*

1. Convert CString to char under Unicode *
Method 1: Use functions T2A and W2A

CString cstr = _T("test")
//声明标识
USES_CONVERSION;
//函数T2A和W2A均支持ATL和MFC中的字符
char * pFileName = T2A(cstr);   
//char * pFileName = W2A(cstr); //也可实现转换

注意:有时候可能还需要添加引用#include <afxpriv.h>

Method 2: Convert using API: WideCharToMultiByte

CString str = _T("test");

//注意:以下n和len的值大小不同,n是按字符计算的,len是按字节计算的
int n = str.GetLength();

//获取宽字节字符的大小,大小是按字节计算的
 int len = WideCharToMultiByte(CP_ACP,0,str,str.GetLength(),NULL,0,NULL,NULL);

//为多字节字符数组申请空间,数组大小为按字节计算的宽字节字节大小
char * pFileName = new char[len+1];   //以字节为单位

//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP,0,str,str.GetLength(),pFileName,len,NULL,NULL);
pFileName[len+1] = '/0';   //多字节字符以'/0'结束

Convert char * to CString under Unicode

Method 1: Convert using API: MultiByteToWideChar

char * pFileName = "test";

//计算char *数组大小,以字节为单位,一个汉字占两个字节
int charLen = strlen(pFileName);

//计算多字节字符的大小,按字符计算。
int len = MultiByteToWideChar(CP_ACP,0,pFileName,charLen,NULL,0);

//为宽字节字符数组申请空间,数组大小为按字节计算的多字节字符大小
TCHAR *buf = new TCHAR[len + 1];

//多字节编码转换成宽字节编码
MultiByteToWideChar(CP_ACP,0,pFileName,charLen,buf,len);

buf[len] = '/0'; //添加字符串结尾,注意不是len+1

//将TCHAR数组转换为CString
CString pWideChar;
pWideChar.Append(buf);

//删除缓冲区
delete []buf;

Method 2: Use functions A2T and A2W

char * pFileName = "test";
USES_CONVERSION;
CString s = A2T(pFileName);
//CString s = A2W(pFileName);

Method 3: Use the _T macro to convert a string to a wide character

//书写代码使用TEXT("")或_T(""),文本在UNICODE和非UNICODE程序里都通用
AfxMessageBox(_T("test string"));  

注意:直接转换在基于MBCS的工程可以,但在基于Unicode字符集的工程中直接转换是不可行的,CString会以Unicode的形式来保存数据,强制类型转换只会返回第一个字符。

3. Frequently asked questions about Visual C++ 64-bit migration (length issues of data types and pointer types)

In order to achieve source code portability between the two platforms smoothly, programmers should write programs or modify existing programs according to the following rules:

A. Pointers cannot be converted into types such as int, uint, long, ulong, and dword whose word length is fixed at 32 bits. If operations on pointers are required, the pointers should be converted into int-ptr or uint-ptr, these two types The correct word length is available on different platforms. In addition, since the handle is essentially a pointer (void *), it is incorrect to convert the handle to a type such as long or ulong.

B. If it is determined that the pointer needs to be truncated, two functions (ptrtolong() and ptrtoulong() (defined in basetsd.h) should be used to do so. They can shield pointer truncation warnings, but the truncated result can no longer be regarded as pointer used.

C. When the out parameter of an api function can return a pointer, the parameter should be handled carefully. In win32, the address of a ulong variable can be converted and passed to the api function, and the returned pointer is stored in the ulong variable , but in win64, the returned pointer has 64 bits. If ulong variable is used, the content of other variables will be destroyed. The correct and simple way is to directly define a pointer variable, and pass the address of the pointer variable as a parameter to the api function .

Reference link: https://blog.csdn.net/u011135902/article/details/50571955


4. c++ - Is it safe to convert uintptr_t returned by _beginthread to HANDLE

On x64 builds, uintptr_t is defined as a 64-bit value:
typedef unsigned __int64 uintptr_t;
so it is safe to cast it to HANDLE in this case

Reference link: https://www.lmlphp.com/user/163619/article/item/3254239


5. Visual Studio displays line numbers

Tools, Options, Text Editor, All Languages, check the upper line number .


6. The VS plug-in Indent Guides displays the vertical dotted lines corresponding to the braces

Tools, Options, Text Editor, General, check Show Structural Guides .
This is a built-in function of VS (vs2017, vs2019, vs2020). Some versions of vs have (higher version) and some do not (lower version). At this time, you can try other methods:

  • Select Edit -> Advanced -> View Indent Guides
  • Select "Extension Manager" under the "Tools" menu, or expand and update, go online, search for Indent Guides , download and install and restart vs.
  • If there is no VS plug-in in the extension and update, you can click the link to download and install: Indent Guides download link
  • After installing the Indent Guides plug-in in the above link, you can make corresponding settings in Tools, Options, and IndentGuide (default settings are fine).

insert image description here
The plug-in after installation is shown in the figure:

insert image description here
Remarks: The Go To Definition plugin is also very useful, it is convenient for ctrl+鼠标左击the function name to go to the definition.

Reference: https://blog.iccfish.com/2015/08/25/release_vsext_indent_guides_chs/


7. Optimize the startup speed of VS

For students with poor machine configuration, you can set it in the settings:
Tools, Options, Environment, General, prohibit automatic adjustment of visual experience based on client performance, and prohibit enriching client visual experience, but please use hardware graphics acceleration when enabled. In this way, although the special effects of VS are less, the runtime will be much smoother.


8. Get the PID according to the process handle

At the R3 layer, the corresponding handle can be obtained by passing in the parameter PID through OpenProcess; the
corresponding process PID can also be obtained by passing in the parameter process handle through ::GetProcessId, or the corresponding thread TID can be obtained by passing in the parameter process handle through ::GetThreadId.

HANDLE WINAPI OpenProcess(
    _In_ DWORD dwDesiredAccess,
    _In_ BOOL bInheritHandle,
    _In_ DWORD dwProcessId
    );

DWORD WINAPI GetProcessId(
    _In_ HANDLE Process
    );
    
DWORD WINAPI GetThreadId(
    _In_ HANDLE Thread
    );

9. Double-click the *.rc file in the project, there is no response after opening vs, and the .rc file cannot be opened

Search for the two files rc.exe and rcdll.dll (local search or Baidu search), and copy them to

C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin

Re-open the *.rc file. If there is still no response, click File, Open, File in the vs menu, and select the .rc file to open it.


10. Copy the interface resources in other people's projects

First, use a visual studio to open the .rc files in your own and other people's projects according to item 9 above, as shown in the following figure:

insert image description here
insert image description here
Drag it into the style shown in the figure above for easy operation, then copy the relevant resources of the other party and paste them into your own project:

insert image description here
insert image description here

In this way, the resources in other people's projects become your own, and you don't need to modify the resource ID. This is very convenient and saves us a lot of time.
Of course, if you don't know what the resources represent, you can double-click to open the corresponding resource, copy the control on the resource, and then paste it to your own dialog box. The copied resource ID remains unchanged.

there is another way

After opening our own project, you click File, Open, File in the vs menu to open the .rc file in other people's projects. At this time, you can't copy resources or drag them. What should you do?
Open the solution explorer of your own project, right-click the source file, add, existing item:

insert image description here

Add the .rc files in other people's projects, so that there are two .rc resource files in our project:

insert image description here

You can drag or copy resources, remember to delete other people's resource files just added after dragging, and don't save other people's things.

Then it is a routine operation, paste the corresponding functional cpp files and .h files in other people's projects into the directory of your own project, click the item in the vs menu, add an existing item, and paste the .cpp and .h files just pasted in your project directory Add the .h file, so that there are corresponding classes in the class view, and then make appropriate modifications and compile, we can easily transplant the functions in other people's projects to our project one by one.


11. Merge two existing .sln projects

Open one of the projects with vs, right-click on the solution , add, existing project, open the file directory of another project, you may not see the .sln file at this time, as shown in the figure below, select the right side of the file name edit box Extension combo box, select Solution File (*.sln):

insert image description here
Open the .sln of another project, and multiple projects in this project will be automatically added, and the class view and resource files will also automatically include the content of another project.


12. Add an array through the VS Add Member Variable Wizard

Right-click a class, add, and add member variables, which will open the add member variable wizard. For example, to add an array, if char StrPath[MAX_PATH]you enter char in the type and KeyPath[MAX_PATH] in the name, an error will be reported:

insert image description here
In fact, we know that the type of this array is char[MAX_PATH], and the variable name is KeyPath, so we can fill it in like this:

insert image description here

13. Header files include each other errors (C2061, C2146, C4430, C2079)

A dialog class and a data processing class, their header files include each other (because they need to use the objects generated by each other’s classes, a data processing class object is defined in the dialog class definition), which can easily lead to many errors:

error C2061: Syntax error: identifier "XXDlg"
This is an error that contains each other. The compiler does not know which class should be generated first and which class should be generated later, which leads to such an error.

Solution
We can declare the dialog class (pre-declaration) before the definition of the data processing class before compiling, so that this error can be avoided.

After the forward declaration solves the C2061 error, there are still other errors after compilation:

error C2146: syntax error: missing ';' (preceding identifier 'm_XXXBase')
error C4430: missing type specifier - int assumed. Note: C++ does not support default int

We declare the data processing class (pre-declaration) before the definition of the dialog class, and the result error becomes 对话框类使用了未定义的数据处理类(a data processing class object is defined in the dialog class definition):

error C2079: 'XXXDlg::m_XXXBase' uses undefined class 'XXXBase'

In this way, we cannot write the data processing class object defined in the dialog class definition into the .h file. We first delete the pre-declaration of the data processing class in front of the dialog class definition, and put it in .cpp This data processing class object becomes a global variable, and the code that uses this object can be modified to solve this error. . . . . .


Guess you like

Origin blog.csdn.net/zhaopeng01zp/article/details/128805453