Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Win32 DLL erstellen (https://www.delphipraxis.net/45094-win32-dll-erstellen.html)

bdaehn 29. Apr 2005 14:37


Win32 DLL erstellen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

ist schon eine Weile her, dass ich mit Delphi mal was gemacht habe und im Moment komme ich bei folgendem Problem nicht weiter:

Ich wuerde gerne ein Extension-DLL fuer einen virtuellen Drucker-Treiber mit Delphi ertellen - Win32 DLL mit Unicode Support - habe angefangen, das entsprechende C-Headerfile umzusetzen, aber irgdendwie scheint das ganze nicht zu funktionieren.
Hier das C-Headerfile:

Delphi-Quellcode:
enum
{
    SC_OUTPUT_BLACKWHITE = 1,
    SC_OUTPUT_GRAYSCALE,
    SC_OUTPUT_COLOR,
};

enum
{
    SC_TIFTYPE_NONE = 1,
    SC_TIFTYPE_PACKBITS,
    SC_TIFTYPE_CCITT_HUFFMAN,
    SC_TIFTYPE_CCITT_T4,
    SC_TIFTYPE_CCITT_T6,
    SC_TIFTYPE_JPEG,
};

typedef struct _SCJOBINFO
{
   // Form name
    TCHAR formName[32];
   
    // Only values between 100 to 300 dpi are accepted
    int printQuality;

    // One of SC_OUTPUT_BLACKWHITE to SC_OUTPUT_COLOR
    int colorType;

    // Only values between 1 to 100 are accepted.
    // Higher value means better quality.
    int jpegQuality;

    // One of SC_TIFTYPE_NONE to SC_TIFTYPE_JPEG.
    // PackBits and one of the CCITT types are only applicable if colorType
    // is set to SC_OUTPUT_BLACKWHITE.
    int tiffCompression;

    // Only applicable if tiffCompression is set to SC_TIFTYPE_JPEG.
    // Only values between 1 to 100 are accepted.
    // Higher value means better quality.
    int tiffQuality;

    // Only values between 1 to 100 are accepted.
    // Higher value means better quality.
    int pdfQuality;
}
SCJOBINFO;

enum
{
    SC_BMP = 1,
    SC_PNG,
    SC_JPG,
    SC_TIF_SINGLE,
    SC_PDF_SINGLE,
    SC_TIF_MULTIPLE,
    SC_PDF_MULTIPLE,
};

typedef struct _SCFILEINFO
{
    // Output filename without extension. This parameter is required.
    wchar_t name[MAX_PATH];
   
    // Extension of output filename. This parameter is optional.
    // If none is supplied, a default extension will be used.
    wchar_t ext[MAX_PATH];
   
    // Output image type, which could be one of SC_BMP to SC_PDF_MULTIPLE. <tt>SC_PDF_MULTIPLE</tt>.
    // This parameter is required.
    int type;
}
SCFILEINFO;

typedef BOOL (WINAPI *SCGETJOBINFOFUNC) (SCJOBINFO*);
typedef BOOL (WINAPI *SCGETSAVEFILENAMEFUNC) (SCFILEINFO*);
typedef void (WINAPI *SCENDOFJOBFUNC) ();

Hier, was ich bislang gemacht habe:
Delphi-Quellcode:
library dll;


uses
  ShareMem, SysUtils, Classes, Windows, Messages, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;


{$R *.res}

const
  REGROOT = 'Software\\bdaehn\\SoftCopy';

type
  SCJOBINFO = record
    formName: Array[0..32-1] of CHAR;
    printQuality: Integer;
    colorType: Integer;
    jpegQuality: Integer;
    tiffCompression: Integer;
    tiffQuality: Integer;
    pdfQuality: Integer;
end;



type
  SCFILEINFO = record
    name: Array[0..MAX_PATH-1] of WCHAR;
    ext: Array[0..MAX_PATH-1] of WCHAR;
    typ : Integer;
end;



function scGetJobInfo(var test: SCJOBINFO):Bool;
begin
//   ShowMessage('buh');
   Result:=True;
end;

function scGetSaveFilename(var test: SCFILEINFO):Bool;
begin
  //ShowMessage('buh');
     Result:=True;
end;

function scEndOfJob():Bool;
begin
//  ShowMessage('buh');
     Result:=True;
end;


begin
end.
Code kompiliert, aber ich bekomme bei der Benutzung des Treibers eine "Memory could not be read" Execptions - irgendeine Idee ? Ich gehe einmal davon aus, dass ich etwas grobes falsch mache, was Uebergabe-Parameter und dergleichen angeht. Wichtig ist wohl auch Unicode-Support fuer diese DLL!
Attached ist noch ein Beispiel in C++ ...

Vielen Dank und Gruss
/bjoern

Mephistopheles 29. Apr 2005 16:32

Re: Win32 DLL erstellen
 
Code:
typedef BOOL (WINAPI *SCGETJOBINFOFUNC) (SCJOBINFO*);
typedef BOOL (WINAPI *SCGETSAVEFILENAMEFUNC) (SCFILEINFO*);
typedef void (WINAPI *SCENDOFJOBFUNC) ();
Dies entspricht:
Delphi-Quellcode:
type
SCGETJOBINFOFUNC = function(var bla: SCJOBINFO): BOOL; stdcall;
SCGETSAVEFILENAMEFUNC = function(var bla:SCFILEINFO):BOOL; stdcall;
SCENDOFJOBFUNC = procedure(); stdcall;
Viel Erfolg!

Es handelt sich also nur um Typendeklarationen für Funktionspointer. Nicht jedoch um statische Importe!!!

Noch'n Nachtrag: stdcall ist hier ganz wichtig. Delphi übergibt, wie bei VC's fastcall die Parameter zuerst in den Registern und dann auf dem Stack. stdcall benutzt ab dem ersten Parameter den Stack. WINAPI impliziert stdcall!

NicoDE 29. Apr 2005 16:59

Re: Win32 DLL erstellen
 
Versuch's mit der Übersetzung (bei Unicode musst Du noch 'UNICODE' definieren)
Delphi-Quellcode:
type
  TScColorType = type Longint;
const
  SC_OUTPUT_BLACKWHITE = TScColorType(1);
  SC_OUTPUT_GRAYSCALE = TScColorType(2);
  SC_OUTPUT_COLOR     = TScColorType(3);

type
  TScTiffCompression = type Longint;
const
  SC_TIFTYPE_NONE         = TScTiffCompression(1);
  SC_TIFTYPE_PACKBITS     = TScTiffCompression(2);
  SC_TIFTYPE_CCITT_HUFFMAN = TScTiffCompression(3);
  SC_TIFTYPE_CCITT_T4      = TScTiffCompression(4);
  SC_TIFTYPE_CCITT_T6      = TScTiffCompression(5);
  SC_TIFTYPE_JPEG         = TScTiffCompression(6);

type
  PScJobInfoA = ^TScJobInfoA;
  TScJobInfoA = packed record
    formName      : array [0..31] of AnsiChar;
    printQuality  : Longint;
    colorType     : TScColorType;
    jpegQuality   : Longint;
    tiffCompression: TScTiffCompression;
    tiffQuality   : Longint;
    pdfQuality    : Longint;
  end;
  PScJobInfoW = ^TScJobInfoW;
  TScJobInfoW = packed record
    formName      : array [0..31] of WideChar;
    printQuality  : Longint;
    colorType     : TScColorType;
    jpegQuality   : Longint;
    tiffCompression: TScTiffCompression;
    tiffQuality   : Longint;
    pdfQuality    : Longint;
  end;
  PScJobInfo = ^TScJobInfo;
{$IFDEF UNICODE}
  TScJobInfo = TScJobInfoW;
{$ELSE}
  TScJobInfo = TScJobInfoA;
{$ENDIF}

type
  TScFileType = type Longint;
const
  SC_BMP         = TScFileType(1);
  SC_PNG         = TScFileType(2);
  SC_JPG         = TScFileType(3);
  SC_TIF_SINGLE  = TScFileType(4);
  SC_PDF_SINGLE  = TScFileType(5);
  SC_TIF_MULTIPLE = TScFileType(6);
  SC_PDF_MULTIPLE = TScFileType(7);

type
  TScFileInfo = packed record
    name : array [0..MAX_PATH-1] of WideChar;
    ext : array [0..MAX_PATH-1] of WideChar;
    type_: TScFileType;
  end;

type
  TFNScGetJobInfoFunc = function(var TScJobInfo): BOOL; stdcall; // scGetJobInfo
  TFNScGetSaveFileNameFunc = function(var TScFileInfo): BOOL; stdcall; // scGetSaveFileName
  TFNScEndOfJobFunc = procedure; stdcall; // scEndOfJobFunc
Zitat:

Zitat von bdaehn
Code kompiliert, aber ich bekomme bei der Benutzung des Treibers eine "Memory could not be read" Execptions - irgendeine Idee ?

Könnte auch mit Initialisierung der Delphi-Runtime in der DLL zu tun habe... aber um das auszuschliessen müsste man eine eigene RTL schreiben...).
Nimm alles aus der Uses-Liste raus was Du nichts brauchst (ShareMem hat in Deiner DLL nichts zu suchen!).

bdaehn 29. Apr 2005 17:20

Re: Win32 DLL erstellen
 
Hallo!

Vielen Dank fuer die echt schnell Hilfe!

Ich habe beide Loesungsansaetze probiert - leider noch immer gleicher Effekt - bekomme 3 spoolsv.exe application errors:

"The instruction at "0x00000000" referenced memory at "0x00000000:. The memory could not be "read".

Ich wuerde einmal auf ein Problem mit den Uebergabe-Parametern tippen... Ich habe auch in anderen dll-Beispielen gesehen, dass dort "exports" benutzt wird, um die Symbole/Funktionen zu exportieren - koennte das evtl. ein Problem sein?

Muss man bei einer DLL nicht auch nicht eine Funktion fuer die dll-Einstiegspunkte setzen? Also etwas in der Art?

Delphi-Quellcode:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
   {
      case DLL_PROCESS_ATTACH:
      case DLL_THREAD_ATTACH:
      case DLL_THREAD_DETACH:
      case DLL_PROCESS_DETACH:
         break;
    }
    return TRUE;
}
Vielen Dank
/bjoern

NicoDE 29. Apr 2005 17:26

Re: Win32 DLL erstellen
 
Zitat:

Zitat von bdaehn
"The instruction at "0x00000000" referenced memory at "0x00000000:. The memory could not be "read".

Siehe letztes Kommentar in meinem bearbeiteten Beitrag.

Zitat:

Zitat von bdaehn
Ich habe auch in anderen dll-Beispielen gesehen, dass dort "exports" benutzt wird, um die Symbole/Funktionen zu exportieren - koennte das evtl. ein Problem sein?

Ja, die drei Funktionen sollten exportiert werden :)

Zitat:

Zitat von bdaehn
Muss man bei einer DLL nicht auch nicht eine Funktion fuer die dll-Einstiegspunkte setzen?

Bei Delphi-DLLs ist das
Delphi-Quellcode:
begin
end.
am Ende.

bdaehn 29. Apr 2005 18:46

Re: Win32 DLL erstellen
 
Sorry, hatte den letzten Absatz in Deiner Antwort schlichtweg uebersehen!

Nachdem ich exports hinzugefuegt habe und die uses-Klausel bereinigt habe, scheint die dll halbswegs zu funktionieren - zumindest wird beim 1. Aufruf der dll (nachdem der print-service neugestartet wurde) die Funktion "scGetJobInfo()" aufgerufen (anschliessend allerdings nicht mehr, aber das kann auch so gewollt sein; muss ich noch einmal genauer untersuchen) und zum Schluss immer "scEndJob()".
"scGetSaveFilename()" wird scheint hingegen wohl nie ausgerufen zu werden...

Ist denn die Uebersetzung von z.B.

Delphi-Quellcode:
BOOL WINAPI scGetSaveFileName(SCFILEINFO* info)
in

Delphi-Quellcode:
function scGetSaveFilename(var test: TScFileInfo):Bool;
korrekt - oder muss man hier auch Pointer uebergeben?

Btw. was macht eigentlich ?

Delphi-Quellcode:
TFNScGetJobInfoFunc = function(var TScJobInfo): BOOL; stdcall;
Denke, dass das wohl die Art und Weise beinflusst, die die Library gelinkt wird - oder?

Gruss
/bjoern

NicoDE 29. Apr 2005 20:12

Re: Win32 DLL erstellen
 
Zitat:

Zitat von bdaehn
Sorry, hatte den letzten Absatz in Deiner Antwort schlichtweg uebersehen!

Ich hatte den Beitrag editiert, da es mir erst hinterher aufgefallen ist.

Zitat:

Zitat von bdaehn
Ist denn die Uebersetzung von z.B.
Delphi-Quellcode:
BOOL WINAPI scGetSaveFileName(SCFILEINFO* info)
in
Delphi-Quellcode:
function scGetSaveFilename(var test: TScFileInfo):Bool;
korrekt - oder muss man hier auch Pointer uebergeben?

WINAPI ist eine Aufrufkonvention. Es muss also lauten:
Delphi-Quellcode:
function scGetSaveFilename(var test: TScFileInfo): LongBool; stdcall;
Nebenbei:
Delphi-Quellcode:
function scGetSaveFilename(ScFileInfo: PScFileInfo): LongBool; stdcall;
ist intern das gleiche wie
Delphi-Quellcode:
function scGetSaveFilename(var ScFileInfo: TScFileInfo): LongBool; stdcall;
Nur, dass man sich bei letzterem darauf verlassen kann, dass die Adresse der Struktur immer gültig ist. Wenn dies nicht der Fall sein sollte (sieht in dem Quellcode nicht danach aus), dann sollte man die erste Varinate der Überszung (mit Pointer) vorziehen und zuerst den Pointer prüfen bevor man die Struktur benutzt...

Zitat:

Zitat von bdaehn
Btw. was macht eigentlich ?
Delphi-Quellcode:
TFNScGetJobInfoFunc = function(var TScJobInfo): BOOL; stdcall;

Das ist nur eine Definition für den Typ einer Funktion. Die Deklaration ist für den Code nicht wichtig. Nur in sofern, dass Dir der Typ als Vorlage für Deine Funktionen dienen soll.

Gruß Nico

bdaehn 1. Mai 2005 18:33

Re: Win32 DLL erstellen
 
Hallo!

So sieht der Code nun im Moment aus - hab's sowohl mit Pointern als auch mit Referenzen (var) probiert - immer dergleiche Effekt ( getjobinfo() wird ab und zu mal aufgerufen, getsavefilename() nie und endofjob() immer) - in meinem Demo greife ich auch ueberhaupt noch gar nicht auf die Uebergabewerte zu - gebe ja nur eine Message aus - deshalb denke ich nicht, dass es mit den Uebergabeparametern was zu tun hat.
Noch irgendeine Idee, was faul sein koennte?

Habe mit einer in Visual C++ geschriebenen DLL ueberprueft, dass wirklich alle 3 Funkionen aufgerufen werden...

Delphi-Quellcode:
library softcopyex;


uses
    Windows,Dialogs;

{$R *.res}

{$DEFINE UNICODE}

type
  TScColorType = type Longint;
const
  SC_OUTPUT_BLACKWHITE = TScColorType(1);
  SC_OUTPUT_GRAYSCALE = TScColorType(2);
  SC_OUTPUT_COLOR     = TScColorType(3);

type
  TScTiffCompression = Longint;
const
  SC_TIFTYPE_NONE         = TScTiffCompression(1);
  SC_TIFTYPE_PACKBITS     = TScTiffCompression(2);
  SC_TIFTYPE_CCITT_HUFFMAN = TScTiffCompression(3);
  SC_TIFTYPE_CCITT_T4      = TScTiffCompression(4);
  SC_TIFTYPE_CCITT_T6      = TScTiffCompression(5);
  SC_TIFTYPE_JPEG         = TScTiffCompression(6);

type
  PScJobInfoA = ^TScJobInfoA;
  TScJobInfoA = packed record
    formName      : array [0..31] of AnsiChar;
    printQuality  : Longint;
    colorType     : TScColorType;
    jpegQuality   : Longint;
    tiffCompression: TScTiffCompression;
    tiffQuality   : Longint;
    pdfQuality    : Longint;
  end;

  PScJobInfoW = ^TScJobInfoW;
  TScJobInfoW = packed record
    formName      : array [0..31] of WideChar;
    printQuality  : Longint;
    colorType     : TScColorType;
    jpegQuality   : Longint;
    tiffCompression: TScTiffCompression;
    tiffQuality   : Longint;
    pdfQuality    : Longint;
  end;

{$IFDEF UNICODE}
  TScJobInfo = TScJobInfoW;
{$ELSE}
  TScJobInfo = TScJobInfoA;
{$ENDIF}
  PScJobInfo = ^TScJobInfo;

type
  TScFileType = type Longint;
const
  SC_BMP         = TScFileType(1);
  SC_PNG         = TScFileType(2);
  SC_JPG         = TScFileType(3);
  SC_TIF_SINGLE  = TScFileType(4);
  SC_PDF_SINGLE  = TScFileType(5);
  SC_TIF_MULTIPLE = TScFileType(6);
  SC_PDF_MULTIPLE = TScFileType(7);

type
  PScFileInfo = ^TScFileInfo;
  TScFileInfo = packed record
    name : array [0..MAX_PATH-1] of WideChar;
    ext : array [0..MAX_PATH-1] of WideChar;
    type_: TScFileType;
  end;

function scGetJobInfo(var test: TScJobInfo):LongBool; stdcall;
var temp : String;

begin
  ShowMessage('GetJobInfo()');
  Result:=True;
end;

function scGetSaveFilename(var test: TScFileInfo):LongBool; stdcall;
var temp : String;

begin
  ShowMessage('scGetSaveFilename()');
  Result:=True;
end;

procedure scEndOfJob(); stdcall;
begin
  ShowMessage('scEndOfJob()');
end;

exports scGetJobInfo, scGetSaveFilename, scEndOfJob;

begin
end.
Vielen Dank und Gruss
/bjoern

Mephistopheles 1. Mai 2005 18:39

Re: Win32 DLL erstellen
 
Ohne die DLL dürfte ab diesem Punkt eine Analyse des Fehlers schwer werden :-\

NicoDE 2. Mai 2005 10:32

Re: Win32 DLL erstellen
 
Zitat:

Zitat von bdaehn
in meinem Demo greife ich auch ueberhaupt noch gar nicht auf die Uebergabewerte zu - gebe ja nur eine Message aus - deshalb denke ich nicht, dass es mit den Uebergabeparametern was zu tun hat.

Ich denke doch. Denn wenn Du die Strukturen nicht mit sinnvollen Daten füllst (wie das Beispiel in C), dann ist es nicht verwunderlich, dass die weiteren Callbacks nicht aufgerufen werden...

ps: die Unit Dialogs um eine Nachricht anzuzeigen ist ziemlicher Overhead, nimm einfach MessageBox :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz