为 HtmlHelp API 升级这些 c 样式转换的 c++ 方法是什么?
What is the c++ approach for upgrading these c style casts for HtmlHelp API?
为 HtmlHelp
API 升级这些 c 风格转换的 c++ 方法是什么?
void CMeetingScheduleAssistantApp::DisplayHelpTopic(CString strTopic)
{
CString strURL = _T("https://help-msa.publictalksoftware.co.uk/") + strTopic;
if (theApp.UseDownloadedHelpDocumentation())
{
// CHM files use 3 letter suffix
strTopic.Replace(_T(".html"), _T(".htm"));
HtmlHelp((DWORD_PTR)(LPCTSTR)strTopic, HH_DISPLAY_TOPIC);
}
else
ShellExecute(nullptr, nullptr, strURL, nullptr, nullptr, SW_SHOWDEFAULT);
}
具体来说:
HtmlHelp((DWORD_PTR)(LPCTSTR)strTopic, HH_DISPLAY_TOPIC);
回答评论中的问题:
这很奇怪,因为 x86 的官方文档 HtmlHelpA
/ HtmlHelpW
确实指出了不同的调用。
它似乎没有在文档中列为 CWinApp
class 的一部分。
(LPCTSTR)strTopic
呼叫 CString::operator LPCTSTR()
。然后 (DWORD_PTR)
将指针 LPCTSTR 转换为 DWORD_PTR。由于源和目标大小不同,无法从 CString 对象直接转换为 DWORD_PTR。
C++ 类型转换可以与 C 类型转换一样短
HtmlHelp(DWORD_PTR(LPCTSTR(strTopic)), HH_DISPLAY_TOPIC);
MFC CWnd 和 CWinApp 类 具有获取类型 DWORD_PTR
的第一个参数的方法
virtual void HtmlHelp(
DWORD_PTR dwData,
UINT nCmd = 0x000F);
reinterpret_cast
will always trigger a code analysys warning
在那种情况下,您可以发明自己的指针转换函数。聪明的编译器很可能会优化它:
#include <cstring>
template<class D, class T>
D ptr_cast(T* x) {
D rv;
static_assert(sizeof rv == sizeof x);
std::memcpy(&rv, &x, sizeof rv);
return rv;
}
然后
HtmlHelp( ptr_cast<DWORD_PTR>(strTopic.GetString()),
HH_DISPLAY_TOPIC);
在 g++ 和 clang++ 中,显式实例化函数
template DWORD_PTR ptr_cast<DWORD_PTR,char>(char*);
进入汇编代码
unsigned long ptr_cast<unsigned long, char>(char*):
mov rax, rdi
ret
内联和优化后(就像在您的代码中一样),函数调用消失了,只剩下到目标 DWORD_PTR
的 mov
(赋值),这正是跟踪reinterpret_cast
会离开。在 MSVC 中,内联它会产生类似的结果:
lea rdx, OFFSET FLAT:`string'
为 HtmlHelp
API 升级这些 c 风格转换的 c++ 方法是什么?
void CMeetingScheduleAssistantApp::DisplayHelpTopic(CString strTopic)
{
CString strURL = _T("https://help-msa.publictalksoftware.co.uk/") + strTopic;
if (theApp.UseDownloadedHelpDocumentation())
{
// CHM files use 3 letter suffix
strTopic.Replace(_T(".html"), _T(".htm"));
HtmlHelp((DWORD_PTR)(LPCTSTR)strTopic, HH_DISPLAY_TOPIC);
}
else
ShellExecute(nullptr, nullptr, strURL, nullptr, nullptr, SW_SHOWDEFAULT);
}
具体来说:
HtmlHelp((DWORD_PTR)(LPCTSTR)strTopic, HH_DISPLAY_TOPIC);
回答评论中的问题:
这很奇怪,因为 x86 的官方文档 HtmlHelpA
/ HtmlHelpW
确实指出了不同的调用。
它似乎没有在文档中列为 CWinApp
class 的一部分。
(LPCTSTR)strTopic
呼叫 CString::operator LPCTSTR()
。然后 (DWORD_PTR)
将指针 LPCTSTR 转换为 DWORD_PTR。由于源和目标大小不同,无法从 CString 对象直接转换为 DWORD_PTR。
C++ 类型转换可以与 C 类型转换一样短
HtmlHelp(DWORD_PTR(LPCTSTR(strTopic)), HH_DISPLAY_TOPIC);
MFC CWnd 和 CWinApp 类 具有获取类型 DWORD_PTR
的第一个参数的方法virtual void HtmlHelp(
DWORD_PTR dwData,
UINT nCmd = 0x000F);
reinterpret_cast
will always trigger a code analysys warning
在那种情况下,您可以发明自己的指针转换函数。聪明的编译器很可能会优化它:
#include <cstring>
template<class D, class T>
D ptr_cast(T* x) {
D rv;
static_assert(sizeof rv == sizeof x);
std::memcpy(&rv, &x, sizeof rv);
return rv;
}
然后
HtmlHelp( ptr_cast<DWORD_PTR>(strTopic.GetString()),
HH_DISPLAY_TOPIC);
在 g++ 和 clang++ 中,显式实例化函数
template DWORD_PTR ptr_cast<DWORD_PTR,char>(char*);
进入汇编代码
unsigned long ptr_cast<unsigned long, char>(char*):
mov rax, rdi
ret
内联和优化后(就像在您的代码中一样),函数调用消失了,只剩下到目标 DWORD_PTR
的 mov
(赋值),这正是跟踪reinterpret_cast
会离开。在 MSVC 中,内联它会产生类似的结果:
lea rdx, OFFSET FLAT:`string'