2017-04-13 73 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; 
}