1

这将是一篇很长的文章,但我不确定要正确解释这个问题需要哪些信息。我有一个试图从 Excel 调用的 C++ DLL。每当我调用它时,其中一个功能会导致 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;
}

转储箱 /exports 的输出:

?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)\Bentley\ProjectWise\bin\XYZ_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

奇怪的是,如果我在函数中包含initialize()函数代码openDoc(),使用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)\Bentley\ProjectWise\bin\XYZ_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()正常工作呢?

4

1 回答 1

3

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

在 C++ 端,对于字符串参数,接收指向以空字符结尾的字符数组 const char* 的指针。由于 std::string 有一个接受 const char* 的构造函数,因此根据您的需要调整这样的参数很简单。

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

于 2013-10-24T19:10:12.053 回答