DLL 导致"Microsoft Excel has stopped working"但它在 Win32 控制台应用中工作正常

DLL causes "Microsoft Excel has stopped working" but it works fine in Win32 console app

本文关键字:应用 控制台 Win32 工作 Excel Microsoft 导致 has stopped DLL working      更新时间:2023-10-16
这将是

一篇很长的文章,但我不确定需要哪些信息来正确解释这个问题。 我有一个C++ DLL,我正在尝试从 Excel 调用它。 每当我调用它时,其中一个函数都会导致 Excel 崩溃并显示"Microsoft Excel 已停止工作"。

头文件:

#include <string>
namespace XYZ_ProjectWise
{
    class FileOperator
    {
    public:
        static __declspec(dllexport) long __stdcall initialize(std::string dbName);
        static __declspec(dllexport) long __stdcall openDoc(long projectID,long docID);
    };
}

initialize()的功能代码:

long FileOperator::initialize(string dbName)
{
    LPCWSTR user=L"";
    LPCWSTR pwd=L"";
    LPCWSTR schema=L"";
    std::wstring sTemp=std::wstring(dbName.begin(),dbName.end());
    LPCWSTR dbName_L=sTemp.c_str();
    bool resultInit=aaApi_Initialize(AAMODULE_ALL);
    bool resultLogin=aaApi_Login(AAAPIDB_UNKNOWN,dbName_L,user,pwd,schema);
    return 0;
}

垃圾桶产量/出口量:

?initialize@FileOperator@XYZ_ProjectWise@@SGJV?$basic_string@DU?$char_traits@D@std@@V?
$allocator@D@2@@std@@@Z

VBA 中的声明:

Private Declare Function initialize Lib "C:Program Files
(x86)BentleyProjectWisebinXYZ_ProjectWiseDLL.dll" _
Alias "?initialize@FileOperator@XYZ_ProjectWise@@SGJV?$basic_string@DU?
$char_traits@D@std@@V?$allocator@D@2@@std@@@Z" _
(ByVal dbName As String) As Long

它在 VBA 中的调用方式:

Public Sub testDLL()
Dim result As Long
result = initialize("ABC.DEF.GHI.com:PWOPPID_XYZ")
End Sub

奇怪的是,如果我在openDoc()函数中包含initialize()函数代码,dbName硬编码,并按如下方式自行调用openDoc(),则不会发生崩溃:

long __stdcall FileOperator::openDoc(long projectID,long docID)
    {
        LPCWSTR dbName=L"ABC.DEF.GHI.com:PWOPPID_XYZ";
        LPCWSTR user=L"";
        LPCWSTR pwd=L"";
        LPCWSTR schema=L"";    
        bool resultInit=aaApi_Initialize(AAMODULE_ALL);    
        bool resultLogin=aaApi_Login(AAAPIDB_UNKNOWN,dbName,user,pwd,schema);
        long resultOpen=aaApi_OpenDocument(projectID,docID,false);
        return resultOpen;
    }
}

VBA 调用:

Private Declare Function openDoc Lib "C:Program Files 
(x86)BentleyProjectWisebinXYZ_ProjectWiseDLL.dll" _
Alias "?openDoc@FileOperator@XYZ_ProjectWise@@SGJJJ@Z" _
(ByVal projectID As Long, ByVal docID As Long) As Long
Public Sub testDLL()
Dim result As Long
result = openDoc(1799,29)
End Sub

那么,为什么 VBA 调用initialize()崩溃,但 VBA 调用中的相同代码openDoc()工作正常?

明显的问题是C++代码使用了对互操作无效的C++类。VBA 编组器根本无法提供 std::string。仅使用简单的 POD 类型进行互操作。

在C++端,对于字符串参数,接收指向以空结尾的字符数组 const char* 的指针。由于 std::string 有一个接受 const char* 的构造函数,因此很容易使这样的参数适应您的需求。

在 VBA 端,您将字符串参数声明为按值字符串,VBA 封送器将转换为 char*。您已经这样做了,因此您唯一需要的更改是在C++代码中。