2010-05-13 4 views
6

Nous avons un assembly .NET (Aspose.Words en fait) et nous voulons que les clients l'utilisent à partir des clients COM sans trop de tracas.Comment obtenir IDL d'un assembly .NET (ou comment convertir TLB en IDL) dans une ligne de commande?

  1. Nous expédions un TLB avec l'ensemble de sorte que le client peut utiliser des langages tels que C++ ou Delphi et ne se soucient pas extraire .TLB eux-mêmes.

  2. Nous expédions également un fichier .IDL avec l'assembly afin que les clients puissent le voir s'ils veulent voir les valeurs d'énumération s'ils sont en train de programmer en ASP par exemple.

  3. Je veux que .TLB et .IDL soient générés par un script de construction. Je peux générer .TLB sans problèmes. Mais je ne peux pas générer .IDL (ou comme alternative convertir .TLB en .IDL) dans une ligne de commande. Je le fais manuellement en utilisant OLEVIEW.EXE ce qui n'est pas sympa.

Entendu à propos de TLIBIMP.EXE de Delphi semble qu'il pourrait le faire, mais il ne semble pas être disponible séparément.

Ainsi, les questions sont les suivantes:

  1. Tout des bruits au-dessus stupide? Comment obtenir .IDL à partir d'un assembly .NET en utilisant une ligne de commande.

Merci.

+0

Vos clients pourraient être en mesure de parcourir les fichiers TLB avec OleView.exe. Il montre le IDL (généré) à partir d'un fichier TLB. –

+0

Copie possible de [Obtenir IDL (pour TLB) à partir d'une DLL COM + quand il n'est pas fourni] (http://stackoverflow.com/questions/18385780/getting-idl-for-tlb-from-a-com-dll- quand-il-est-non-fourni) – DaveInCaz

Répondre

0

La bibliothèque de types est suffisante pour n'importe quelle langue pour utiliser votre serveur. L'IDL serait seulement utile pour générer une bibliothèque de types, que vous fournissez déjà, ou pour générer un fichier d'en-tête C++, qui est beaucoup plus facile à générer avec le #import directive.

Ce qui serait une façon peut-être si vous voulez vraiment faire cela, compilez un petit programme C++ qui utilise # import, fournissez le fichier .tlh généré.

+0

Merci et je vais sérieusement envisager de ne pas fournir IDL. Si vous programmez en VBScript/Perl/PHP/Python et que vous n'utilisez pas un IDE avec un Object Browser TLB, alors .IDL permet de voir comment.Les signatures de méthode exposées NET, par exemple RÉSULTAT Save_2 ([in] BSTR fileName); et valeurs enum HeightRule_AtLeast enum {= 0, HeightRule_Exactly = 1, } HeightRule; Mais je suppose qu'il n'y a pas beaucoup de développeurs là-bas qui font cela et s'ils rendent leur vie déjà si difficile, ils pourront bien lire l'aide pour convertir TLB en IDL si nécessaire. – romeok

2

J'ai écrit ce hack rapide et sale pour extraire l'IDL d'un TLB. Il utilise le même objet COM (au mieux de ma connaissance) qu'OLEVIEW.EXE utilise.

/* 
    Extract the IDL from a tlb file and print it to stdout. 

    The tlb file is analysed by a COM object of type CLSID_ITypeLibViewer and 
    the extracted IDL is shown in a window created by the same object. 

    This program extracts the IDL from that window. 

    Usually Microsoft's OLEViewer (a.k.a. OLE/COM Object Viewer) registers a 
    COM object of that CLSID_ITypeLibViewer (for example inside a dll called 
    IViewers.Dll), I've tested it with: 
    IVIEWERS.DLL "OLE/COM Object Interface Viewer" Version 6.0.6000.16384 

    This software is provided "as-is," without any express or implied warranty. 
*/ 

#define _CRT_SECURE_NO_WARNINGS 

#include <Windows.h> 
#include <atlbase.h> 
#include <comdef.h> 

#include <iostream> 
#include <string> 
#include <ctime> 

const char IDL_window_name[] = "ITypeLib Viewer"; 

const IID IID_IInterfaceViewer = { 0xfc37e5ba, 0x4a8e, 0x11ce, { 0x87, 0x0b, 
            0x08, 0x00, 0x36, 0x8d, 0x23, 0x02 } }; 

const CLSID CLSID_ITypeLibViewer = { 0x57efbf49, 0x4a8b, 0x11ce, { 0x87, 0x0b, 
            0x08, 0x00, 0x36, 0x8d, 0x23, 0x02 } }; 

#define RICHEDIT_CONTROL_ID 0xE901 // found by Spy++ 
#define RICHEDIT_PARENT_ID 0xE900 // found by Spy++ 

#define CHECK(hr) if (FAILED(hr)) { std::wcerr << L"COM error: " << stringify_hr(hr) << L"\n"; return __LINE__; } 

std::string myself; 
std::string tlb; 

// My installation of Microsoft Visual Studio 2010 has a sample folder where 
// I can find the source of OleView: 
// C:\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\1033\VC2010Samples.zip 
// 
// Unzipping the file gives me the solution for Visual Studio 2010 
// C++\MFC\ole\oleview\oleview.sln 
// 
// The following declaration comes from that sample. 
// The sample has also the source for the CLSID_ITypeLibViewer object but 
// unfortunately the method View is not implemented (the code in my sample says 
// "Implement interface viewer UI here."). 
DECLARE_INTERFACE_(IInterfaceViewer, IUnknown) 
{ 
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; 
    STDMETHOD_(ULONG,AddRef) (THIS) PURE; 
    STDMETHOD_(ULONG,Release) (THIS) PURE; 

    STDMETHOD(View) (HWND hwndParent, REFIID riid, LPUNKNOWN punk) PURE; 
}; 

std::string replace_all(const char* txt, const std::string& old_s, const std::string& new_s); 
std::string adapt(const char* txt); 
std::string now(); 
std::wstring stringify_hr(HRESULT hr); 

DWORD WINAPI scrape(LPVOID) 
{ 
    HWND hwnd = 0; 
    int guard = 100; 

    while(guard-- > 0 && (hwnd = ::FindWindowA(0,IDL_window_name)) == 0) { 
     ::Sleep(100); 
    } 

    if (guard <= 0) { 
     std::cerr << "No window found with name '" << IDL_window_name << "'\n"; 
     return __LINE__; 
    } 

    guard = 100; 
    const size_t sz = 100*1024; 
    char text[sz]; 
    do { 
     HWND parent_hwnd = ::GetDlgItem(hwnd,RICHEDIT_PARENT_ID); 
     if (parent_hwnd == 0) { 
     ::SendMessage(hwnd,WM_CLOSE,0,0); 
     std::cerr << "No parent with ID " << std::hex << "0x" 
        << RICHEDIT_PARENT_ID << " found in window with name '" 
        << IDL_window_name << "'\n"; 
     return __LINE__; 
     } 
     HWND richedit_hwnd = ::GetDlgItem(parent_hwnd,RICHEDIT_CONTROL_ID); 
     if (richedit_hwnd == 0) { 
     ::SendMessage(hwnd,WM_CLOSE,0,0); 
     std::cerr << "No richedit with ID " << std::hex << "0x" 
        << RICHEDIT_CONTROL_ID << " found in window with name '" 
        << IDL_window_name << "'\n"; 
     return __LINE__; 
     } 
     ::GetWindowTextA(richedit_hwnd,text,sz); 
     ::Sleep(100); 
    } while (guard-- > 0 && strlen(text) == 0); 

    if (guard <= 0) { 
     ::SendMessage(hwnd,WM_CLOSE,0,0); 
     std::cerr << "No IDL found in window with name '" 
       << IDL_window_name << "'\n"; 
     return __LINE__; 
    } 

    std::cout << "// IDL extracted from " << tlb << " by tlb2idl (" 
      << myself << ") on " << now() << "\n" << adapt(text); 

    ::SendMessage(hwnd,WM_CLOSE,0,0); 
    return 0; 
} 

int main(int argc, char* argv[]) 
{ 
    myself = argv[0]; 
    if (argc <= 1) { 
     std::cerr << "\nPrint to stdout the IDL extracted from file.tlb\n\nUsage:\n" 
       << myself << " file.tlb\n"; 
     return __LINE__; 
    } 

    DWORD exit_code = 0; 
    CHECK(::CoInitialize(0)); 
    { 
    CComPtr<ITypeLib> ptl; 
    tlb = argv[1]; 
    CHECK(::LoadTypeLib(std::wstring(tlb.begin(),tlb.end()).c_str(), &ptl)); 

    CComPtr<IInterfaceViewer> piv; 
    CHECK(::CoCreateInstance(CLSID_ITypeLibViewer, NULL, CLSCTX_SERVER, 
           IID_IInterfaceViewer, (void**)&piv)); 

    HANDLE th = ::CreateThread(0, 0, scrape, 0, 0, 0); 
    CHECK(piv->View(0,IID_ITypeLib,ptl)); 
    ::WaitForSingleObject(th,1000); 
    ::GetExitCodeThread(th,&exit_code); 
    } 
    ::CoUninitialize(); 
    return exit_code; 
} 

std::string replace_all(const char* txt, const std::string& old_s, const std::string& new_s) 
{ 
    std::string str(txt); 
    size_t start_pos = 0; 
    while((start_pos = str.find(old_s, start_pos)) != std::string::npos) { 
     str.replace(start_pos, old_s.length(), new_s); 
     start_pos += new_s.length(); 
    } 
    return str; 
} 

std::string adapt(const char* txt) 
{ 
    std::string str(replace_all(txt,"\r\n","\n")); 
    return replace_all(str.c_str(),"\r","\n"); 
} 

std::string now() 
{ 
    time_t szClock; 
    time(&szClock); 
    struct tm *newTime = localtime(&szClock); 
    return asctime(newTime); 
} 

std::wstring stringify_hr(HRESULT hr) 
{ 
    return _com_error(hr).ErrorMessage(); 
} 
2

qui est très bien, ne fixent que la fonction now à vs 2012:

std::string now() 
{ 
    char buffer[32]; 
    errno_t errNum; 
    _time32(&aclock); 
    _localtime32_s(&newtime, &aclock); 

    errNum = asctime_s(buffer, 32, &newtime); 

    return buffer; 
} 

doit veiller à ce que vous avez OLEVIEW pas ouvert.

Questions connexes