为什么PrivateFontCollection AddFontFile引发访问冲突异常? 尝试使用以下代码将自定义字体添加到C++ MFC应用程序: void CMFCApplication1View::OnInitialUpdate() { CFormView::OnInitialUpdate(); // ... // dynamic path std::string test = std::string("Oswald.ttf"); std::string path = this->ExePath() + test; std::wstring widestr = std::wstring(path.begin(), path.end()); const wchar_t* widecstr = widestr.c_str(); // hardcoded path std::string s = R"(D:\DEV\C\CTests\MFCApplication1\Debug\Oswald.ttf)"; std::wstring r = std::wstring(s.begin(), s.end()); const wchar_t* t = r.c_str(); Gdiplus::PrivateFontCollection m_fontcollection; Gdiplus::Status nResults = m_fontcollection.AddFontFile(t); // access violation exception thrown here // ... } std::string CMFCApplication1View::ExePath() { char buffer[MAX_PATH]; GetModuleFileNameA(NULL, buffer, MAX_PATH); std::string::size_type pos = std::string(buffer).find_last_of("\\/"); return std::string(buffer).substr(0, pos + 1); } 我是C++的新手(来自C语言)。调用AddFontFile时,代码会引发访问冲突异常,包括硬编码版本和动态版本,但路径的值是正确的

为什么PrivateFontCollection AddFontFile引发访问冲突异常? 尝试使用以下代码将自定义字体添加到C++ MFC应用程序: void CMFCApplication1View::OnInitialUpdate() { CFormView::OnInitialUpdate(); // ... // dynamic path std::string test = std::string("Oswald.ttf"); std::string path = this->ExePath() + test; std::wstring widestr = std::wstring(path.begin(), path.end()); const wchar_t* widecstr = widestr.c_str(); // hardcoded path std::string s = R"(D:\DEV\C\CTests\MFCApplication1\Debug\Oswald.ttf)"; std::wstring r = std::wstring(s.begin(), s.end()); const wchar_t* t = r.c_str(); Gdiplus::PrivateFontCollection m_fontcollection; Gdiplus::Status nResults = m_fontcollection.AddFontFile(t); // access violation exception thrown here // ... } std::string CMFCApplication1View::ExePath() { char buffer[MAX_PATH]; GetModuleFileNameA(NULL, buffer, MAX_PATH); std::string::size_type pos = std::string(buffer).find_last_of("\\/"); return std::string(buffer).substr(0, pos + 1); } 我是C++的新手(来自C语言)。调用AddFontFile时,代码会引发访问冲突异常,包括硬编码版本和动态版本,但路径的值是正确的,c++,mfc,gdi+,C++,Mfc,Gdi+,我错过了什么明显的东西吗 更新 根据我的评论,这就是我现在所做的。这似乎是工作,并没有更多的转换的东西,但正如我所说,这将需要一段时间,直到我确信我这样做是正确的 void CMFCApplication1View::OnInitialUpdate() { CFormView::OnInitialUpdate(); // ... // font path // const wchar_t* path = (this->ExePath() + std:

我错过了什么明显的东西吗


更新

根据我的评论,这就是我现在所做的。这似乎是工作,并没有更多的转换的东西,但正如我所说,这将需要一段时间,直到我确信我这样做是正确的

void CMFCApplication1View::OnInitialUpdate()
{
    CFormView::OnInitialUpdate();

    // ...

    // font path 
    // const wchar_t* path = (this->ExePath() + std::wstring(L"Oswald.ttf")).c_str();
    const wchar_t* path = &(this->ExePath() + std::wstring(L"Oswald.ttf"))[0];

    // Gdiplus init
    ULONG_PTR gdiplusToken; 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // Gdiplus font
    Gdiplus::PrivateFontCollection m_fontcollection;
    Gdiplus::Status nResults = m_fontcollection.AddFontFile(path);

    // ...
}

std::wstring CMFCApplication1View::ExePath() {
    wchar_t buffer[MAX_PATH];
    GetModuleFileNameW(NULL, buffer, MAX_PATH);
    std::wstring::size_type pos = (std::wstring(buffer)).find_last_of(L"\\/");
    return std::wstring(buffer).substr(0, pos + 1);
}
上面使用c_str()或赋值&wstring[0]的转换基于以下答案:

您是否初始化了GDI+?正如Michael Chourdakis所说,我们看不到您在哪里初始化了GDI+。比如:
Gdiplus::GdiplusStartupInput GdiplusStartupInput;ULONG_PTR gdiplusToken;Gdiplus::GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL)
可能不相关,但是隐式的
char
to
wchar\t
强制转换很奇怪。为什么不直接编写
std::wstring r=LR“(D:\DEV\C\CTests\mfcapapplication1\Debug\Oswald.ttf)”例如?类似地,在
ExePath()
中,您应该调用
getModuleFileName
并返回
std::wstring
。一致地使用
wchar\u t
wstring
,而不是随机地混淆
std::string
std::wstring
。操作系统在内部只使用Unicode,因此您强制它使用遗留代码在ANSI和Unicode之间进行转换(这可能根本不会成功)!MichaelChourdakis:就是这样。卡斯托里克斯:成功了,谢谢!我不知道这是必需的。如果你们中有人想发布一个带有初始化代码的答案,我会接受的。zett42:因为在我掌握cpp中的字符串/字符操作之前,我需要吸收大量的东西。会尽力做到你说的,谢谢你的评论
widestr.c_str()
返回一个不属于自己的指针。确保您了解对象生命周期的后果。尝试将窄字符串转换为宽字符串(
std::wstring(s.begin(),s.end())
)时无法转换。它随机丢弃数据。如果您的路径包含非ASCII字符,则看起来很有效,但完全没有乐趣。你将调试这个数小时。要么在整个过程中使用宽字符串,要么执行适当的转换(例如,通过使用MFC/ATL转换宏)。您是否初始化了GDI+?正如Michael Chourdakis所说,我们看不到您在哪里初始化了GDI+。比如:
Gdiplus::GdiplusStartupInput GdiplusStartupInput;ULONG_PTR gdiplusToken;Gdiplus::GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL)
可能不相关,但是隐式的
char
to
wchar\t
强制转换很奇怪。为什么不直接编写
std::wstring r=LR“(D:\DEV\C\CTests\mfcapapplication1\Debug\Oswald.ttf)”例如?类似地,在
ExePath()
中,您应该调用
getModuleFileName
并返回
std::wstring
。一致地使用
wchar\u t
wstring
,而不是随机地混淆
std::string
std::wstring
。操作系统在内部只使用Unicode,因此您强制它使用遗留代码在ANSI和Unicode之间进行转换(这可能根本不会成功)!MichaelChourdakis:就是这样。卡斯托里克斯:成功了,谢谢!我不知道这是必需的。如果你们中有人想发布一个带有初始化代码的答案,我会接受的。zett42:因为在我掌握cpp中的字符串/字符操作之前,我需要吸收大量的东西。会尽力做到你说的,谢谢你的评论
widestr.c_str()
返回一个不属于自己的指针。确保您了解对象生命周期的后果。尝试将窄字符串转换为宽字符串(
std::wstring(s.begin(),s.end())
)时无法转换。它随机丢弃数据。如果您的路径包含非ASCII字符,则看起来很有效,但完全没有乐趣。你将调试这个数小时。在整个过程中使用宽字符串,或执行适当的转换(例如,通过使用MFC/ATL转换宏)。