2017-04-13 55 views
1

我已经成功地写了一个32位Excel RTD server。这是在Excel中加载罚款,并在单元格中输入=RTD(...)的作品。然而,我的64位版本的相同的代码不起作用,我想知道任何方式来调试。我找不到任何相关文档。如何调试Excel的COM服务器加载?

我有一个64位RTD服务器DLL。依赖Walker不会显示任何缺少DLL依赖关系的问题,事实上,如果我链接一个玩具可执行文件,我可以调用该DLL。

DLL已成功注册到regsvr32。

Excel甚至可以看到它,但将其列为“非活动”。过去,在开发32位版本时,这通常是由于缺少DLL依赖项(但没有错误消息)而发生的。如前所述,我可以链接到DLL,并且依赖项步行者不会显示任何问题。

我还能做些什么来调试这个问题?如果它是开源的,我会看看Excel源代码并尝试做它正在做的事情,但显然这不是一个选项。

相同的代码产生一个32位的DLL,32位Excel运行正常。但64位Excel似乎无法使用64位DLL。

+0

你确定它是用regsvr32的64位版本注册的吗?在编写64位COM服务器并且未安装在注册表的右侧时,我遇到了一些问题 – Neil

+1

尝试在调试器下运行DLL,将项目首选项中的目标可执行文件设置为Excel –

回答

0

问题是DLL的注册表项。为了回答我自己的问题(并且在了解了有关COM的更多信息之后(比我想象的更多),最好的方法是编写一个COM客户端应用程序,并尝试以多种方式实例化COM服务器。对于RTD,以下是我使用的示例客户端应用程序。如果任何人有类似的问题,我建议首先尝试使用CoCreateInstance,然后看看你是否可以从ProgId获取CLSID,然后使用ProgId创建实例,因为这是Excel所做的。用你的ProgId替换UUID和"VCRTDServer.RTDFunctions"。代码:

/** 
    Small test program to check that the COM DLL was properly 
    registered 
*/ 

#include <objbase.h> 

#ifndef RTD_ARCH 
# define RTD_ARCH 32 
#endif 

// 
//Here we do a #import on the DLL ,you can also do a #import on the .TLB 
//The #import directive generates two files in the output folders. 
// 
#import "bin\\VCRTDServer.dll" 

#include <iostream> 
#include <stdexcept> 
#include <string> 
#include <tchar.h> 
#include "IRTDServer_h.h" 

using namespace std; 


#define PROGID _T("VCRTDServer.RTDFunctions") 
#define CLSID_STRING _T("{8D2EEA35-CBEB-49b1-8F3E-68C8F50F38D8}") 

const CLSID CLSID_RTD = {0x8D2EEA35, 0xCBEB, 0x49B1, 
         {0x8F, 0x3E, 0x68, 0xC8, 0xF5, 0x0F, 0x38, 0xD8}}; 

const CLSID IID_RTD_UpdateEvent = {0xa43788c1, 0xd91b, 0x11d3, 
            0x8f, 0x39, 0x00, 0xc0, 0x4f, 0x36, 0x51, 0xb8}; 

const CLSID IID_RTD = {0xec0e6191, 0xdb41, 0x11d3, 
         0x8f, 0xe3, 0x00, 0xc0, 0x4f, 0x36, 0x51, 0xb8}; 

static string GetLastErrorAsString(); 
static void run(); 

int main() { 
    try { 
     run(); 
     CoUninitialize(); 
     return 0; 
    } catch(const exception& ex) { 
     cerr << "Error: " << ex.what() << endl; 
     CoUninitialize(); 
     return 1; 
    } 
} 

void run() { 
    cout << "CoInitializing" << endl; 
    CoInitialize(nullptr); 

    // if CoCreateInstance doesn't work, nothing else will 
    // cout << "Checking CoCreateInstance" << endl; 
    // IRtdServer *obj; 
    // const auto hr = CoCreateInstance(CLSID_RTD, 
    //         nullptr, 
    //         CLSCTX_INPROC_SERVER, 
    //         IID_RTD_UpdateEvent, 
    //         (void**)&obj); 
    // if(hr != S_OK) 
    //  throw runtime_error("CoCreateInstance failed: " + GetLastErrorAsString()); 

    cout << "Converting prog id to clsid" << endl; 
    CLSID clsid; 
    const auto ptoc_res = CLSIDFromProgID(L"VCRTDServer.RTDFunctions", &clsid); 
    if(ptoc_res != S_OK) 
     throw runtime_error("CLSID error: " + GetLastErrorAsString()); 
    cout << "Printing out class ID" << endl; 
    cout << "Class ID: " << *((int*)&clsid) << endl; 

    LPOLESTR progId; 
    const auto progIdResult = ProgIDFromCLSID(
     CLSID_RTD, &progId); 
    if(progIdResult != S_OK) 
     throw runtime_error("Prog ID error: " + GetLastErrorAsString()); 

    char buf[40]; 
    WideCharToMultiByte(CP_ACP, NULL, progId, -1, buf, 40, NULL, NULL); 
    cout << "prog id is '" << buf << "'" << endl; 

    cout << "Creating instance" << endl; 
    RTDServerLib::IRtdServerPtr rtdServer; 
    if(rtdServer.CreateInstance(CLSID_RTD) != S_OK) 
     throw runtime_error("Could not create instance: " + 
          GetLastErrorAsString()); 

    cout << "Starting RTD server" << endl; 
    const auto startResult = rtdServer->ServerStart(nullptr); 
    cout << "Start result was: " << startResult << endl; 
} 



//Returns the last Win32 error, in string format. Returns an empty string if there is no error. 
std::string GetLastErrorAsString() { 
    //Get the error message, if any. 
    const auto errorMessageID = ::GetLastError(); 
    if(errorMessageID == 0) 
     return {}; //No error message has been recorded 

    LPSTR messageBuffer = nullptr; 
    size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
           NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, nullptr); 

    std::string message(messageBuffer, size); 

    //Free the buffer. 
    LocalFree(messageBuffer); 

    return message; 
}