Jeg har de sidste par dage huseret her i Delphi miljøet. Nu smider jeg så en lidt større opgave. Eller rettere: Jeg smider den opgave der ligger til grund for mine tidligere spørgsmål. Jeg har fået følgende med mig:
Interfaces til ACSDLL.DLL:
Alle funktioner skal deklareres, men behøver ikke nødvendigvis bruges.
function Init(Var S: PChar): integer; export;
Kaldes når ACSAgent startes op, her kan man lave initialisering af diverse ting og sager. Parametren S sendes tilbage til ACSAgent, og angiver hvad menupunktet som kalder DLLUserCmd skal have som caption.
function Done: integer; export;
Kaldes når ACSAgent lukkes ned, her kan man rydde op o.s.v.
function FindCustomer(Navn: Pchar): integer; export;
Selve søgerutinen, når agenten tager et kald, kaldes denne rutine. Parametren NAVN kan være hvad som helst, bare det er i strengformat. (Navn, kundenummer o.s.v.)
function DLLUserCmd(S:PChar): Integer; export;
Rutine som kan kaldes fra ACSAgent, f.eks. "Vis alle i Access"
//CUT---
unit DLLMain;
interface
function Init(Var S: PChar): integer; export; function Done: integer; export; function FindCustomer(Navn: Pchar): integer; export; function DLLUserCmd(S:PChar): Integer; export;
var Nix, Acc:Variant; FormName, DB, FFilePath: string;
function Init(Var S: PChar): integer; Var IniFile : TIniFile; buffer : array [0..255] of char; S1 : String; begin CoInitialize(nil); GetWindowsDirectory(buffer,SizeOf(buffer)); S := 'Vis alle i Access'; S1 := String(Buffer)+'\ACS4000.ini'; IniFile := TIniFile.Create(S1); With IniFile Do Begin FormName := ReadString('DLL','FormName','Hovedvindue'); DB := ReadString('DLL', 'Database', 'C:\Access\TP Teknik.Mdb'); Free; End; Try Acc := GetActiveOleObject('Access.Application'); Except Acc := CreateOleObject('Access.Application'); End; Acc.Visible := True; Try Acc.OpenCurrentDatabase(DB, False); Acc.DoCmd.OpenForm(FormName, acViewNormal, Nix, Nix, acEdit, acWindowNormal, Nix); Result := 0; Except Result := -1; End; end;
function Done: integer; begin OleUninitialize; Result := 0; end;
function FindCustomer(Navn: Pchar): integer; Var S :String; V :Integer; C :Int64; begin S := String(Navn); Val(S,C,V); If V = 0 Then Begin S := Format('([Telefon] = ''%d'') OR ',[C]); //OR S := S+Format('([Primær nummerserie fra] <= ''%d'' AND [Primær nummerserie til] >= ''%d'')',[C,C]); S := S+Format(' OR ([Sekundær nummerserie fra] <= ''%d'' AND [Sekundær nummerserie til] >= ''%d'')',[C,C]); Acc.DoCmd.OpenForm(FormName,acViewNormal,Nix,S,acEdit,acWindowNormal,Nix); Result := 0; End Else Result :=-1; end;
function DLLUserCmd(S:PChar): Integer; Begin Acc.DoCmd.ShowAllRecords; Result := 0; End;
initialization
end.
Mit spørgsmål er, hvordan jeg får lavet denne 'unit' om til et library (DLL). Ydermere er jeg meget usikker hvorvidt der er nogle logiske fejl. Er jo ikke så rutineret en programmør :-D
Dit spørgsmål giver ikke mening. Derfor har du ingen svar fået på det !
Hvis du vil have en DLL fil skal du vælge det under New projekt.
Forskellen (mend projektet er i Delphi) er at DPR filen startet med "library" og ikke med "program". Hvis du har en unit du ønsker at bruge i Din DLL fil skal du bare use den på samme måde som i en Exe fil !
Tak for svaret, Jens. Det som jeg ikke lige fik nævnt er, at det er reverse engineering. Derfor har jeg selv siddet og rodet med det. Og jeg tror faktisk at det endte med at være nogenlunde.
{ Code start }
library ACSDLL;
{ Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. }
uses SysUtils, Classes, Windows, Inifiles, ComObj, ActiveX, Dialogs; // Not nessesary at this point, but required for userdialogs
{$R *.res}
const // Global Constants - All used for MS Access interaction acViewNormal = $00000000; acViewDesign = $00000001; acViewPreview = $00000002; acAdd = $00000000; acEdit = $00000001; acReadOnly = $00000002; acWindowNormal = $00000000; acHidden = $00000001; acIcon = $00000002; acDialog = $00000003;
var // Global Variables Nix, Access: Variant; // Access variable is the MS Access Database FormName, DB, FFilePath: string;
function Init(var S: PChar): Integer; export; var IniFile : TIniFile; buffer : array [0..255] of char; S1 : string;
begin CoInitialize(nil); GetWindowsDirectory(buffer,SizeOf(buffer)); S := 'Vis alle i Access'; S1 := string(buffer)+'\ACS4000.ini'; IniFile := TIniFile.Create(S1); with IniFile do begin FormName := ReadString('DLL','FormName','Hovedvindue'); DB := ReadString('DLL','Database','C:\ACSTEST\TEST_DAB.mdb'); Free; end; // With try { open the Access application } Access := GetActiveOleObject('Access.Application'); except Access := CreateOleObject('Access.Application'); end; // Try Access.Visible := True; try { open the database The second parameter specifies whether you want to open the database in Exclusive mode } Access.OpenCurrentDatabase(DB, False); { open the form The value for the second parameter should be one of acViewDesign, acViewNormal, or acViewPreview. acViewNormal, which is the default } Access.DoCmd.OpenForm(FormName, acViewNormal, Nix, Nix, acEdit, acWindowNormal, Nix); Result := 0; except Result := -1; end; // Try end; // function Init
function Done: Integer; export; begin OleUninitialize; Result := 0; end; // function Done
function FindCustomer(Navn: PChar): Integer; export; var S : string; V : Integer; C : Int64;
begin S := string(Navn); Val(S,C,V); if V = 0 then begin S := Format('([Telefon] = ''%d'') OR ',[C]); //OR S := S + Format('([Primær nummerserie fra] <= ''%d'' AND [Primær nummerserie til] >= ''%d'')',[C,C]); S := S + Format(' OR ([Sekundær nummerserie fra] <= ''%d'' AND [Sekundær nummerserie til] >= ''%d'')',[C,C]); Access.DoCmd.OpenForm(FormName,acViewNormal,Nix,S,acEdit,acWindowNormal,Nix); Result := 0; end // If else Result :=-1; end; // function FindCustomer
function DLLUserCmd(S: PChar): Integer; export; begin Access.DoCmd.ShowAllRecords; Result := 0; end; // function DLLUserCmd
Jeg har dog stadig lige et spørgsmål vedrørende 'string' i forhold til 'PChar'. Det er vist ikke så godt med 'string'. Kan jeg i dette tilfælde bare udskifte uden problemer? Det samme gør sig sådan set gældende for 'val' og 'en-anden-jeg-ikke-lige-kan-huske'
Du kan bare bruge Stenge blot du følger de anvisninger der er i toppen af din fil. Ellers brug ShortString, eller Pchar. Og ja det skulle ikke betyde noget
Et andet spørgsmål der har givet mig rigtig mange kvaler. Denne DLL skal erstatte en eksisterende DLL i et program. Der er også et ønske om et brugerinterface. En af mine 'S' variabler skal trigge et spørgsmål til brugeren. Eksempelvis: 'Vil du se denne bruger i Access? (Y/N). Problemet er at al arbejde skal foregå i Dll'en. Mener du det vil være meget svært? Jeg tror det må være noget med at Init kalder en function, der prompter brugeren (funtion UserPropt), og returnerer en 'boolean' (eller lignende) til Init. function UserPrompt skal så kalde en 'Messagebox' rutine. Er dette helt skævt?
Fik udskiftet alle 'string' med 'ShortString' og den compiler uden problemer. Tak for det.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.