45 天系列:Codeproject VC++ 论坛问答 - VII
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) | 如何用编程方式设置弹出框的大小? | 
| 答案 | 有几种方法 
 | 
| 问题(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 之后,如何向属性表添加或删除属性页? | 
| 答案 | 在你的  
 | 
| 问题(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 控件出现奇怪的行为时,我总会去查看位于  
 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 驱动器? | 
| 答案 | 使用 GetDriveTypeWIN32 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 (固定基地址) 链接器选项。 | 
| 问题(WIN3211) | 我如何检查一个窗口是否被另一个窗口遮挡? | 
| 答案 | 
 GetClipBox 函数在窗口完全被遮挡时会返回一个 NULLREGION。不幸的是,如果启用了 DWM/Aero,这将不起作用,您可能需要计算交集。 | 
| 问题(WIN3212) | 动态链接与动态加载有什么区别? | 
| 答案 | 
 具体的正则表达式不是某人拥有的东西。这是需要根据任务构建的东西。在需要严肃解析器的地方,它们帮不上忙。我理解得对吗,您想解析 C++ 代码?您需要学习这个领域。从这里开始: | 
| 问题((WIN3213) | 有没有办法在我的应用程序运行时阻止用户注销他们的 Windows 账户? | 
| 答案 | 
 根据我的经验,XP 或更早版本的方法与 Vista/Win7 略有不同。 | 
| 通用 | |
| 问题(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) | 将文本复制到剪贴板? | 
| 完整问题 | 
 现在,当将文本复制到剪贴板时,将  | 
| 答案 | 
 回答#1  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 用于发送文件。对于发送简单文本,使用  | 
| 问题(GEN12) | 如何获取所有活动的 Windows Com 端口? | 
| 答案 | 
 您可以参考这篇文章 串口。枚举和 FIFO 控制 | 
| 问题(GEN13) | 我的进程不应被任务管理器杀死? | 
| 完整问题 | 
 我在 Windows 启动时启动了一个进程。我希望这个进程不会被任务管理器或任何此类应用程序杀死。我该怎么做呢? 
 | 
| 答案 | 
 回答#1 
 如果您在“ 用户级别”操作(您的进程在用户账户下运行,相对于操作系统而言),那么您无法做到这一点(而且这样做听起来非常可疑)。您的应用程序,相对于用户而言,拥有与其他任何应用程序完全相同的权限,并且不包括改变操作系统相对于计算机(它属于用户,不属于您)或用户本人(他有许可证使用他付费购买的所有操作系统功能,而不是您)行为的权利。 当然,你可以实现一些技巧,比如让另一个进程来控制第一个进程,并在它死掉时重启它。但用户自己可以把它们都停掉。 如果您拥有这些计算机(即它们属于您和您的用户也所属的同一个组织),那么干净的解决方案是运行一个在系统级别运行的进程(实际上是一个服务),该进程在一个与用户账户不同的管理账户下运行(理想情况下是特定的一个),并且有权在用户模拟下启动进程。换句话说,您在您的组织中创建了一个有权控制用户运行进程的“用户”。 | 
| 问题(GEN14) | 
 
 | 
| 答案 | 回答#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
 
 要搜索单引号和双引号的字面量字符串,并用 _T 宏替换它们 
 #include语句和其他各种不希望出现的阳性匹配。您应该备份您的项目,以防万一出现问题。 | 
| 问题(GEN17) | 为什么 C++ 没有虚拟构造函数? | 
| 答案 | 
 “ | 
| 问题(GEN18) | 什么是中断号?什么是 AX 寄存器? | 
| 答案 | 
 中断号是硬件用来在某些外部事件发生时向操作系统发信号的。 | 
| 问题(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"?在调试模式下它会崩溃。我猜原因可能是自动内存分配是“只读”的。如果我使用  #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升水。 我们不做你的作业 | 
| 问题(FUN03) | 如何解压带密码的 RAR 文件? | 
| 答案 | 如果你想看看能处理 RAR 文件的程序的源代码,那么可以看看 7-Zip 的源码。另一方面,如果你想破解一个有密码保护的 RAR 文件,我怀疑你在这里得不到帮助。 | 
专家
| 以上问题由以下专家(按字母顺序排列)回答:- | 
| 
 | 
特别感谢
- 我的父母、我的妻子和帕克希!
- 所有活跃的贡献者/Visual C++ 论坛 [CodeProject] 的成员,没有他们,这篇文章就不会问世。
本系列的其他文章
- 45 天系列:CodeProject VC++ 论坛问答 - VI
- 45 天系列:CodeProject VC++ 论坛问答 - V
- 45天系列:CodeProject VC++ 论坛问答 - IV
- 45 天系列:CodeProject VC++ 论坛问答 - I
历史
- 2012年6月22日:发布于 CodeProject。
- 2012年6月21日:开始撰写本文。



