Announcement

Collapse
No announcement yet.

Microsoft.Office.Interop.Excel

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Microsoft.Office.Interop.Excel

    Hallo,

    ich habe eine Anwendung die Microsoft.Office.Interop.Excel Version 10.0.4504.0 benutzt
    Wenn ich jetzt aber das Programm auf einem Rechner starten will der eine andere Excel Versionsnummer hat zB (11.0) kriege ich einen Fehler Meldung.
    Wie kann ich dem Programm so umstellen das er mit allem Excel Versionen zu recht kommt??

    Noch eine Frage, ist der weg durch Microsoft.Office.Interop.Excel
    auf Excel zugreifen richtig oder gibt es da bessere Methoden???

    Vielen Dank

  • #2
    Hallo,
    in derartigen Situationen kapsele ich die Automation-Zugriffe auf Excel/Word in eine mit VB geschriebene Assembly. Denn in VB kann über <b>Option Strict Off</b> die Sache ungemein erleichtert werden :-)<br>
    Das folgende Beispiel ruft Excel über die <b>ProgID</b> auf, so dass die auf dem Rechner installierte Excel-Version keine Rolle spielt:
    <pre style="font-size:10pt;font-family:Courier New;font-weight:normal;font-style:normal;color:#282828;background-color:white;">
    <font color="#0000FF">Dim</font> XlApp <font color="#0000FF">As</font> <font color="#0000FF">Object</font>
    <font color="#0000FF">Dim</font> XlBook <font color="#0000FF">As</font> <font color="#0000FF">Object</font>
    <font color="#0000FF">Dim</font> XlWorkBooks <font color="#0000FF">As</font> <font color="#0000FF">Object</font>
    <font color="#0000FF">Dim</font> XlSheet <font color="#0000FF">As</font> <font color="#0000FF">Object</font>

    <font color="#0000FF">Try</font>
    <font color="#008000">' Versuch 1: Auf laufende Instanz aus der ROT aufschalten</font>
    XlApp = GetObject(, "Excel.<font color="#008080">Application</font>")
    <font color="#0000FF">Catch</font> err <font color="#0000FF">As</font> System.<font color="#008080">Exception</font>
    <font color="#0000FF">Try</font>
    <font color="#008000">' Versuch 2: Neue Instanz anfordern</font>
    XlApp = CreateObject("Excel.<font color="#008080">Application</font>")
    <font color="#0000FF">Catch</font> ex <font color="#0000FF">As</font> <font color="#008080">Exception</font>
    <font color="#008080">MessageBox</font>.Show("Automation-Instanz von Excel kann nicht angefordert werden,", _
    "Fehler", <font color="#008080">MessageBoxButtons</font>.OK, <font color="#008080">MessageBoxIcon</font>.<font color="#0000FF">Error</font>)
    <font color="#0000FF">End</font> <font color="#0000FF">Try</font>

    <font color="#0000FF">End</font> <font color="#0000FF">Try</font>
    XlApp.ScreenUpdating = <font color="#0000FF">False</font>
    XlWorkBooks = XlApp.Workbooks
    XlBook = XlWorkBooks.Add
    XlSheet = XlBook.worksheets(1)
    XlSheet.activate()
    <font color="#008000">' Spaltenüberschrift</font>
    <font color="#0000FF">Dim</font> Col <font color="#0000FF">As</font> <font color="#0000FF">Integer</font>
    <font color="#0000FF">For</font> Col = 1 <font color="#0000FF">To</font> 3
    XlSheet.cells(1, Col).font.bold = <font color="#0000FF">True</font>
    XlSheet.cells(1, Col) = <font color="#0000FF">String</font>.<font color="#008080">Format</font>("Spalte {0}", Col)
    <font color="#0000FF">Next</font> Col
    XlApp.screenupdating = <font color="#0000FF">True</font>
    <font color="#008000">' Benutzer soll mit Excel-GUI arbeiten</font>
    XlApp.usercontrol = <font color="#0000FF">True</font>
    <font color="#0000FF">Dim</font> ApplicationObject <font color="#0000FF">As</font> <font color="#0000FF">Object</font>
    ApplicationObject = XlSheet.application
    <font color="#008000">' Excel anzeigen</font>
    ApplicationObject.visible = <font color="#0000FF">True</font>

    <font color="#008080">MessageBox</font>.Show("Excel ist sichtbar")

    <font color="#008000">' Automation-Instanz von Excel schließen</font>
    XlBook.Close(SaveChanges:=<font color="#0000FF">False</font>)
    XlApp.Quit()
    <font color="#008000">' Verweise auf die Interface-Zeiger freigegeben</font>
    <font color="#008080">Marshal</font>.ReleaseComObject(ApplicationObject)
    <font color="#008080">Marshal</font>.ReleaseComObject(XlSheet)
    <font color="#008080">Marshal</font>.ReleaseComObject(XlBook)
    <font color="#008080">Marshal</font>.ReleaseComObject(XlWorkBooks)
    <font color="#008080">Marshal</font>.ReleaseComObject(XlApp)
    <font color="#0000FF">End</font> <font color="#0000FF">Sub</font>
    </pre&gt

    Comment


    • #3
      Hallo und vielen dank für die Antwort,

      es ist also nicht so dass die Assembly aufwärts kompatibel sind??
      Wenn ich jetzt richtig Ihren Ansatz verstanden habe, rufen Sie dann die im VB geschriebene
      Assembly im C# Programm auf um zu auf Excel zugreifen, wenn ja wie sieht dann denn Aufruf von C# aus, ist das was Sie im Beispiel anzeigen eben die VB Assembly??

      Vielen Dan

      Comment


      • #4
        Hallo,
        eine PIA (Primary Interop Assembly) ist immer exakt an die Version des COM-Objekts gekoppelt, für die sie angelegt wurde. Für eine C#-Anwendung, die universell auf verschiedene Excel-Varianten zugreifen muss, gibt es prinzipiell 3 Alternativen:
        <br>
        1. Mehrere Hilfsassemblies für jede PIA: Das C#-Programm prüft vor dem ersten Zugriff, welche Excel-Version installiert ist. Je nach der vorgefundenen Version wird die "richtige" Assembly geladen. Für jede PIA wird eine separate Aufruf-Assembly bereitsgestellt, wobei alle das gleiche Interface implementieren. Die C#-Anwendung greift nur über das eigene Interface auf die Hilfs-Assemblies zu, so dass nur die Instanzierung abhängig von der Excel-Version ist (aber nicht die späteren Aufrufe).
        <br>
        2. Die C#-Anwendung lagert die Aufrufe über die späte Bindung in eine VB-Assembly aus, wobei bei der späten Bindung die installierte Excel-Version keine Rolle spielt. Die VB-Assembly stellt öffentliche Methoden zur Verfügung, über die das C#-Programm dessen Dienste nutzen kann. Wenn die C#-Anwendung die VB-Assembly als Verweis einbindet, unterscheidet sich der Zugriff nicht von den anderen .NET-Assemblies. Für den Zugriff auf Microsoft Word könnte dies so aussehen:
        <code>
        <font color="#0000FF">Imports</font> System.Runtime.InteropServices

        <font color="#0000FF">Public</font> <font color="#0000FF">Class</font> WordLateBound

        <font color="#0000FF">Private</font> <font color="#0000FF">Const</font> cPROGID <font color="#0000FF">As</font> <font color="#0000FF">String</font> = "Word.<font color="#008080">Application</font>"
        <font color="#0000FF">Private</font> <font color="#0000FF">Const</font> cNEWCAPTION <font color="#0000FF">As</font> <font color="#0000FF">String</font> = "Achtung: Word wird fernbedient !"
        <font color="#0000FF">Private</font> aWordApp <font color="#0000FF">As</font> <font color="#0000FF">Object</font>
        <font color="#0000FF">Private</font> aWordDoc <font color="#0000FF">As</font> <font color="#0000FF">Object</font>
        <font color="#0000FF">Private</font> sOldCaption <font color="#0000FF">As</font> <font color="#0000FF">String</font>
        <font color="#0000FF">Private</font> sCurrentDocName <font color="#0000FF">As</font> <font color="#0000FF">String</font> = <font color="#0000FF">String</font>.<font color="#008080">Empty</font>
        <br>
        <font color="#0000FF">Public</font> <font color="#0000FF">Sub</font> DoWordStart(<font color="#0000FF">ByVal</font> bVisible <font color="#0000FF">As</font> <font color="#008080"><font color="#0000FF">Boolean</font></font>)
        <font color="#008000">' Automation-Instanz über die späte Bindung erzeugen</font>
        aWordApp = CreateObject(cPROGID)
        aWordApp.Visible = bVisible
        <font color="#0000FF">End</font> <font color="#0000FF">Sub</font>
        <br>
        <font color="#0000FF">Public</font> <font color="#0000FF">Function</font> DoNewDoc(<font color="#0000FF">ByVal</font> sDOT <font color="#0000FF">As</font> <font color="#0000FF">String</font>) <font color="#0000FF">As</font> <font color="#0000FF">Integer</font>
        <font color="#0000FF">If</font> <font color="#0000FF">Not</font> aWordApp <font color="#0000FF">Is</font> <font color="#0000FF">Nothing</font> <font color="#0000FF">Then</font>
        aWordApp.Documents.Add(sDOT)
        aWordDoc = aWordApp.ActiveDocument
        sCurrentDocName = aWordDoc.Name
        <font color="#0000FF">Return</font> 1
        <font color="#0000FF">Else</font>
        <font color="#0000FF">Return</font> 0
        <font color="#0000FF">End</font> <font color="#0000FF">If</font>
        <font color="#0000FF">End</font> <font color="#0000FF">Function</font>
        <br>
        <font color="#0000FF">Public</font> <font color="#0000FF">Function</font> DoInsertAtBookmark(<font color="#0000FF">ByVal</font> sBookmark <font color="#0000FF">As</font> <font color="#0000FF">String</font>, <font color="#0000FF">ByVal</font> sTxt <font color="#0000FF">As</font> <font color="#0000FF">String</font>) <font color="#0000FF">As</font> <font color="#0000FF">Integer</font>
        <font color="#0000FF">If</font> <font color="#0000FF">Not</font> aWordDoc <font color="#0000FF">Is</font> <font color="#0000FF">Nothing</font> <font color="#0000FF">Then</font>
        <font color="#0000FF">If</font> aWordDoc.Name = sCurrentDocName <font color="#0000FF">Then</font>
        aWordDoc.Bookmarks(sBookmark).<font color="#008080"><font color="#008080">Range</font></font>.Text = sTxt
        <font color="#0000FF">Else</font>
        <font color="#008000">' Fehler: Es ist nicht mehr das gleiche Dokument aktiv</font>
        <font color="#0000FF">Return</font> 2
        <font color="#0000FF">End</font> <font color="#0000FF">If</font>
        <font color="#0000FF">Return</font> 1
        <font color="#0000FF">Else</font>
        <font color="#008000">' Fehler: Der Verweis auf das Document-Objekt von Word ist ungültig</font>
        <font color="#0000FF">Return</font> 0
        <font color="#0000FF">End</font> <font color="#0000FF">If</font>
        <font color="#0000FF">End</font> <font color="#0000FF">Function</font>
        <br>
        <font color="#0000FF">Public</font> <font color="#0000FF">Function</font> DoPrintCurrentDoc() <font color="#0000FF">As</font> <font color="#0000FF">Integer</font>
        <font color="#0000FF">If</font> <font color="#0000FF">Not</font> aWordDoc <font color="#0000FF">Is</font> <font color="#0000FF">Nothing</font> <font color="#0000FF">Then</font>
        aWordDoc.PrintOut(Background:=<font color="#0000FF">False</font>)
        <font color="#0000FF">Return</font> 1
        <font color="#0000FF">Else</font>
        <font color="#0000FF">Return</font> 0
        <font color="#0000FF">End</font> <font color="#0000FF">If</font>
        <font color="#0000FF">End</font> <font color="#0000FF">Function</font>
        <br>
        <font color="#0000FF">Public</font> <font color="#0000FF">Function</font> DoSaveCloseDoc(<font color="#0000FF">ByVal</font> sDOC <font color="#0000FF">As</font> <font color="#0000FF">String</font>) <font color="#0000FF">As</font> <font color="#0000FF">Integer</font>
        <font color="#0000FF">If</font> <font color="#0000FF">Not</font> aWordApp <font color="#0000FF">Is</font> <font color="#0000FF">Nothing</font> <font color="#0000FF">Then</font>
        aWordDoc.SaveAs(sDOC)
        aWordDoc.Close()
        sCurrentDocName = <font color="#0000FF">String</font>.<font color="#008080">Empty</font>
        <font color="#008080">Marshal</font>.ReleaseComObject(aWordDoc)
        aWordDoc = <font color="#0000FF">Nothing</font>
        <font color="#0000FF">Return</font> 1
        <font color="#0000FF">Else</font>
        <font color="#0000FF">Return</font> 0
        <font color="#0000FF">End</font> <font color="#0000FF">If</font>
        <font color="#0000FF">End</font> <font color="#0000FF">Function</font>
        <br>
        <font color="#0000FF">Public</font> <font color="#0000FF">Sub</font> DoWordStop()
        <font color="#0000FF">If</font> <font color="#0000FF">Not</font> aWordApp <font color="#0000FF">Is</font> <font color="#0000FF">Nothing</font> <font color="#0000FF">Then</font>
        aWordApp.Quit()
        <font color="#008080">Marshal</font>.ReleaseComObject(aWordApp)
        aWordApp = <font color="#0000FF">Nothing</font>
        <font color="#0000FF">End</font> <font color="#0000FF">If</font>
        <font color="#0000FF">End</font> <font color="#0000FF">Sub</font>
        <font color="#0000FF">End</font> <font color="#0000FF">Class</font>
        </code>
        <br>
        3. Die C#-Anwendung implementiert die Aufrufe der späten Bindung selbst (ohne die Mithilfe von VB), allerdings ist dies bei C# generell komplizierter, da man mit <b>InvokeMember</b> (Reflection) hantieren muss. Gerade bei Microsoft Excel oder Word stellt dieser Weg für die dort oftmals verwendeten optionalen oder benannten Parametern eine Herausforderung dar - während VB dank der späten Bindung einfach die "nicht benötigten" Parameter beim Aufruf einer Excel-Methode weglassen darf

        Comment


        • #5
          > eine PIA (Primary Interop Assembly) ist immer exakt an die Version des COM-Objekts gekoppelt, für die sie angelegt wurde. Für eine C#-Anwendung, die universell auf verschiedene Excel-Varianten zugreifen muss, gibt es prinzipiell 3 Alternativen:

          Da bleibt mir nur der Spruch: Alles wird einfacher.

          Welchen Grund hat es das es diese strikte Versionabhänigkeit gibt?
          Keine der 3 Lösungsmöglichkeiten ist für mich eine wirkliche alternative zu der unter Win32 gewohnten Aufwärtskompatiblität auch mit der frühen Bindung

          Comment


          • #6
            Hallo Bernhard,
            früher hat bei Win32 die Versionsnummer eine DLL keine Rolle gespielt, aber unter .NET prüft die CLR penibel die im Manifest der Anwendung vermerkten Versionsnummern (typsicherer Zugriff). Die Medizin gegen die "DLL-Hölle" schmeckt zwangsläufig etwas bitter und hat stellenweise auch unverwünschte Nebenwirkungen.
            <br>
            P.S: Auch früher gab es unerwünschte Nebenwirkungen, und sei es nur deshalb, weil Microsoft in einer Word-Version die eigenen (strengen) Regeln zur Unveränderlichkeit eines einfach veröffentlichten Interfaces nicht eingehalten hat. Diese Gefahrenstelle ist mit einer PIA jetzt geflickt :-

            Comment


            • #7
              > früher hat bei Win32 die Versionsnummer eine DLL keine Rolle gespielt, aber unter .NET prüft die CLR penibel die im Manifest der Anwendung vermerkten Versionsnummern (typsicherer Zugriff). Die Medizin gegen die "DLL-Hölle" schmeckt zwangsläufig etwas bitter und hat stellenweise auch unverwünschte Nebenwirkungen.

              Super. Damit darf ich jetzt jede Office-Version anpassen. Ich hoffe dieser Überprüfung geht nicht soweit das auch jedes ServicePack oder Hotfix mit einer Versionsnnummer vergeben ist.

              > Auch früher gab es unerwünschte Nebenwirkungen, und sei es nur deshalb, weil Microsoft in einer Word-Version die eigenen (strengen) Regeln zur Unveränderlichkeit eines einfach veröffentlichten Interfaces nicht eingehalten hat. Diese Gefahrenstelle ist mit einer PIA jetzt geflickt :-)

              Das ist schon klar. Ein nicht unerheblicher Teil der normalen Arbeitszeit ist ja schon die Fehler in Anwendungen wie Office/IE oder Acrobat Reader zu umschiffen. Und jetzt unter .NET auch noch diese Baustelle zu haben macht die Sache nicht einfacher/besser.

              Den VB-Umweg sehe ich auch nicht als Lösung. Schön und gut das man unter .NET zwar viele Programmiersprachen mischen kann, aber ich bin der Meinung das man dies möglichst vermeiden sollte

              Comment


              • #8
                Hallo Bernhard,
                &gt;..aber ich bin der Meinung das man dies möglichst vermeiden sollte.
                Du bist also ein Verfechter des Grundsatzes "Eine Größe muss allen passen" :-)
                <br>
                Das Problem bei der Automation von den Office-Anwendung ist, dass diese vom Aufbau her zu sehr an die Scriptsprachen bzw. VB angelegt sind. Aus historischen Gründen (siehe Word Basic) verwenden die Automation-Objekte nur als Verweis übergebene Parameter (passed by reference) , so dass C# alle Parameter als <i>ref</i> übergeben muss. Außerdem nutzt Office sehr häufig optionale Parameter (die ebenfalls als Verweis interpretiert werden), was mit C# bei vernünftigen Aufwand schon gar nicht geht. Die Liste aller Problemstellen für C# sieht dann so aus: <br>
                a) Übergabe von ref-Parametern an eine Interface-Methode <br>
                b) Verwendung von optionalen Parametern einer Interface-Methode <br>
                c) Verwendung der späten Bindung bei COM-Objekten, die nur die späte Bindung unterstützen (Beispiel: <i>Dialogs</i>-Objekt aus dem Word-Objektmodell) <br>
                c) Sonderfall Excel: Parametrisierte Eigenschaften<br>
                d) Sonderfall Word: Versteckte Zugriffsmethoden
                <br>
                Aus meiner Sicht ist es reine Selbst-Geißelung, wenn ein Entwickler für den Automation-Aufruf von Office-Anwendungen zu C# greift.

                Comment


                • #9
                  > Du bist also ein Verfechter des Grundsatzes "Eine Größe muss allen passen" :-)
                  Eher: Nicht alles verwenden was möglich ist. Denn dann kennt sich irgendwann keiner mehr aus bzw. muß dann die Syntax von 10 Sprachen kennen.

                  Wieso wurde eigentlich C# keinen ähnliche Möglichkeiten wie VB oder wie es Delphi auch kann spendiert um sowohl frühe als auch späte Bindung zu unterstützen?

                  Hat aber nicht MS für .NET nicht spezielle Wrapper-Klassen bereitgestellt, evtl. ähnlich den Office-Wrappern in Delphi? Oder verwechsel ich da was

                  Comment


                  • #10
                    Hallo Bernhard,
                    weil Microsoft die Sprachen C# und VB nicht als Konkurrenten betrachtet, sondern als <i>Ergänzung</i>. Nicht ohne Grund unterstützt Visual Studio sowohl C# als auch VB (neben C++ und J#).
                    <br>
                    &gt;Hat aber nicht MS für .NET nicht spezielle Wrapper-Klassen bereitgestellt
                    Ja - das folgende Beispiel ist eine von Microsoft bereitgestellte derartige Hilfsklasse für C# für den Aufruf über die späte Bindung:
                    <pre>
                    <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border-top: windowtext 1pt solid; padding-top: 0pt; border-left: windowtext 1pt solid; padding-left: 0pt; border-right: windowtext 1pt solid; padding-right: 0pt; border-bottom: windowtext 1pt solid; padding-bottom: 0pt;"><p style="margin: 0px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> LateBoundComHelper : IDisposable</p><p style="margin: 0px;">{</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span> Type _type;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span> <span style="color: blue;">object</span> _obj;</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span> LateBoundComHelper(<span style="color: blue;">string</span> progId)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>(Type.GetTypeFromProgID(progId, <span style="color: blue;">true</span>))</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span> LateBoundComHelper(Type t)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (t == <span style="color: blue;">null</span>) <span style="color: blue;">throw</span> <span style="color: blue;">new</span> ArgumentNullException(<span style="color: maroon;">"t"</span>);</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _type = t;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _obj = Activator.CreateInstance(t);</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">object</span> Invoke(<span style="color: blue;">string</span> methodName, <span style="color: blue;">params</span> <span style="color: blue;">object</span>[] args)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ThrowIfDisposed();</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> _type.InvokeMember(methodName,</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BindingFlags.InvokeMethod, <span style="color: blue;">null</span>, _obj, args);</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">object</span> <span style="color: blue;">this</span>[<span style="color: blue;">string</span> propertyName]</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">get</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ThrowIfDisposed();</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> _type.InvokeMember(propertyName,</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BindingFlags.GetProperty, <span style="color: blue;">null</span>, _obj, <span style="color: blue;">null</span>);</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">set</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ThrowIfDisposed();</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _type.InvokeMember(propertyName, BindingFlags.SetProperty,</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; <span style="color: blue;">null</span>, _obj, <span style="color: blue;">new</span> <span style="color: blue;">object</span>[] { <span style="color: blue;">value</span> });</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span> <span style="color: blue;">void</span> ThrowIfDisposed()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (_obj == <span style="color: blue;">null</span>) <span style="color: blue;">throw</span> <span style="color: blue;">new</span> ObjectDisposedException(GetType().Name)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span> <span style="color: blue;">void</span> Dispose()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (_obj != <span style="color: blue;">null</span>)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (_type.IsCOMObject)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">while</span> (Marshal.ReleaseComObject(_obj) &gt; 0) ;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">else</span> <span style="color: blue;">if</span> (_obj <span style="color: blue;">is</span> IDisposable) ((IDisposable)_obj).Dispose();</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _obj = <span style="color: blue;">null</span>;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">}</p></div>
                    </pre>
                    Es bleibt aber immer noch der Aufwand beim Aufruf der Hilfsklasse.
                    <br>
                    Die anderen Hilfsklassen sind die PIAs (Primary Interop Assemblies), die gemäß des Knigge nur der Herausgeber des COM-Objekts auf einem Benutzer-Rechner installieren darf (daher auch die Abhängigkeit von der Versionsnummern, denn das Anwendungs-Manifest listet nur die Versionsnummer der PIA auf, aber nicht die der Office-Anwendung). Wenn man sich <b>nicht</b> an die Regeln hält und die PIAs der "falschen" (ältesten) Office-Version auf dem Anwender-Rechner registriert, kann man auch mehrere Office-Anwendunge gleichzeitig bedienen, solange die neuen Office-Versionen die Methoden-Signaturen im Interface nicht ändern (was ja gemäß des COM-Knigge nicht zulässig wäre). In diesem Fall darf der Anwender aber nicht die Reparatur-Funktion der neueren Office-MSI aufrufen, denn diese würde ja die PIA "reparieren" :-) <br>
                    Ich gehe daher immer den sicheren Weg - auch wenn dieser etwas beschwerlicher ist, weil für jede Office-Version eine separate Ansteuerung notwendig wird. Außerdem installiere ich niemals eine fremde PIA selbst, sondern verlasse mich immer auf das originale Setup. Das hat auch den Vorteil, dass dann der Herausgaber (im Fall der Office-Anwendungen als Microsoft) dafür verantwortlich ist, bei einer geänderten PIA über eine im GAC installierte Policy-Assembly auch die Versionsnummern umzubiegen (<i>bindingRedirect</i>), so dass die "alten" Anwendungen trotz der gepatchten PIA immer noch laufen.
                    &#10

                    Comment


                    • #11
                      > weil Microsoft die Sprachen C# und VB nicht als Konkurrenten betrachtet, sondern als Ergänzung. Nicht ohne Grund unterstützt Visual Studio sowohl C# als auch VB (neben C++ und J#).

                      Einer Sprache m.E. solche Einschränkung aufzuerlegen "nur" um die Existenzberechtigung einer anderen Sprache zu erhalten und damit sagen zu können "Seht Ihr könnt wählen was ihr wollt" hallte ich für Blödsinn. Ich kann in Delphi beide wege (frühe/späte Bindung) wählen. Wieso soll jetzt das "viel bessere System" (.NET) mich zwingen um den gleichen Komfort zu haben jetzt neben (der m.E. primären Sprache C#) auch noch eine 2te Sprache zu können?

                      Die "Lösung" über die untergeschobenen PIA's ist aufgrund der schon geschilderten Probleme auch keine.

                      Also bleibt, um nicht alle paar Monate ein Update der Software zu liefern, nur die Verwendung von VB.NET als Wrapper wenn man mit COM-Komponenten per Interop arbeiten muss

                      Comment


                      • #12
                        Hallo Bernhard,
                        man stelle sich nur den Aufschrei in der C-Community vor, wenn eine C-Sprache einen Teil von VB übernimmt :-)<br>
                        Microsoft bedient mit C# und VB primär die eigene Sprach-Klientel, alle "Exoten" (so auch die Delphianer) müssen sich hier als Minderheit unterordnen

                        Comment


                        • #13
                          > man stelle sich nur den Aufschrei in der C-Community vor, wenn eine C-Sprache einen Teil von VB übernimmt :-)
                          Man muß es nur gut verkaufen können. So wie ich C# eher als Java-Basierende Sprache als eine C-Basierende Sprache ansehe.
                          Wieviel "Eigenheiten" wurden von Java übernommen und wieviel von C außer der "Mächtigkeit"

                          Comment


                          • #14
                            Hallo Bernhard,
                            es gibt auch noch eine andere Theorie, wie Java entstanden ist. Das folgende Zitat (das vollständige Original ist über die URL <i>http://dotnetmasters.com/HistoryOfCFamily.htm</i> abrufbar) ist ein Auszug daraus :-)

                            <i>
                            1990 – By this time, all C compilers have turned into C++ compilers. But, since most C++ programs do not use any of the object oriented features of the language, this means in practical terms that bloated code structures with pointers into the operating system are now being compiled with an object-oriented compiler.
                            <br>
                            1990 – After hiring some industry analysts that switched from crack to sniffing glue, Sun decides to create a language called Oak to program set-top television boxes. Since all their programmers have had stilted C syntax imprinted into their DNA by this time, the new language borrows heavily from C and C++ syntax. However the set-top boxes don’t have an operating system for bad pointers to get to, so pointers are eliminated from the language.
                            <br>
                            1994 – Someone at Sun finally realizes what a stupid idea it was to develop a special language just for set-top television boxes. The language is renamed Java and repositioned as an “Internet” language that is supposed to be portable to many platforms. This works well as a marketing campaign, since less than 3% of people in the industry at this time realize what the Internet is, and since hallucinating industry analysts continue to be suckers for the mythical idea of "portability to different platforms".
                            <br>
                            1995 - Sun offers free psychedelic mushrooms to industry analysts, who immediately start writing articles about how Java is the future of programming because of its portability and integration with the Internet.
                            <br>
                            Mid 1996 – 17,468,972 articles appear about how Java is the future of programming. The age of Java applets in web pages begins.
                            <br>
                            Late 1996 – Programmers trying to produce actual web pages with applets that really work commit mass suicide out of frustration and depression. Industry analysts increase their dosage of hallucinogens to compensate.
                            <br>
                            1997 – Taking the advice of hallucinating industry analysts, Corel decides to rewrite all their applications, including WordPerfect, in Java. The end result is the first known word processor that is slower to use than a typewriter.
                            </i&gt

                            Comment

                            Working...
                            X