2016-09-25 1 views
11

Könnten Sie mir bitte helfen zu verstehen, was mit FPU Control Word in meiner Delphi-Anwendung auf Win32-Plattform vorgeht.Warum startet eine Anwendung mit einem anderen FPU-Steuerwort als Default8087CW?

Wenn wir eine neue VCL-Anwendung erstellen, wird das Steuerwort auf 1372h gesetzt. Dies ist das erste, was ich nicht verstehe, warum es 1372h statt 1332h ist, die Default8087CW in System Einheit definiert ist.

Der Unterschied zwischen diesen beiden:

1001101110010 //1372h 
1001100110010 //1332h 

ist das 6. Bit, das Dokumentation nach reserviert ist oder nicht verwendet wird.

Die zweite Frage betrifft CreateOleObject.

function CreateOleObject(const ClassName: string): IDispatch; 
var 
    ClassID: TCLSID; 
begin 
    try 
    ClassID := ProgIDToClassID(ClassName); 
{$IFDEF CPUX86} 
    try 
     Set8087CW(Default8087CW or $08); 
{$ENDIF CPUX86} 
     OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or 
     CLSCTX_LOCAL_SERVER, IDispatch, Result)); 
{$IFDEF CPUX86} 
    finally 
     Reset8087CW; 
    end; 
{$ENDIF CPUX86} 
    except 
    on E: EOleSysError do 
     raise EOleSysError.Create(Format('%s, ProgID: "%s"',[E.Message, ClassName]),E.ErrorCode,0) { Do not localize } 
    end;  
end; 

Die obige Funktion 137Ah Steuerwort ändert, so wird er auf der 3. Bit (Überlauf-Maske) drehen. Ich verstehe nicht, warum es Reset8087CW danach aufruft, anstatt den Zustand des Wortes wieder herzustellen, das war, bevor ich in die Funktion eintrat?

Antwort

5

Das 6. Bit ist reserviert und wird ignoriert. Diese beiden Steuerwörter sind tatsächlich in dem Sinne gleich, dass sich die FPU gleich verhält. Das System setzt zufällig das reservierte Bit. Selbst wenn Sie versuchen, den Wert auf $1332 zu setzen, wird das System es auf $1372 setzen. Egal welchen Wert Sie das 6. Bit haben, es wird immer gesetzt. Also, wenn Sie diese Werte vergleichen, müssen Sie dieses Bit ignorieren. Hier brauchst du dir keine Sorgen zu machen.

Wie für CreateOleObject entschieden die Autoren, dass, wenn Sie diese Funktion verwenden werden, Sie auch Überlauf maskieren werden, wenn Sie das COM-Objekt und tatsächlich darüber hinaus verwenden. Wer weiß warum, und nur für 32-Bit-Code? Wahrscheinlich haben sie eine Reihe von COM-Objekten gefunden, die routinemäßig übergelaufen sind, und so dieses Heftpflaster hinzugefügt. Es war nicht genug, um den Überlauf bei der Erstellung zu maskieren, es muss auch gemacht werden, wenn das Objekt so verwendet wird. Die RTL-Designer entschieden sich dafür, den Überlauf von nun an zu demaskieren.

Oder vielleicht war es ein Fehler. Sie beschlossen, es nicht für 32-Bit-Code zu beheben, weil sich die Leute auf das Verhalten verlassen, aber sie haben sich für 64-Bit-Code entschieden.

In jedem Fall macht diese Funktion nichts besonderes. Sie brauchen es nicht zu benutzen. Sie können Ihre eigenen schreiben, die tun, was Sie wollen.

Die Gleitpunktsteuerung ist ein Problem bei der Arbeit mit Interop. Delphi-Code erwartet unmaskierte Ausnahmen. Code, der mit anderen Tools erstellt wird, maskiert sie normalerweise. Im Idealfall würden Sie Exceptions maskieren, wenn Sie Ihren Delphi-Code aufrufen und sie bei der Rückkehr demaskieren. Erwarten Sie, dass andere Bibliotheken das Steuerwort willkürlich ändern. Beachten Sie auch, dass Set8087CW nicht Thread-sicher ist, was ein massives Problem ist, das Embarcadero seit vielen Jahren ablehnen.

Es gibt keinen einfachen Weg vorwärts. Wenn Sie in Ihrem Programm keinen Fließkommawert verwenden, können Sie Ausnahmen einfach maskieren und wahrscheinlich in Ordnung sein. Andernfalls müssen Sie sicherstellen, dass das Steuerwort an allen Punkten in allen Threads entsprechend gesetzt ist. Im Allgemeinen ist das mit dem Standard Delphi RTL nahezu unmöglich. Ich persönlich gehe damit um, indem ich die wichtigsten Teile des RTL durch threadsichere Versionen ersetze. Ich habe dokumentiert, wie dies in diesem QC-Bericht zu tun ist: QC#107411.

+0

Die Datei wurde in Ihrem QC-Bericht heruntergeladen. Beachten Sie, dass der Dateiname abgeschnitten und ohne Erweiterung ist. Durch das Hinzufügen von '.zip' wurde dieses Problem behoben. Schade, dass @AllenBauer den langen RTL-Bug nicht beheben konnte, während er an Bord war. –

+2

@LURD Ich denke, er wollte, aber das Management würde es nicht zulassen. –

+0

Danke, das habe ich mir gedacht. Es kam mir nicht in den Sinn, dass es keine Möglichkeit gibt, CW auf 1332 Dollar zu setzen. – Wodzu

1

Haftungsausschluss: Ich debuggte die Fragen in Delphi XE.

Erstens, die zweite Frage.

Wenn Sie auf dem Code von Set8087CW betrachten, werden Sie sehen, dass es den neuen FPU CW-Wert in Default8087CW Variable speichert und Reset8087CW wieder FPU CW aus Default8087CW; so der Reset8087CW Anruf nach Set8087CW tut gar nichts, die von

demonstriert
Memo1.Lines.Clear; 
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 1372 
Set8087CW(Default8087CW or $08); 
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 137A 
Reset8087CW; 
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 137A 

offenbar ein Fehler.

Jetzt die erste Frage - es war eine interessante Debugging-Übung.

Default8087CW Der Wert von Delphi VCL Anwendung wird aus hex 1332-1372 von Windows.CreateWindowEx Funktion von TApplication.Create von Classes.AllocateHWnd, genannt von Initialisierungsabschnitt von Controls.pas Einheit genannt genannt verändert.

Schauen Sie sich CreateWindowEx Code - es erklärt, was passiert. Ich möchte es nicht wirklich weiter diskutieren - die FPU-Unterstützung in Delphi ist zu unordentlich und fehlerhaft.

+0

'Reset8087CW' tut tatsächlich etwas. Es setzt das Steuerwort auf das, was aktuell in 'Default8087CW' zu finden ist. Und das könnte sehr wohl Auswirkungen haben, wenn 'CoCreateInstance' das Kontrollwort modifiziert hat, wie es oft vorkommt. Und deine andere Analyse ist falsch. 'CreateWindowEx' ruft' Set8087CW' auf, übergibt jedoch den Wert, der von einem Aufruf an 'Get8087CW' zurückgegeben wird. Viel Glück, dass die FP-Einheit $ 1332 hält. Das lässt dich das einfach nicht tun. –

+0

Also, wenn Sie dies genauer debuggen, werden Sie sehen, dass die FPU in einem Aufruf von '_FpuInit' aus dem Initialisierungsabschnitt von' System' initialisiert wird. Es übergibt alles, was in 'Default8087CW' ist, typischerweise '$ 1332', aber das System erzwingt, dass das 6. Bit gesetzt wird, und so ist der eingestellte Wert' $ 1372'. Nichts mit irgendwelchen Aufrufen von 'CreateWindowEx' zu tun. –

+0

@DavidHeffernan - die Analyse ist korrekt, ich habe verfolgt, wie 'Default8087CW' im Debugger ändert. FPU CW wird nie auf $ 1332 gesetzt, und 'CreateWindowEx' setzt' Default8087CW' auf $ 1372, indem $ $ 1372 von FPU CW gelesen wird. – kludg

Verwandte Themen