.NET tut net... (13. Dezember 2004)

Auf meine alten Tage befasse ich mich doch tatsächlich auch noch mit solchen Dingen wie Microsoft .NET. Wenn man mir das während meines Studiums und meiner hyperaktiven Atari-Zeit prophezeit hätte...

Nun denn. Kommt mir neulich so ein häßlicher kleiner Käfer entgegen. Und das kam so: Wenn man Werte vom Typ bool aus "managed code" in "unmanaged code" per Marshaling überträgt, geht das in so richtig großen Stil schief.

Der "managed code" (in C++) stellt einen einfachen Aufruf zur Verfügung mit einem Rückgabewert vom Typ bool. Vereinfachter Beispielcode:

  public __gc __interface IBool {
    bool Foo(void);
  };

  public __gc class Booltest : public IBool 
  {
  public:
    Booltest() {}
    bool Foo(void) { return false; }
  };

Diesen Code übersetzt man in ein Assembly, und daraus produziert man mittels regasm eine Typenbibliothek (tlb-Datei). Gleichzeitig registriert regasm das Assembly; und hinterher werfen wir das Assembly in den Schlund des GAC. Auszug aus der erzeugten Typenbibliothek:

    interface IBool : IDispatch {
        [id(0x60020000)]
        HRESULT Foo([out, retval] unsigned char* pRetVal);
    };

Man beachte, daß der Typ des Rückgabewerts vom bool nach unsigned char abgeändert wurde. Soweit keine Überraschung, denn Nathan erwähnt in seiner COM-Interop-Bibel, daß der Marshaling-Typ für Werte vom Typ bool eben UnmanagedType::U1 ist - also unsigned char.

So richtig übel wird es aber, wenn ich nun Foo() aus einem COM-Client zu rufen versuche. Der COM-Client erzeugt sich einen "smart pointer" vom Typ IBoolPtr und ruft dann Foo():

  bool ret = pBool->Foo();

Nach diesem Aufruf ist allerdings der Stack beschädigt. Läft man im Einzelschritt durch den Code, merkt man, daß der COM-Client denkt, der Rückgabewert sei ein Byte gross; daher legt er auch nur ein Byte auf dem Stack für die Ergebnisvariable ret an. Der Marshaling-Code allerdings schreibt munter vier Bytes!

Das gleiche passiert, wenn man im "managed code" das Attribut [MarshalAs(UnmanagedType::U1)] ausdrücklich anwendet. Microsoft beschreibt im Knowledge-Base-Artikel 823071 einen möglicherweise verwandten Fehler beim Marshaling von bool-Werten, allerdings hilft der vorgeschlagene Hotfix in meinem Fall nicht. Ändere ich den Marshaling-Typ auf U2, wird's noch lustiger: Dann überschreibt der Marshaler zwar keinen Speicher mehr, räumt dafür aber den Stackpointer nach dem Aufruf nicht mehr auf!

Hat jemand Ideen?

(Siehe auch http://groups.google.de/groups?hl=de&lr=&threadm=10gd95ifu6uoe9a%40corp.supernews.com.)

PS: Einige Zeit später hat uns Microsoft bestätigt, daß das in der Tat ein Fehler in .NET 1.1 war. .NET 2.0 macht's nun richtig.



When asked for a TWiki account, use your own or the default TWikiGuest account.


Revision: r1.1 - 28 Jan 2007 - 22:25 - ClausBrod
Blog > BlogOnSoftware20041213
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback