unit iac_dbrw; interface implementation uses windows, messages, commctrl, global, iac_global, m_api,dbsettings, common,mirutils,wrapper, editwrapper,contact,dlgshare; {$include i_cnst_database.inc} {$resource iac_database.res} const opt_module = 'module'; opt_setting = 'setting'; opt_value = 'value'; const ioOper = 'oper'; ioDelete = 'delete'; ioWrite = 'write'; ioCurrent = 'current'; ioParam = 'param'; ioResult = 'result'; ioModule = 'module'; ioSetting = 'setting'; ioContact = 'contact'; ioFileVariable = 'modvariables'; ioArgVariable = 'argvariables'; ioVariables = 'variables'; ioType = 'type'; ioByte = 'byte'; ioWord = 'word'; ioDword = 'dword'; ioAnsi = 'ansi'; ioLast = 'last'; ioSaveValue = 'savevalue'; const ACF_DBWRITE = $00000001; // write to (not read from) DB ACF_DBDELETE = $00000002; // delete setting ACF_DBBYTE = $00000004; // read/write byte (def. dword) ACF_DBWORD = $00000008; // read/write word (def. dword) ACF_DBUTEXT = $00000010; // read/write Unicode string ACF_DBANSI = $00000020; // read/write ANSI string ACF_PARAM = $00000040; // hContact from parameter ACF_CURRENT = $00000080; // hContact is 0 (user settings) ACF_RESULT = $00000100; // hContact is last result value ACF_LAST = $00000200; // use last result for DB writing ACF_SAVE = $00000400; // save writing value to Last Result // dummy ACF_DBDWORD = 0; ACF_DBREAD = 0; ACF_MANUAL = 0; ACF_NOCONTACT = ACF_PARAM or ACF_CURRENT or ACF_RESULT; ACF_VALUETYPE = ACF_DBBYTE or ACF_DBWORD or ACF_DBUTEXT or ACF_DBANSI; ACF_TEXT = ACF_DBUTEXT or ACF_DBANSI; ACF_OPERATION = ACF_DBWRITE or ACF_DBDELETE; ACF_RW_MODULE = $00001000; // script for module name ACF_RW_SETTING = $00002000; // script for setting name ACF_RW_VALUE = $00004000; // script for data value type tDataBaseAction = class(tBaseAction) private dbcontact:HCONTACT; dbmodule :PWideChar; dbsetting:PWideChar; dbvalue :PWideChar; // keep all in unicode (str to int translation fast) public constructor Create(uid:dword); destructor Destroy; override; // function Clone:tBaseAction; override; function DoAction(var WorkData:tWorkData):LRESULT; override; procedure Save(node:pointer;fmt:integer); override; procedure Load(node:pointer;fmt:integer); override; end; //----- Support functions ----- //----- Object realization ----- constructor tDataBaseACtion.Create(uid:dword); begin inherited Create(uid); dbcontact:=0; dbmodule :=nil; dbsetting:=nil; dbvalue :=nil; end; destructor tDataBaseAction.Destroy; begin mFreeMem(dbmodule); mFreeMem(dbsetting); mFreeMem(dbvalue); inherited Destroy; end; { function tDataBaseAction.Clone:tBaseAction; var tmp:tDataBaseAction; begin result:=tDataBaseAction.Create(0); Duplicate(result); tmp.dbcontact:=dbcontact; StrDupW(tmp.dbmodule ,dbmodule); StrDupW(tmp.dbsetting,dbsetting); if ((flags and ACF_DBDELETE)=0) and ((flags and ACF_LAST)=0) then StrDupW(tmp.dbvalue,dbvalue); result:=tmp; end; } function tDataBaseAction.DoAction(var WorkData:tWorkData):LRESULT; var sbuf:array [0..31] of WideChar; bufw:array [0..255] of WideChar; ambuf,asbuf:array [0..127] of AnsiChar; ls,tmp:pWideChar; tmpa,tmpa1:pAnsiChar; hContact:THCONTACT; proto:pAnsiChar; avalue:uint_ptr; begin result:=0; // contact case (flags and ACF_NOCONTACT) of ACF_CURRENT: hContact:=0; ACF_PARAM : hContact:=WorkData.Parameter; ACF_RESULT : hContact:=WorkData.LastResult; else hContact:=dbcontact; end; //--- // last result for scripts if WorkData.ResultType=rtWide then ls:=pWideChar(WorkData.LastResult) else begin ls:=@sbuf; IntToStr(sbuf,WorkData.LastResult); end; proto:=GetContactProtoAcc(hContact); // now need to process module if (flags and ACF_RW_MODULE)<>0 then begin tmp:=ParseVarString(dbmodule,hContact,ls); StrCopyW(bufw,tmp); mFreeMem(tmp); end else StrCopyW(bufw,dbmodule); StrReplaceW(@bufw,'',ls); FastWideToAnsiBuf(bufw,ambuf,SizeOf(ambuf)-1); StrReplace(ambuf,protostr,proto); // now process settings if (flags and ACF_RW_SETTING)<>0 then begin tmp:=ParseVarString(dbsetting,hContact,ls); StrCopyW(bufw,tmp); mFreeMem(tmp); end else StrCopyW(bufw,dbsetting); StrReplaceW(@bufw,'',ls); FastWideToAnsiBuf(bufw,asbuf,SizeOf(asbuf)-1); StrReplace(asbuf,protostr,proto); // Delete data if (flags and ACF_DBDELETE)<>0 then begin if (asbuf[0]='*') or (asbuf[StrLen(asbuf)-1]='*') then DBDeleteGroup(hContact,ambuf,asbuf) else DBDeleteSetting(hContact,ambuf,asbuf); end else begin if (flags and ACF_LAST)<>0 then begin avalue:=WorkData.LastResult; if WorkData.ResultType=rtInt then // have number begin if (flags and ACF_DBUTEXT)=ACF_DBUTEXT then // need wide text avalue:=uint_ptr(IntToStr(sbuf,avalue)) else if (flags and ACF_DBANSI)=ACF_DBANSI then // need ansi text avalue:=uint_ptr(IntToStr(pAnsiChar(@sbuf),avalue)); end // got wide text else if (flags and ACF_TEXT)=0 then // need number avalue:=NumToInt(pWideChar(avalue)); { val=LR(wide) (wide,ansi) val=pointer to static buffer (wide, ansi) val=number(number) } end else begin if (flags and ACF_RW_VALUE)<>0 then begin avalue:=uint_ptr(ParseVarString(dbvalue,hContact,ls)); end else avalue:=uint_ptr(dbvalue); if (flags and ACF_TEXT)=0 then // need a number begin tmp:=pWideChar(avalue); avalue:=NumToInt(pWideChar(avalue)); if (flags and ACF_RW_VALUE)<>0 then mFreeMem(tmp); end; { val=uint_ptr if need number(number) val=script result wide(need to free) (wide,ansi) val=original dbvalue wide (wide,ansi) } end; // Write value if (flags and ACF_DBWRITE)<>0 then begin case (flags and ACF_VALUETYPE) of ACF_DBBYTE: DBWriteByte(hContact,ambuf,asbuf,avalue); ACF_DBWORD: DBWriteWord(hContact,ambuf,asbuf,avalue); ACF_DBANSI: begin WideToAnsi(pWideChar(avalue),tmpa,MirandaCP); DBWriteString(hContact,ambuf,asbuf,tmpa); mFreeMem(tmpa); end; ACF_DBUTEXT: begin DBWriteUnicode(hContact,ambuf,asbuf,pWideChar(avalue)); end; else DBWriteDWord(hContact,ambuf,asbuf,avalue); end; if (flags and ACF_SAVE)<>0 then begin ClearResult(WorkData); case (flags and ACF_VALUETYPE) of ACF_DBANSI, ACF_DBUTEXT: begin StrDupW(pWideChar(WorkData.LastResult),pWideChar(avalue)); WorkData.ResultType:=rtWide; end; else WorkData.LastResult:=avalue; WorkData.ResultType:=rtInt; end; end; end // Read value else begin ClearResult(WorkData); WorkData.ResultType:=rtInt; case (flags and ACF_VALUETYPE) of ACF_DBBYTE: WorkData.LastResult:=DBReadByte(hContact,ambuf,asbuf,avalue); ACF_DBWORD: WorkData.LastResult:=DBReadWord(hContact,ambuf,asbuf,avalue); ACF_DBANSI: begin WideToAnsi(pWideChar(avalue),tmpa1,MirandaCP); tmpa:=DBReadString(hContact,ambuf,asbuf,tmpa1); AnsiToWide(tmpa,PWideChar(WorkData.LastResult),MirandaCP); WorkData.ResultType:=rtWide; mFreeMem(tmpa1); mFreeMem(tmpa); end; ACF_DBUTEXT: begin WorkData.LastResult:=uint_ptr(DBReadUnicode(hContact,ambuf,asbuf,pWideChar(avalue))); WorkData.ResultType:=rtWide; end else WorkData.LastResult:=DBReadDWord(hContact,ambuf,asbuf,avalue); end; end; if (flags and ACF_RW_VALUE)<>0 then begin if (flags and ACF_TEXT)<>0 then begin mFreeMem(avalue); end; end; end; end; procedure tDataBaseAction.Load(node:pointer;fmt:integer); var section: array [0..127] of AnsiChar; pc:pAnsiChar; tmp:pWideChar; begin inherited Load(node,fmt); case fmt of 0: begin if (flags and ACF_NOCONTACT)=0 then dbcontact:=LoadContact(DBBranch,node); pc:=StrCopyE(section,pAnsiChar(node)); StrCopy(pc,opt_module ); dbmodule :=DBReadUnicode(0,DBBranch,section); StrCopy(pc,opt_setting); dbsetting:=DBReadUnicode(0,DBBranch,section); if ((flags and ACF_DBDELETE)=0) and ((flags and ACF_LAST)=0) then begin StrCopy(pc,opt_value); dbvalue:=DBReadUnicode(0,DBBranch,section); end; end; 1: begin with xmlparser do begin tmp:=getAttrValue(HXML(node),ioOper); if lstrcmpiw(tmp,ioDelete)=0 then flags:=flags or ACF_DBDELETE else if lstrcmpiw(tmp,ioWrite )=0 then flags:=flags or ACF_DBWRITE; // else if lstrcmpiw(tmp,ioRead)=0 then ; tmp:=getAttrValue(HXML(node),ioContact); if lstrcmpiw(tmp,ioCurrent)=0 then flags:=flags or ACF_CURRENT else if lstrcmpiw(tmp,ioResult )=0 then flags:=flags or ACF_RESULT else if lstrcmpiw(tmp,ioParam )=0 then flags:=flags or ACF_PARAM else if lstrcmpiw(tmp,ioContact)=0 then begin dbcontact:=ImportContact(HXML(node)); end; StrDupW(dbmodule ,getAttrValue(HXML(node),ioModule)); StrDupW(dbsetting,getAttrValue(HXML(node),ioSetting)); if StrToInt(getAttrValue(HXML(node),ioFileVariable))=1 then flags:=flags or ACF_RW_MODULE; if StrToInt(getAttrValue(HXML(node),ioArgVariable ))=1 then flags:=flags or ACF_RW_SETTING; if StrToInt(getAttrValue(HXML(node),ioVariables ))=1 then flags:=flags or ACF_RW_VALUE; tmp:=getAttrValue(HXML(node),ioType); if lstrcmpiw(tmp,ioByte )=0 then flags:=flags or ACF_DBBYTE else if lstrcmpiw(tmp,ioWord )=0 then flags:=flags or ACF_DBWORD else if lstrcmpiw(tmp,ioDword)=0 then else if lstrcmpiw(tmp,ioAnsi )=0 then flags:=flags or ACF_DBANSI else flags:=flags or ACF_DBUTEXT; if StrToInt(getAttrValue(HXML(node),ioSaveValue))=1 then flags:=flags or ACF_SAVE; if StrToInt(getAttrValue(HXML(node),ioLast))=1 then flags:=flags or ACF_LAST else StrDupW(dbvalue,getText(HXML(node))); end; end; { 2: begin pc:=GetParamSectionStr(node,ioOper); if lstrcmpi(pc,ioDelete)=0 then flags:=flags or ACF_DBDELETE else if lstrcmpi(pc,ioWrite )=0 then flags:=flags or ACF_DBWRITE; // else if lstrcmpiw(tmp,ioRead)=0 then ; pc:=GetParamSectionStr(node,ioContact); if lstrcmpi(pc,ioCurrent)=0 then flags:=flags or ACF_CURRENT else if lstrcmpi(pc,ioResult )=0 then flags:=flags or ACF_RESULT else if lstrcmpi(pc,ioParam )=0 then flags:=flags or ACF_PARAM else if lstrcmpi(pc,ioContact)=0 then begin dbcontact:=ImportContactINI(node); end; UF8ToWide(GetParamSectionStr(node,ioModule ),dbmodule); UF8ToWide(GetParamSectionStr(node,ioSetting),dbsetting); if GetParamSectionInt(node,ioFileVariable)=1 then flags:=flags or ACF_RW_MODULE; if GetParamSectionInt(node,ioArgVariable )=1 then flags:=flags or ACF_RW_SETTING; if GetParamSectionInt(node,ioVariables )=1 then flags:=flags or ACF_RW_VALUE; pc:=GetParamSectionStr(node,ioType); if lstrcmpi(pc,ioByte )=0 then flags:=flags or ACF_DBBYTE else if lstrcmpi(pc,ioWord )=0 then flags:=flags or ACF_DBWORD else if lstrcmpi(pc,ioDword)=0 then else if lstrcmpi(pc,ioAnsi )=0 then flags:=flags or ACF_DBANSI else flags:=flags or ACF_DBUTEXT; if GetParamSectionInt(node,ioLast))=1 then flags:=flags or ACF_LAST else UF8ToWide(GetParamSectionStr(node,'value'),dbvalue); //!! end; } end; end; procedure tDataBaseAction.Save(node:pointer;fmt:integer); var section: array [0..127] of AnsiChar; pc:pAnsiChar; begin inherited Save(node,fmt); case fmt of 0: begin if (flags and ACF_NOCONTACT)=0 then SaveContact(dbcontact,DBBranch,node); pc:=StrCopyE(section,pAnsiChar(node)); StrCopy(pc,opt_module ); DBWriteUnicode(0,DBBranch,section,dbmodule); StrCopy(pc,opt_setting); DBWriteUnicode(0,DBBranch,section,dbsetting); if ((flags and ACF_DBDELETE)=0) and ((flags and ACF_LAST)=0) then begin StrCopy(pc,opt_value); DBWriteUnicode(0,DBBranch,section,dbvalue); end; end; { 1: begin end; } end; end; //----- Dialog realization ----- procedure MakeDataTypeList(wnd:HWND); begin SendMessage(wnd,CB_RESETCONTENT,0,0); InsertString(wnd,0,'Byte'); InsertString(wnd,1,'Word'); InsertString(wnd,2,'DWord'); InsertString(wnd,3,'Ansi'); InsertString(wnd,4,'Unicode'); SendMessage(wnd,CB_SETCURSEL,0,0); end; procedure ClearFields(Dialog:HWND); begin CheckDlgButton(Dialog,IDC_RW_LAST,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_SAVE,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_CURRENT,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_MANUAL ,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_PARAM ,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_RESULT ,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_READ ,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_WRITE ,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_RW_DELETE,BST_UNCHECKED); end; function DlgProc(Dialog:HWnd;hMessage:UINT;wParam:WPARAM;lParam:LPARAM):lresult; stdcall; const NoProcess:boolean=true; var wnd:HWND; i:integer; bb:boolean; begin result:=0; case hMessage of WM_INITDIALOG: begin TranslateDialogDefault(Dialog); MakeDataTypeList(GetDlgItem(Dialog,IDC_RW_DATATYPE)); wnd:=GetDlgItem(Dialog,IDC_CNT_REFRESH); OptSetButtonIcon(wnd,ACI_REFRESH); SendMessage(wnd,BUTTONADDTOOLTIP,TWPARAM(TranslateW('Refresh')),BATF_UNICODE); OptFillContactList(GetDlgItem(Dialog,IDC_CONTACTLIST)); MakeEditField(Dialog,IDC_RW_MODULE); MakeEditField(Dialog,IDC_RW_SETTING); MakeEditField(Dialog,IDC_RW_VALUE); end; WM_ACT_SETVALUE: begin NoProcess:=true; ClearFields(Dialog); with tDataBaseAction(lParam) do begin // operation if (flags and ACF_DBDELETE)<>0 then i:=IDC_RW_DELETE else if (flags and ACF_DBWRITE )= 0 then i:=IDC_RW_READ else i:=IDC_RW_WRITE; CheckDlgButton(Dialog,i,BST_CHECKED); // contact bb:=false; case (flags and ACF_NOCONTACT) of ACF_CURRENT: i:=IDC_RW_CURRENT; ACF_PARAM : i:=IDC_RW_PARAM; ACF_RESULT : i:=IDC_RW_RESULT; else i:=IDC_RW_MANUAL; bb:=true; SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_SETCURSEL, FindContact(GetDlgItem(Dialog,IDC_CONTACTLIST),dbcontact),0); end; CheckDlgButton(Dialog,i,BST_CHECKED); EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),bb); SetDlgItemTextW(Dialog,IDC_RW_MODULE ,dbmodule); SetDlgItemTextW(Dialog,IDC_RW_SETTING,dbsetting); SetEditFlags(Dialog,IDC_RW_MODULE ,EF_SCRIPT,ord((flags and ACF_RW_MODULE )<>0)); SetEditFlags(Dialog,IDC_RW_SETTING,EF_SCRIPT,ord((flags and ACF_RW_SETTING)<>0)); // values bb:=true; if (flags and ACF_LAST)<>0 then begin CheckDlgButton(Dialog,IDC_RW_LAST,BST_CHECKED); bb:=false; end; if (flags and ACF_DBDELETE)<>0 then bb:=false; EnableWindow(GetDlgItem(Dialog,IDC_RW_VALUE),bb); if (flags and ACF_SAVE)<>0 then CheckDlgButton(Dialog,IDC_RW_SAVE,BST_CHECKED); EnableWindow(GetDlgItem(Dialog,IDC_RW_SAVE),(flags and ACF_DBWRITE)<>0); case (flags and ACF_VALUETYPE) of ACF_DBBYTE : i:=0; ACF_DBWORD : i:=1; ACF_DBANSI : i:=3; ACF_DBUTEXT: i:=4; else i:=2; end; CB_SelectData(GetDlgItem(Dialog,IDC_RW_DATATYPE),i); SetDlgItemTextW(Dialog,IDC_RW_VALUE,dbvalue); SetEditFlags(Dialog,IDC_RW_VALUE,EF_SCRIPT,ord((flags and ACF_RW_VALUE)<>0)); end; NoProcess:=false; end; WM_ACT_RESET: begin NoProcess:=true; ClearFields(Dialog); SetDlgItemTextW(Dialog,IDC_RW_MODULE ,nil); SetDlgItemTextW(Dialog,IDC_RW_SETTING,nil); SetDlgItemTextW(Dialog,IDC_RW_VALUE ,nil); SetEditFlags(Dialog,IDC_RW_MODULE ,EF_ALL,0); SetEditFlags(Dialog,IDC_RW_SETTING,EF_ALL,0); SetEditFlags(Dialog,IDC_RW_VALUE ,EF_ALL,0); CB_SelectData(GetDlgItem(Dialog,IDC_RW_DATATYPE),0); CheckDlgButton(Dialog,IDC_RW_READ ,BST_CHECKED); CheckDlgButton(Dialog,IDC_RW_MANUAL,BST_CHECKED); EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),true); EnableWindow(GetDlgItem(Dialog,IDC_RW_VALUE),true); NoProcess:=false; end; WM_ACT_SAVE: begin with tDataBaseAction(lParam) do begin // contact if IsDlgButtonChecked(Dialog,IDC_RW_CURRENT)=BST_CHECKED then flags:=flags or ACF_CURRENT else if IsDlgButtonChecked(Dialog,IDC_RW_RESULT )=BST_CHECKED then flags:=flags or ACF_RESULT else if IsDlgButtonChecked(Dialog,IDC_RW_PARAM )=BST_CHECKED then flags:=flags or ACF_PARAM else dbcontact:=SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_GETITEMDATA, SendDlgItemMessage(Dialog,IDC_CONTACTLIST,CB_GETCURSEL,0,0),0); {mFreeMem(dbmodule ); }dbmodule :=GetDlgText(Dialog,IDC_RW_MODULE); {mFreeMem(dbsetting); }dbsetting:=GetDlgText(Dialog,IDC_RW_SETTING); if (GetEditFlags(Dialog,IDC_RW_MODULE ) and EF_SCRIPT)<>0 then flags:=flags or ACF_RW_MODULE; if (GetEditFlags(Dialog,IDC_RW_SETTING) and EF_SCRIPT)<>0 then flags:=flags or ACF_RW_SETTING; // operation if IsDlgButtonChecked(Dialog,IDC_RW_WRITE )=BST_CHECKED then flags:=flags or ACF_DBWRITE else if IsDlgButtonChecked(Dialog,IDC_RW_DELETE)=BST_CHECKED then flags:=flags or ACF_DBDELETE; // value if IsDlgButtonChecked(Dialog,IDC_RW_LAST)<>BST_UNCHECKED then flags:=flags or ACF_LAST else if (flags and ACF_DBDELETE)=0 then begin {mFreeMem(dbvalue); }dbvalue:=GetDlgText(Dialog,IDC_RW_VALUE); if (GetEditFlags(Dialog,IDC_RW_VALUE) and EF_SCRIPT)<>0 then flags:=flags or ACF_RW_VALUE; end; if IsDlgButtonChecked(Dialog,IDC_RW_SAVE)<>BST_UNCHECKED then flags:=flags or ACF_SAVE; i:=CB_GetData(GetDlgItem(Dialog,IDC_RW_DATATYPE)); case i of 0: flags:=flags or ACF_DBBYTE; 1: flags:=flags or ACF_DBWORD; 2: flags:=flags or 0; 3: flags:=flags or ACF_DBANSI; 4: flags:=flags or ACF_DBUTEXT; end; end; end; WM_COMMAND: begin case wParam shr 16 of CBN_SELCHANGE, EN_CHANGE: if not NoProcess then SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0); BN_CLICKED: begin case loword(wParam) of IDC_RW_READ, IDC_RW_WRITE, IDC_RW_DELETE: begin bb:=IsDlgButtonChecked(Dialog,IDC_RW_DELETE)=BST_UNCHECKED; EnableWindow(GetDlgItem(Dialog,IDC_RW_DATATYPE),bb); EnableWindow(GetDlgItem(Dialog,IDC_RW_LAST),bb); if bb then bb:=IsDlgButtonChecked(Dialog,IDC_RW_LAST)=BST_UNCHECKED; EnableEditField(GetDlgItem(Dialog,IDC_RW_VALUE),bb); bb:=loword(wParam)=IDC_RW_WRITE; EnableWindow(GetDlgItem(Dialog,IDC_RW_SAVE),bb); end; IDC_RW_CURRENT, IDC_RW_PARAM, IDC_RW_RESULT: EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),false); IDC_RW_MANUAL: EnableWindow(GetDlgItem(Dialog,IDC_CONTACTLIST),true); IDC_RW_LAST: begin EnableEditField(GetDlgItem(Dialog,IDC_RW_VALUE), IsDlgButtonChecked(Dialog,IDC_RW_LAST)=BST_UNCHECKED); end; IDC_CNT_REFRESH: begin OptFillContactList(GetDlgItem(Dialog,IDC_CONTACTLIST)); exit; end; end; SendMessage(GetParent(GetParent(Dialog)),PSM_CHANGED,0,0); end; end; end; WM_HELP: begin result:=1; end; end; end; //----- Export/interface functions ----- var vc:tActModule; function CreateAction:tBaseAction; begin result:=tDataBaseAction.Create(vc.Hash); end; function CreateDialog(parent:HWND):HWND; begin result:=CreateDialogW(hInstance,'IDD_ACTDATABASE',parent,@DlgProc); end; procedure Init; begin vc.Next :=ModuleLink; vc.Name :='Database'; vc.Dialog :=@CreateDialog; vc.Create :=@CreateAction; vc.Icon :='IDI_DATABASE'; vc.Hash :=0; ModuleLink :=@vc; end; begin Init; end.