String ByVal, ByRef, BSTR

29/11/2007 - 21:36 von Juergen Thuemmler | Report spam
Hi *.*,

ich habe eine externe Fremd-Dll und von dieser eine für .NET geschriebene
Funktionsdeklaration, bei der ein String übergeben werden muß. Ich habe das
nach VB5/6 transformiert und den String wie in der Vorgabe ByVal übergeben.
Alles bestens. Bei mir und andren. Bei wieder anderen Absturz. Bei Analyse
anderen Codes stellte sich heraus, daß die Funktion an der Stelle einen BSTR
erwartet. Ohne so recht zu wissen, was ich tue, habe ich in der
Funktionsdeklaration von ByVal auf ByRef umgestellt in der Erwartung, daß es
dann bei mir crasht. Aber mitnichten - es funktionert. Noch mehr - es tut
jetzt auch dort, wo es vorher crashte.
Kann mir jemand erklàren, wann/warum es egal ist, ob ich einen String ByVal
oder ByRef übergebe???

Jürgen.
 

Lesen sie die antworten

#1 Thorsten Albers
30/11/2007 - 16:30 | Warnen spam
Juergen Thuemmler schrieb im Beitrag
...
ich habe eine externe Fremd-Dll und von dieser eine für .NET geschriebene

Funktionsdeklaration, bei der ein String übergeben werden muß. Ich habe


das
nach VB5/6 transformiert und den String wie in der Vorgabe ByVal


übergeben.
Alles bestens. Bei mir und andren. Bei wieder anderen Absturz. Bei


Analyse
anderen Codes stellte sich heraus, daß die Funktion an der Stelle einen


BSTR
erwartet. Ohne so recht zu wissen, was ich tue, habe ich in der
Funktionsdeklaration von ByVal auf ByRef umgestellt in der Erwartung, daß


es
dann bei mir crasht. Aber mitnichten - es funktionert. Noch mehr - es tut

jetzt auch dort, wo es vorher crashte.
Kann mir jemand erklàren, wann/warum es egal ist, ob ich einen String


ByVal
oder ByRef übergebe???



Daß da überhaupt irgendwo "alles bestens" sein kann, erstaunt mich sehr: VB
übergibt bei einer Deklaration mit 'As String' in jedem Fall einen 'STR',
also einen ANSI-String, im Falle von 'ByVal' einen Zeiger auf einen STR
(StrPtr(MyString)), im Falle von 'ByRef' einen Zeiger auf einen Zeiger auf
einen STR (VarPtr(MyString)); dabei wird, da VB ja mit UNICODE-Strings
(letztlich auch BSTRs) arbeitet, intern zunàchst eine ANSI-Kopie des
Strings erstellt.
Ein BSTR ist aber ein Zeiger auf einen UNICODE-String. Der von VB
'geschickte' String müßte also in der DLL völlig falsch ankommen und im
geringsten Fall zu Darstellungsproblemen führen.

Daß es das eine oder andere Mal kracht, ließe sich eigentlich leicht
erklàren: Ein BSTR ist ein Zeiger auf einen String >mit einem
Làngenpràfix<. Dieses Làngenpràfix, ein DWORD-Wert, steht unmittelbar vor
dem ersten Zeichen des Strings, der BSTR-Zeiger zeigt aber auf das erste
Zeichen des Strings. Die DLL nimmt jetzt also den von VB erhaltenen Zeiger
und interpretiert das DWORD vor dem ersten Zeichen, auf das dieser Zeiger
zeigt, als Làngenpràfix. Dabei können zwei Crash-Situationen entstehen:
1. VB setzt vor die intern erstellte ANSI-Kopie m.W. >>kein<< Làngenpràfix
(warum auch?). Die DLL greift also mit dem Auslesen des Làngenpràfix
entweder auf nicht allozierten Speicher zu, oder der Wert des gelesenen
Làngenpràfix ist zufàllig und möglicherweise derart, daß bei einem spàteren
Zugriff auf den String der Crash kommt, weil über die tatsàchliche
String-Grenze hinaus gelesen oder geschrieben wird.
2. Da VB einen Zeiger auf einen ANSI-String übergibt, die DLL den Zeiger
aber als Zeiger auf einen UNICODE-String interpretiert, wird die DLL immer
auf mehr Speicher zugreifen, als für den String alloziert wurde. Wenn es
nicht zu einem Crash kommt, dann ist das eher Zufall, sprich im Speicher
liegt hinter dem für den String allozierten Speicher weiterer von dem
jeweiligen Prozess allozierter Speicher, dessen Inhalt dann aber natürlich
möglicherweise 'beschàdigt' wird.

Diese Erklàrung ist allerdings nicht mit Deiner Aussage "alles bestens"
vereinbar...

Um einen Zeiger auf einen BSTR zu übergeben, muß die Declare-Anweisung an
entsprechender Stelle 'ByVal ... As Long' enthalten und der Zeiger dann mit
'StrPtr(MyString)' übergeben werden.

-
THORSTEN ALBERS Universitàt Freiburg
albers@
uni-freiburg.de
-

Ähnliche fragen