Discussion:
PLPWSTR zu String wandeln
(zu alt für eine Antwort)
Sascha Ott
2009-12-08 19:02:19 UTC
Permalink
Hallo!

Kann mir bitte jemand mal helfen eine PLPWSTR Var zum String zu
wandeln? Ich habs mit diversen @ und ^ versucht - ich komme einfach
nicht drauf :-(

Danke und Gruß,
Sascha
Arno Garrels
2009-12-08 19:30:20 UTC
Permalink
Post by Sascha Ott
Hallo!
Kann mir bitte jemand mal helfen eine PLPWSTR Var zum String zu
nicht drauf :-(
Den Typ PLPWSTR gibt's nicht in der Windows API. Wo und wie ist dieser
Typ definiert? LPWSTR sollte einem PWideChar entsprechen, dann wäre
PLPWSTR vermutlich ein Zeiger auf ein LPWSTR, wenn meine Glaskugel
sich nicht irrt.

--
Arno Garrels
Hubert Seidel
2009-12-08 19:52:55 UTC
Permalink
Hallo Sascha,
Post by Sascha Ott
Kann mir bitte jemand mal helfen eine PLPWSTR Var zum String zu
nicht drauf :-(
procedure TForm1.FormCreate(Sender: TObject);
var
ws:WideString;
pw:PWideChar;
pp:PLPWSTR;
begin
ws:='HelloWorld';
pw:=@ws[1];
pp:=@pw;
Caption := pp^;
end;

Alle Klarheiten beseitigt?

mfg.
Herby
--
http://www.hubert-seidel.eu
Sascha Ott
2009-12-10 09:17:49 UTC
Permalink
Post by Hubert Seidel
Alle Klarheiten beseitigt?
varname^ war auch mein erster Versuch... doch das brachte nur mist
raus... Meine Deklaration des IIinterface, daß diese Var benutzt hat
war falsch. Konnte ich jetzt korrigieren. Danke!

Gruß Sascha
M. Behrendt
2015-12-29 21:22:16 UTC
Permalink
Post by Hubert Seidel
Hallo Sascha,
eine PLPWSTR Var zum String zu wandeln?
procedure TForm1.FormCreate(Sender: TObject);
var
ws:WideString;
pw:PWideChar;
pp:PLPWSTR;
begin
ws:='HelloWorld';
Caption := pp^;
end;
Alle Klarheiten beseitigt?
nein, denn die Frage war genau umgekehrt
hier wird aus einem WideString ein PLPWSTR gemacht
Die Zuweisung Form1.Caption:=pp^ funktioniert jedoch nicht.

Wenn ich nun also einen PLPWSTR gegeben bekomme, wie bei IMMDeviceCollection.GetId, wie kann ich diesen dann in einem printf, caption, Tedit, TLabel verwenden oder einfach in einen "gewöhnlichen String umwandeln?

Danke,
Mike.

MSDN:
"The LPWSTR type is a 32-bit pointer to a string of 16-bit Unicode characters, which MAY be null-terminated. The LPWSTR type specifies a pointer to a sequence of Unicode characters, which MAY be terminated by a null character (usually referred to as "null-terminated Unicode")."
und PLPWSTR ist dann ein Pointer darauf
also ein Pointer auf einen 32bit Pointer auf eine Folge von 16bit Unicode-Zeichen

aber sonst?
früher gabs ein Hammer, ein Meissel und eine Steinplatte...

(achso: ja ich weiss, der thread ist schon älter, aber halt sehr dicht dran an dem was ich brauche)
Peter Below
2015-12-30 07:27:55 UTC
Permalink
Post by Hubert Seidel
Hallo Sascha,
.. >> eine PLPWSTR Var zum String zu wandeln?
Post by Hubert Seidel
procedure TForm1.FormCreate(Sender: TObject);
var
ws:WideString;
pw:PWideChar;
pp:PLPWSTR;
begin
ws:='HelloWorld';
Caption := pp^;
end;
Alle Klarheiten beseitigt?
nein, denn die Frage war genau umgekehrt
hier wird aus einem WideString ein PLPWSTR gemacht
Die Zuweisung Form1.Caption:=pp^ funktioniert jedoch nicht.
Doch, tut sie, aber nur in Delphi-Versionen, in denen String =
UnicodeString ist (also D2009 oder neuer). Hab'S gerade mal in Delphi
Seattle ausprobiert:

procedure TForm1.Button1Click(Sender: TObject);
var
ws:String; // UnicodeString!
pw:PWideChar;
pp:PLPWSTR;
begin
ws:='HelloWorld';
pw:=@ws[1];
pp:=@pw;
Caption := pp^;
end;

Der Ausdruck pp^ gibt einen PWidechar, den man einem (Unicode)String
zuweisen kann.
--
Peter Below
TeamB
M. Behrendt
2015-12-30 14:17:51 UTC
Permalink
Post by Peter Below
Der Ausdruck pp^ gibt einen PWidechar, den man einem (Unicode)String
zuweisen kann.
ich bin noch bei Turbo Delphi 2006 (denn ich heiss ja nich Krösus)
und da geht's nicht
ich bekomm da nur unsinnige Chars
also nur ein Zeichen, das sich bei jedem Aufruf ändert, was es aber definitiv nicht sollte
M. Behrendt
2015-12-30 14:55:20 UTC
Permalink
Post by M. Behrendt
also nur ein Zeichen, das sich bei jedem Aufruf ändert, was es aber definitiv nicht sollte
im Lazarus gehts (Ver. 1.4.2), ellerdings gibts da als Ergebnis von
hr2:=mydevice.GetId(ident);
Form1.ListBox1.Items.add('ident: '+ident^);
nur sowas "ident: ???????????????????????????????????????????????????????"
Hans-Peter Diettrich
2015-12-31 03:12:51 UTC
Permalink
Post by M. Behrendt
Post by M. Behrendt
also nur ein Zeichen, das sich bei jedem Aufruf ändert, was es aber definitiv nicht sollte
Das deutet mir auf eine fehlende Unicode/Ansi Konvertierung hin, ohne
die praktisch jedes 2. Byte Null ist und damit das String-Ende signalisier.
Post by M. Behrendt
im Lazarus gehts (Ver. 1.4.2), ellerdings gibts da als Ergebnis von
hr2:=mydevice.GetId(ident);
Form1.ListBox1.Items.add('ident: '+ident^);
nur sowas "ident: ???????????????????????????????????????????????????????"
Da würde ich die Zeichen (pp^) erst mal an eine UnicodeString Variable
zuweisen, und die an AnsiString Variable zuweisen, das Encocing testen
(könnte RawByteString sein), und dann erst die (Ansi)Strings
aneinanderhängen. Wenn das klappt kannst Du prüfen, welche Schritte
weggelassen werden können.

Hängt die Anzahl der angezeigten Fragezeichen mit der Stringlänge
zusammen? Mit 1 oder 2 '?' pro Zeichen?

Embarcadero hat RawByteString aus Performance-Gründen unsicher gemacht,
und FPC hat das ziemlich genau nachgebildet. Da kann man sich Strings
mit gemischtem Encoding zusammenbasteln, wenn man nicht aufpaßt, die
dann weder gültige Ansi noch Unicode Strings sind. Bei Lazarus bin ich
nicht auf dem Laufenden, aber Unicode in einer Ansi-LCL (UTF-8) ist ein
Minenfeld :-(

Dazu kommt, das Lazarus zumindest im GUI UTF8Strings benutzt, möglichst
noch ohne richtiges Encoding, noch so eine Möglichkeit für ein
falsches/unkonvertiertes Encoding.

DoDi
M. Behrendt
2016-01-01 13:48:19 UTC
Permalink
FROHES NEUES JAHR 2016!
Post by Hans-Peter Diettrich
Post by M. Behrendt
nur sowas "ident: ???????????????????????????????????????????????????????"
Da würde ich die Zeichen (pp^) erst mal an eine UnicodeString Variable
zuweisen, und die an AnsiString Variable zuweisen, das Encocing testen
(könnte RawByteString sein), und dann erst die (Ansi)Strings
aneinanderhängen. Wenn das klappt kannst Du prüfen, welche Schritte
weggelassen werden können.
ich habe nun folgenden Code
[code]
ident:plpwstr;
identUTF8:UTF8String;
identstr:ansistring;

..

hr2:=mydevice.GetId(ident);
identutf8:=ident^^;
//test:=LPWSTR2String(identstr, ident^);
Form1.ListBox1.Items.add(inttostr(i)+' 1 ident: '+(ident^^)+' |2: '+widestring(ident^^)+' |3: '+leftstr(widechartostring(ident^),6)+' |4: '+identutf8+' |5: '+utf8toansi(ident^^)+' |6: '+utf8toansi(identutf8)+' | Status: '+inttostr(Status));
[/code]

in Lazarus bekomme ich
(nach jeder Compilierung und bei Direktaufruf der .exe unterschiedlich)
0 1 ident: ? |2: ? |3: ?????? |4: ? |5: ? |6: ? | Status: 1

in TurboDelphi ist die Ausgabe ähnlich, nur dass "ident^^" manchmal und "widechartostr" immer eine Zugriffverletzung produzieren
außerdem ist das "?" durch ein anderes Zeichen (0xFB bei Schriftart "Symbol") ersetzt
Post by Hans-Peter Diettrich
Hängt die Anzahl der angezeigten Fragezeichen mit der Stringlänge
zusammen? Mit 1 oder 2 '?' pro Zeichen?
nein, anscheinend nicht

ein anderes Programm gibt mir
Device 0:
Identifier {0.0.0.00000000}.{0e037929-3cdd-4870-8293-2cef7e8957cb}
State DEVICE_STATE_ACTIVE 0x01
..
Device 2:
Identifier {0.0.0.00000000}.{579ddd7d-bd66-4e7a-a18c-20db4406ab4c}
State DEVICE_STATE_ACTIVE 0x01
Identifier ist also von fester Länge.
Post by Hans-Peter Diettrich
Embarcadero hat RawByteString aus Performance-Gründen unsicher gemacht,
und FPC hat das ziemlich genau nachgebildet. Da kann man sich Strings
mit gemischtem Encoding zusammenbasteln, wenn man nicht aufpaßt, die
dann weder gültige Ansi noch Unicode Strings sind. Bei Lazarus bin ich
nicht auf dem Laufenden, aber Unicode in einer Ansi-LCL (UTF-8) ist ein
Minenfeld :-(
Dazu kommt, das Lazarus zumindest im GUI UTF8Strings benutzt, möglichst
noch ohne richtiges Encoding, noch so eine Möglichkeit für ein
falsches/unkonvertiertes Encoding.
DoDi
das meiste da klingt für mich wie Bahnhof in bömischen Wäldern
Hans-Peter Diettrich
2016-01-02 02:43:45 UTC
Permalink
Post by M. Behrendt
in Lazarus bekomme ich
(nach jeder Compilierung und bei Direktaufruf der .exe unterschiedlich)
0 1 ident: ? |2: ? |3: ?????? |4: ? |5: ? |6: ? | Status: 1
Dann sind Deine Pointer kaputt, irgendwas ist nicht initialisiert.
Korrigiere das erst mal, bevor Du den Fehler wo anders suchst.

DoDi
Peter Below
2015-12-31 14:11:21 UTC
Permalink
Post by M. Behrendt
Post by Peter Below
Der Ausdruck pp^ gibt einen PWidechar, den man einem (Unicode)String
zuweisen kann.
ich bin noch bei Turbo Delphi 2006 (denn ich heiss ja nich Krösus)
und da geht's nicht
Klar, da ist string noch gleich AnsiString.

Was funktionieren könnte ist

Caption := WideString(pp^);

Bei einer Zuweisung eines WideStrings zu String wird automatisch eine
Konvertierung von Unicode nach ANSI durchgeführt. Dabei können aber
auch Zeichen verlorengehen (werden durch ? ersetzt), wenn es für sie
keine Repräsentation in dem Zeichensatz der aktuellen ANSI Codepage
gibt.

Caption := WidecharToString(pp^);

Macht die Konvertierung explizit, das Ergebniss sollte aber das gleiche
sein.
--
Peter Below
TeamB
M. Behrendt
2016-01-01 13:49:27 UTC
Permalink
Post by Peter Below
Caption := WidecharToString(pp^);
Macht die Konvertierung explizit, das Ergebniss sollte aber das gleiche
sein.
bringt leider auch nix
siehe Antwort an Herrn Diettrich
Peter Below
2016-01-01 14:20:02 UTC
Permalink
Post by M. Behrendt
Post by Peter Below
Caption := WidecharToString(pp^);
Macht die Konvertierung explizit, das Ergebniss sollte aber das
gleiche sein.
bringt leider auch nix
siehe Antwort an Herrn Diettrich
Da ist was oberfaul, das sieht stark danach aus, als wenn der
zurückgegebene Pointer gar kein Pointer auf einen string von Unicode
Zeichen ist sondern dein Device API einen Widestring als container für
binäre Daten missbraucht.

Wie auch immer, Du gehst das ganze Problem total falsch an. Wenn Du
keine vernünftige Dokumentation für das API hast, dass Du da verwenden
willst, mußt Du erstmal herausfinden, wass da eigentlich zurückgegeben
wird. Verlass dich nicht blind auf den Datentyp!

var
pTemp: PBYte;
S: string;

pTemp := pp;

Jetzt kannst Du die Daten ein Byte nach dem anderen ausgeben:

S:= '';
memo1.clear;
try
repeat
if Length(S) >= 60 then begin
memo1.lines.add(S);
S:= '';
end;
S:= S * Format('%2.2x ',[pTemp^]);
Inc(PTemp);
util memo1.gettextlen > 256; // just to have an end condition
except
S:= S + '!end of readable memory';
end;
memo1.lines.add(S);

Der resultierende Hexdump sollte klar machen, ob der Inhalt wirklich
ein Widestring ist oder vielleicht eine GUOID oder sowas.
--
Peter Below
TeamB
M. Behrendt
2016-01-01 16:35:27 UTC
Permalink
Post by Peter Below
Length(S)
Welchen String sollte ich da untersuchen?
Laenge:integer;

length(ident^^) bringt einen Integer-Überlauf! (unter Turbo-Delphi)
Peter Below
2016-01-02 14:07:21 UTC
Permalink
Post by M. Behrendt
Post by Peter Below
Length(S)
Welchen String sollte ich da untersuchen?
S ist eine locale Variable in meinem Beispielkode, die dient nur zur
Accumulation der hexadezimalen Repräsentation der einzelnen Bytes.

"pp" bezieht sich auf deine vorhergehenden Posts, das ist der Pointer,
den deine GetDevice-Funktion geliefert hat.
--
Peter Below
TeamB
Hans-Peter Diettrich
2016-01-02 03:26:17 UTC
Permalink
Post by Peter Below
Da ist was oberfaul, das sieht stark danach aus, als wenn der
zurückgegebene Pointer gar kein Pointer auf einen string von Unicode
Zeichen ist sondern dein Device API einen Widestring als container für
binäre Daten missbraucht.
Wie auch immer, Du gehst das ganze Problem total falsch an. Wenn Du
keine vernünftige Dokumentation für das API hast, dass Du da verwenden
willst, mußt Du erstmal herausfinden, wass da eigentlich zurückgegeben
wird. Verlass dich nicht blind auf den Datentyp!
Mir fällt gerade auf, daß PLP... in C üblicherweise einem var Parameter
in Delphi entspricht. Das würde erklären, warum der nicht-initialisierte
Pointer ident vom Aufruf garnicht initialisiert wird, und weiter wild
ins Gelände zeigt. Zudem würde dann der Aufruf den LPWSTRING irgendwo im
Speicher ablegen, mit beliebigen Folgefehlern.

Die Variable ident müßte dann ein PWideChar oder PWideString sein, deren
*Adresse* als PLPWSTR übergeben wird. AFAIR ist ein Delphi WideString
ein echter Windows/COM BSTR, dann sollte PWideString der richtige Typ sein.

Dann müßte der Aufruf etwa so aussehen:

var
ident: PWideString; // oder PWideChar;
...
GetIdent(@ident); //hier den richtigen Aufruf einsetzen

Wie sieht denn die Daklaration der API-Funktion bisher aus?

DoDi
M. Behrendt
2016-01-02 14:19:34 UTC
Permalink
const
IID_IMMDevice : TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}';
IID_IMMDeviceCollection : TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';

type
IMMDevice = interface(IUnknown)
['{D666063F-1587-4E43-81F1-B948E807363F}'] //[IID_IMMDevice]
function Activate(const refId: TGUID; dwClsCtx: DWORD; pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): HRESULT; stdCall;
function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): HRESULT; stdcall;
function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
function GetState(out State: Integer): HRESULT; stdcall;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
MMDeviceCollection: IMMDeviceCollection;
MMDeviceEnumerator: IMMDeviceEnumerator;
hr,hr1,hr2,hr3: HResult;
count : UINT;
i:UINT;
devicename:string;
myDevice:IMMDevice;
ident:plpwstr;
ident2:PWideString;
identUTF8:UTF8String;
identstr:ansistring;
Status,laenge:integer;
test:boolean;

begin
hr := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, MMDeviceEnumerator);
hr := MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, MMDeviceCollection);
ShowMessage(SysErrorMessage(hr));
hr := MMDeviceCollection.GetCount(count);
form1.caption:=inttostr(count);
if count=0
then Form1.ListBox1.Items.add('keine eRender-Devices gefunden')
else
for i:=0 to count-1 do
begin

hr:=MMDeviceCollection.Item(i,myDevice);
hr1:=mydevice.GetState(Status);
hr2:=mydevice.GetId(ident);
hr3:=mydevice.GetId(@ident2); //Error: Can't assign values to an address
hr3:=mydevice.GetId(ident2^); //Warning: Local variable "ident2" does not seem to be initialized
sowie
Error: Call by var for arg no. 1 has to match exactly: Got "WideString" expected "PLPWStr"

laenge:=length(ident^^);
identutf8:=ident^^;
//test:=LPWSTR2String(identstr, ident^);
Form1.ListBox1.Items.add(inttostr(i)+' 1 ident: '+(ident^^)+' |2: '+widestring(ident^^)+' |3: '+leftstr(widechartostring(ident^),6)+' |4: '+identutf8+' |5: '+utf8toansi(ident^^)+' |6: '+utf8toansi(identutf8)+' | Länge: '+inttostr(laenge)+' | Status: '+inttostr(Status));//identstr+
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
MMDeviceCollection: IMMDeviceCollection;
MMDeviceEnumerator: IMMDeviceEnumerator;
hr: HRESULT;
count : UINT;

begin
hr := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, MMDeviceEnumerator);
if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

MMDeviceCollection := nil; // wegen dem OUT-Parameter *1
hr := MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, MMDeviceCollection);
if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

hr := MMDeviceCollection.GetCount(count);
if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));
end;
M. Behrendt
2016-01-02 16:15:44 UTC
Permalink
beim Debuggen zeigt mir die Überwachung
ident=plpwstr($06BD7818)
ident^=pwidechar($0030007B) <Address 0x30007b out of bounds>
ident^^=Cannot access memory at address 0x30007b

sagt uns das jetzt was?
Sieghard Schicktanz
2016-01-02 19:04:55 UTC
Permalink
Hallo M.,
Post by M. Behrendt
beim Debuggen zeigt mir die Überwachung
ident=plpwstr($06BD7818)
ident^=pwidechar($0030007B) <Address 0x30007b out of bounds>
ident^^=Cannot access memory at address 0x30007b
sagt uns das jetzt was?
Du hast vermutlich eine Derefenzierung zu viel, Dein "ident" _ist_ schon
der (Zeiger auf den) String, "ident^" ist kein Zeiger mehr, sondern der
Anfang des Inhalts des Strings, der anscheinend mit "0x" beginnt (#$30#$78).
--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
M. Behrendt
2016-01-02 20:24:39 UTC
Permalink
"The LPWSTR type is a 32-bit pointer to a string of 16-bit Unicode characters"

und ich habe einen PLPWSTR, also einen Pointer auf einen LPWSTR

das andere Programm gibt mir als Inhalt
"Identifier {0.0.0.00000000}.{57493323-ff2c-417b-ac78-3dc1a3857749}"
zurück, welches irgendwie anders aussieht als "0x..."

wenn
ident^=pwidechar($0030007B) <Address 0x30007b out of bounds>
schon ein Teilstring ist, wie bekomme ich dann den Rest nach "0x30007b" manuell aus dem Speicher ausgelesen
(sry, aber mit Pointer hab ich das nich so...)
Sieghard Schicktanz
2016-01-02 23:50:15 UTC
Permalink
Hallo M.,
Post by M. Behrendt
"The LPWSTR type is a 32-bit pointer to a string of 16-bit Unicode characters"
und ich habe einen PLPWSTR, also einen Pointer auf einen LPWSTR
Offensichtlich nicht. Du kriegst einen "LPWSTR" (>-I) 'raus.
Post by M. Behrendt
das andere Programm gibt mir als Inhalt
"Identifier
{0.0.0.00000000}.{57493323-ff2c-417b-ac78-3dc1a3857749}" zurück, welches
irgendwie anders aussieht als "0x..."
_was_ gibt Dir "das andere Programm" zurück? Den (erwarteten) _Inhalt_ des
"???"-Strings? Oder was soll der Text bedeuten? Das liest sich eher wie
(der Name für) ein(en) Registry-Eintrag.
Post by M. Behrendt
wenn
ident^=pwidechar($0030007B) <Address 0x30007b out of bounds>
Was ja angeblich Dein Debugger behauptet,
Post by M. Behrendt
schon ein Teilstring ist, wie bekomme ich dann den Rest nach "0x30007b"
manuell aus dem Speicher ausgelesen (sry, aber mit Pointer hab ich das
nich so...)
Indem Du einfach ein "Caret" ("^") bei der Zuweisung wegläßt.
--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
M. Behrendt
2016-01-03 19:17:51 UTC
Permalink
Post by Sieghard Schicktanz
Offensichtlich nicht. Du kriegst einen "LPWSTR" (>-I) 'raus.
Post by M. Behrendt
das andere Programm gibt mir als Inhalt
"Identifier
{0.0.0.00000000}.{57493323-ff2c-417b-ac78-3dc1a3857749}" zurück, welches
irgendwie anders aussieht als "0x..."
_was_ gibt Dir "das andere Programm" zurück? Den (erwarteten) _Inhalt_ des
"???"-Strings? Oder was soll der Text bedeuten? Das liest sich eher wie
(der Name für) ein(en) Registry-Eintrag.
das ist der Identifier eines IMMDevice aus der MMDevice-API von Windows
also eines Sound-Ein- oder Ausgabegerätes (Mikrofon, Lautsprecher, S/PDif-in/-out, Line-In, usw.)
https://msdn.microsoft.com/de-de/library/windows/desktop/dd371407%28v=vs.85%29.aspx

(ist gespeichert in der registry (Win8) z.B. für meinen "Line-In" unter
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\{6de313b2-ce1c-4bad-aba7-dcc4117d4f04}

Das größte Problem für mich ist, dass das meiste für solche Dinge in C# geschrieben ist und mir die direkte Verwendung in C# bzw. die Umwandlung nach Delphi nie so recht gelingt.

"HRESULT GetId(
[out] LPWSTR *ppstrId
);
Parameters

ppstrId [out]

Pointer to a pointer variable into which the method writes the address of a null-terminated, wide-character string containing the endpoint device ID. The method allocates the storage for the string. The caller is responsible for freeing the storage, when it is no longer needed, by calling the CoTaskMemFree function. If the GetId call fails, *ppstrId is NULL. For information about CoTaskMemFree, see the Windows SDK documentation.
"
Da scheitere ich schon dran, LPWSTR sollte ein long-pointer auf einen Pointer auf einen Widestring sein, dann wäre aber PLPWSTR schon ein dreifacher Pointer, oder wie?

jedoch lautet die offizielle Deklaration
IMMDevice = interface(IUnknown)
['{D666063F-1587-4E43-81F1-B948E807363F}'] //[IID_IMMDevice]
..
function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
..
end;

und da liegt auch der Fehler, zumindest bei der Verwendung unter Lazarus
ändere ich in "out ppstrId: LPWSTR"

kann ich mit
MMDeviceCollection: IMMDeviceCollection;
MMDeviceEnumerator: IMMDeviceEnumerator;
hr,hr1,hr2,hr3: HResult;
count : UINT;
i:UINT;
myDevice:IMMDevice;
ident:lpwstr;
ident2:PWideChar;

..
MyDevice:=nil;
ident:=nil;
ident2:=nil;
if count=0
then Form1.ListBox1.Items.add('keine eRender-Devices gefunden')
else
for i:=0 to count-1 do
begin
hr:=MMDeviceCollection.Item(i,&myDevice);
hr2:=mydevice.GetId(ident);
ident2:=ident;
hr3:=mydevice.GetId(ident2);
laenge:=length(ident^);
Form1.ListBox1.Items.add(inttostr(i)+' |3: '+widechartostring(ident2)+' |4: '+ident2);

den korrekten Wert auslesen, wobei bei 3: und 4: das gleiche angezeigt wird

die Ausgabe nur von ident^ und widestring(ident^) bringen nur das erste Zeichen des ident2-Strings, also "{"

Wieso muss ich da erst die functions-Deklarationen ändern...?

Ohh man!

Vielen lieben Dank für die richtungsweisenden Antworten!

Mike
Sieghard Schicktanz
2016-01-04 00:41:58 UTC
Permalink
Hallo M.,
Post by M. Behrendt
Post by Sieghard Schicktanz
Offensichtlich nicht. Du kriegst einen "LPWSTR" (>-I) 'raus.
Post by M. Behrendt
das andere Programm gibt mir als Inhalt
...
Post by M. Behrendt
Das größte Problem für mich ist, dass das meiste für solche Dinge in C#
geschrieben ist und mir die direkte Verwendung in C# bzw. die Umwandlung
nach Delphi nie so recht gelingt.
Da muß man halt die internen Darstellungen der diversen Datentypen
einigermaßen kennen, d.h. beides mal anschauen,
Post by M. Behrendt
"HRESULT GetId(
[out] LPWSTR *ppstrId
Ein "out"-Parameter (gibt's ja in Delphi mittlerweise auch) entspricht
einem "VAR" in Pascal und wird mit einer zusätzlichen Referenzstufe
implementiert. In C halt explizit als Pointer auf den Basistyp, der hier
aber selber ein Pointer ("LPWSTR") ist.
Post by M. Behrendt
ppstrId [out]
Pointer to a pointer variable into which the method writes the
address of a null-terminated, wide-character string containing the
Das ist allerdings recht umständlich ausgedrückt, und das Wort "string"
hier bezeichent _nicht_ wie in Delphi üblich die Pointer-Variable, sondern
das direkte Zeichen-Array.
Post by M. Behrendt
SDK documentation. " Da scheitere ich schon dran, LPWSTR sollte ein
long-pointer auf einen Pointer auf einen Widestring sein, dann wäre aber
Nein, "LPWSTR" ist ein Pointer auf ein Array von "(wide) characters".
Da steht "pointer to a pointer variable into which the method writes the
address of a null-terminated, wide-character string" - d.h. der Parameter
ist ein Zeiger auf eine Zeigervariable, in die die "Methode" die _Adresse_
(des Speicherbereichs) eines 0-terminierten "Wide Strings" (Zeichen-Arrays)
schreibt.
Post by M. Behrendt
PLPWSTR schon ein dreifacher Pointer, oder wie?
Das ergibt ich dann daraus - nein.
Post by M. Behrendt
jedoch lautet die offizielle Deklaration
IMMDevice = interface(IUnknown)
['{D666063F-1587-4E43-81F1-B948E807363F}'] //[IID_IMMDevice]
..
function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
D.h. dann wohl, daß das "[out]" in dieser Deklaration nur ein zaghafter
Hinweis darauf ist, daß dieser Parameter ein Ergebnis zurückliefert. Für
die Typisierung hat er keinen Einfluß.
Post by M. Behrendt
und da liegt auch der Fehler, zumindest bei der Verwendung unter Lazarus
ändere ich in "out ppstrId: LPWSTR"
kann ich mit
...
Post by M. Behrendt
den korrekten Wert auslesen, wobei bei 3: und 4: das gleiche angezeigt wird
Das _ist_ ja dann auch das gleiche. Der Cast ist hier eine Null-Operation.
Post by M. Behrendt
die Ausgabe nur von ident^ und widestring(ident^) bringen nur das erste
Zeichen des ident2-Strings, also "{"
Ist klar: ein "PWideChar" ist ein "Pointer to Wide Char", und liefert bei
Dereferenzierung eben einfach einen "Wide Char" ab, also ein einzelnes
Zeichen.
Post by M. Behrendt
Wieso muss ich da erst die functions-Deklarationen ändern...?
Weil in Delphi ein "out"-Parameter eben eine Referenzstufe zusätzlich
impliziert und _bewirkt_. C#-"[out]" und Delphi-"out" sind halt
unterschiedlich definiert. (Was ich auch nur aus den von Dir beschriebenen
Effekten abgeleitet habe - ich habe noch nie mit C# direkt zu tun gehabt.)
Post by M. Behrendt
Vielen lieben Dank für die richtungsweisenden Antworten!
Hauptsache, Du hast den richtigen Weg gefunden!
--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
Hans-Peter Diettrich
2016-01-03 08:37:53 UTC
Permalink
Post by Peter Below
procedure TForm1.Button1Click(Sender: TObject);
var
MMDeviceCollection: IMMDeviceCollection;
MMDeviceEnumerator: IMMDeviceEnumerator;
hr,hr1,hr2,hr3: HResult;
count : UINT;
i:UINT;
devicename:string;
myDevice:IMMDevice;
ident:plpwstr;
Richtig:
ident: lpwstr;
DoDi
Loading...