2016-04-19 2 views
1

Ich habe versucht, Informationen von einer EXE, die in Delphi geschrieben wurde, zu erhalten. Die EXE gibt mir einen Zeiger auf einer seiner Datenstrukturen:Delphi WideString in Visual Studio MFC

Type 
    RecordType = Record 
    St: WideString; 
    Next: Pointer; 
    End; 

Var 
    DataRec: ^RecordType; 

So in Visual Studio MFC ich einen Datentyp deklariert haben, die ähnlich sein sollte:

struct RecordRec 
{ 
    BSTR St; 
    void *Next; 
}; 

RecordRec *DataRec; 

Die Delphi-Hilfe sagt, dass ein Wide ist kompatibel mit einem BSTR, dies funktioniert jedoch nicht. Wenn ich meine St in Debug-Modus aussehen sagt es

"0x0000000000000000 <Bad Ptr> wchar_t *" 

Ich weiß nicht, wie das Äquivalent eines Wide in Visual Studio MFC zu erklären.

Wenn es ein Short ist ich würde erklären:

struct RecordRec 
{ 
    BYTE StLen; 
    char St[255]; 
    void *Next; 
}; 

aber für einen Wide nicht funktioniert und ich, ich glaube wirklich nicht, eine Variable mit ~ 2^30 (1073741824) Zeichen erklären sollte in es.

Was fehlt mir? Ich hoffe wirklich, dass jemand helfen kann.

+3

Pointer .... In dessen Adressraum? Mit welcher Methode wird ein Zeiger gesendet? – MBo

+1

Es ist sehr kompliziert. Die erste Sache ist, dass es einen Windows Service gibt. Der Dienst wird automatisch gestartet und ausgeführt, wenn Windows gestartet wird. Wenn das Delphi-EXE ausgeführt wird, ruft es eine Funktion in einer DLL auf, die Teil des Diensts ist, und übergibt dem Dienst einen Zeiger auf seine Daten. Das Visual Studio MFC-Programm ruft dann eine Funktion in dem Dienst auf, um eine Kopie des Zeigers zu erhalten. Wenn es jedoch zu meinem MFC-Programm kommt, sehe ich Bad Ptr. Das alles funktionierte, wenn ein ShortString verwendet wurde, aber dann wurden die Dinge zu einem WideString aktualisiert und ich weiß nicht, was die entsprechende Deklaration in MFC wäre. – Gary

+1

Fügen Sie alle Details im Fragenhauptteil hinzu. Sie sind von entscheidender Bedeutung. Das Übergeben des WideString-Typs an/von DLL ist ein richtiger Ansatz, aber beschreiben Sie alle Umstände – MBo

Antwort

1

Ein Delphi WideString ist in der Tat ein Wrapper für ein BSTR, aber das bedeutet nicht, dass ein roher BSTR Zeiger wie es ist von Prozess zu Prozess weitergegeben werden kann. Seine Daten müssen marshalled beim Überschreiten von Prozessgrenzen sein. Normalerweise verarbeitet COM das automatisch, aber das Übergeben eines rohen BSTR-Zeigers manuell nicht.

Wenn Sie die Delphi-App nicht ändern können, um einen IPC-sicheren Datenblock für die Zeichendaten bereitzustellen (ähnlich der Problemumgehung ShortString), muss die empfangende App die Daten BSTR manuell marshalieren.Es kann ReadProcessMemory() für diese Verwendung:

  • die 'Länge s innerhalb der Adreßraum des Delphi app (a BSTR' BSTR lesen s Zeichendaten mit einem 4-Byte-Ganzzahl Angabe seiner Länge in wchar_t Elemente vorangestellt ist)
  • ordnen Sie ein wchar_t[] Array der angegebenen Länge innerhalb seines eigenen Adressraums
  • Lesen Sie die Zeichendaten aus dem Adressraum der Delphi-App in das Array in einem eigenen Adressraum.

Zum Beispiel (Fehlerbehandlung der Kürze halber weggelassen):

RecordRec *DataRec = ...; 
std::wstring DataSt; 

if (DataRec->St) 
{ 
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, TheDelphiAppProcessID); 
    int len = 0; 
    SIZE_T numRead = 0; 
    ReadProcessMemory(hProcess, LPBYTE(DataRec->St)-4, &len, 4, &numRead); 
    if (len > 0) 
    { 
     DataSt.resize(len); 
     ReadProcessMemory(hProcess, DataRec->St, &DataSt[0], len*2, &numRead); 
    } 
    CloseHandle(hProcess); 
} 

// use DataSt as needed... 
+1

@RudyVelthuis: Sie lesen diese Dokumentation falsch. Ein 'BSTR' wird * von COM-Funktionen * zugeordnet, wobei ein zentralisierter Systemspeichermanager verwendet wird (was eine der Gründe dafür ist, dass 'WideString' weniger effizient ist als' UnicodeString'), aber die Daten selbst befinden sich im Adressraum der zuweisenden App. wie alles andere auch. Sie können eine 'BSTR' an jede Funktion der App übergeben, die ein' wchar_t * 'als Eingabe akzeptiert und die Funktion wird direkten Zugriff auf die Zeichendaten haben. Die fragliche Delphi-Anwendung ruft eine DLL-Funktion auf, und diese Funktion leitet die Daten an einen separaten Dienstprozess weiter. –

+1

'var b: BSTR; b: = SysAllocString ('Test'); MessageBoxW (0, PWideChar (b), '', MB_OK); SysFreeString (b); 'Dieser Code kann nicht ausgeführt werden, wenn die' BSTR'-Daten nicht im Adressraum des App-Prozesses verfügbar sind, der die Zuweisung des 'BSTR' anfordert. Es spielt keine Rolle, ob COM der verwendete Speichermanager ist, genauso wie es keine Rolle spielt, ob eine Delphi-Zeichenfolge mit BorlandMM vs FastMM vs ScaleMM zugewiesen wird. Die zugewiesenen Daten befinden sich im Speicheradressraum der aufrufenden Anwendung, so dass auf sie zugegriffen werden kann, und sie werden vom Speichermanager * verfolgt *, sodass sie später korrekt freigegeben werden können. –

+1

Wenn ein 'BSTR' innerhalb von COM selbst auf der Systemschicht residierte, dann wäre kein Marshalling erforderlich, um einen' BSTR' über Prozessgrenzen hinweg zu übergeben, der 'BSTR'-Zeiger konnte unverändert übergeben werden (wie ein 'HWND' kann)). Aber das ist nicht der Fall, weil "BSTR" -Zeiger keinen globalen Gültigkeitsbereich haben, sondern Prozessbereich, wie die meisten Speicherzuweisungen.Daher müssen "BSTR" -Daten über Prozessgrenzen hinweg von einem Adressraum zu einem anderen übertragen werden. –

2

Sie verpassen nichts. Delphi's WideString entspricht tatsächlich BSTR. Der Wert, den Sie im Debugger sehen, ist ein Nullzeiger. Delphi würde das als eine leere Zeichenfolge behandeln; Sie sollten es wahrscheinlich genauso behandeln.

+1

aufgerufen wird Aber ich weiß, auf der Delphi-Seite ist es nicht leer. Ich habe es getestet und einen Wert eingegeben, den ich auf der MFC-Seite erwarten würde. – Gary

+2

Dann liegt Ihr Problem woanders. Es ist nichts falsch an dem, was Sie in der Frage angegeben haben. –

1

Sie haben also zwei verschiedene Prozesse - Delphi eins (DP) und VS eins (VSP). Jeder hat eigenen Adressraum, und ein gültiger Zeiger in der DP ist in VSP nicht gültig. Deshalb erscheint <Bad Ptr> (Ausnahme?).

Übrigens, ich habe bemerkt, dass die Adresse in VSP 64-Bit ist. Behandelt Delphi auch 64-Bit?

Sie benötigen eine Art Interprozesskommunikation (IPC) über den gemeinsamen Speicher.

Da Sie die Kontrolle über den Dienst und das MFC-Programm haben, können Sie empfangene Daten in benannte Speicherabbilddatei in DLL speichern, dann wird MFC-Prozess es öffnen und Daten lesen.

+1

@Rudy Velthuis Ich sehe, aber der Autor schreibt: 'EXE übergibt mir einen ** Zeiger ** auf eine seiner Datenstrukturen' und zeigt '^ RecordType'typ – MBo

Verwandte Themen