2014-11-03 73 views
0

我正在用COM Interop寫一個C++/CLI項目來公開VBA客戶端的方法和對象。爲什麼RegAsm在某些方法簽名上添加'W'?

到目前爲止都很好,但是我遇到了一個奇怪的問題:某些方法會導出一個(不需要的)'W'後綴(例如GetUserNameW)!

讓我詳細解釋...

我有一個實用工具類,寫這樣的:

MyUtils.h

#pragma once 

namespace MyApp { 

    [System::Runtime::InteropServices::ComVisible(true)] 
    [System::Runtime::InteropServices::Guid("...guid...")] 
    [System::Runtime::InteropServices::InterfaceType(System::Runtime::InteropServices::ComInterfaceType::InterfaceIsDual)] 
    public interface class IMyUtils 
    { 
     System::String^ CombinePaths(System::String^ path1, System::String^ path2); 
     System::String^ GetDocumentsDirectory(); 
     System::String^ GetMachineName(); 
     System::String^ GetSystemDirectory(); 
     System::String^ GetUserName(); 
    }; 

    [System::Runtime::InteropServices::ComVisible(true)] 
    [System::Runtime::InteropServices::Guid("...another guid...")] 
    [System::Runtime::InteropServices::ClassInterface(System::Runtime::InteropServices::ClassInterfaceType::None)] 
    public ref class MyUtils : IMyUtils 
    { 
    public: 
     MyUtils(); 

     virtual System::String^ CombinePaths(System::String^ path1, System::String^ path2); 

     virtual System::String^ GetDocumentsDirectory(); 

     virtual System::String^ GetMachineName(); 

     virtual System::String^ GetSystemDirectory(); 

     virtual System::String^ GetUserName(); 
    }; 
} 

MyUtils.cpp

#include "stdafx.h" 
#include "MyUtils.h" 

using namespace System; 
using namespace System::Data; 
using namespace System::IO; 
using namespace System::Runtime::InteropServices; 

namespace MyApp 
{ 
    MyUtils::MyUtils() 
    { 
     // Do nothing... 
    } 

    String^ MyUtils::CombinePaths(String^ path1, String^ path2) 
    { 
     return Path::Combine(path1, path2); 
    } 

    String^ MyUtils::GetDocumentsDirectory() 
    { 
     return Environment::GetFolderPath(Environment::SpecialFolder::MyDocuments); 
    } 

    String^ MyUtils::GetMachineName() 
    { 
     return Environment::MachineName; 
    } 

    String^ MyUtils::GetSystemDirectory() 
    { 
     return Environment::SystemDirectory; 
    } 

    String^ MyUtils::GetUserName() 
    { 
     return Environment::UserName; 
    } 
} 

這裏沒什麼困難。

然後,我創建了TLB和使用此命令行註冊程序集:

regasm MyLib.dll /codebase /tlb 

現在,當我嘗試使用對象的VBA客戶端上,我有這樣的:

Dim utils As New MWUtils 

utils.CombinePaths "C:\Windows", "System32" 
utils.GetDocumentsDirectory 
utils.GetMachineName 
utils.GetSystemDirectoryW '<== What? 
utils.GetUserNameW '<== Again? 

注意GetSystemDirectoryGetUserName方法上的'W'後綴!

中介問題:它從哪裏來?

好吧,看看生成的IDL的接口:

[ 
    uuid(...guid...), 
    dual, 
    oleautomation 
] 
interface IMyUtils : IDispatch { 
    [id(0x60020000)] 
    HRESULT CombinePaths(
     [in] BSTR path1, 
     [in] BSTR path2, 
     [out, retval] BSTR* pRetVal 
    ); 
    [id(0x60020001)] 
    HRESULT GetDocumentsDirectory([out, retval] BSTR* pRetVal); 
    [id(0x60020002)] 
    HRESULT GetMachineName([out, retval] BSTR* pRetVal); 
    [id(0x60020003)] 
    HRESULT GetSystemDirectoryW([out, retval] BSTR* pRetVal); 
    [id(0x60020004)] 
    HRESULT GetUserNameW([out, retval] BSTR* pRetVal); 

}; 

很顯然現在的RegAsm工具有改變的方法的簽名,但爲什麼

'W'後綴表示一個Unicode字符串,但這是我第一次看到這種改變!

最終問題#1:爲什麼RegAsm表示這兩種方法的Unicode字符串?

最終問題#2:我該如何抑制這種「改變」?

回答

2

您正在使用Windows winapi正在使用的標識符。像GetUserName()和GetSystemDirectory()一樣。這些winapi函數有兩個版本,W版本採用Unicode字符串,A版本採用傳統的8位字符串。若要使此工作,SDK頭包含重命名GetUserName()爲GetUserNameW()如果UNICODE宏定義。

宏的標準問題是它們沒有選擇性,標識符名爲「GetUserName」將被重命名。包括你的。

兩種基本的方式來解決這個問題:

  • 選取其他的名稱,在客戶端代碼少出事故那種方式,以及當它是用C或C++。
  • 將#include添加到winapi頭文件後添加#undef GetUserName,以便禁用此宏。必要時重複。
+0

非常微妙。 C#中不存在的另一個C++/CLI陷阱。因此,在添加stdafx.h之後,我添加了'#undef GetUserName'和'#undef GetSystemDirectory',但之前添加了MyUtils.h並且它可以正常工作!非常感謝你! – 2014-11-03 14:17:04

1

它不是RegAsm修改你的程序集,它首先被編譯成這樣。

如果您在WINDOWS.H看,你會發現有一個爲每個可以採取一個字符串作爲參數法兩個簽名:FooMethodA,需要一個char*,並FooMethodW,需要一個wchar_t*。 ('A'和'W'代表ASCII和Widechar。)但是,您不需要鍵入尾部'A'或'W',只需輸入方法的名稱即可:這是通過#define完成的。對於採用字符串的每種方法,FooMethod#define編輯爲FooMethodAFooMethodW

由於#define是一個原始文本替換,它會影響一切。包括在您的類中聲明的共享Windows API名稱的方法GetSystemDirectoryGetUserName

爲了解決這個問題,#undef GetSystemDirectory和GetUserName。如果您需要使用這些方法,請明確撥打實際名稱,GetSystemDriectoryWGetUserNameW

+1

'A'用於ANSI而不是ASCII。 – 2014-11-04 01:17:43

相關問題