windows - Typelib Generation og Installation med WiX

Indlæg af Hanne Mølgaard Plasc

Problem



Efter at have spurgt om, hvad Visual Studio gør for at registrere et COM-bibliotek, blev det klart, at VS gjorde to ting til COM-registrering:



  1. Registreret COM-biblioteket

  2. Opretter og registrerer et Type bibliotek



Visual Studio synes at gøre denne registrering ved hjælp af regasm.exe. For første del (den direkte COM-registrering), der bruger tallow eller heat (WiX 2.0 eller WiX 3.0) synes at få alle de grundlæggende COM-registreringsoplysninger korrekt.


Men hvad talg/varme synes ikke at gøre er at oprette en type biblioteksinstallation. Det ville være muligt at oprette en brugerdefineret handling for at gøre dette med et WiX-installationsprogram og regasm.exe, men påberåbning af brugerdefinerede handlinger er ikke bedste praksis, når Det kommer til Microsoft installatørbaserede installationsprogrammer.


Efter yderligere forskning ser det ud til, at en msi har evnen til at generere typebiblioteket ved installationen. Faktisk synes WiX at have direkte støtte til det! I et filelement kan du tilføje et Typelib-element. Faktisk har en artikel herom på wix et eksempel på at udfylde TypeLib-elementet med grænsefladeelementer. [17] [18] [19]


Det ser ud til, at der er mindst to nødvendige attributter til et grænsefladeelement:



  1. Id

  2. Navn



Larry Osterman taler om de andre dele af grænsefladen, der skal registreres for en TypeLib generelt, og denne Interface-indgang ser ud til at tage sig af de enkelte dele. Larry siger, at vi skal angive ProxyStubClassId32 som '{00020424-0000-0000-C000-000000000046}', så vi kan nemt tilføje det. [20]


Hvor skal man hen derfra og hvad man skal udfylde til de forskellige grænseelementer, har jeg stumpet. Jeg har gået videre og tilføjet TypeLib-elementet til min wix-fil, og det kompilerer det med succes. Jeg er lidt clueless om, hvordan du konfigurerer grænsefladeelementerne selv. Hvad skal vi gøre for at udfylde TypeLib-elementet korrekt, og hvilke apps eller værktøjer kan jeg bruge til at få det?


Svaret nedenfor af wcoenen ser lovende ud ... Jeg skal give det et skud.


Opdatering: Indsendt min sidste løsning nedenfor som et svar.

Bedste reference


Her er den dovne mands måde at løse dette problem på: Brug heat fra WiX 3.0.


Hvis du har et type bibliotek genereret automatisk og installeret via regasm, kan heat tage .tlb som et argument i


heat file c:mypath	omy.tlb -out tlb.wxs


Det vil generere alle de typelib- og grænsefladeelementer, du skal registrere. Dette løser ikke problemet med at kende dem på forhånd, og det vil ikke løse problemet med GUID'er, der ændrer sig, når versionen af ​​forsamlingen ændres (selvom grænsefladen ikke gør det - det er den eneste gang du ' re skulle ændre det) men det vil få dig delway der.

Andre referencer 1


Følgende trick kan hjælpe med at høste eventuelle registreringsdatabaseændringer og gøre dem til en wxs-fil, inklusive det typelib-element, du er efter.



  1. Først skal du bringe dit registreringsdatabase tilbage i en tilstand, hvor typebiblioteket ikke var registreret:


    c:WINDOWSMicrosoft.NETFrameworkv2.0.50727
    egasm.exe /tlb /u mylib.dll
    

  2. Eksporter denne ren tilstand af registreringsdatabasen til hklm-before.reg:


    c:WINDOWSsystem32
    eg.exe export HKLM hklm-before.reg
    

  3. Registrér typebiblioteket igen:


    c:WINDOWSMicrosoft.NETFrameworkv2.0.50727
    egasm.exe /tlb mylib.dll
    

  4. Eksporter den nye tilstand af registreringsdatabasen til hklm-after.reg:


    c:WINDOWSsystem32
    eg.exe export HKLM hklm-after.reg
    

  5. Nu har vi to tekstfiler, hklm-before.reg og hklm-after.reg. Opret en diff.reg-fil , som kun indeholder de relevante forskelle mellem disse. Du kan nemt finde forskellene med et forskelligt værktøj. Jeg kan godt lide at bruge diff værktøjet inkluderet i TortoiseSVN, da jeg allerede bruger det hver dag. (WinDiff synes ikke at fungere godt i dette tilfælde på grund af tekstkodningsproblemer.)

  6. Vi kan nu konvertere diff.reg til en .wxs ved at kalde heat.exe med kommandoen reg. (Kræver wix 3.5 eller nyere.)


    heat reg diff.reg -out typelib.wxs
    


Andre referencer 2


Det ser ud til at registrere et Type bibliotek, bedste måde ville være at generere din egen IDL eller ODL fil, som vil indeholde dine GUIDs. Typelib'erne, der genereres direkte fra forsamlingen, er [[i]] afhængige [[/i]] på enhedsversionsnumre: GUID'erne genereres ud fra disse oplysninger, selvom grænsefladen ikke er ændret. Visual Studio bruger regasm til at registrere og generere typelib Under det bruger den RegisterTypeLib, et win32-opkald. Brug af typelib-elementet synes at gøre noget lignende. Ikke godt.


Imidlertid! Oprettelse af typebiblioteket med hånden er smertefuldt. Det er muligt at få disse GUID'er på en anden måde: grave dem ud af typelib og skabe elementerne selv.


Larry Osterman har de oplysninger, der er nødvendige: Der er visse registreringsnøgler, der skal indstilles. Du kan gøre dem med registertabellen (og i Wix3 betyder det RegistryValue-elementer.) Tricket her er at få GUID'erne: Enhver gammel GUID vil ikke fungere. Normalt er at få GUID'erne simpelthen et spørgsmål om at kigge i IDL'en til dit bibliotek (du skrev din egen IDL, right? :)).


Hvis du ikke skrev en IDL eller ODL-fil til kompilering i en typelib, eksisterer de stadig i filen. Microsoft indeholder flere praktiske værktøjer: LoadTypeLibEx og ITypeLib-grænsefladen. Med disse grænseflader kan du gennemse typebiblioteket og få alle slags information. Hvordan gennemser vi biblioteket?


Jeg tog bare et kig på, hvordan Regasm gjorde det! En hurtig dissassemble senere, og vi finder, at regasm er skrevet i C # også. Ære dag. Jeg startede et projekt, og med nogle få brug af erklæringer og en PInvoke senere har vi:


using System.Runtime.InteropServices;          // for struct marshaling 
using System.Runtime.InteropServices.ComTypes; // for the ITypeLib + related types

// TYPELIBATTR lives in two places: Interop and ComTypes, but the one
// in Interop is deprecated.
using TYPELIBATTR = System.Runtime.InteropServices.ComTypes.TYPELIBATTR; 

/// <summary>
/// The registry kind enumeration for LoadTypeLibEx.  This must be made
/// here, since it doesn't exist anywhere else in C# afaik.  This is found
/// here: http://msdn.microsoft.com/en-us/library/ms221159.aspx
/// </summary>
enum REGKIND
{
    REGKIND\_DEFAULT,
    REGKIND\_REGISTER,
    REGKIND\_NONE
}

// and this is how we get the library.
[DllImport("oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
  private static extern void LoadTypeLibEx(string strTypeLibName, REGKIND regKind, out ITypeLib TypeLib);


Puha! Når vi har dette ud, skal vi navigere strukturen. Dette interagerer med uhåndterede ressourcer, så gør dig klar til at være Marshal ing ting rundt.


ITypeLib lib = null;
LoadTypeLibEx(Value, REGKIND.REGKIND\_NONE, out lib);
IntPtr libInfoPtr = IntPtr.Zero;
lib.GetLibAttr(out libInfoPtr);
TYPELIBATTR libInfo = 
    (TYPELIBATTR) Marshal.PtrToStructure(libInfoPtr, typeof(TYPELIBATTR));
int typeCount = lib.GetTypeInfoCount();
for (int i = 0; i < typeCount; ++i)
{
    ITypeInfo info;
    lib.GetTypeInfo(i, out info);
    IntPtr typeDescrPtr = IntPtr.Zero;
    info.GetTypeAttr(out typeDescrPtr);
    TYPELIBATTR type =
        (TYPELIBATTR)Marshal.PtrToStructure(typeDescrPtr, typeof(TYPELIBATTR));
    // get GUID, other info from the specific type
}

lib.ReleaseTLibAttr(libInfoPtr);
libInfoPtr = IntPtr.Zero;


Puha. Så du skal skrive nogle kode for at udtrække informationen. Når du har gjort det, skal du udfylde disse oplysninger i Registy Entries, som angivet af Larry Osterman. [22]


Selvfølgelig kan du undgå det trin ved blot at skrive din egen IDL-fil til at begynde med. Valget i smerte: Det er op til dig!