Interop on the fly

Interop on the fly
2021-02-04T08:46:54+01:00
2021-02-17T09:47:04+01:00
2022-08-12T01:00:30+02:00
petersz
Lehetséges úgy használni Intreop dll-eket hogy nem fordítom bele a kódba?
Az megvan hogy a referencia tulajdonságainál ki lehet választani hogy Embed Interop Types = False, ilyenkor mellépakolja a kifordított kód mellé és ezt fel tudom telepíteni a saját kóddal, de ez nekem nem megoldás.
Azt szeretném hogy a feltelepített program könyvtárait használja, vagy abból a saját tool telepítésekor előállítani az Interop dll-t. (pl.: tlbimp-el)
Régóta küzdök a problémával és nehéz elhinni hogy nincs megoldás.
Van valakinek ebben tapasztalata?
Mutasd a teljes hozzászólást!
Mindenképpen furcsa az eset, mivel az implementáció valóban a natív COM-komponensben van.

Az nem világos hogy generálja a .Net az interop dll-t. 

Ezek dokumentálva vannak, ld. a post végén a linkeket.

Adott a natív COM komponensed, ebből a tlbexp.exe generál egy type library-t (.tlb), ami egy híd (típusdefiníció) a natív és a .NET típusok között. A tlbimp.exe pedig ebből generálja a .NET-es interop assembly-t.

Elvileg a Catia COM komponensed regisztrálva van. Amikor hozzáadod referenciaként, a VS is a tlbimp.exe-t futtatja a háttérben, hogy létrehozza az interop assembly-t, és ezt adja hozzá referenciának.

Tehát lényegében egy csak egy interface: ha hozzáadtad egy régebbi Catia verzióét, és közben a Catia ugyan frissül, akkor nem látod az új metódusokat, de a meglévőeknek ugyanúgy működnie kéne. Nincs más logikus magyarázat, mint hogy a Catia a verziók között megváltoztatta a paraméterezést, nem teljesen kompatibilis önmagával.

Esetleg el lehet gondolkodni egy workaround-on, ami nem egyszerű, de működhet: azonosítsd a Catia verziókat, amelyek szükségesek, hogy működjenek, és mindegyiknek legyen meg a saját tlb-ből generált interop assembly-je (akár külön könyvtárakban, hogy ne akadjanak össze).

Induláskor detektáld a futó verziót és dinamikusan töltsd be a szükséges interop assembly-t. Az egészet el tudod fedni a program többi részére egy interface-szel.

Ezt a komplex logikát tudnád kiváltani dynamic-kal, ha működne. Érthetetlen, hogy az miért nem működik.

Linkek:

Interoperability Overview - C# Programming Guide

How to: Generate Interop Assemblies from Type Libraries

Tlbexp.exe (Type Library Exporter)

Tlbimp.exe (Type Library Importer)
Mutasd a teljes hozzászólást!

  • Nekem nem világos, pontosan mire gondolsz, nem tudnál egy konkrét példát írni?

    Pl. Office interop is on the fly működik.
    Mutasd a teljes hozzászólást!
  • using MECMOD; using PARTITF; using System; using System.Windows.Forms; namespace PartDesign3 { public partial class Form1 : Form { private INFITF.Application CATIA; private PartDocument oPartDoc; private Part oPart; private ShapeFactory SFact; public Form1() { InitializeComponent(); } private void Form1_Shown(object sender, EventArgs e) { CATIA = (INFITF.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("CATIA.Application"); oPartDoc = (PartDocument)CATIA.ActiveDocument; oPart = oPartDoc.Part; this.Text += " - " + oPartDoc.Product.get_PartNumber(); SFact = (ShapeFactory)oPart.ShapeFactory; } }
    A referencia beállítását csatolom képben.
    A fenti kód működik, de azt szeretném ha nem a kifordításkor mellérakott Interop.INFITF.dll-t használná, hanem azt valahogy a telepített programból (Ez esetben CATIA, de lehet Excel, vagy más) nyerné ki. 

    Hogyha különböző klienseken használják különböző programverziókkal, akkor is működjön és ne legyen verzióütközés.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • (Előrebocsátom, hogy konkrétan ilyet még nem csináltam, de hátha gondolatot ébresztek.)

    A doksi szerint a GetActiveObject() ProgID paramétert vár (nálad ez a CATIA.Application), és ennek pont az a lényege, hogy verziótól függetlenül megtalálja az adott objektumot a jövőben is.

    Ha különböző programverziókkal is működnie kell, akkor nyilván csak olyan funkciót használhatsz, ami mindben benne van.

    Logikusan ha a minimum verzióra fordítod (amiben benne van a szükséges funkció), annak utána működnie kéne egy újabb verzión is. Ez nem így működik? Mi a hiba?
    Mutasd a teljes hozzászólást!
  • Nagyon szépen összefoglaltad. Ezt csinálom most.
    Mindenhol elindul és fut.
    De különböző magasabb verzióknál bizonyos funkcióknál teljesen váratlan hibák jönnek elő. Van hogy kivételt nem is okoz, csak logikai hibát.
    Ha anélkül hogy bármit változtatnék a kódon, újrafordítom az adott programverzióval, akkor tovább ketyeg hibátlanul. Hát ez nem fér a fejembe
    Mutasd a teljes hozzászólást!
  • Szerintem előfordulhat, hogy a Catia későbbi verziói nem teljesen kompatibilisek a korábbiakkal, és alapvetően ez okozza a gondot.

    Próbáltad dynamic-kal, static compile helyett?

    Itt a kollégák AutoCad-dal szenvednek, hasonló problémával:

    string progId = "AutoCAD.Application"; dynamic acadApp; try { acadApp = Marshal.GetActiveObject(progId); } catch { acadApp = Activator.CreateInstance(Type.GetTypeFromProgID(progId)); }

    Esetleg egyből ugorhatsz a második sorra:

    dynamic acadApp = Activator.CreateInstance(Type.GetTypeFromProgID(progId));
    Mutasd a teljes hozzászólást!
  • Köszönöm a hozzászólást. 
    Kipróbáltam.
    Sajnos nem működött

    dynamic CATIA; const string ProgID = "CATIA.Application"; //CATIA = System.Runtime.InteropServices.Marshal.GetActiveObject(ProgID); CATIA = Activator.CreateInstance(Type.GetTypeFromProgID(ProgID)); dynamic drawingDocument = CATIA.Documents.Open(@"D:\work\FeasibilityAssessment\...\TestDrawingR26.CATDrawing");
    Mindnkét esetben a következő utasításnál COMException hibát kapok.
    System.Runtime.InteropServices.COMException: 'Egy COM-komponens hívása HRESULT E_FAIL hibát adott vissza.'

    Ha működne, akkor is problémásnak érzem hogy nem használható az intellisens ami nélkül elég nehézkes a fejlesztés, de ez most részletkérdés.

    Lehet némi inkompatiblitás a verziók között ahogy írtad, de ugyan azokat az osztályokat ugyan azokkal metódusokkal és paraméterekkel használom. Ha újrafordítom ugyan azt a kódot másik verzióval akkor működik.
    Ezért fér nehezen a fejembe hogy ne lenne megoldás arra hogy ne fordulj bele a kódba az interop dll?!?!

    Valami trükk? Nuget? dll csere a háttérben? Interop dll előállítása telepítéskor? bitek átrakása szemöldökcsipesszel??
    Mutasd a teljes hozzászólást!
  • A Marshal.GetActiveObject() egy meglévő példányt próbál megszerezni, az Activator.CreateInstance() pedig készíteni próbál egyet. Lehet, hogy ez utóbbi a gond.

    Viszont elvileg tudod dynamic-ká cast-olni:

    dynamic obj = Marshal.GetActiveObject("MyLibrary.Application");
    Szerk.: ja, most látom, ezzel is próbáltad, csak a kikommentezett részen automatikusan átsiklottam.
    Mutasd a teljes hozzászólást!
  • Próbáltam a TlbImp.exe-vel előállítani a tlb fájlból a dll-t, és hozzáadni referenciaként a projekthez,

    "c:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\x64\TlbImp.exe" ...\bin\InfTypeLib.tlb /out:"....\INFITF.dll" /machine:Agnostic /namespace: Interop.INFITF

    de nem vette be a VS.

    Azt mondja: Severity Code Description Project File Line Suppression State
    Error CS0012 The type 'Document' is defined in an assembly that is not referenced. You must add a reference to assembly 'Interop.INFITF, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. VersionProofCATIAApp....
    Mutasd a teljes hozzászólást!
  • Kipróbáltam, itt egy iskolapélda Excel-lel. Úgy működik, ahogy a leírás írja.

    dynamic excel = Marshal.GetActiveObject("Excel.Application");
    Ehhez egy már futó példány kell, különben hiba jön:

    System.Runtime.InteropServices.COMException: 'Operation unavailable (Exception from HRESULT: 0x800401E3


    Ha nem fut példány, létre tudsz hozni:

    dynamic excel = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));

    Ezután a meghívott metódusoknak működnie kell, pl.:

    excel.Workbooks.Add();

    Próbáld ki ezzel, hogy ez nálad úgy működik-e, ahogyan kell neki vagy már ez is hibákat dob. Ez utóbbi esetben valami más gond lesz.

    (Néztem a Catia-t, de még demo sincs belőle, amit ki tudnék próbálni.)
    Mutasd a teljes hozzászólást!
  • Maga a CATIA levétele az még működik.(GetActiveObject) (Ha nem fut akkor elindít egyet a háttérben a CreateInstace)

    De a következő objektum metódusa már kifagy. 
    felrakok egy képet (Static OK, dynamic KO)
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Miért cast-olod Application-né, egyáltalán mi az? Gondolom, nem a System.Windows.Forms.Application.

    Próbáltad cast nélkül?
    Mutasd a teljes hozzászólást!
  • Bocsi. Benne maradt a statikus kódból.
    INFITF.Application 
    Az eredmény sajnos ugyan az.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Itt azt írják, hogy a TLB file-ok ott vannak a telepített könyvtárban.

    Pl. INFITF:

    C:\Program Files (x86)\Dassault Systemes\B21\intel_a\code\bin\InfTypeLib.tlb
    Próbáltad, hogy azt hivatkozod be saját generálás helyett? Így is, úgy is függesz a Catiától.

    Így a megfelelő verziót fogod használni minden verzióhoz.

    (Nem csak tippelgetnék, hanem kipróbálnám, ha lehetne, de nem tudom.)
    Mutasd a teljes hozzászólást!
  • Nagyon tetszett az ötlet, kipróbáltam.
    Az lenne benne a jó, ha a tlb-fájlt mindig fel tudnám használni közvetlen a feltelepített CATIA-ból.
    Hozzá lehet adni közvetlen referenciaként.
    A probléma az, hogy amint hozzáadom, már Interop.XXX.dll-ként jelenik meg a kifordított könyvtárban. Tehát nem tudom kicserélni a telepített tlb-re.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Copy local property?
    Mutasd a teljes hozzászólást!


  • System.IO.FileNotFoundException
      HResult=0x80070002
      Message=A(z) „Interop.INFITF, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null” fájl vagy szerelvény, illetve annak egyik függősége nem tölthető be. A rendszer nem találja a megadott fájlt.
      Source=<Cannot evaluate the exception source>
      StackTrace:
    <Cannot evaluate the exception stack trace>
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Oké, és ha bemásolod, akkor is jelentkezik a probléma?

    Tehát használd a Catia által terjesztett tlb-t különböző (újabb) verziókhoz. Célszerű a legkisebb támogatott Catia verzióét hozzáadni.
    Mutasd a teljes hozzászólást!
  • Logikus amit mondasz, de sajnos pont innen indultunk

    ... különböző magasabb verzióknál bizonyos funkcióknál teljesen váratlan hibák jönnek elő. Van hogy kivételt nem is okoz, csak logikai hibát.

    Az nem világos hogy miért kell mindenképpen beledrótoznom a kódba egy adott verzióhoz tartozó tlb (vagy dll) fájlt.
    Én úgy képzelem el hogy ez csak interface-eket tartalmaz, ami leírja hogy milyen osztályok, metódusok milyen paramétereket használnak. Ha a megvalósítás a telepített programnál van, akkor ... ?
    Ha csak hivatkoznék a tlb fájlra és azt telepítéskor cserélgethetném az adott verzióból akkor nem lenne semmi gondom.

    Lehet hogy van valami nyomós ok, csak az én tudásom ehhez kevés...
    Mutasd a teljes hozzászólást!
  • Bizonyára félreértettelek, mert eddig úgy tűnt, te generálod a .tlb-t, és azt rakod hozzá. A javaslat arról szólt, hogy a Catia-val szállítottat rakd hozzá.

    Elvileg nem kéne beledrótozni a .tlb-t, az lényegében pont azt csinálja, amit mondasz, egy proxy. Ld. Office esete.

    Normális esetben annyit kéne csinálni, hogy hozzáadod a Catia-t vagy INFITF-et vagy ilyesmit a COM reference dialog-on (ld. csatolmány), és kész, minden jövőbeli verzióval működnie kéne (nyilván amennyiben a gyártó kompatibilis marad magával).

    Alternatívaként lehet ezt dinamikusan generálni is, ezt próbáltuk eddig, de az is hibára fut nálad.

    Én a helyedben Office-szal kísérleteznék (ld. a fenti példám), hogy az rendesen működik-e. Ha minden lukra fut, Catia support javasolt. Dokumentálj nekik egy konkrét metódust, ami törik két verzió között, megjelölve a pontos verziókat.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Ez a standard, dokumentált módja a fejlesztésnek. Jól ismerem a gyártó hivatalos doksiját és a support (korlátait) is.

    Azt meg tudom érteni hogy továbbfejlesztenek valamit és más van az interface mögött, pl javítottak rajta valamit. Az a fura hogy ezek szerint nem csak az interface van a kódban, hanem az adott verzióhoz tartozó megvalósítás is belekerül a kimásolt Interop dll-be. Hiszen különben nem lehetne inkompatibilitás.

    Minden kódhoz másmilyen Interop.dll-t kapok kifordítás után.

    Az nem világos hogy generálja a .Net az interop dll-t. Lehet-e ezt befolyásolni? Nem ismerem mélységeiben a Marshal-t, meg az InteropServices lehetőségeit.
    Mutasd a teljes hozzászólást!
  • Mindenképpen furcsa az eset, mivel az implementáció valóban a natív COM-komponensben van.

    Az nem világos hogy generálja a .Net az interop dll-t. 

    Ezek dokumentálva vannak, ld. a post végén a linkeket.

    Adott a natív COM komponensed, ebből a tlbexp.exe generál egy type library-t (.tlb), ami egy híd (típusdefiníció) a natív és a .NET típusok között. A tlbimp.exe pedig ebből generálja a .NET-es interop assembly-t.

    Elvileg a Catia COM komponensed regisztrálva van. Amikor hozzáadod referenciaként, a VS is a tlbimp.exe-t futtatja a háttérben, hogy létrehozza az interop assembly-t, és ezt adja hozzá referenciának.

    Tehát lényegében egy csak egy interface: ha hozzáadtad egy régebbi Catia verzióét, és közben a Catia ugyan frissül, akkor nem látod az új metódusokat, de a meglévőeknek ugyanúgy működnie kéne. Nincs más logikus magyarázat, mint hogy a Catia a verziók között megváltoztatta a paraméterezést, nem teljesen kompatibilis önmagával.

    Esetleg el lehet gondolkodni egy workaround-on, ami nem egyszerű, de működhet: azonosítsd a Catia verziókat, amelyek szükségesek, hogy működjenek, és mindegyiknek legyen meg a saját tlb-ből generált interop assembly-je (akár külön könyvtárakban, hogy ne akadjanak össze).

    Induláskor detektáld a futó verziót és dinamikusan töltsd be a szükséges interop assembly-t. Az egészet el tudod fedni a program többi részére egy interface-szel.

    Ezt a komplex logikát tudnád kiváltani dynamic-kal, ha működne. Érthetetlen, hogy az miért nem működik.

    Linkek:

    Interoperability Overview - C# Programming Guide

    How to: Generate Interop Assemblies from Type Libraries

    Tlbexp.exe (Type Library Exporter)

    Tlbimp.exe (Type Library Importer)
    Mutasd a teljes hozzászólást!
  • Nagyon köszönöm a kitartó segítséget!

    Úgy tűnik sikerült olyan dll-eket előállítani amik nem változnak meg a fordítás során. Így felül tudom őket írni az aktuális CATIA verzió DLL-jeivel.

    "c:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\TlbImp.exe" "%CATIAPath%InfTypeLib.tlb" /out:"INFITF.dll" /transform:dispret /machine:Agnostic /noclassmembers /verbose
    Már csak azt kell megoldanom hogy ez dinamikusan futás időben történjen, de ez már így is nagy előrelépés, akár a tool telepítésekor kifordíthatom a telepített CATIA dll-eket a "release" könyvtárba.
    Mutasd a teljes hozzászólást!
abcd