Entwickler-Ecke
Dateizugriff - DLL in Projekt einbinden
LittleBen - Fr 10.12.10 18:10
Titel: DLL in Projekt einbinden
Hallo Zusammen!
Es gibt zwar schon ein Thread zu diesem Thema, aber dieser hat mir nicht wirklich geholfen.
Also:
Ich möchte eine Komponente Benutzen, die aber eine lästige DLL benötigt. Nun möchte ich diese DLL in mein Projekt sozusagen "einbinden", damit ich diese lästige DLL nicht im Programmpfad oder im System32 haben muss. Ich möchte mein Programm später vielleicht auch mal auf meine Seite stellen oder Freunden schicken und da wäre die DLL(s) sehr unschön...
Doch kann man überhaupt eine DLL "einbinden" oder habe ich das grad nur erfunden? :D
Hoffe ihr könnt mir helfen!
Grüße,
Benny
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Fr 10.12.2010 um 19:50
HenryHux - Fr 10.12.10 18:36
Hmm reicht das nicht, die einfach in den Programmordner zu kopieren?
Bei mir klappt es eigentlich immer wenn ich die entweder in den system32- oder in den .exe Ordner kopiere.
Lg
MisterBum83 - Fr 10.12.10 20:08
Kopiere die notwendige DLL in dein Programmverzeichnis, binde diese (dynamisch oder statisch) in dein Programm ein und nutze die notwendige Funktion.
Dann kannst du allen dein Programm mit der DLL zur Verfügung stellen.
Gruß MisterBum
Narses - Fr 10.12.10 20:53
Moin!
LittleBen hat folgendes geschrieben : |
Doch kann man überhaupt eine DLL "einbinden" oder habe ich das grad nur erfunden? |
Man kann mit viel Aufwand ein Executable aus einem MemoryStream starten, also theoretisch auch eine DLL. :nixweiss:
Aber mal als einfacher Absatz: pack die DLL als Resource ein und löse sie ins Programmverzeichnis, wenn sie nicht da ist. :idea: Hat zwar auch ein paar Haken, aber gut...
cu
Narses
Delete - Fr 10.12.10 20:54
LittleBen hat folgendes geschrieben : |
Doch kann man überhaupt eine DLL "einbinden" |
Kommt darauf an, was du unter "einbinden" verstehst.
delfiphan - Fr 10.12.10 23:16
MoleBox/VMWare ThinApp wäre dafür gedacht, aber ich würde davon abraten. Am besten machst du eine Setup, die die Applikation sauber installiert und wieder deinstalliert.
LittleBen - Sa 11.12.10 15:16
Vielen Dank für die vielen Antworten!
Also auf meinem Computer habe ich die DLL ins System32 kopiert, kein Problem.
Es geht nur darum, dass wenn ich mein Programm online stelle, möchte ich nicht, dass der Anwender immer so unschöne DLL im Programmpfad haben muss, wie z.B auf dem Desktop.
Aber das Einbinden kann ich wohl vergessen ;-)
Wie könnte ich den so ein Setup erstellen?
Grüße,
Benny
jaenicke - Sa 11.12.10 15:36
LittleBen hat folgendes geschrieben : |
möchte ich nicht, dass der Anwender immer so unschöne DLL im Programmpfad haben muss, wie z.B auf dem Desktop. |
Was ist daran unschön? :gruebel:
LittleBen hat folgendes geschrieben : |
Aber das Einbinden kann ich wohl vergessen ;-) |
Du könntest die DLL dynamisch einbinden, dann muss diese beim Start nicht vorhanden sein. Auf diese Weise kannst du diese wie bereits geschrieben wurde in der Exe mitliefern und dann auspacken, wenn sie benötigt wird.
LittleBen hat folgendes geschrieben : |
Wie könnte ich den so ein Setup erstellen? |
Zum Beispiel mit
InnoSetup [
http://www.jrsoftware.org/isinfo.php], das ich persönlich für das beste Setuptool in dem Segment halte.
Martok - Sa 11.12.10 16:01
jaenicke hat folgendes geschrieben : |
LittleBen hat folgendes geschrieben : | möchte ich nicht, dass der Anwender immer so unschöne DLL im Programmpfad haben muss, wie z.B auf dem Desktop. | Was ist daran unschön? :gruebel: |
Dass das Programm auf dem Desktop liegt?
Wer das macht, gehört bestraft, da ist eine DLL noch das mindeste. Ich wäre ja eher für
format C:...
Delete - Sa 11.12.10 16:11
Also wenn der Anwender die Programmdateien aus dem Archiv auf dem Desktop entpackt und er da nun ein paar Dateien rumfliegen hat, ist das sein Problem.
Delphi-Laie - Sa 11.12.10 19:12
LittleBen hat folgendes geschrieben : |
Hallo Zusammen! |
Hallo auseinander!
LittleBen hat folgendes geschrieben : |
Es gibt zwar schon ein Thread zu diesem Thema, aber dieser hat mir nicht wirklich geholfen. |
Nicht wirklich? Also unwirklich?
LittleBen hat folgendes geschrieben : |
Ich möchte eine Komponente Benutzen, die aber eine lästige DLL benötigt. Nun möchte ich diese DLL in mein Projekt sozusagen "einbinden", damit ich diese lästige DLL nicht im Programmpfad oder im System32 haben muss. Ich möchte mein Programm später vielleicht auch mal auf meine Seite stellen oder Freunden schicken und da wäre die DLL(s) sehr unschön...
Doch kann man überhaupt eine DLL "einbinden" oder habe ich das grad nur erfunden? :D |
Was Du suchst, kann das Programm "PEBundle", das sich über eine Internetsuchseite leicht beschaffen lassen müßte. Es vereint zu einer neuen Exe-Datei. Es kann aber durchaus (in seltenen Fällen?) sein, daß die Funktionalität des Programms (bzw. des Duos, das aus Exe- und DLL-Datei besteht), dann nicht oder zumindest nicht vollständig gegeben ist. Bei globalen Hooks z.B. klappt es mit erheblicher Wahrscheinlichkeit nicht, also war es für mich nach anfänglicher Euphorie uninteressant. Was man in einer Datei vereint und dann immer noch funktioniert, kann man dann aber gleich in eine Programmdatei implementieren, falls möglich (also die Quelltexte vorliegen).
LittleBen - So 12.12.10 17:07
Also ich habe mich jetzt mal mit den Resourcen beschäftigt. Habe auch schon Musik, Bilder etc. "reingepackt" und aufgerufen.
Die *.rc datei sieht ja so aus:
Zitat: |
Song1 WAVE Test.wav |
Und aufrufen so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| implementation
{$R *.dfm} {$R MyRes.res} procedure TForm1.Button1Click(Sender: TObject); begin PlaySound(PChar('Song1'), hInstance, SND_RESOURCE Or SND_ASYNC); end; |
Funktioniert alles,gut...Aber wie sieht die *.rc Datei mit na DLL aus?
so..?
Zitat: |
Datei1 RCDATA Test.dll |
Wenn ja, wie rufe ich sie auf?
jaenicke - So 12.12.10 17:31
LittleBen hat folgendes geschrieben : |
Wenn ja, wie rufe ich sie auf? |
Indem du die dann zur Laufzeit auspackst bevor du diese mit LoadLibrary lädst. Zum Beispiel mit TResourceStream.
LittleBen - So 12.12.10 18:26
So?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| implementation
{$R *.dfm} {$R MyRes.res} procedure TForm1.FormCreate(Sender: TObject); var Res: TResourceStream; begin if FindResource(hInstance, 'Datei1', RT_RCDATA) <> 0 then begin Res := TResourceStream.Create(hInstance, 'Datei1', RT_RCDATA); showmessage('Gefunden'); end; end; |
jaenicke - So 12.12.10 19:42
Ja, dann noch mit CopyFrom in einen TFileStream und damit ins Tempverzeichnis packen, dann von dort laden, fertig.
LittleBen - So 12.12.10 19:48
...? Mhhh, kannst du mit vielleicht mal ein Beispiel machen?
LittleBen - Fr 17.12.10 19:37
Ich versteh nur das mit dem Tempverzeichnis nicht. Könntest du mir mal mit ein bisschen Code auf die Sprünge helfen?
jaenicke - Fr 17.12.10 20:24
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| var TempPath: PChar; TempPathBufferSize: Integer; begin TempPathBufferSize := GetTempPath(0, nil); GetMem(TempPath, TempPathBufferSize); try if GetTempPath(TempPathBufferSize, TempPath) <> 0 then begin ShowMessage('Das temporäre Verzeichnis ist: ' + TempPath); end else raise Exception.Create(SysErrorMessage(GetLastError)); finally FreeMem(TempPath, TempPathBufferSize); end; |
Statt dem ShowMessage kannst du dann in dem Verzeichnis die DLL ablegen und danach mit LoadLibrary usw. laden. Und nach der Benutzung und dem Entladen mit FreeLibrary kannst du die DLL auch direkt wieder löschen.
LittleBen - Fr 17.12.10 21:38
Okay, dahin soll ich die DLL kopieren. Wie mach ich das am besten? DU hast mal "CopyFrom" angesprochen. Habe noch nie damit hantiert. Könntest du mir zeigen wie ich das da rein kopiere?
jaenicke - Fr 17.12.10 23:01
Du erzeugst einen TFileStream mit dem Temppfad und dem Namen der DLL, dann kopierst du mit CopyFrom den Inhalt deines TResourceStream da rein.
LittleBen - Di 21.12.10 16:10
Also so(?):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| var Stream: TResourceStream; begin Stream := TResourceStream.Create(hInstance, 'Datei1', RT_RCDATA); showmessage('Gefunden'); try Stream.SaveToFile(Tempverzeichnis); finally Stream.Free; end; end; |
jaenicke - Di 21.12.10 17:13
Wenn in der Variablen Tempverzeichnis nicht nur dieses sondern auch der Dateiname drin ist, ja.
Dass TResourceStream auch SaveToFile hat, wusste ich gar nicht. Dann brauchst du natürlich keinen TFileStream.
LittleBen - Di 21.12.10 17:57
Vielen Dank!
Doch noch eine Frage:
Ich habe einen Komponente, die eine DLL benötigt. Also wird das Programm nicht gestartet, weil die DLL ja benötigt wird.
Wie schaff ich es, dass erst die DLL ins Tempverzeichnis kopiert wird und dann die Komponente aufgerufen wird?
Momentan kopier ich die DLL ins Tempverzeichnis vor dem Initialisieren der Appllication.
Was mach ich falsch?
delphi10 - Di 21.12.10 18:21
LittleBen hat folgendes geschrieben : |
Vielen Dank!
Doch noch eine Frage:
Ich habe einen Komponente, die eine DLL benötigt. Also wird das Programm nicht gestartet, weil die DLL ja benötigt wird.
Wie schaff ich es, dass erst die DLL ins Tempverzeichnis kopiert wird und dann die Komponente aufgerufen wird?
Momentan kopier ich die DLL ins Tempverzeichnis vor dem Initialisieren der Appllication.
Was mach ich falsch? |
Schreib die Kopieranweisung in die *.DPR
LittleBen - Di 21.12.10 18:28
Das meinte ich mit
Zitat: |
Momentan kopier ich die DLL ins Tempverzeichnis vor dem Initialisieren der Appllication |
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:
| program Project1; uses Forms, Classes, Windows, SysUtils, Unit1 in 'Unit1.pas' ; {$R *.res} {$R MyRes.res} var Res: TResourceStream; t: string; begin t:= SysUtils.GetEnvironmentVariable('temp');
Res := TResourceStream.Create(hInstance, 'Datei1', RT_RCDATA); try Res.SavetoFile(t+'\DieDll'); finally Res.Free; end; Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. |
delphi10 - Di 21.12.10 19:04
Verstehe ich jetzt nicht. Was soll daran falsch sein oder nicht funktionieren?
LittleBen - Di 21.12.10 19:36
Ich auch nicht :D
Sobald ich die Komponente aus der "Uses" entferne funktioniert ja auch alles...
jaenicke - Di 21.12.10 19:59
Wie schon früher erwähnt:
Die DLL muss danach dann dynamisch mit LoadLibrary geladen werden. Wenn das die Interface-Unit der DLL derzeit nicht macht, musst du das so umschreiben, dass es dynamisch geladen wird.
Es ist eben etwas Aufwand dabei, wenn du dich nicht an die Standards halten möchtest (DLL einfach normal mitliefern).
LittleBen - Di 21.12.10 20:20
Also in die *.dpr einfach noch dazu:
Delphi-Quelltext
1:
| LoadLibrary(PChar(t+'DieDLL')); |
???
@jaenicke: Ich habe vorhin auf deiner Seite "SJ Bubble Breaker Clone" runtergeladen. Du hast da so ein schönes Setup. Wie hast du das hinbekommen?
jaenicke - Di 21.12.10 20:24
Naja, du musst die Funktionen aus der DLL schon auch noch laden. Also alles was bis jetzt statisch in der Interface-Unit steht, musst du auf dynamisches Laden umstellen.
Die Setups mache ich mit dem kostenlosen Open Source Tool InnoSetup:
http://www.jrsoftware.org/isinfo.php
Es gibt auch noch andere ähnliche Tools, aber für normale Projekte halte ich InnoSetup für das beste. Insbesondere weil es in Delphi geschrieben ist und man damit auch Pascal Skripte erstellen kann um eigenen Code während des Setups auszuführen. Meistens reicht für kleine Projekte aber auch die Standardfunktionalität.
LittleBen - Di 21.12.10 20:31
Naja, dann lass ich das mit den Ressourcen. Nachdem du mir so ein tolles Programm gegeben hast!! Vielen Danke!
TomasB - Mi 22.12.10 00:06
Hallo,
zu diesem Thema hätte ich eine Frage: Sqlite wird normalerweise als DLL benutzt. Disqlite ist eine Sqlite-Variante für Delphi, bei der Sqlite direkt in der Exe landet. Wenn man Disqlite benutzt, hat man am Ende also nur eine einzige Exe, die selbständig lauffähig ist. Weiss jemand, wie der Autor von Disqlite das erreicht hat? Wie binde ich eine DLL, deren C-Quelltext ich habe, so in Delphi ein? Geht es auch ohne den Quelltext (und ohne PEbundle)? Das wäre ja die gesuchte Lösung für die ursprüngliche Frage.
Tomas
LittleBen - Sa 08.10.11 13:17
Nun möchte ich dieses Thema nochmal aufgreifen, da das dynamische Laden der
sqlite3.dll ansteht. Wenn ich die DLL in das temporäre Verzeichnis speicher, was muss ich dann in der folgenden Unit tun, um die DLL von dort zu laden.
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: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252:
| unit SQLite3;
{$IFDEF FPC} {$MODE DELPHI} {$H+} {$PACKENUM 4} {$PACKRECORDS C} {$ELSE} {$MINENUMSIZE 4} {$ENDIF}
interface
const {$IF Defined(MSWINDOWS)} SQLiteDLL = 'sqlite3.dll'; {$ELSEIF Defined(DARWIN)} SQLiteDLL = 'libsqlite3.dylib'; {$linklib libsqlite3} {$ELSEIF Defined(UNIX)} SQLiteDLL = 'sqlite3.so'; {$IFEND}
const SQLITE_OK = 0; SQLITE_ERROR = 1; SQLITE_INTERNAL = 2; SQLITE_PERM = 3; SQLITE_ABORT = 4; SQLITE_BUSY = 5; SQLITE_LOCKED = 6; SQLITE_NOMEM = 7; SQLITE_READONLY = 8; SQLITE_INTERRUPT = 9; SQLITE_IOERR = 10; SQLITE_CORRUPT = 11; SQLITE_NOTFOUND = 12; SQLITE_FULL = 13; SQLITE_CANTOPEN = 14; SQLITE_PROTOCOL = 15; SQLITE_EMPTY = 16; SQLITE_SCHEMA = 17; SQLITE_TOOBIG = 18; SQLITE_CONSTRAINT = 19; SQLITE_MISMATCH = 20; SQLITE_MISUSE = 21; SQLITE_NOLFS = 22; SQLITE_AUTH = 23; SQLITE_FORMAT = 24; SQLITE_RANGE = 25; SQLITE_NOTADB = 26; SQLITE_ROW = 100; SQLITE_DONE = 101; SQLITE_INTEGER = 1; SQLITE_FLOAT = 2; SQLITE_TEXT = 3; SQLITE_BLOB = 4; SQLITE_NULL = 5;
SQLITE_UTF8 = 1; SQLITE_UTF16 = 2; SQLITE_UTF16BE = 3; SQLITE_UTF16LE = 4; SQLITE_ANY = 5;
SQLITE_STATIC = Pointer(0); SQLITE_TRANSIENT = Pointer(-1);
type TSQLiteDB = Pointer; TSQLiteResult = ^PAnsiChar; TSQLiteStmt = Pointer;
type PPAnsiCharArray = ^TPAnsiCharArray; TPAnsiCharArray = array[0 .. (MaxInt div SizeOf(PAnsiChar))-1] of PAnsiChar;
type TSQLiteExecCallback = function(UserData: Pointer; NumCols: integer; ColValues: PPAnsiCharArray; ColNames: PPAnsiCharArray): integer; cdecl; TSQLiteBusyHandlerCallback = function(UserData: Pointer; P2: integer): integer; cdecl;
TCollateXCompare = function(UserData: pointer; Buf1Len: integer; Buf1: pointer; Buf2Len: integer; Buf2: pointer): integer; cdecl;
function SQLite3_Open(filename: PAnsiChar; var db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_open'; function SQLite3_Close(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_close'; function SQLite3_Exec(db: TSQLiteDB; SQLStatement: PAnsiChar; CallbackPtr: TSQLiteExecCallback; UserData: Pointer; var ErrMsg: PAnsiChar): integer; cdecl; external SQLiteDLL name 'sqlite3_exec'; function SQLite3_Version(): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_libversion'; function SQLite3_ErrMsg(db: TSQLiteDB): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_errmsg'; function SQLite3_ErrCode(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_errcode'; procedure SQlite3_Free(P: PAnsiChar); cdecl; external SQLiteDLL name 'sqlite3_free'; function SQLite3_GetTable(db: TSQLiteDB; SQLStatement: PAnsiChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PAnsiChar): integer; cdecl; external SQLiteDLL name 'sqlite3_get_table'; procedure SQLite3_FreeTable(Table: TSQLiteResult); cdecl; external SQLiteDLL name 'sqlite3_free_table'; function SQLite3_Complete(P: PAnsiChar): boolean; cdecl; external SQLiteDLL name 'sqlite3_complete'; function SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external SQLiteDLL name 'sqlite3_last_insert_rowid'; procedure SQLite3_Interrupt(db: TSQLiteDB); cdecl; external SQLiteDLL name 'sqlite3_interrupt'; procedure SQLite3_BusyHandler(db: TSQLiteDB; CallbackPtr: TSQLiteBusyHandlerCallback; UserData: Pointer); cdecl; external SQLiteDLL name 'sqlite3_busy_handler'; procedure SQLite3_BusyTimeout(db: TSQLiteDB; TimeOut: integer); cdecl; external SQLiteDLL name 'sqlite3_busy_timeout'; function SQLite3_Changes(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_changes'; function SQLite3_TotalChanges(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_total_changes'; function SQLite3_Prepare(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; cdecl; external SQLiteDLL name 'sqlite3_prepare'; function SQLite3_Prepare_v2(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; cdecl; external SQLiteDLL name 'sqlite3_prepare_v2'; function SQLite3_ColumnCount(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_column_count'; function SQLite3_ColumnName(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_column_name'; function SQLite3_ColumnDeclType(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_column_decltype'; function SQLite3_Step(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_step'; function SQLite3_DataCount(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_data_count';
function SQLite3_ColumnBlob(hStmt: TSqliteStmt; ColNum: integer): pointer; cdecl; external SQLiteDLL name 'sqlite3_column_blob'; function SQLite3_ColumnBytes(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_bytes'; function SQLite3_ColumnDouble(hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external SQLiteDLL name 'sqlite3_column_double'; function SQLite3_ColumnInt(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_int'; function SQLite3_ColumnText(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_column_text'; function SQLite3_ColumnType(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_type'; function SQLite3_ColumnInt64(hStmt: TSqliteStmt; ColNum: integer): Int64; cdecl; external SQLiteDLL name 'sqlite3_column_int64'; function SQLite3_Finalize(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_finalize'; function SQLite3_Reset(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_reset';
type TSQLite3Destructor = procedure(Ptr: Pointer); cdecl;
function sqlite3_bind_blob(hStmt: TSqliteStmt; ParamNum: integer; ptrData: pointer; numBytes: integer; ptrDestructor: TSQLite3Destructor): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_blob'; function sqlite3_bind_text(hStmt: TSqliteStmt; ParamNum: integer; Text: PAnsiChar; numBytes: integer; ptrDestructor: TSQLite3Destructor): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_text'; function sqlite3_bind_double(hStmt: TSqliteStmt; ParamNum: integer; Data: Double): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_double'; function sqlite3_bind_int(hStmt: TSqLiteStmt; ParamNum: integer; Data: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_int'; function sqlite3_bind_int64(hStmt: TSqliteStmt; ParamNum: integer; Data: int64): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_int64'; function sqlite3_bind_null(hStmt: TSqliteStmt; ParamNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_null';
function sqlite3_bind_parameter_index(hStmt: TSqliteStmt; zName: PAnsiChar): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_parameter_index';
function sqlite3_enable_shared_cache(Value: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_enable_shared_cache';
function SQLite3_create_collation(db: TSQLiteDB; Name: PAnsiChar; eTextRep: integer; UserData: pointer; xCompare: TCollateXCompare): integer; cdecl; external SQLiteDLL name 'sqlite3_create_collation';
function SQLiteFieldType(SQLiteFieldTypeCode: Integer): AnsiString; function SQLiteErrorStr(SQLiteErrorCode: Integer): AnsiString;
implementation
uses SysUtils;
function SQLiteFieldType(SQLiteFieldTypeCode: Integer): AnsiString; begin case SQLiteFieldTypeCode of SQLITE_INTEGER: Result := 'Integer'; SQLITE_FLOAT: Result := 'Float'; SQLITE_TEXT: Result := 'Text'; SQLITE_BLOB: Result := 'Blob'; SQLITE_NULL: Result := 'Null'; else Result := 'Unknown SQLite Field Type Code "' + IntToStr(SQLiteFieldTypeCode) + '"'; end; end;
function SQLiteErrorStr(SQLiteErrorCode: Integer): AnsiString; begin case SQLiteErrorCode of SQLITE_OK: Result := 'Successful result'; SQLITE_ERROR: Result := 'SQL error or missing database'; SQLITE_INTERNAL: Result := 'An internal logic error in SQLite'; SQLITE_PERM: Result := 'Access permission denied'; SQLITE_ABORT: Result := 'Callback routine requested an abort'; SQLITE_BUSY: Result := 'The database file is locked'; SQLITE_LOCKED: Result := 'A table in the database is locked'; SQLITE_NOMEM: Result := 'A malloc() failed'; SQLITE_READONLY: Result := 'Attempt to write a readonly database'; SQLITE_INTERRUPT: Result := 'Operation terminated by sqlite3_interrupt()'; SQLITE_IOERR: Result := 'Some kind of disk I/O error occurred'; SQLITE_CORRUPT: Result := 'The database disk image is malformed'; SQLITE_NOTFOUND: Result := '(Internal Only) Table or record not found'; SQLITE_FULL: Result := 'Insertion failed because database is full'; SQLITE_CANTOPEN: Result := 'Unable to open the database file'; SQLITE_PROTOCOL: Result := 'Database lock protocol error'; SQLITE_EMPTY: Result := 'Database is empty'; SQLITE_SCHEMA: Result := 'The database schema changed'; SQLITE_TOOBIG: Result := 'Too much data for one row of a table'; SQLITE_CONSTRAINT: Result := 'Abort due to contraint violation'; SQLITE_MISMATCH: Result := 'Data type mismatch'; SQLITE_MISUSE: Result := 'Library used incorrectly'; SQLITE_NOLFS: Result := 'Uses OS features not supported on host'; SQLITE_AUTH: Result := 'Authorization denied'; SQLITE_FORMAT: Result := 'Auxiliary database format error'; SQLITE_RANGE: Result := '2nd parameter to sqlite3_bind out of range'; SQLITE_NOTADB: Result := 'File opened that is not a database file'; SQLITE_ROW: Result := 'sqlite3_step() has another row ready'; SQLITE_DONE: Result := 'sqlite3_step() has finished executing'; else Result := 'Unknown SQLite Error Code "' + IntToStr(SQLiteErrorCode) + '"'; end; end;
function ColValueToStr(Value: PAnsiChar): AnsiString; begin if (Value = nil) then Result := 'NULL' else Result := Value; end;
end. |
jaenicke - Sa 08.10.11 13:41
Du musst jede Funktion so umschreiben, dass sie nicht mehr statisch aus der DLL geladen wird, sondern dynamisch. Sprich vom Prinzip her:
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: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
| type TSQLiteDLLLoader = class public type EDLLNotLoadedException = class(Exception) public constructor Create(const ARoutine: string); overload; end; strict private type TSQLite3_Open = function(filename: PAnsiChar; var db: TSQLiteDB): integer; cdecl; var FSQLiteDLLHandle: THandle FSQLite3_Open: TSQLite3_Open; public function LoadDLL(ADLLPath: string): Boolean; procedure UnloadDLL; function SQLite3_Open(AFilename: AnsiString; var db: TSQLiteDB): Integer; end;
constructor TSQLiteDLLLoader.EDLLNotLoadedException.Create(const ARoutine: string); begin inherited Create('The SQLite library was not loaded before calling ' + ARoutine); end; function TSQLiteDLLLoader.LoadDLL(ADLLPath: string): Boolean; begin FSQLiteDLLHandle := LoadLibrary(ADLLPath); Result := FSQLiteDLLHandle <> 0; if Result then begin @FSQLite3_Open := GetProcAddress(FMyDLLHandle, "SQLite3_Open"); end; end;
procedure TSQLiteDLLLoader.UnloadDLL; begin if FSQLiteDLLHandle <> 0 then begin FreeLibrary(FSQLiteDLLHandle); FMyDLLHandle := 0; end; end;
function TSQLiteDLLLoader.SQLite3_Open(AFilename: AnsiString; var db: TSQLiteDB): Integer; begin if Assigned(FSQLite3_Open) then Result := FSQLite3_Open(PAnsiChar(AFilename), db) else raise EDLLNotLoadedException.Create('SQLite3_Open'); end; |
Ungetestet natürlich.
Du könntest theoretisch auch die Funktionsfelder public machen und direkt darauf zugreifen, aber dann würde es ohne konkrete Meldung einfach nur knallen, wenn die DLL nicht vorher geladen wurde.
// EDIT:
Für alte Delphiversionen (vor 2006) musst du die Deklarationen entsprechend ändern.
LittleBen - Sa 08.10.11 14:10
Okay...das sieht nach viel Arbeit aus. Von der Logik her habe ich es verstanden, aber wie der der Aufbau aussehen soll nicht. Würde das so in etwa stimmen?
EDIT: Habe mir nun die Arbeit gemacht:
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: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294:
| unit sqlite3;
{$IFDEF FPC} {$MODE DELPHI} {$H+} {$PACKENUM 4} {$PACKRECORDS C} {$ELSE} {$MINENUMSIZE 4} {$ENDIF}
interface
const SQLITE_OK = 0; SQLITE_ERROR = 1; SQLITE_INTERNAL = 2; SQLITE_PERM = 3; SQLITE_ABORT = 4; SQLITE_BUSY = 5; SQLITE_LOCKED = 6; SQLITE_NOMEM = 7; SQLITE_READONLY = 8; SQLITE_INTERRUPT = 9; SQLITE_IOERR = 10; SQLITE_CORRUPT = 11; SQLITE_NOTFOUND = 12; SQLITE_FULL = 13; SQLITE_CANTOPEN = 14; SQLITE_PROTOCOL = 15; SQLITE_EMPTY = 16; SQLITE_SCHEMA = 17; SQLITE_TOOBIG = 18; SQLITE_CONSTRAINT = 19; SQLITE_MISMATCH = 20; SQLITE_MISUSE = 21; SQLITE_NOLFS = 22; SQLITE_AUTH = 23; SQLITE_FORMAT = 24; SQLITE_RANGE = 25; SQLITE_NOTADB = 26; SQLITE_ROW = 100; SQLITE_DONE = 101; SQLITE_INTEGER = 1; SQLITE_FLOAT = 2; SQLITE_TEXT = 3; SQLITE_BLOB = 4; SQLITE_NULL = 5;
SQLITE_UTF8 = 1; SQLITE_UTF16 = 2; SQLITE_UTF16BE = 3; SQLITE_UTF16LE = 4; SQLITE_ANY = 5;
SQLITE_STATIC = Pointer(0); SQLITE_TRANSIENT = Pointer(-1);
type TSQLiteDB = Pointer; TSQLiteResult = ^PAnsiChar; TSQLiteStmt = Pointer;
type PPAnsiCharArray = ^TPAnsiCharArray; TPAnsiCharArray = array[0 .. (MaxInt div SizeOf(PAnsiChar))-1] of PAnsiChar;
type TSQLiteExecCallback = function(UserData: Pointer; NumCols: integer; ColValues: PPAnsiCharArray; ColNames: PPAnsiCharArray): integer; cdecl; TSQLiteBusyHandlerCallback = function(UserData: Pointer; P2: integer): integer; cdecl;
TCollateXCompare = function(UserData: pointer; Buf1Len: integer; Buf1: pointer; Buf2Len: integer; Buf2: pointer): integer; cdecl;
type TSQLiteDLLLoader = class public type EDLLNotLoadedException = class(Exception) public constructor Create(const ARoutine: string); overload; end; strict private type TSQLite3_Open = function(filename: PAnsiChar; var db: TSQLiteDB): integer; cdecl; TSQLite3_Close = function(db: TSQLiteDB): integer; cdecl; TSQLite3_Exec = function(db: TSQLiteDB; SQLStatement: PAnsiChar; CallbackPtr: TSQLiteExecCallback; UserData: Pointer; var ErrMsg: PAnsiChar): integer; cdecl; TSQLite3_Version = function(): PAnsiChar; cdecl; TSQLite3_ErrMsg = function(db: TSQLiteDB): PAnsiChar; cdecl; TSQLite3_ErrCode = function(db: TSQLiteDB): integer; cdecl; TSQlite3_Free = procedure(P: PAnsiChar); cdecl; TSQLite3_GetTable = function(db: TSQLiteDB; SQLStatement: PAnsiChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PAnsiChar): integer; cdecl; TSQLite3_FreeTable = procedure(Table: TSQLiteResult); cdecl; TSQLite3_Complete = function(P: PAnsiChar): boolean; cdecl; TSQLite3_LastInsertRowID = function(db: TSQLiteDB): int64; cdecl; TSQLite3_Interrupt = procedure(db: TSQLiteDB): integer; cdecl; TSQLite3_BusyHandler = procedure(db: TSQLiteDB; CallbackPtr: TSQLiteBusyHandlerCallback; UserData: Pointer); cdecl; TSQLite3_BusyTimeout = procedure(db: TSQLiteDB; TimeOut: integer); cdecl; TSQLite3_Changes = function(db: TSQLiteDB): integer; cdecl; TSQLite3_TotalChanges = function(db: TSQLiteDB): integer; cdecl; TSQLite3_Prepare = function(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; cdecl; TSQLite3_Prepare_v2 = function(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; cdecl; TSQLite3_ColumnCount = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_ColumnName = function(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; TSQLite3_ColumnDeclType = function(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; TSQLite3_Step = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_DataCount = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_ColumnBlob = function(hStmt: TSqliteStmt; ColNum: integer): pointer; cdecl; TSQLite3_ColumnBytes = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnDouble = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnInt = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnText = function(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; TSQLite3_ColumnType = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnInt64 = function(hStmt: TSqliteStmt; ColNum: integer): Int64; cdecl; TSQLite3_Finalize = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_Reset = function(hStmt: TSqliteStmt): integer; cdecl; var FSQLiteDLLHandle: THandle FSQLite3_Open: TSQLite3_Open; FSQLite3_Close: TSQLite3_Close; FSQLite3_Exec: TSQLite3_Exec; FSQLite3_Version: TSQLite3_Version; FSQLite3_ErrMsg: TSQLite3_ErrMsg; FSQLite3_ErrCode: TSQLite3_ErrCode; FSQlite3_Free: TSQlite3_Free; FSQLite3_GetTable: TSQLite3_GetTable; FSQLite3_FreeTable: TSQLite3_FreeTable; FSQLite3_Complete: TSQLite3_Complete; FSQLite3_LastInsertRowID: TSQLite3_LastInsertRowID; FSQLite3_Interrupt: TSQLite3_Interrupt; FSQLite3_BusyHandler: TSQLite3_BusyHandler; FSQLite3_BusyTimeout: TSQLite3_BusyTimeout; FSQLite3_Changes: TSQLite3_Changes; FSQLite3_TotalChanges: TSQLite3_TotalChanges; FSQLite3_Prepare: TSQLite3_Prepare; FSQLite3_Prepare_v2: TSQLite3_Prepare_v2; FSQLite3_ColumnCount: TSQLite3_ColumnCount; FSQLite3_ColumnName: TSQLite3_ColumnName; FSQLite3_ColumnDeclType: TSQLite3_ColumnDeclType; FSQLite3_Step: TSQLite3_Step; FSQLite3_DataCount: TSQLite3_DataCount; FSQLite3_ColumnBlob: TSQLite3_ColumnBlob; FSQLite3_ColumnBytes: TSQLite3_ColumnBytes; FSQLite3_ColumnDouble: TSQLite3_ColumnDouble; FSQLite3_ColumnInt: TSQLite3_ColumnInt; FSQLite3_ColumnText: TSQLite3_ColumnText; FSQLite3_ColumnType: TSQLite3_ColumnType; FSQLite3_ColumnInt64: TSQLite3_ColumnInt64; FSQLite3_Finalize: TSQLite3_Finalize; FSQLite3_Reset: TSQLite3_Reset; public function LoadDLL(ADLLPath: string): Boolean; procedure UnloadDLL; function SQLite3_Open(AFilename: AnsiString; var db: TSQLiteDB): Integer; function SQLite3_Close(db: TSQLiteDB): integer; function SQLite3_Exec(db: TSQLiteDB; SQLStatement: PAnsiChar; CallbackPtr: TSQLiteExecCallback; UserData: Pointer; var ErrMsg: PAnsiChar): integer; function SQLite3_Version(): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_libversion'; function SQLite3_ErrMsg(db: TSQLiteDB): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_errmsg'; function SQLite3_ErrCode(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_errcode'; procedure SQlite3_Free(P: PAnsiChar); cdecl; external SQLiteDLL name 'sqlite3_free'; function SQLite3_GetTable(db: TSQLiteDB; SQLStatement: PAnsiChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PAnsiChar): integer; procedure SQLite3_FreeTable(Table: TSQLiteResult); cdecl; external SQLiteDLL name 'sqlite3_free_table'; function SQLite3_Complete(P: PAnsiChar): boolean; cdecl; external SQLiteDLL name 'sqlite3_complete'; function SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external SQLiteDLL name 'sqlite3_last_insert_rowid'; procedure SQLite3_Interrupt(db: TSQLiteDB); cdecl; external SQLiteDLL name 'sqlite3_interrupt'; procedure SQLite3_BusyHandler(db: TSQLiteDB; CallbackPtr: TSQLiteBusyHandlerCallback; UserData: Pointer); procedure SQLite3_BusyTimeout(db: TSQLiteDB; TimeOut: integer); cdecl; external SQLiteDLL name 'sqlite3_busy_timeout'; function SQLite3_Changes(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_changes'; function SQLite3_TotalChanges(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_total_changes'; function SQLite3_Prepare(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; function SQLite3_Prepare_v2(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; function SQLite3_ColumnCount(hStmt: TSqliteStmt): integer; function SQLite3_ColumnName(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; function SQLite3_ColumnDeclType(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; function SQLite3_Step(hStmt: TSqliteStmt): integer; function SQLite3_DataCount(hStmt: TSqliteStmt): integer; function SQLite3_ColumnBlob(hStmt: TSqliteStmt; ColNum: integer): pointer; function SQLite3_ColumnBytes(hStmt: TSqliteStmt; ColNum: integer): integer; function SQLite3_ColumnDouble(hStmt: TSqliteStmt; ColNum: integer): double; function SQLite3_ColumnInt(hStmt: TSqliteStmt; ColNum: integer): integer; function SQLite3_ColumnText(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; function SQLite3_ColumnType(hStmt: TSqliteStmt; ColNum: integer): integer; function SQLite3_ColumnInt64(hStmt: TSqliteStmt; ColNum: integer): Int64; function SQLite3_Finalize(hStmt: TSqliteStmt): integer; function SQLite3_Reset(hStmt: TSqliteStmt): integer; end;
type TSQLite3Destructor = procedure(Ptr: Pointer); cdecl;
function sqlite3_bind_blob(hStmt: TSqliteStmt; ParamNum: integer; ptrData: pointer; numBytes: integer; ptrDestructor: TSQLite3Destructor): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_blob'; function sqlite3_bind_text(hStmt: TSqliteStmt; ParamNum: integer; Text: PAnsiChar; numBytes: integer; ptrDestructor: TSQLite3Destructor): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_text'; function sqlite3_bind_double(hStmt: TSqliteStmt; ParamNum: integer; Data: Double): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_double'; function sqlite3_bind_int(hStmt: TSqLiteStmt; ParamNum: integer; Data: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_int'; function sqlite3_bind_int64(hStmt: TSqliteStmt; ParamNum: integer; Data: int64): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_int64'; function sqlite3_bind_null(hStmt: TSqliteStmt; ParamNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_null';
function sqlite3_bind_parameter_index(hStmt: TSqliteStmt; zName: PAnsiChar): integer; cdecl; external SQLiteDLL name 'sqlite3_bind_parameter_index';
function sqlite3_enable_shared_cache(Value: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_enable_shared_cache';
function SQLite3_create_collation(db: TSQLiteDB; Name: PAnsiChar; eTextRep: integer; UserData: pointer; xCompare: TCollateXCompare): integer; cdecl; external SQLiteDLL name 'sqlite3_create_collation';
function SQLiteFieldType(SQLiteFieldTypeCode: Integer): AnsiString; function SQLiteErrorStr(SQLiteErrorCode: Integer): AnsiString;
implementation
uses SysUtils;
function SQLiteFieldType(SQLiteFieldTypeCode: Integer): AnsiString; begin case SQLiteFieldTypeCode of SQLITE_INTEGER: Result := 'Integer'; SQLITE_FLOAT: Result := 'Float'; SQLITE_TEXT: Result := 'Text'; SQLITE_BLOB: Result := 'Blob'; SQLITE_NULL: Result := 'Null'; else Result := 'Unknown SQLite Field Type Code "' + IntToStr(SQLiteFieldTypeCode) + '"'; end; end;
function SQLiteErrorStr(SQLiteErrorCode: Integer): AnsiString; begin case SQLiteErrorCode of SQLITE_OK: Result := 'Successful result'; SQLITE_ERROR: Result := 'SQL error or missing database'; SQLITE_INTERNAL: Result := 'An internal logic error in SQLite'; SQLITE_PERM: Result := 'Access permission denied'; SQLITE_ABORT: Result := 'Callback routine requested an abort'; SQLITE_BUSY: Result := 'The database file is locked'; SQLITE_LOCKED: Result := 'A table in the database is locked'; SQLITE_NOMEM: Result := 'A malloc() failed'; SQLITE_READONLY: Result := 'Attempt to write a readonly database'; SQLITE_INTERRUPT: Result := 'Operation terminated by sqlite3_interrupt()'; SQLITE_IOERR: Result := 'Some kind of disk I/O error occurred'; SQLITE_CORRUPT: Result := 'The database disk image is malformed'; SQLITE_NOTFOUND: Result := '(Internal Only) Table or record not found'; SQLITE_FULL: Result := 'Insertion failed because database is full'; SQLITE_CANTOPEN: Result := 'Unable to open the database file'; SQLITE_PROTOCOL: Result := 'Database lock protocol error'; SQLITE_EMPTY: Result := 'Database is empty'; SQLITE_SCHEMA: Result := 'The database schema changed'; SQLITE_TOOBIG: Result := 'Too much data for one row of a table'; SQLITE_CONSTRAINT: Result := 'Abort due to contraint violation'; SQLITE_MISMATCH: Result := 'Data type mismatch'; SQLITE_MISUSE: Result := 'Library used incorrectly'; SQLITE_NOLFS: Result := 'Uses OS features not supported on host'; SQLITE_AUTH: Result := 'Authorization denied'; SQLITE_FORMAT: Result := 'Auxiliary database format error'; SQLITE_RANGE: Result := '2nd parameter to sqlite3_bind out of range'; SQLITE_NOTADB: Result := 'File opened that is not a database file'; SQLITE_ROW: Result := 'sqlite3_step() has another row ready'; SQLITE_DONE: Result := 'sqlite3_step() has finished executing'; else Result := 'Unknown SQLite Error Code "' + IntToStr(SQLiteErrorCode) + '"'; end; end;
function ColValueToStr(Value: PAnsiChar): AnsiString; begin if (Value = nil) then Result := 'NULL' else Result := Value; end;
end. |
jaenicke - Sa 08.10.11 17:34
Ja, das sieht so richtig aus und die restlichen Funktionen müssen auch in die Klasse, ja.
LittleBen - Sa 08.10.11 17:44
Beim Versuch das zu kompilieren gibt's Fehlermeldungen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| type TSQLiteDLLLoader = class public type EDLLNotLoadedException = class(Exception) public constructor Create(const ARoutine: string); overload; end; strict private type TSQLite3_Open = function(filename: PAnsiChar; var db: TSQLiteDB): integer; cdecl; var FSQLiteDLLHandle: THandle FSQLite3_Open: TSQLite3_Open; public function LoadDLL(ADLLPath: string): Boolean; procedure UnloadDLL; function SQLite3_Open(AFilename: AnsiString; var db: TSQLiteDB): Integer; end; |
Finde diese Abschnitt auch sehr seltsam. Wie schreibt man ihn um?
jaenicke - Sa 08.10.11 21:31
Für Delphi 7? Das müsste so gehen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| uses Classes;
type EDLLNotLoadedException = class(Exception) public constructor Create(const ARoutine: string); overload; end;
TSQLite3_Open = function(filename: PAnsiChar; var db: TSQLiteDB): integer; cdecl;
TSQLiteDLLLoader = class private FSQLiteDLLHandle: THandle FSQLite3_Open: TSQLite3_Open; public function LoadDLL(ADLLPath: string): Boolean; procedure UnloadDLL; function SQLite3_Open(AFilename: AnsiString; var db: TSQLiteDB): Integer; end; |
Nested types und strict gab es in den Uraltversionen leider noch nicht. Aber die Typdefinitionen müssen nur lose außerhalb der Klasse hin, dann klappt das. Und die Klasse Exception ist in der Unit Classes deklariert glaube ich (grad keine Lust zu schauen ;-)).
LittleBen - So 09.10.11 02:09
Gut, soweit funktionierts schonmal. Mir ist gerade aufgefallen, dass ich manche Funktionen in die Klasse gemacht habe, dich gar nicht mit der DLL zutun haben:
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: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111:
| type EDLLNotLoadedException = class(Exception) public constructor Create(const ARoutine: string); overload; end;
TSQLite3_Open = function(filename: PAnsiChar; var db: TSQLiteDB): integer; cdecl; TSQLite3_Close = function(db: TSQLiteDB): integer; cdecl; TSQLite3_Exec = function(db: TSQLiteDB; SQLStatement: PAnsiChar; CallbackPtr: TSQLiteExecCallback; UserData: Pointer; var ErrMsg: PAnsiChar): integer; cdecl; TSQLite3_Version = function(): PAnsiChar; cdecl; TSQLite3_ErrMsg = function(db: TSQLiteDB): PAnsiChar; cdecl; TSQLite3_ErrCode = function(db: TSQLiteDB): integer; cdecl; TSQlite3_Free = procedure(P: PAnsiChar); cdecl; TSQLite3_GetTable = function(db: TSQLiteDB; SQLStatement: PAnsiChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PAnsiChar): integer; cdecl; TSQLite3_FreeTable = procedure(Table: TSQLiteResult); cdecl; TSQLite3_Complete = function(P: PAnsiChar): boolean; cdecl; TSQLite3_LastInsertRowID = function(db: TSQLiteDB): int64; cdecl; TSQLite3_Interrupt = procedure(db: TSQLiteDB); cdecl; TSQLite3_BusyHandler = procedure(db: TSQLiteDB; CallbackPtr: TSQLiteBusyHandlerCallback; UserData: Pointer); cdecl; TSQLite3_BusyTimeout = procedure(db: TSQLiteDB; TimeOut: integer); cdecl; TSQLite3_Changes = function(db: TSQLiteDB): integer; cdecl; TSQLite3_TotalChanges = function(db: TSQLiteDB): integer; cdecl; TSQLite3_Prepare = function(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; cdecl; TSQLite3_Prepare_v2 = function(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; cdecl; TSQLite3_ColumnCount = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_ColumnName = function(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; TSQLite3_ColumnDeclType = function(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; TSQLite3_Step = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_DataCount = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_ColumnBlob = function(hStmt: TSqliteStmt; ColNum: integer): pointer; cdecl; TSQLite3_ColumnBytes = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnDouble = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnInt = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnText = function(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; cdecl; TSQLite3_ColumnType = function(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; TSQLite3_ColumnInt64 = function(hStmt: TSqliteStmt; ColNum: integer): Int64; cdecl; TSQLite3_Finalize = function(hStmt: TSqliteStmt): integer; cdecl; TSQLite3_Reset = function(hStmt: TSqliteStmt): integer; cdecl;
TSQLiteDLLLoader = class private FSQLiteDLLHandle: THandle; FSQLite3_Open: TSQLite3_Open; FSQLite3_Close: TSQLite3_Close; FSQLite3_Exec: TSQLite3_Exec; FSQLite3_Version: TSQLite3_Version; FSQLite3_ErrMsg: TSQLite3_ErrMsg; FSQLite3_ErrCode: TSQLite3_ErrCode; FSQlite3_Free: TSQlite3_Free; FSQLite3_GetTable: TSQLite3_GetTable; FSQLite3_FreeTable: TSQLite3_FreeTable; FSQLite3_Complete: TSQLite3_Complete; FSQLite3_LastInsertRowID: TSQLite3_LastInsertRowID; FSQLite3_Interrupt: TSQLite3_Interrupt; FSQLite3_BusyHandler: TSQLite3_BusyHandler; FSQLite3_BusyTimeout: TSQLite3_BusyTimeout; FSQLite3_Changes: TSQLite3_Changes; FSQLite3_TotalChanges: TSQLite3_TotalChanges; FSQLite3_Prepare: TSQLite3_Prepare; FSQLite3_Prepare_v2: TSQLite3_Prepare_v2; FSQLite3_ColumnCount: TSQLite3_ColumnCount; FSQLite3_ColumnName: TSQLite3_ColumnName; FSQLite3_ColumnDeclType: TSQLite3_ColumnDeclType; FSQLite3_Step: TSQLite3_Step; FSQLite3_DataCount: TSQLite3_DataCount; FSQLite3_ColumnBlob: TSQLite3_ColumnBlob; FSQLite3_ColumnBytes: TSQLite3_ColumnBytes; FSQLite3_ColumnDouble: TSQLite3_ColumnDouble; FSQLite3_ColumnInt: TSQLite3_ColumnInt; FSQLite3_ColumnText: TSQLite3_ColumnText; FSQLite3_ColumnType: TSQLite3_ColumnType; FSQLite3_ColumnInt64: TSQLite3_ColumnInt64; FSQLite3_Finalize: TSQLite3_Finalize; FSQLite3_Reset: TSQLite3_Reset; public function LoadDLL(ADLLPath: string): Boolean; procedure UnloadDLL; function SQLite3_Open(AFilename: AnsiString; var db: TSQLiteDB): Integer; function SQLite3_Close(db: TSQLiteDB): integer; function SQLite3_Exec(db: TSQLiteDB; SQLStatement: PAnsiChar; CallbackPtr: TSQLiteExecCallback; UserData: Pointer; var ErrMsg: PAnsiChar): integer; function SQLite3_Version(): PAnsiChar; function SQLite3_ErrMsg(db: TSQLiteDB): PAnsiChar; function SQLite3_ErrCode(db: TSQLiteDB): integer; procedure SQlite3_Free(P: PAnsiChar); function SQLite3_GetTable(db: TSQLiteDB; SQLStatement: PAnsiChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PAnsiChar): integer; procedure SQLite3_FreeTable(Table: TSQLiteResult); function SQLite3_Complete(P: PAnsiChar): boolean; function SQLite3_LastInsertRowID(db: TSQLiteDB): int64; procedure SQLite3_Interrupt(db: TSQLiteDB); procedure SQLite3_BusyHandler(db: TSQLiteDB; CallbackPtr: TSQLiteBusyHandlerCallback; UserData: Pointer); procedure SQLite3_BusyTimeout(db: TSQLiteDB; TimeOut: integer); function SQLite3_Changes(db: TSQLiteDB): integer; function SQLite3_TotalChanges(db: TSQLiteDB): integer; function SQLite3_Prepare(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; function SQLite3_Prepare_v2(db: TSQLiteDB; SQLStatement: PAnsiChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PAnsiChar): integer; function SQLite3_ColumnCount(hStmt: TSqliteStmt): integer; function SQLite3_ColumnName(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; function SQLite3_ColumnDeclType(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; function SQLite3_Step(hStmt: TSqliteStmt): integer; function SQLite3_DataCount(hStmt: TSqliteStmt): integer; function SQLite3_ColumnBlob(hStmt: TSqliteStmt; ColNum: integer): pointer; function SQLite3_ColumnBytes(hStmt: TSqliteStmt; ColNum: integer): integer; function SQLite3_ColumnDouble(hStmt: TSqliteStmt; ColNum: integer): double; function SQLite3_ColumnInt(hStmt: TSqliteStmt; ColNum: integer): integer; function SQLite3_ColumnText(hStmt: TSqliteStmt; ColNum: integer): PAnsiChar; function SQLite3_ColumnType(hStmt: TSqliteStmt; ColNum: integer): integer; function SQLite3_ColumnInt64(hStmt: TSqliteStmt; ColNum: integer): Int64; function SQLite3_Finalize(hStmt: TSqliteStmt): integer; function SQLite3_Reset(hStmt: TSqliteStmt): integer; end; |
Die muss ich dort wieder raus machen, oder???
EDIT: Ach, dann habe ich noch eine kleine Frage zu diesem Teil:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| function TSQLiteDLLLoader.LoadDLL(ADLLPath: string): Boolean; begin FSQLiteDLLHandle := LoadLibrary(ADLLPath); Result := FSQLiteDLLHandle <> 0; if Result then begin @FSQLite3_Open := GetProcAddress(FMyDLLHandle, "SQLite3_Open"); end; end;
procedure TSQLiteDLLLoader.UnloadDLL; begin if FSQLiteDLLHandle <> 0 then begin FreeLibrary(FSQLiteDLLHandle); FMyDLLHandle := 0; end; end; |
jaenicke - So 09.10.11 09:01
Öhm, ja, FMyDLLHandle ist übriggeblieben, ich habe zuerst nur ein Beispiel im Browser angefangen zu tippen und dann doch die Open-Funktion und die richtige DLL genommen. ;-)
Welche Funktionen du brauchst und drin haben willst / musst, musst du doch selbst wissen, aber was du mit nicht mit der DLL zu tun meinst, sehe ich gerade nicht. :gruebel:
LittleBen - So 09.10.11 11:27
Meinte etwas anderes.
Es müssen doch eigentlich nur solche Funktionen
Delphi-Quelltext
1:
| function SQLite3_Version(): PAnsiChar; cdecl; external SQLiteDLL name 'sqlite3_libversion'; |
in die Klasse, da die aus der DLL stammen. Aber solche
function SQLiteErrorStr(SQLiteErrorCode: Integer): AnsiString; sollen nicht rein. So ist es, oder?
jaenicke - So 09.10.11 11:50
Ach so, doch, die können ja auch rein, die gehören ja dazu, auch wenn sie nicht aus der DLL stammen. Die Kapselung in einer Klasse dient aber auch der Zusammenfassung der Funktionen, deshalb macht es Sinn alles reinzupacken.
(Denn theoretisch würde sich das auch ohne eigene Klasse machen lassen, aber nicht so schön.)
LittleBen - So 09.10.11 13:25
jaenicke - So 09.10.11 13:56
Erstens hast du vergessen auch die anderen Funktionen in LoadDLL zu laden und zweitens habe ich gerade nochmal ins Original geschaut, die Funktionsnamen in der DLL sind ja kleingeschrieben, also muss das auch so heißen. Außerdem hatte ich vergessen Result nochmal ggf. zu korrigieren. Aber den Rückghabewert von LoadDLL hast du ja in deinem Quelltext ohnehin weggeworfen und nicht geprüft.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| function TSQLiteDLLLoader.LoadDLL(ADLLPath: string): Boolean; begin FSQLiteDLLHandle := LoadLibrary(PChar(ADLLPath)); Result := FSQLiteDLLHandle <> 0; if Result then begin @FSQLite3_Open := GetProcAddress(FSQLiteDLLHandle, 'sqlite3_open'); @...
Result := Assigned(FSQLite3_Open) and Assigned... end; end; |
// EDIT:
Nebenbei würde ich PAnsiChar überall durch AnsiString ersetzen in den Aufrufen von außen. Dann kannst du das immer an die Original-DLL-Funktion per Cast weitergeben, aber nach außen sind es normale Delphi-AnsiStrings. Das macht den Aufruf einfacher, deshalb hatte ich das auch so gemacht im Beispiel.
LittleBen - So 09.10.11 14:31
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!