Forum: PC-Programmierung STM-Link mit CubeProgrammer_API.dll unter Delphi ansprechen


von Stefan S. (energizer)


Lesenswert?

Hallo,

ich möchte aus einer Delphiapplikation den STM32-Link ansprechen und
versuche auf die CubeProgrammer_API.dll zuzugreifen:
1
const
2
3
DLL_NAME = 'C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\api\lib\CubeProgrammer_API.dll';
4
5
function LoadCubeProgrammerApi: Cardinal;
6
begin
7
  hDll := LoadLibrary(DLL_NAME);
8
  Result := GetLastError();
9
end;


Als last error kommt immer 193 zurück. Google sagt dass das passiert
wenn man eine 32-Bit DLL aus einer 64-Bit Anwendung aufruft und
umgekehrt. Der Fehler kommt aber bei beiden Targets (64 und 32 Bit).
Weiß jemand wie das klappen könnte?

Gruß
Stefan

von Max H. (nilsp)


Lesenswert?

Check mal, ob LoadLibrary wirklich 0 zurückliefert. GetLastError macht 
erst dann Sinn, wenn wirklich ein Fehler aufgetreten ist.

von Harald K. (kirnbichler)


Lesenswert?

Max H. schrieb:
> GetLastError macht
> erst dann Sinn, wenn wirklich ein Fehler aufgetreten ist.

Wenn keiner aufgetreten ist, liefert es aber einen passenden (Nicht-) 
Fehlercode, und keinen Unfug.

von Stefan S. (energizer)


Lesenswert?

Ja, LoadLibrary liefert 0 zurück.

von C-hater (c-hater)


Lesenswert?

Stefan S. schrieb:

> Als last error kommt immer 193 zurück. Google sagt dass das passiert
> wenn man eine 32-Bit DLL aus einer 64-Bit Anwendung aufruft und
> umgekehrt.

Ja, das ist ERROR_BAD_EXE_FORMAT und in diesen beiden Fällen kommt das 
tatsächlich. Aber auch noch in vielen anderen...

> Der Fehler kommt aber bei beiden Targets (64 und 32 Bit).

Damit habe ich keine Erfahrung, obwohl ich weit über ein Jahrzeht mit 
Delphi programmiert habe. Damals(TM) konnte Delphi aber noch keine 
64Bit-Anwendungen erstellen.

> Weiß jemand wie das klappen könnte?

Kompiliere deine (Test-)Anwendung für 64Bit, lege sie in das 
Verzeichnis, in der auch die DLL liegt und starte sie dort. Geht's 
dann?

Noch ein kleiner Hinweis: Die DLL hat ihrerseits wiederum etliche 
Abhängigkeiten, die im gleichen Verzeichnis liegen, in dem auch die DLL 
liegt.

von Stefan S. (energizer)


Lesenswert?

>Kompiliere deine (Test-)Anwendung für 64Bit, lege sie in das
>Verzeichnis, in der auch die DLL liegt und starte sie dort. Geht's
>dann?

Treffer! Dann funktioniert LoadLibrary schonmal, jetzt muss ich nur noch 
schauen wie ich das hinbiege; die Exe beim Zielsystem ins STM Cube 
Verzeichnis zu kopieren ist eher unschön.

Gruß & Dank
Stefan

von Harald K. (kirnbichler)


Lesenswert?

Stefan S. schrieb:
> Dann funktioniert LoadLibrary schonmal, jetzt muss ich nur noch
> schauen wie ich das hinbiege; die Exe beim Zielsystem ins STM Cube
> Verzeichnis zu kopieren ist eher unschön.

Daß LoadLibrary nicht mit dem absoluten Pfad zurechtkommt, verwundert.
Du könntest vor dem Aufruf von LoadLibrary ein SetDllDirectory in das 
betreffende Verzeichnis ausführen.

Siehe
https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya
und
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setdlldirectorya

: Bearbeitet durch User
von Michael B. (laberkopp)


Lesenswert?

Harald K. schrieb:
> Daß LoadLibrary nicht mit dem absoluten Pfad zurechtkommt, verwundert

LoadLibrary kommt mit einem absoluten Pfad klar. Aber wenn die DLL 
ihrerseits irgendwelche DLL lädt und dabei ein 32/64bit mismatch 
auftritt, gibt es denselben Fehler und keiner weiss, von welcher DLL er 
ausgelöst wurde.

von Stefan S. (energizer)


Lesenswert?

Fein, setDllDirectory war die Lösung, funktioniert nun! Vielen Dank!

von Stefan S. (energizer)


Lesenswert?

...so halb zumindest...

Aufruf von getStLinkList liefert wunderbar Ergebnise zurück, aber 
connectStLink scheppert eine Accessviolation:

Project CubeProgrammer.exe raised exception class EAccessViolation with 
message 'Access violation at address 0000000000000000. Execution of 
address 0000000000000000'.
1
{$MINENUMSIZE 4}
2
TDebugConnectParameters = record
3
    dbgPort: TDebugPort;                        // < Select the type of debug interface #debugPort.
4
    index: Integer;                             // < Select one of the debug ports connected.
5
    serialNumber: array[0..32] of AnsiChar;     // < ST-LINK serial number.
6
    firmwareVersion: array[0..19] of AnsiChar;  // < Firmware version.
7
    targetVoltage: array[0..4] of AnsiChar;     // < Operate voltage.
8
    accessPortNumber: Integer;                  // < Number of available access port.
9
    accessPort: Integer;                        // < Select access port controller.
10
    debugConnectMode: TDebugConnectMode;        // < Select the debug CONNECT mode #debugConnectMode. */
11
    debugResetMode: TDebugResetMode;            // < Select the debug RESET mode #debugResetMode. */
12
    isOldFirmware: Integer;                     // < Check Old ST-LINK firmware version. */
13
    freq: TFrequencies;                         // < Supported frequencies #frequencies. */
14
    frequency: Integer;                         // < Select specific frequency. */
15
    isBridge: Integer;                          // < Indicates if it's Bridge device or not. */
16
    shared: Integer;                            // < Select connection type, if it's shared, use ST-LINK Server. */
17
    board: array[0..99] of AnsiChar;            // < board Name
18
    DBG_Sleep: Integer;
19
    speed: Integer;                             // < Select speed flashing of Cortex M33 series. */}
20
  end;
21
  pDebugConnectParameters = ^TDebugConnectParameters;
22
23
function getStLinkList(var stLinkList: pDebugConnectParameters; shared: LongBool): Integer; cdecl; external DLL_NAME delayed;
24
function connectStLink(debugParameters: TDebugConnectParameters): Integer; cdecl; external DLL_NAME delayed;

Die Elemente in den Delphirecords habe ich mit alle von den Größen 
angesehen, das passt soweit.
Die von ST mitgelieferten Beispiele in C++ lassen sich in Visual Studio 
bauen und ohne Fehler ausführen. Vielleicht ist ein Delphi-Guru hier der 
noch eine Idee hat?

von Thomas Z. (usbman)


Lesenswert?

Stefan S. schrieb:
> Access violation at address 0000000000000000
ist typischerweise ein kaputer Pointer

> function connectStLink(debugParameters: TDebugConnectParameters)....

bist du da sicher? Ich würde da eher einen Pointer erwarten
-> pTDebugConnectParameters

Integer Größe passt?

von Stefan S. (energizer)


Lesenswert?

>bist du da sicher?
Kam mir auch komisch vor, sollte aber nach meinem Verständnis so richtig 
sein. Hier sind die Signaturen aus dem C-Header:
1
int getStLinkList(debugConnectParameters** stLinkList, int shared);
2
int connectStLink(debugConnectParameters debugParameters);
Hab's trotzdem mal als Pointer übergeben, kommt aber die gleiche 
Accessviolation.

Integergröße habe ich auch nochmal jeweils nachgesehen, jeweils 4 Bytes.

von Thomas Z. (usbman)


Lesenswert?

Stefan S. schrieb:
> Hab's trotzdem mal als Pointer übergeben, kommt aber die gleiche
> Accessviolation.
ich hab mal in die dll mit ida geschaut, debugParameters wird 
tatsächlich als record übergeben.

Ich mal prüfen ob die structs in c und pascal gleich groß ist.

von Stefan S. (energizer)


Lesenswert?

Hab ich mal jeweils ausgeben lassen, in beiden Fällen werden 312 Bytes 
gemeldet. Habe auch mal Hexdumps gemacht, der Inhalt ist gleich, außer 
die letzten 4 Bytes (speed), da steht in Delphi 0x0D 0xF0 0xAD 0xBA und 
in c 0xFF 0xFF 0xFF 0xFF, das ist auffällig. Der Hexdump wird jeweils 
ausgegeben unittelbar bevor connectStLink aufgerufen wird.

von Thomas Z. (usbman)


Lesenswert?

dann würde ich zum Test speed in der Delphi Version einfach mal hart auf 
-1 vor dem Aufruf setzen. Wenn es dann fehlerfrei durchläuft musst du 
<nur> rausfinden warum du in Pascal die seltsamen Werte  für speed 
bekommst :-)

von C-hater (c-hater)


Lesenswert?

Thomas Z. schrieb:

> Ich mal prüfen ob die structs in c und pascal gleich groß ist.

Ich tippe eher auf falsche Aufrufkonvention. Was passiert, wenn du das 
"cdecl" in deinen Pascal-Deklarationen der ST-Funktionen mal auf 
"winapi" änderst (in beiden Funktionen)?

von Thomas Z. (usbman)


Lesenswert?


: Bearbeitet durch User
von C-hater (c-hater)


Lesenswert?

Thomas Z. schrieb:

> In Delphi wäre das dann StdCall.

Richtig, so heißt das da wirklich. Ist halt doch schon 'ne ganze Weile 
her. ;o)

von Stefan S. (energizer)


Lesenswert?

>dann würde ich zum Test speed in der Delphi Version einfach mal hart auf
>-1 vor dem Aufruf setzen

Habe ich mal gemacht, Ergebnis bleibt leider das Gleiche.

>Ich tippe eher auf falsche Aufrufkonvention
Ich habe mal alle durchprobiert, aber ich habe gesehen dass es unter 
64-Bit eh keine unterschiedlichen Aufrufkonventionen gibt und die Angabe 
für 64-Bit Targets ignoriert wird.

Gruß
Stefan

von Sven K. (svenk)


Lesenswert?

Hallo Stefan,
hast Du auch zuerst die callback Funktion berücksichtigt?

setDisplayCallbacks

Das habe ich in den Aufrufen zur API
Gesehen bevor andere Aufrufe starten.

Gruß Sven

von Stefan S. (energizer)


Lesenswert?

Hallo Sven,

>setDisplayCallbacks

Das hatte ich tatsächlich nicht gesehen. Ich habe mal die Funktion und 
die zugehörige Struktur in Delphi gebaut, nun funktioniert auch erstmal 
der connectStLink Aufruf!

Herzlichen Dank & Gruß
Stefan

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.