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.