DLL导致“Microsoft Excel已停止工作”但它在Win32控制台应用程序中工作正常

时间:2013-10-24 18:58:40

标签: c++ vba visual-studio-2012 dll

这将是一篇很长的帖子,但我不确定需要哪些信息来正确解释这个问题。我有一个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;
}

dumpbin / 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()会崩溃,但是对openDoc()的VBA调用中的相同代码工作得很好?

1 个答案:

答案 0 :(得分:3)

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

在C ++方面,对于字符串参数,接收指向空终止字符数组的指针const char *。由于std :: string有一个接受const char *的构造函数,因此很容易根据需要调整这样的参数。

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