Autor Beitrag
Shyran
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Di 22.11.11 14:57 
Huhu ihr lieben Hilfswilligen :-)

Aus einer Application Note von Silabs habe ich die Beschreibung beispielhaft folgender Funktion, die in einer mitgeliferten DLL enthalten ist:

===

  • 5.1. CP210x_GetNumDevices
  • Description: This function returns the number of CP210x devices connected to the host.
  • Supported Devices: CP2101, CP2102, CP2103, CP2104, CP2105
  • Location: CP210x Manufacturing DLL
  • Prototype: CP210x_STATUS CP210x_GetNumDevices( LPDWORD NumDevices )
  • Parameters: 1. NumDevices—Address of a DWORD that will contain the number of devices.
  • Return Value: CP210x_STATUS=CP210x_SUCCESS,
    CP210x_DEVICE_NOT_FOUND,
    CP210x_INVALID_PARAMETER
===

Daraus ergab sich nun für mich folgender Code:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);

  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function CP210x_GetNumDevices(lpdwNumDevices: LPDWORD): integer; cdeclexternal 'CP210xManufacturing.dll';


procedure TForm1.Button1Click(Sender: TObject);
var
status : Cardinal;
dwNumDevices: DWORD;
begin
dwNumDevices:= 0;
status :=CP210x_GetNumDevices(Addr(dwNumDevices));
end;

end.


Aber schon direkt nach Start des Programmes hängt sich dieses auf. Ich vermute mal, ich habe beim Parameter übergeben etwas falsch gemacht, aber wie geht es richtig? Mehr über die DLL als solches weiß ich nicht, aufgrund der Deklaration in der Application Note vermute ich mal, dass diese in C geschrieben wurde.

Liebe Grüße,

-Shyran
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 22.11.11 15:27 
Was heißt "aufhängen"? Kommt eine Fehlermeldung oder was anderes brauchbares? Und iw kommst du auf die Aufrufkonvention cdecl?
Shyran Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Di 22.11.11 16:07 
Nun, aufhängen:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
"VIDPIDder.exe funktioniert nicht mehr ....

Problemsignatur:
  Problemereignisname:  APPCRASH
  Anwendungsname:  VIDPIDder.exe
  Anwendungsversion:  0.0.0.0
  Anwendungszeitstempel:  4ecbab1c
  Fehlermodulname:  CP210xManufacturing.dll
  Fehlermodulversion:  6.0.6002.18327
  Fehlermodulzeitstempel:  4cb73436
  Ausnahmecode:  c0000135
  Ausnahmeoffset:  00009f7d
  Betriebsystemversion:  6.0.6002.2.2.0.256.6
  Gebietsschema-ID:  1031
  Zusatzinformation 1:  9d13
  Zusatzinformation 2:  1abee00edb3fc1158f9ad6f44f0f6be8
  Zusatzinformation 3:  9d13
  Zusatzinformation 4:  1abee00edb3fc1158f9ad6f44f0f6be8


Wenn Du mit dem Fehler etwas anfangen kannst, mehr hätte ich nicht parat.

stdcall hatte ich standardmäßig probiert, mit dem gleichen Ergebnis leider.

-Shyran
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Di 22.11.11 21:12 
Das VAR fehlt vermutlich, in lpdwNumDevices soll ja etwas zurück!!
Jetzt interpretiert die DLL den (zufällig vorhandenen Wert) on lpdwNumDevices als Adresse und verscuht "in die Wüchte" zu schreiben.

function CP210x_GetNumDevices(VAR lpdwNumDevices: LPDWORD): integer; cdecl; external 'CP210xManufacturing.dll';


Gruß
GuaAck

Für diesen Beitrag haben gedankt: Shyran
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 22.11.11 21:59 
Dann aber wohl so:
ausblenden Delphi-Quelltext
1:
function CP210x_GetNumDevices(VAR lpdwNumDevices: DWORD): integer; cdeclexternal 'CP210xManufacturing.dll';					

Für diesen Beitrag haben gedankt: Shyran
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Di 22.11.11 23:21 
wenn die DLL das tut was der Name vermute lässt, ist das gehupft wie gehechtelt
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
Procedure test(lpdwNumDevices: LPDWORD);
begin
   lpdwNumDevices^:= 20;
end;

Procedure test2(Var NumDevices: DWORD);
begin
   test(@NumDevices);
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  t:Dword;
begin
  t := 1;
//  test(Addr(t));
  test2(t);
  Showmessage(IntToStr(t));
end;

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS

Für diesen Beitrag haben gedankt: Shyran
Shyran Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Mi 23.11.11 11:02 
Guten Morgen,

erstmal herzlichen Dank für die bereits investierte Zeit und Mühe an euch um das Thema hier.

Ich habe nun Luckie's Prototyp genutzt wie oben geschrieben und habe ebenso mal bummi's Prozeduren eingebunden. Zumindest der Compiler schimpft nicht mehr, das Programm läuft durch. Allerdings muss ich jezt sagen, dass sich mir der Sinn gar nicht erschließt, speziell natürlich beim Beispiel bummi's ?

Die Funktion sollte mir doch wohl eigentlich die Anzahl (der Devices) zurückgeben, wenn ich dann zuvor in die Variable eine 20 hineinschreibe - wo ist da dann der Sinn?

ggf. stehe ich auch auf einem großen Gartenschlauch, für einen Stubs von selbigem würde ich erneut danke sagen :)

-Shyran

PS Noch eine Anfängerfrage: Was bedeutet die Schreibweise "lpdwNumDevices^:= 20;" ? Also der Akzent dort? Der accent circonflex ?
PPS: Anfängerfrage ignorieren, bissi Syntax verstehen half mir dabei schon :)
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 43



BeitragVerfasst: Mi 23.11.11 11:25 
bummi wollte vermutlich nur darauf hinweisen, beide Deklarationen sind gültig:
ausblenden Delphi-Quelltext
1:
2:
function CP210x_GetNumDevices(VAR dwNumDevices: DWORD): integer; cdeclexternal 'CP210xManufacturing.dll';
function CP210x_GetNumDevices(lpdwNumDevices: LPDWORD): integer; cdeclexternal 'CP210xManufacturing.dll';

Wenn der Variablen dwNumDevices vor dem Aufruf nichts zugewiesen wurde, könnte der Compiler aber eine Warnung ausgeben. Deshalb würde ich so deklarieren:
ausblenden Delphi-Quelltext
1:
function CP210x_GetNumDevices(OUT dwNumDevices: DWORD): integer; cdeclexternal 'CP210xManufacturing.dll';					

Für diesen Beitrag haben gedankt: Shyran
Shyran Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Mi 23.11.11 12:04 
Ah okay!

Wie muss ich dabei nun die eigentliche Funktion aufrufen? Also die CP210x_GetNumDevices ? Dort muss ich doch eine Adresse nun angeben, an der nach dem Aufruf der Funktion doch wohl dann diese Anzahl ->"This function returns the number of CP210x devices connected to the host." befindet, richtig?

Tante Edith sagt noch:

Ich probierte nun zunächst mal

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure TForm1.Button1Click(Sender: TObject);
var
  t:Dword;
  i:Cardinal;
begin
  t := 1;
  test2(t);
  i:=CP210x_GetNumDevices(t);
  Edit1.Text:=IntToStr(i);
end;

wobei sich das Programm nach Buttonclick aufhängte.

Im Anschluss ersetzte ich das cdecl durch stdcall:

ausblenden Delphi-Quelltext
1:
function CP210x_GetNumDevices(OUT dwNumDevices: DWORD): integer; stdcallexternal 'CP210xManufacturing.dll';					


Immerhin tut der Knopf nun etwas, liefert mir aber als Ergebnis eine "0". Sind aber nachweislich 2 Geräte angeschlossen, lt. Gerätemanager.

-Shyran
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 23.11.11 12:58 
Du gibst ja auch i statt t aus. ;-)

Das ist ja der Status, und die 0 dürfte CP210x_SUCCESS sein, also alles ok. ;-)

// EDIT:
Wie wäre es so?
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure TForm1.Button1Click(Sender: TObject);
const
  CP210x_SUCCESS = 0;
var
  DeviceCount: DWord;
begin
  DeviceCount := 0;
  case CP210x_GetNumDevices(DeviceCount) of
    CP210x_SUCCESS:
      Edit1.Text := IntToStr(DeviceCount);
    // ...
  else
    Edit1.Text := '<error>';
  end;
end;

Für diesen Beitrag haben gedankt: Shyran
Shyran Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Mi 23.11.11 13:11 
Mensch ... ich sehe schon ich bin total verwirrt gewesen, aber nun fällt es mir wie Schuppen von den Augen - Du hast natürlich völlig Recht! Der Rückgabewert entspricht dem Status, wer er auch in der Application Note beschrieben ist und ist demnach - natürlich! - derzeit "0", weil alles in Ordnung ist und funktioniert.

Mir ist auch eben erst, als ich mir mal den Inhalt der Variablen im Debugger anschaut klar geworden "Mensch, in t steht ja verdächtigerweise eine 2" - guck an ... und dann, klar, wenn ich nun die Funktion simpel aufrufe per

ausblenden Delphi-Quelltext
1:
  CP210x_GetNumDevices(t);					


Steht natürlich in t exakt die gesuchte Anzahl nach Ausführung.

Wald ... Bäume ... herzlichen Dank, nun spiele ich mal weiter herum. Den Code-Schnippsel von Dir, jaenicke schnappe ichmir umgehend, heißen Dank!
Shyran Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Mi 23.11.11 15:25 
So nach und nach kämpfe ich mich durch die verschiedenen Funktionen der DLL, zwei weitere konnte ich nun selbständig einbinden und die funktionieren, nun sitze ich an:

===

  • 5.20 CP210x_GetDeviceProductString
  • Description: Returns the Product Description String of the String Descriptor of a CP210x device. If the ConvertToASCII parameter is set, the string will be converted to ASCII format before being returned to the caller. The character size limit (in characters, not bytes), NOT including a NULL terminator, is CP210x_MAX_PRODUCT_STRLEN.
  • Supported Devices: CP2101, CP2102, CP2103, CP2104, CP2105
  • Location: CP210x Manufacturing DLL
  • Prototype: CP210x_STATUS CP210x_GetDeviceProductString( HANDLE Handle, LPVOID Product, LPBYTE Length, BOOL ConvertToASCII=TRUE )
  • Parameters: 1. Handle—Handle to the device to close as returned by CP210x_Open().
    2. Product—Pointer to a buffer returning the Product String value.
    3. Length—Pointer to a BYTE value returning the length of the string in characters (not bytes), NOT including a NULL terminator.
    4. ConvertToASCII—Boolean flag that tells the function whether the string needs to be converted to ASCII before it is returned to the caller. The flag is set to TRUE by default (i.e., the caller is expecting the string in ASCII format).
  • Return Value: CP210x_STATUS=CP210x_SUCCESS,
    CP210x_INVALID_PARAMETER,
    CP210x_INVALID_HANDLE,
    CP210x_DEVICE_IO_FAILED
===

Sprich natürlich Deklaration und im folgenden auch der Funktionsaufruf sin derneut meine Sorgen. Hab's mal bisher so versucht:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
function CP210x_GetDeviceProductString(Handle: THandle ; Product : Pointer; Length : Byte; ConvertToASCII : Boolean): integer; cdeclexternal 'CP210xManufacturing.dll';
[...]
procedure TForm1.Button2Click(Sender: TObject);
var
PartNum : byte;
PSLength : byte;
m_hUSBDevice: THandle;
status:integer;
p : Pointer;
begin
status := CP210x_Open(0, Addr(m_hUSBDevice));

status := CP210x_GetPartNumber(m_hUSBDevice, Addr(PartNum));

CP210x_GetDeviceProductString(m_hUSBDevice,p,PSLength,true);

end;


Ergebnis ist eine Zugriffsverletzung an Adresse sowieso.

LPVoid entspricht ja offenbar einem Zeiger in Delphi. Wo ist hier nun mein Denkfehler? Wie komme ich an den Productstring?
guinnes
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 182
Erhaltene Danke: 14



BeitragVerfasst: Mi 23.11.11 15:31 
Du brauchst ein LPByte für die Länge, also ein PByte

Für diesen Beitrag haben gedankt: Shyran
Shyran Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Mi 23.11.11 16:29 
Okay danke, logisch. Steht ja auch im Prototyp ... *seufz*.

Deklaration also geändert in:

ausblenden Delphi-Quelltext
1:
function CP210x_GetDeviceProductString(OUT Handle: THandle ; Product : Pointer; Length : PByte; ConvertToASCII : Boolean): integer; cdeclexternal 'CP210xManufacturing.dll';					


Wie komme ich nun an meine Daten dort?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure TForm1.Button2Click(Sender: TObject);
var
PartNum : byte;
PSLength : PByte;
m_hUSBDevice: THandle;
status:integer;
pPString : Pointer;
s : String;
begin
status := CP210x_Open(0, Addr(m_hUSBDevice));
// now status = CP210x_SUCCESS

status := CP210x_GetPartNumber(m_hUSBDevice, Addr(PartNum));
// now status=CP210x_DEVICE_IO_FAILED
CP210x_GetDeviceProductString(m_hUSBDevice,pPString,PSLength,true);
// Was muss hier nun hin, um an den eigentl. String zu kommen und den in "s" zu schieben?


Was muss hier nun hin, um an den eigentl. String zu gelangen (und den in "s" zu schieben)?

Danke!
guinnes
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 182
Erhaltene Danke: 14



BeitragVerfasst: Mi 23.11.11 16:48 
1. Mach aus deinem Pointer einen PChar und
2. reserviere die xx Bytes für den PChar.
3. Die Reservierte Länge schreibst du in deinen PByte als Initwert.

( So oder so ähnlich wird das eigentlich auch in der Win-API gemacht )

Aus der Hilfe :
Zitat:
In bestimmten Fällen liegt eine lokale String-Variable vor, die durch den Aufruf einer Funktion initialisiert werden muß, die ihrerseits einen PChar als Parameter entgegennimmt. Eine mögliche Lösung ist die Erstellung eines lokalen array of char, das dann an die Funktion übergeben wird. Nach Ausführung der Funktion kann die Variable einem String zugewiesen werden:

// MAX_SIZE ist hier eine vordefinierte Konstante

var
i: Integer;
buf: array[0..MAX_SIZE] of char;
S: string;
begin
i := GetModuleFilename(0, @buf, SizeOf(buf)); // Behandelt @buf als PChar
S := buf;
// Anweisungen
end;


Zuletzt bearbeitet von guinnes am Mi 23.11.11 17:02, insgesamt 1-mal bearbeitet
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 23.11.11 16:54 
Die Länge ist hier ja mit CP210x_MAX_PRODUCT_STRLEN vorgegeben. Insofern ist wohl das am einfachsten:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
var
  ProductString: AnsiString;
  ProductStringLength: Byte;
begin
  ProductStringLength := CP210x_MAX_PRODUCT_STRLEN;
  SetLength(ProductString, ProductStringLength);
  case CP210x_GetDeviceProductString(m_hUSBDevice, PAnsiChar(ProductString), @ProductStringLength, True) of
    CP210x_SUCCESS:
      begin
        SetLength(ProductString, ProductStringLength); 
        ShowMessage(ProductString);
      end;
    // ...
  else
    ShowMessage('Fehler');
  end;
Ich würde aber den zweiten Parameter gleich als PAnsiChar deklarieren.


Zuletzt bearbeitet von jaenicke am Mi 23.11.11 17:12, insgesamt 1-mal bearbeitet
Shyran Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 20


Rad Studio XE
BeitragVerfasst: Mi 23.11.11 17:06 
Lieben Dank erstmal für die weiteren Stubse in die richtige Richtung, morgen stürze ich mich weiter auf's Thema, bis dahin herzlichen Dank!