提问人:PRinCEKtd 提问时间:5/31/2016 最后编辑:PRinCEKtd 更新时间:6/1/2016 访问量:898
为什么我不能在为 Windows CE 创建的 MFC DLL 中使用 CString 作为返回类型或参数?
Why cannot I use CString as return types or parameters in a MFC DLL made for windows CE?
问:
我有一个为桌面 Windows 项目制作的库。它是由其他人在 MFC VC++ 中完成的,并且工作正常。我将使用库中的一个特定函数作为示例来解释这种情况。
示例函数如下所示:
CString GetFulPath(); // .h file
在 cpp 文件中,
CString CwFolderBrowser::GetFullPath()
{
CString path;
if(this->M_pIDLIST!=NULL)
{
LPTSTR fullPath=path.GetBuffer(MAX_PATH);
::SHGetPathFromIDList(this->M_pIDLIST, fullPath); //ITEMIDLISTからパスを得る
path.ReleaseBuffer();
}
return path;
}
现在,我可以将这个库包含在我的项目中,并执行如下操作:
CwFolderBrowser cFolderBrowser;
if(cFolderBrowser.ShowDialog() == TRUE)
cPath = cFolderBrowser.GetFullPath();
这将显示一个文件夹浏览器对话框,让我选择一个文件夹。它在桌面窗口上运行良好。
目前,我正在使用 Windows CE 设备。我们通过删除不支持的函数和内容来转换该库以用于 Windows CE。该库可以正确编译和构建,而不会出现错误。
接下来,我创建一个 MFC 智能设备项目,包括转换后的库、其 h 文件和 lib 文件,并为 dll 设置适当的目录。项目构建良好。我也可以正确 #include 库的 h 文件。
一旦我调用 GetFullPath 函数,问题就会出现:
cPath = cFolderBrowser.GetFullPath();
它给了我一个未解决的外部链接错误!Intellisense 确实在其列表中显示了此函数,我可以选择它和所有内容。但徒劳无功。
奇怪的是,如果我修改库并更改 GetFullPath() 的签名,如下所示,
LPCTSTR GetFulPath(); // .h file LPCTSTR instead of CString
在 cpp 文件中,
LPCTSTR CwFolderBrowser::GetFullPath() // Return type changed to LPCTSTR
{ // instead of CString
... // Body modified accordingly
}
然后,未解决的外部链接错误消失,它起作用了!
我对这种奇怪的行为感到困惑,因为,我可以在 MFC 智能设备项目中正常使用 CString,并且没有错误。仅当我尝试从库(和其他此类库)dll 调用函数时,才会显示链接错误。同时,BOOL、int 等作为函数返回类型似乎没有问题。
当然,我可以遍历每个库并将 CString 返回的每个实例更改为 LPCTSTR,但这将是一个非常大的更改。我想知道为什么 CString 在桌面上时在项目和 dll 中都能正常工作,而在 Win CE 上,它在项目中工作,但在 DLL 中不起作用(同时,DLL 本身编译良好,无论它使用 CString 还是 LPCTSTR!
所以,基本上,如果可能的话,我想保留函数 CString,并想知道发生这种情况的原因。完全相同的错误也发生在其他库中。
任何帮助都是值得赞赏的。谢谢。
更新:我在 ATL 和 MFC 7.0 上看到一个页面,其中谈到了使用 /Zc:wchat_t 选项。我已经检查了Dll项目以及我的应用程序。两者都使用相同的选项“将wchar_t视为内置类型”作为“是”。因此,该选项匹配。 此外,正如我上面提到的,将函数返回更改为 LPCTSTR 是有效的。错误消失。一切顺利,直到我将返回的 LPCTSTR 转换回 CString。CString 结果为空/Null。这既发生在 dll 代码本身内部,也发生在我的应用程序代码中。
UPDATE2:感谢 Michael 和 Cody,我将函数更改为 LPCTSTR,并确保这些值不会超出范围,然后才能像他们建议的那样使用它们。现在空/Null 问题解决了,我可以正确获取路径值。
剩下的问题是我必须将所有CString函数转换为LPCTSTR,这并不完全可行。我想将函数保留为 CString。
答:
这是一个经典的问题,在 SO 上经常被问到。
这不起作用:
LPCTSTR CwFolderBrowser::GetFullPath()
{
CString path;
if(this->M_pIDLIST!=NULL)
{
LPTSTR fullPath=path.GetBuffer(MAX_PATH);
::SHGetPathFromIDList(this->M_pIDLIST, fullPath);
path.ReleaseBuffer();
}
return (LPCTSTR)path; // << here you return a pointer to the zero
// terminated string in the path object,
} // but path will be deleted as soon as it goes
// out of scope
也许在某些情况下,该函数似乎可以工作,因为已删除的 CString 对象的内存尚未被覆盖。
您应该这样做(为简单起见,此处没有错误处理):
LPCTSTR CwFolderBrowser::GetFullPath(TCHAR *pathbuffer)
{
if(this->M_pIDLIST!=NULL)
{
::SHGetPathFromIDList(this->M_pIDLIST, pathbuffer);
}
return (LPCTSTR)pathbuffer;
}
...
// call like this
TCHAR pathbuffer[MAX_PATH];
GetFullPath(pathbuffer);
评论
pathbuffer
评论