65.9K
CodeProject 正在变化。 阅读更多。
Home

45 天系列:Codeproject VC++ 论坛问答 - VII

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (12投票s)

2012年6月22日

CPOL

25分钟阅读

viewsIcon

31839

VC++ 论坛的问答集合。

引言

一如往常,没什么特别……本文是 Code Project Visual C++ 论坛上所提问题的问答汇编。同时,这也是“45天系列”的第四篇文章。我希望能为这个系列带来更多内容。

感谢大家在 CodeProject 论坛上为帮助同行所做的贡献。为适应/保持文章的观感,我对一些原文评论做了修改(为此我深表歉意)。如果我遗漏了什么,请随时发邮件给我或在底部留言。

内容 


MFC

MFC01 选择集合类有什么建议?
MFC02 我需要在一个按钮上实现悬停效果,告诉我该怎么做?
MFC03 如何用编程方式设置弹出框的大小?
MFC04 如何获取 CTabCtrl 选项卡的标题文本?
MFC05 如何让 CString::Format 生成 12,345.00 这种格式(即带逗号的数字)?
MFC06 在调用 domodal 之后,如何向属性表添加或删除属性页?
MFC07 如何在运行时设置/移除 CEdit 的 ES_READONLY 样式?
MFC08 什么是 StdAfx.h,为什么我应该使用它?
MFC09 CDialog 的 OnCreate 与 OnInitDialog 有什么区别?
MFC10 如何消除“未使用参数”的警告?
MFC11 有没有人尝试过使用 CMFCMaskedEdit 类并调用 GetWindowTextLength() 来检查控件中是否有用户输入的文本?
   

WINDOW32

 
Win3201 在没有插入光盘的情况下,如何通过编程区分 CD 驱动器和 DVD 驱动器?
Win3202 如何创建虚拟注册表?
Win3203 一个关于 FreeLibrary 的问题?
Win3204 如何全局禁用“Alt”键?
Win3205 CreateWindow() 和 CreateWindowEx 有什么区别?
Win3206 如何获取 DosDevice 的 GUID?
Win3207 如何获取控制台窗口的 WM_MINIMIZE 消息?
Win3208 如何获取一个进程(已知其 ID)的主线程 ID?
Win3209 我们如何确定已加载 DLL 的基地址?
Win3210 如何告诉系统在我指定的基地址加载 DLL?
Win3211 我如何检查一个窗口是否被另一个窗口遮挡?
Win3212 动态链接与动态加载有什么区别?
Win3213 有没有办法在我的应用程序运行时阻止用户注销他们的 Windows 账户?
   

通用

 
GEN01 我应该在纯虚类中使用析构函数吗?什么时候使用?
GEN02 我有一个 8 字节的变量 (ULONGLONG)。如何从中提取前 6 个字节?
GEN03 能否告诉我,为什么以下运算符不能被重载?
GEN04 如何实现像 Windows Media Player 最小化时的迷你栏那样的弹出窗口?
GEN05 程序如何知道是否安装了“Microsoft Visual C++ 2010 Redistributable Package (x86)”?
GEN06 如何读取 UDF 格式的文件?
GEN07 在 Windows 7 上模拟 DOS 6.12 环境?
GEN08 一个度分秒格式的值,其返回类型应该是什么?
GEN09 将文本复制到剪贴板?
GEN10 如何限制一个对象在堆上分配?
GEN11 蓝牙中“文本传输”的 GUID 是什么?
GEN12 如何获取所有活动的 Windows COM 端口?
GEN13 我的进程不应被任务管理器杀死?
GEN14 strcpy_s 与 StringCchCopy 之间的区别?
GEN15 带有纯虚函数的多级继承?
GEN16 如何查找字符串字面量?
GEN17 为什么 C++ 没有虚拟构造函数?
GEN18 什么是中断号?什么是 AX 寄存器?
GEN19 如何将 double 转换为 BSTR?
GEN20 我在哪里可以得到 WinUSB.sys 和 WinUSB.dll?
GEN21 请提供交叉转换的实用代码?
GEN22 为什么 "var" 打印 "Whats up" 而不是 "newval"?
   

有趣

 
FUN01 星座配对算法?
FUN02 水壶问题的解决方案?1
FUN03 如何解压带密码的 RAR 文件?
   
   

答案

 

MFC

 
   
问题(MFC01) 选择集合类有什么建议?
答案 请查看 MSDN 网站上的这个页面
 
问题(MFC02) 我需要在一个按钮上实现悬停效果,告诉我该怎么做?
答案 你必须调用 TrackMouseEvent 函数,这通常在 WM_MOUSEMOVE 处理程序中进行。这里有一个例子 - http://blogs.msdn.com/b/oldnewthing/archive/2003/10/13/55279.aspx
 
问题(MFC03) 如何用编程方式设置弹出框的大小?
答案 有几种方法
  • 在对话框上调用 Create() 时设置大小。
  • 使用 SetWindowPos() 更改大小
  • 使用 MoveWindow() 更改大小
 
问题(MFC04) 如何获取 CTabCtrl 选项卡的标题文本?
完整问题 以下代码在最后一行崩溃
TCITEM tcItem;
tcItem.mask = TCIF_TEXT;
m_ReportTabCtrl.GetItem(ID_PANE_FOUND, &tcItem);
CString csText = tcItem.pszText;
答案 你没有正确初始化你的 TCITEM 结构;请参阅 MSDN 文档此处。最好检查所有 Windows 函数调用的返回值,而不是仅仅假设它们已经成功。
 
问题(MFC05) 如何让 CString::Format 生成 12,345.00 格式(即带逗号的数字)?
答案 考虑使用 API GetNumberFormat()。
 
问题(MFC06) 在调用 domodal 之后,如何向属性表添加或删除属性页?
答案

在你的 PropertyPage 的按钮事件处理程序中,只需调用父属性表(PropertySheet)的 "RemovePage()" 函数,例如,"RemovePage(this)"。请注意,如果你正在移除活动页面(很可能如此),你应该使用属性表的 "SetActivePage()" 函数来使其他某个页面(比如你的欢迎页面)变为活动状态。


我也使用 CTreePropSheet 类或其派生类,我记得在删除页面并让树正确重绘方面存在一些问题。我会先用标准的 CPropertySheet 测试这个,观察选项卡正确出现和消失,然后再回到 CTreePropSheet 类。

 
问题(MFC07) 如何在运行时设置/移除 CEdit 的 ES_READONLY 样式?
答案 你可以尝试 ModifyStyle()SetReadOnly()
 
问题(MFC08) 什么是 StdAfx.h,为什么我应该使用它?
答案 预编译头用于通过将经常需要的包含文件添加到其中来减少编译时间。浏览 http://en.wikipedia.org/wiki/Precompiled_header

我建议你将大部分其他应用程序代码所需的包含文件添加到 stdafx.h 中。这会显著减少构建项目的时间。
 
问题(MFC09) CDialog 的 OnCreate 与 OnInitDialog 有什么区别?
答案 OnCreate 仅在应用程序请求调用 Create 函数时被调用。因此,不能保证窗口已完全创建。OnInitDialog 是在窗口(在这种情况下是对话框)完全创建后被调用的。
当您动态创建一个控件时,您将指定其父窗口句柄,因此它必须被完全创建。所以,正如上一个回答中所说,始终在 OnInitDialog 中执行此操作。
 
问题(MFC10) 如何消除“未使用参数”的警告?
答案 以下任一方法都可以消除该警告 -
void MyClass::reset(ErrorType)
{
}
OR
void MyClass::reset(ErrorType error)
{
error;
}
或者您可以使用 UNREFERENCED_PARAMETER 宏,其作用与第二种方法相同 -
void MyClass::reset(ErrorType error)
{
UNREFERENCED_PARAMETER(error);
}
   
问题(MFC11) 有没有人尝试过使用 CMFCMaskedEdit 类并调用 GetWindowTextLength() 来检查控件中是否有用户输入的文本?
答案

当 MFC 控件出现奇怪的行为时,我总会去查看位于 \VC\atlmfc\src\mfc 安装路径下的控件源代码。


如果你查看 afxmaskededit.cpp 中的 Microsoft 实现,你会发现 CMFCMaskedEdit 类处理 WM_GETTEXTLENGTH、WM_GETTEXTWM_SETTEXT 消息,覆盖了默认的 CWnd 行为。

CMFCMaskedEdit 类实际上是响应 WM_GETTEXTLENGTH 消息返回其内部 CString 缓冲区的长度。因此,微软文档中陈述的:“当用户采取可能改变编辑控件中文本的操作时,会发送 EN_CHANGE 通知代码。与 EN_UPDATE 通知代码不同,此通知代码是在系统更新屏幕后发送的。”并不适用于这个特定的窗口类。不幸的是,你将不得不在这里实现一些非常规的方法。有几个想法:

选项 [1]
将 afxmaskededit.cpp 和 afxmaskededit.h 中的所有代码高亮显示,然后复制/粘贴到一个名为 DavidCrowsMaskedEdit 的新类中,并更改/改进其行为。

选项 [2] 你可以重写 PreTranslateMessage 并检查属于 CMFCMaskedEdit 控件的 WM_KEYUP 消息。一旦控件接收到此消息... CMFCMaskedEdit 应该已经更新了其内部缓冲区,因为它是在响应 WM_CHAR 消息时进行过滤的。请注意,此方法无法处理剪贴板的复制/剪切/粘贴,因此效果可能不一。

BOOL YourMaskDlg::PreTranslateMessage(MSG* pMsg)
{
if(WM_KEYUP == pMsg->message)
{
if(::GetDlgCtrlID(pMsg->hwnd) == m_YourMaskEdit.GetDlgCtrlID())
{
int iLength = m_YourMaskEdit.GetWindowTextLength();
	
if(iLength)
{
	CString str;
	m_YourMaskEdit.EnableGetMaskedCharsOnly(TRUE);
	m_YourMaskEdit.GetWindowText(str);
	str.Remove(_T('_'));
 
	BOOL UserAddedText = str.GetLength();
}
}
}
return CDialog::PreTranslateMessage(pMsg);
}
选项 [3] 你实际上可以在你的 WM_CTLCOLOR 处理程序中获取窗口文本或文本长度。类似于这样
HBRUSH YourMaskDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
 
if(pWnd->GetDlgCtrlID() == m_YourMaskEdit.GetDlgCtrlID())
{
//Check to see if user added some text
}
return hbr;
}
我知道在 WM_CTLCOLOR 处理程序中查看窗口文本看起来像是一个彻头彻尾的“黑客”做法……但实际上 Joseph Newcomer 博士在他旧的验证 CEdit 类中就是这么做的。这确实是我能想到的解决你问题的所有办法了。

老实说,我通常会避免使用许多 MFC 类……我通常会“重新发明轮子”……因为有时我的轮子更圆。而且,如果我的新轮子最终是方的……好吧,至少我在此过程中学到了一些东西。
   
 

WINDOW32

 
   
问题(WIN3201) 在没有插入光盘的情况下,如何通过编程区分 CD 驱动器和 DVD 驱动器?
答案 使用 GetDriveType WIN32 API,然后确定设备是否真的是DVD驱动器的方法是使用 DeviceIOControl,如下所示
#include
<winioctl.h>
BOOL DeviceSupportsDVDMedia(TCHAR *szDrive)
{
BOOL bRet = FALSE;
if(NULL != szDrive && DRIVE_CDROM == GetDriveType(szDrive))
{
GET_MEDIA_TYPES media[CHAR_MAX];
TCHAR szVol[MAX_PATH] = {0};
DWORD dwBytesRet =0;
int iSize = CHAR_MAX * sizeof(GET_MEDIA_TYPES);
_stprintf(szVol,_T("\\\\.\\%c:"),szDrive[0]);
HANDLE hDevice = CreateFile(szVol,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,0);
if(INVALID_HANDLE_VALUE != hDevice)
{
if(DeviceIoControl(hDevice,IOCTL_STORAGE_GET_MEDIA_TYPES_EX,NULL,0,media,iSize,&dwBytesRet,FALSE))
{
	bRet = FILE_DEVICE_DVD == media->DeviceType;
}
}
}
return bRet;
}
 
问题(WIN3202) 如何创建虚拟注册表?
答案 请看这里 注册表虚拟化[^]
 
问题(WIN3203) 一个关于 FreeLibrary 的问题?
完整问题
 
HMODULE hModule  = ::LoadLibrary("GameLogicWZQ.dll");
typedef GameObject* (*CreateObjProc)();
CreateObjProc pCreateProc = (CreateObjProc)::GetProcAddress(hModule,"CreateGameObject");
m_pGameObject = pCreateProc();
::FreeLibrary(hModule);
如果 pCreateProc() 函数分配了一个大小为 1024 的缓冲区(使用 new),那么在调用 ::FreeLibrary(hModule) 之后,这个缓冲区会被释放吗?
答案 不,不会。应该从 DLL 中导出一个相应的函数来释放那块内存。并且这个函数可以被调用(调用方式与 Create 函数相同)。
 
问题(WIN3204) 如何全局禁用“Alt”键?
答案 你可能需要一个内核模式的设备驱动程序。 http://technet.microsoft.com/en-us/sysinternals/bb897578.aspx
 
问题(WIN3205) CreateWindow() 和 CreateWindowEx 有什么区别?
答案 这些是可以在 MSDN 上找到的 WinApi 调用。Ex 代表 extension(扩展),如果你看一下链接,你会发现 Ex 版本有一些在 Windows 95/98 时代不可用的更多选项。顺便说一下,还有许多其他方法的 API 扩展。
 
问题(WIN3206) 如何获取 DosDevice 的 GUID?
完整问题 我正在尝试将一个形如“\Device\HarddiskVolumeXX”的设备名转换为形如“\\?\Volume{GUID}”的名称。
答案

 

首先,运行

mountvol /?
mountvol /L
您将看到您系统可用的挂载点。
请参阅 http://technet.microsoft.com/en-us/library/cc772586%28WS.10%29.aspx

阅读这篇 CodeProject 文章:深入 Mountvol.exe:关于卷挂载点和 SDK API。另请参阅
 
问题(WIN3207) 我如何获取控制台窗口的 WM_MINIMIZE 消息?
答案 这可能不是一个好主意,看看下面的讨论 “控制台应用中的消息处理”
 
问题(WIN3208) 如何获取一个进程(已知其 ID)的主线程 ID?
答案 速度更快,但仅限 WIN32:使用此函数获取线程ID
/* CAUTION: ONLY WIN32
* get the threadId of the main thread of a target process
*
* params:
*     DWORD pId    processId of the target process
*
* return:
*     Success      threadId
*     Error        NULL
*/
DWORD GetMainThreadId(DWORD pId)
{
LPVOID lpThId;
 
_asm
{
mov eax, fs:[18h]
add eax, 36
mov [lpThId], eax
}
 
HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, pId);
if(hProcess == NULL)
return NULL;
 
DWORD tId;
if(ReadProcessMemory(hProcess, lpThId, &tId, sizeof(tId), NULL) == FALSE)
{
CloseHandle(hProcess);
return NULL;
}
 
CloseHandle(hProcess);
 
return tId;
}
 
问题(WIN3209) 我们如何确定已加载 DLL 的基地址?
答案 您从 GetModuleHandle 函数获得的 HMODULE 与基地址相同。如果您正在编写 MFC 应用程序... 这将与 AfxGetResourceHandle 返回的地址相同。而 AfxGetInstanceHandle 函数实际上返回的是主应用程序映像的基地址。

如果您使用的是微软编译器,那么您还可以访问一个外部变量 __ImageBase,它可用于访问这些基地址。因为它等于一个 HMODULE,所以您也可以使用这个变量来加载资源
现在我们有了基地址,我们可以读取 PE 映像头并检查大小
DWORD GetSizeOfImage(HMODULE hModule))
{
DWORD dwSize = 0;
PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)hModule;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)hModule + pDOSHeader->e_lfanew);
if(IMAGE_NT_SIGNATURE == pNTHeader->Signature)
{
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((PBYTE)&pNTHeader->FileHeader);
PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((PBYTE)&pNTHeader->OptionalHeader);
if(IMAGE_NT_OPTIONAL_HDR32_MAGIC ==  pNTHeader->OptionalHeader.Magic)
{
dwSize = pNTHeader->OptionalHeader.SizeOfImage;
}
}
return dwSize;
}
 
问题(WIN3210) 如何告诉系统在我指定的基地址加载 DLL?
答案

 

查看 /FIXED (固定基地址) 链接器选项。

我认为固定基址是一个不安全的选项……我强烈建议所有软件工程师都支持动态基址。

支持 ASLR 的 PE 映像将在 PE 映像特性中设置 IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 位。这些模块实质上是在说“把我放在你想要的任何地方……我不在乎”,然后内核会伪随机地选择一个地址来映射该映像。

对于不支持 ASLR 的 PE 映像……NT 内核会尝试在它的首选地址 pNTHeader->OptionalHeader.ImageBase 加载该映像。如果该地址已经被分配,内核会尝试在另一个地址映射该映像并应用其修复(fixups)。

 
问题(WIN3211) 我如何检查一个窗口是否被另一个窗口遮挡?
答案

 

GetClipBox 函数在窗口完全被遮挡时会返回一个 NULLREGION。不幸的是,如果启用了 DWM/Aero,这将不起作用,您可能需要计算交集。

 
问题(WIN3212) 动态链接与动态加载有什么区别?
答案

具体的正则表达式不是某人拥有的东西。这是需要根据任务构建的东西。在需要严肃解析器的地方,它们帮不上忙。我理解得对吗,您想解析 C++ 代码?您需要学习这个领域。从这里开始:

动态加载您的代码可以发现、加载和执行来自共享库的代码。但这些共享库在运行时甚至可能不存在。您的代码会显式地加载共享库。最好的例子就是插件。

 
问题((WIN3213) 有没有办法在我的应用程序运行时阻止用户注销他们的 Windows 账户?
答案

 

根据我的经验,XP 或更早版本的方法与 Vista/Win7 略有不同。

对于 XP 或更早版本,为 WM_QUERYENDSESSION 返回 0 就应该足够了。

对于 Vista/Win7,我还没有找到完全阻止注销的方法。但暂时阻止注销是可能的。我会为 WM_QUERYENDSESSION 返回 1,并在 WM_ENDSESSION 期间通过调用 ShutdownBlockReasonCreate 注册一个阻止原因。然后在应用程序运行完毕后调用 ShutdownBlockReasonDestroy。

您应该遵守 WM_ENDSESSION 消息WM_QUERYENDSESSION 中描述的说明,以确保用户和 Windows 系统都满意。

 
   

通用

 
   
问题(GEN01) 我应该在纯虚类中使用析构函数吗?什么时候使用?
完整问题 最近,我遇到了一个关于纯虚类的问题。有时我需要为我的工作设计一个接口,看起来像这样
class CInterface
{
virtual ~CInterface()=0{}
virtual void SomeAction()=0;
}
 
class DerivedA:public CInterface
{
DerivedA(){}
~DerivedA(){}
void SomeAction()
{
cout<<"Action from Derived class A ."<<endl;
}
}
But what make me confused is that it works well after I change CInterface,like below:

class CInterface
{
//virtual ~CInterface()=0{}
virtual void SomeAction()=0;
}
那么,我的问题是,我应该在纯虚类中使用析构函数吗?什么时候用?
 
 
答案 回答#1
只有当您需要释放纯虚类本身内部分配的指针(或释放资源)时,才需要析构函数。

答案#2
我认为你将 CInterface 的析构函数声明为 private(默认声明),所以这就是为什么你的第一个代码不起作用的原因。在第二个代码中,因为你注释掉了它,编译器为你生成了默认的析构函数。但据我所知,你应该在接口(泛型类)中声明虚析构函数。这个析构函数的用处将在这个例子中解释,
class CInterface
{
public:
virtual ~CInterface() = 0 {};
virtual void SomeAction()=0;
};
class DerivedA:public CInterface
{
public:
DerivedA(){}
~DerivedA(){cout<<"In Deriveda"<<endl;}
void SomeAction()
{
cout<<"Action from Derived class A ."<<endl;
}
};
int main()
{
CInterface* A = new DerivedA;
delete A;
return 0;
}
所以如果你删除 A 指针,CInterface 的析构函数将被编译器自动调用。如果你不把它声明为 virtual 或者根本不声明,CInterface 的析构函数将不会被调用。据我所知,virtual ~CInterface() = 0; 和 virtual ~CInterface(); 在一个接口中是相同的,只有一个区别。即,如果你想让一个类成为纯虚类,而这个类没有任何函数,那么你可以把析构函数设为纯虚的,这样整个类就变成了虚类。

回答#3
如果您的基类没有定义虚析构函数,而您的继承类实现了析构函数,那么您将遇到他描述的问题:如果您删除的对象不是来自那个确切的类(一个基类指针),那么您的派生类析构函数将不会被调用。简而言之,我会说:总是在您的基抽象类中定义一个虚析构函数。
  • 如果您在派生类型中实现了一个析构函数,这个析构函数在任何情况下都会被调用。
  • 如果您在继承的类中不需要析构函数,这也不会有什么坏处。
 
问题(GEN02) 我有一个8字节的变量 (ULONGLONG)。如何从中提取前6个字节?
答案

 

这也许能帮到你

#include <windows.h>
#include <iostream>

using namespace std;
 
union MyUnion
{
ULONGLONG ull;
BYTE b[8];
};
 
int main()
{
ULONGLONG v = 0x0123456789ABCDEF;
MyUnion mu;
mu.ull = v;
for (int i=0; i<6; i++)
{
// assuming you need the least significative bytes
cout << hex << (INT) mu.b[i] << endl;
}
}
 
问题(GEN03) 能否告诉我,为什么以下运算符(. :: ?: sizeof)不能被重载?
答案

 

你可以阅读该语言的发明者 Bjarne Stroustrup 对此的看法,就在这里[^]。没有人能比他给你更好的解释了。

 
问题(GEN04) 如何实现像 Windows Media Player 最小化时的迷你栏那样的弹出窗口?
答案

 

你需要的是一个桌面工具栏(Deskband)。有4种类型的桌面工具栏对象。其中3种位于 Internet Explorer 内部。最后一种在桌面上。请看文章 实现 Shell 桌面工具栏和 Internet Explorer 工具栏中的第二张图片。

 
问题(GEN05) 程序如何知道是否安装了“Microsoft Visual C++ 2010 Redistributable Package (x86)”?
答案

 

来自 MSDN 博客:如何检测是否存在 Visual C++ 2010 可再发行组件包

 
问题(GEN06) 如何读取 UDF 格式的文件?
答案

 

您需要的内容可以在这里找到: http://msdn.microsoft.com/en-us/library/aa366216(VS.85).aspx 所有必要的接口都在那里...

 
问题(GEN07) 在 Windows 7 上模拟 DOS 6.12 环境?
答案

 

你可以在 Windows XP 下使用 DosBox。它应该也可以在 Windows 7 下工作。

 
问题(GEN08) 一个度分秒格式的值,其返回类型应该是什么?
答案

 

我认为返回类型应该是一个 Angle(或 Bearing 等)。创建一个 Angle 类来使用。内部它可以使用一个浮点成员来表示十进制值。然后添加一个字符串格式化成员函数,以便在需要时获取所需的字符串。


优点:易于进行计算,并且可以降低混合单位(如度和弧度)的风险。如果对您有任何帮助,我使用以下代码

class angle
{
public:
enum unit
{
rad = 0,
deg = 1
};
angle() : r(0.) {}
explicit angle(double a, unit u = rad) {
if (u == rad) r = a; else r = a*M_PI/180;
}
angle(const angle& fi) : r(fi.r) {}
double radians() const { return r; }
double degrees() const { return r*180/M_PI; }
 
// -pi <= a < pi
void normalize() {
while(r<-M_PI)r+=2*M_PI;while(r>=M_PI)r-=2*M_PI;
}
// 0 <= a < 2pi
void normalize_positive() {
while(r<0.)r+=2*M_PI;while(r>=2*M_PI)r-=2*M_PI;
}
 
angle& operator=  (const angle &fi) { if (&fi != this) r = fi.r; return *this; }
angle& operator+= (const angle &fi) { r += fi.r; return *this; }
angle& operator-= (const angle &fi) { r -= fi.r; return *this; }
bool   operator== (const angle &fi) { return r == fi.r; }
bool   operator>  (const angle &fi) { return r > fi.r; }
bool   operator<  (const angle &fi) { return r < fi.r; }
bool   operator>= (const angle &fi) { return r >= fi.r; }
bool   operator<= (const angle &fi) { return r <= fi.r; }
angle  operator-  () { return angle(-r); }
angle  operator-  (const angle& fi) { return angle(r-fi.r); }
protected:
double r;
};
您可以轻松地将您的格式化函数添加到这个类中,或者更好的是,创建一个格式化类,对一个角度实例进行处理
 
问题(GEN09) 将文本复制到剪贴板?
完整问题

 

现在,当将文本复制到剪贴板时,将 SetClipboardData 设置为 CF_UNICODETEXT 是否比 CF_TEXT 更好?这会对粘贴方产生影响吗?

答案

回答#1
根据 MSDN:系统会在某些剪贴板格式之间隐式转换数据:如果一个窗口请求的数据格式不在剪贴板上,系统会将一种可用格式转换为所请求的格式。系统可以按下表所示转换数据。

Clipboard Format | Conversion Format | Platform Support 
 
CF_OEMTEXT       | CF_TEXT           | Windows NT/Windows 2000, Windows 95/Windows 98/Windows Me 
CF_OEMTEXT       | CF_UNICODETEXT    | Windows NT/Windows 2000 
CF_TEXT          | CF_OEMTEXT        | Windows NT/Windows 2000, Windows 95/Windows 98/Windows Me 
CF_TEXT          | CF_UNICODETEXT    | Windows NT/Windows 2000 
CF_UNICODETEXT   | CF_OEMTEXT        | Windows NT/Windows 2000 
CF_UNICODETEXT   | CF_TEXT           | Windows NT/Windows 2000 
让我在 Windows XP 上简单试一下
SetClipboardData(/*an ansi string*/, CF_TEXT);
// then
IsClipboardFormatAvailable(CF_TEXT); // success
IsClipboardFormatAvailable(CF_UNICODETEXT); // success
GetClipboardData(CF_TEXT); // success and read right string
GetClipboardData(CF_UNICODETEXT); // success and read right string
// unicode string also can test passed
但是我在 Windows 98 上测试,如果你用 CF_TEXT 设置 SetClipboardData,那么你必须用 CF_TEXT 调用 GetClipboardData;如果你用 CF_UNICODETEXT 设置 SetClipboardData,你必须用 CF_UNICODETEXT 调用 GetClipboardData。当我用 CF_UNICODETEXT 设置 SetClipboardData 时,记事本(Win98)无法从剪贴板粘贴文本。所以,如果你想支持 Windows 98,你必须用 CF_TEXT 设置 SetClipboardData,否则你可以使用它们中的任何一个。我建议你使用 Unicode。

回答#2
它更好仅仅是因为你可以使用 Unicode。如果你的应用程序允许输入任何 Unicode 字符,那么 CF_TEXT 是完全不可接受的,请使用 CF_UNICODETEXT。这就把问题简化为:你是否想支持 Unicode?这完全取决于你的应用程序和需求。一个应用程序如果只支持 ASCII(甚至不支持超出 127 码点的 ANSI),那么它确实可以是非 Unicode 的。有些这样的应用程序确实有其存在的理由。不过,根据经验法则,我认为最好假设非 Unicode 文本的时代已经过去了。
 
问题(GEN10) 如何限制一个对象在堆上被分配?
答案

 

一种方法是在类中声明一个

private:
operator new(size_t);
在类中。不需要实现。简单地说,像 `new yourclass` 这样的表达式无法编译,因为类的 new 运算符虽然已声明,但由于是私有的而无法被调用。这与将复制和赋值声明为私有以禁用默认生成的复制和赋值功能类似。
 
问题(GEN11) 蓝牙中“文本传输”的 GUID 是什么?
答案

 

OBEX 用于发送文件。对于发送简单文本,使用 SerialPortServiceClass_UUID

 
问题(GEN12) 如何获取所有活动的 Windows Com 端口?
答案

 

您可以参考这篇文章 串口。枚举和 FIFO 控制

 
问题(GEN13) 我的进程不应被任务管理器杀死?
完整问题

 

我在 Windows 启动时启动了一个进程。我希望这个进程不会被任务管理器或任何此类应用程序杀死。我该怎么做呢?

答案

回答#1
我相信一种常见的方法是使用一个“看门狗”进程来监视主进程,并在主进程被终止时重新启动它。当然,主进程也必须监视看门狗。这并非万无一失,但足够烦人。

答案#2

  • Windows 有 Job 内核对象,可用于监控进程的活动,甚至可以用于监控创建它的进程。
  • JOB_OBJECT_MSG_EXIT_PROCESS 可用于判断进程是否被终止。
  • 通过处理上述消息,可以通过调用 CreateProcess() 或 spawn() 重新启动被终止的进程。
回答#3
如果您在“用户级别”操作(您的进程在用户账户下运行,相对于操作系统而言),那么您无法做到这一点(而且这样做听起来非常可疑)。

您的应用程序,相对于用户而言,拥有与其他任何应用程序完全相同的权限,并且不包括改变操作系统相对于计算机(它属于用户,不属于您)或用户本人(他有许可证使用他付费购买的所有操作系统功能,而不是您)行为的权利。

当然,你可以实现一些技巧,比如让另一个进程来控制第一个进程,并在它死掉时重启它。但用户自己可以把它们都停掉。

如果您拥有这些计算机(即它们属于您和您的用户也所属的同一个组织),那么干净的解决方案是运行一个在系统级别运行的进程(实际上是一个服务),该进程在一个与用户账户不同的管理账户下运行(理想情况下是特定的一个),并且有权在用户模拟下启动进程。换句话说,您在您的组织中创建了一个有权控制用户运行进程的“用户”。
 
问题(GEN14)

strcpy_sStringCchCopy 之间有什么区别?

答案 回答#1
如果你真的想用那些“安全”的(它们并不真的安全,而且很慢),我建议用 strcpy_s。它是由 CRT 提供的,而 StringCchCopy 依赖于 Windows 版本——它只在 XP SP2 及以上版本中支持。

回答#2
两个版本都是“安全”的。我个人更喜欢 “StringCchCopy” 版本,因为它们比 *_S 版本更清晰、更一致。
 
问题(GEN15) 带有纯虚函数的多级继承?
完整问题 假设类层次结构如下所示
A
|
B
|
C

类 C 派生自类 B,而类 B 又派生自类 A;
类 A 有一些纯虚函数,这些函数已由 B 根据其上下文进行了定义;
我的问题是:如果要在类 C 中根据其特定上下文重新定义这些纯虚函数,我该怎么做?
答案 例如:
#include
<iostream> 
using namespace std; 
 
class A
{
public:
virtual void show()=0;
};
 
class B: public A
{
public:
virtual void show(){cout << "Hey, I'm a B" << endl;}
};
 
class C: public B
{
public:
virtual void show(){cout << "Hey, I'm a C" << endl;}
};
 
int main()
{
A * p = new C();
p->show();
}
输出
Hey, I'm a C
 
问题(GEN16)

如何查找字符串字面量?

答案

答案#1
具体的正则表达式不是什么可以被认为是某人拥有的东西。这是需要根据所需任务构建的东西。不,它们在需要一个严肃的解析器的地方帮不了你。我是否正确理解了您想解析 C++ 代码?您将需要学习这个领域。从这里开始

回答#2 Visual Studio 中的查找和替换功能接受正则表达式:正则表达式 (Visual Studio)
要搜索单引号和双引号的字面量字符串,并用 _T 宏替换它们
  1. 备份你的项目!我对结果不承担任何责任。
  2. 打开“查找和替换”菜单。
  3. 将以下文本添加到查找框中: {:q}
  4. 将以下内容添加到替换框中: _T(\1)
  5. 遍历匹配项并有选择地替换你的字符串。我建议避免使用“全部替换”按钮,因为可能无法撤销操作。
请注意,使用此方法会出现 #include 语句和其他各种不希望出现的阳性匹配。您应该备份您的项目,以防万一出现问题。
 
问题(GEN17) 为什么 C++ 没有虚拟构造函数?
答案

 

virtual”机制依赖于 VTable,而 VTable 将由构造函数设置。因此,构造函数本身不能是虚拟的(在 C++ 中不行),尽管你可以尝试像这样的东西。我提供给你的链接是互联网上最好的 C++ FAQ 之一。你也可以参考它来阅读关于虚拟析构函数和其他基础 C++ 的内容。

当您构造对象时,您总是知道当时想要创建的对象类型(您总是调用一个特定的构造函数,而不是基类的构造函数)。因此,拥有一个虚构造函数没有意义。虚析构函数更有意义:当您销毁对象时,您通常将对象作为指向其基类的指针来操作(这是使用多态的典型场景)。在这种情况下,您希望调用析构函数的正确版本。

 
问题(GEN18) 什么是中断号?什么是 AX 寄存器?
答案

 

中断号是硬件用来在某些外部事件发生时向操作系统发信号的。AX 寄存器仅仅是 CPU 使用的一个通用寄存器。它们都不是特定于鼠标程序(无论那可能是什么)的。请看这里,了解一些关于处理器如何工作的信息。

 
问题(GEN19) 如何将 double 转换为 BSTR
答案 答案#1
你可以用一个 BSTR 来表示一个 double 值,例如
#include <windows.h>
#include <tchar.h>
#include <sstream>
using namespace std;
 
int main()
{
wostringstream wos;
double d = 0.57;
wos << d;
BSTR bstr = SysAllocString(wos.str().c_str());
// enjoy with bstr
// ...
SysFreeString(bstr);
}

答案#2
为什么不使用 VarBstrFromR8 Windows API?
Windows 还提供了许多其他数据类型转换函数
 
问题(GEN20) 我在哪里可以得到 WinUSB.sys 和 WinUSB.dll?
答案 它作为 WDK 的一个联合安装程序提供。请阅读此页面上的 winusb_howto.docx - 如何使用 WinUSB 与 USB 设备通信
   
问题(GEN21) 请提供交叉转换的实用代码?
答案 我将给出一个通用的例子。想象我们有四个类:ANIMAL, FLYER, DOG, CROW
class Animal {
public:
virtual ~Animal() {};
void talk (string sound) {
cout << " Grrrr " << (char *)&sound <<  endl;
}
};
 

class Flyer {
public:
void fly (string destination) {
cout << " Flying to " << (char *)&destination <<  endl;
}
}; 
 
class Dog:public Animal{
};
 

class Crow:public Animal, public Flyer{
};
要保存 Dog 和 Crow 类型的对象,我们需要向上转型到基类 animal。当我们需要调用每个 Crow 的 fly() 方法时,我们需要知道这个 animal 是否继承自 Flyer 类,这是通过交叉转型(cross-cast)完成的。
Flyer* myAnimal = dynamic_cast<Flyer*>(pAnimal);
 
if(!myAnimal)
cout<<" my animal can't fly :( ..."<< endl;
else
cout<<" my animal can flye :) ..."<< endl;
   
问题(GEN22) 为什么 "var" 打印 "Whats up" 而不是 "newval"?
完整问题

 

在 VS2008 的发布模式下,为什么 "var" 打印 "Whats up" 而不是 "newval"?在调试模式下它会崩溃。我猜原因可能是自动内存分配是“只读”的。如果我使用 char *var = new char[15],那么它就工作正常。

#include <stdio.h>
#include <conio.h>
#include <string>
 
int main()
{
char *var = "\nWhats Up";
strcpy(var, "newval");
printf(var);
getch();
return 0;
}
答案 当你用这种方式创建 var 时,它指向一个常量字符串,所以你的 strcpy() 命令是不允许的。你应该这样编码
char *var = "\nWhats Up";
var = "newval";
// or
char var[] = "\nWhats Up";
strcpy(var, "newval");
尽管在第二种情况下,如果你不小心,很容易会覆盖缓冲区。
   

有趣

 
   
问题(FUN01) 星座配对算法?
完整问题

占星术是一门完整的科学,学习它需要数年时间。通过谷歌学习是没有捷径的。
您需要循序渐进去学习基础知识。我不认为您能像那样在网上找到一个算法。


这是只有占星学教授才能告诉你的事。请联系他们。

答案 试试用搜索引擎。
 
问题(FUN02) 水壶问题的解决方案?
完整问题

 

有5个装有不同水量水壶,所有水壶的总水量为10升。
现在我们想让每个壶里都有2升水,并且交易次数最少。开始时我们可以用一个数组来表示每个壶里水的初始含量,或者也可以用其他结构。
所以请给我建议任何算法或者方法,以便我能找到一个解决上述问题的算法。

答案 把壶装满水,然后等待足够长的时间,直到壶里只剩下2升水。
我们不做你的作业
 
问题(FUN03) 如何解压带密码的 RAR 文件?
答案 如果你想看看能处理 RAR 文件的程序的源代码,那么可以看看 7-Zip 的源码。另一方面,如果你想破解一个有密码保护的 RAR 文件,我怀疑你在这里得不到帮助。
   

专家

以上问题由以下专家(按字母顺序排列)回答:-
  • Aescleal
  • Alain Rist
  • CPallini
  • DavidCrow
  • Iain Clarke
  • J_E_D_I
  • Jackson2010
  • Mark Salsbery
  • Maxwell Chen
  • Michael Dunn
  • Michael Schubert
  • 迈克·奥尼尔
  • Moak
  • Naveen
  • Nibu babu thomas
  • Niklas Lindquist
  • Nuri Ismail
  • PJ Arends
  • Rajesh R Subramanian
  • Rajkumar R
  • Randor
  • Richard MacCutchan
  • Roger Stoltz
  • SandipG
  • Sauro
  • Stephen Hewitt
  • ThatsAlok
  • Thaddeus Jones
  • Viti
  • cmk
  • cofi++
  • emilio_grv
  • led mike
  • «_Superman_»
  • వేంకటనారాయణ(venkatmakam)
  • Ou Wei

   

特别感谢

  • 我的父母、我的妻子和帕克希!
  • 所有活跃的贡献者/Visual C++ 论坛 [CodeProject] 的成员,没有他们,这篇文章就不会问世。

本系列的其他文章

历史

  • 2012年6月22日:发布于 CodeProject。
  • 2012年6月21日:开始撰写本文。
© . All rights reserved.