{ in dialog: sends CBN_EDITCHANGE for changes } unit srvblock; interface uses windows, awkservices; //----- Service dialog ----- function CreateServiceBlock(parent:HWND;x,y,width,height:integer;flags:dword=0):HWND; procedure ClearServiceBlock (Dialog:HWND); procedure SetServiceListMode(Dialog:HWND;mode:integer); function SetSrvBlockValue(Dialog:HWND;const value:tServiceValue):boolean; function GetSrvBlockValue(Dialog:HWND;var value:tServiceValue):boolean; // service setting for templates procedure SetSrvBlockService(Dialog:HWND; service:PAnsiChar); function GetSrvBlockService(Dialog:HWND):PAnsiChar; //----- ServiceValue functions ----- procedure CopyServiceValue (var dst :tServiceValue; const src:tServiceValue); procedure ClearServiceValue(var data:tServiceValue); procedure SaveServiceValue (const data:tServiceValue; module,setting:PAnsiChar); procedure LoadServiceValue (var data:tServiceValue; module,setting:PAnsiChar); //----- Service execute ----- function ExecuteService(const service:tServiceValue; var data:tSubstData):boolean; implementation uses messages, common, m_api, syswin, wrapper,Editwrapper, dbsettings,mApiCardM, mirutils,mircontacts, sparam,strans; //----- Service dialog ----- const IDC_S_SERVICE = 2040; IDC_C_SERVICE = 2041; IDC_CLOSE_WPAR = 2042; IDC_CLOSE_LPAR = 2043; IDC_CLOSE_RES = 2044; function GetApiCard(Dialog:HWND):tmApiCard; begin result:=tmApiCard(GetWindowLongPtrW(GetDlgItem(Dialog,IDC_S_SERVICE),GWLP_USERDATA)); end; function GetWPar(Dialog:HWND):HWND; begin result:=GetWindowLongPtrW(GetDlgItem(Dialog,IDC_CLOSE_WPAR),GWLP_USERDATA); end; function GetLPar(Dialog:HWND):HWND; begin result:=GetWindowLongPtrW(GetDlgItem(Dialog,IDC_CLOSE_LPAR),GWLP_USERDATA); end; function GetRes(Dialog:HWND):HWND; begin result:=GetWindowLongPtrW(GetDlgItem(Dialog,IDC_CLOSE_RES),GWLP_USERDATA); end; procedure ShowBlock(Dialog:HWND;id:integer); var wpar ,lpar ,res:HWND; wparb,lparb,resb:HWND; wnd,wndb:HWND; rc,rc1:TRECT; pt:TPOINT; begin // buttons wpar:=GetDlgItem(Dialog,IDC_CLOSE_WPAR); lpar:=GetDlgItem(Dialog,IDC_CLOSE_LPAR); res :=GetDlgItem(Dialog,IDC_CLOSE_RES); // blocks wparb:=GetWindowLongPtrW(wpar,GWLP_USERDATA); lparb:=GetWindowLongPtrW(lpar,GWLP_USERDATA); resb :=GetWindowLongPtrW(res ,GWLP_USERDATA); if id=0 then begin ShowWindow(wparb,SW_HIDE); ShowWindow(lparb,SW_HIDE); ShowWindow(resb ,SW_HIDE); exit; end; // starting point of coords GetWindowRect(wpar,rc); pt.x:=rc.left; pt.y:=rc.bottom; ScreenToClient(Dialog,pt); // show/hide blocks // enable/disable buttons // move buttons to new place case id of IDC_CLOSE_WPAR: begin CheckDlgButton(Dialog,IDC_CLOSE_WPAR,BST_CHECKED); CheckDlgButton(Dialog,IDC_CLOSE_LPAR,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_CLOSE_RES ,BST_UNCHECKED); EnableWindow(lpar,true); EnableWindow(res ,true); ShowWindow(lparb,SW_HIDE); ShowWindow(resb ,SW_HIDE); wnd :=wpar; wndb:=wparb; GetClientRect(wparb,rc1); SetWindowPos(lpar,HWND_TOP,pt.x,pt.y+rc1.bottom+5,0,0,SWP_NOZORDER or SWP_NOSIZE); GetClientRect(lpar,rc); SetWindowPos(res,HWND_TOP,pt.x,pt.y+rc1.bottom+rc.bottom+10,0,0,SWP_NOZORDER or SWP_NOSIZE); end; IDC_CLOSE_LPAR: begin CheckDlgButton(Dialog,IDC_CLOSE_WPAR,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_CLOSE_LPAR,BST_CHECKED); CheckDlgButton(Dialog,IDC_CLOSE_RES ,BST_UNCHECKED); EnableWindow(wpar,true); EnableWindow(res ,true); ShowWindow(wparb,SW_HIDE); ShowWindow(resb ,SW_HIDE); wnd :=lpar; wndb:=lparb; SetWindowPos(lpar,HWND_TOP,pt.x,pt.y+5,0,0,SWP_NOZORDER or SWP_NOSIZE); GetClientRect(lpar ,rc); GetClientRect(lparb,rc1); SetWindowPos(res,HWND_TOP,pt.x,pt.y+rc1.bottom+rc.bottom+10,0,0,SWP_NOZORDER or SWP_NOSIZE); end; IDC_CLOSE_RES: begin CheckDlgButton(Dialog,IDC_CLOSE_WPAR,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_CLOSE_LPAR,BST_UNCHECKED); CheckDlgButton(Dialog,IDC_CLOSE_RES ,BST_CHECKED); EnableWindow(wpar,true); EnableWindow(lpar,true); ShowWindow(wparb,SW_HIDE); ShowWindow(lparb,SW_HIDE); wnd :=res; wndb:=resb; SetWindowPos(lpar,HWND_TOP,pt.x,pt.y+5,0,0,SWP_NOZORDER or SWP_NOSIZE); GetClientRect(lpar,rc); SetWindowPos(res,HWND_TOP,pt.x,pt.y+rc.bottom+10,0,0,SWP_NOZORDER or SWP_NOSIZE); end; else wnd:=0; wndb:=0; end; if wnd<>0 then begin EnableWindow(wnd ,false); ShowWindow (wndb,SW_SHOW); end; end; procedure ReloadService(Dialog:HWND;srv:PAnsiChar;setvalue:boolean); var pc:PAnsiChar; ApiCard:tmApiCard; flag:dword; begin ApiCard:=GetApiCard(Dialog); ApiCard.Service:=srv; pc:=ApiCard.GetParam(true); if pc<>nil then begin FillParam(GetWPar(Dialog),pc); mFreeMem(pc); end; pc:=ApiCard.GetParam(false); if pc<>nil then begin FillParam(GetLPar(Dialog),pc); mFreeMem(pc); end; pc:=ApiCard.ResultType; flag:=ACF_TYPE_NUMBER; if pc<>nil then begin if lstrcmpia(pc,'struct')=0 then flag:=ACF_TYPE_STRUCT else if lstrcmpia(pc,'str' )=0 then flag:=ACF_TYPE_STRING else if lstrcmpia(pc,'wide' )=0 then flag:=ACF_TYPE_UNICODE; mFreeMem(pc); end; SetResultValue(GetRes(Dialog),flag); end; procedure FillTemplate(Dialog:HWND); var wnd:HWND; buf:array [0..127] of AnsiChar; begin wnd:=GetDlgItem(Dialog,IDC_C_SERVICE); SendMessageA(wnd,CB_GETLBTEXT,SendMessage(wnd,CB_GETCURSEL,0,0),tlparam(@buf)); ReloadService(Dialog,@buf,true); end; function DlgServiceProc(Dialog:HWND;hMessage:uint;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall; var proc:pointer; pc:PAnsiChar; ApiCard:tmApiCard; begin result:=0; case hMessage of WM_DESTROY: begin ApiCard:=GetApiCard(Dialog); if ApiCard<>nil then ApiCard.Free; end; WM_HELP: begin ApiCard:=GetApiCard(Dialog); pc:=ApiCard.NameFromList(GetDlgItem(Dialog,IDC_C_SERVICE)); ApiCard.Service:=pc; mFreeMem(pc); ApiCard.Show; result:=1; end; WM_COMMAND: begin case wParam shr 16 of CBN_EDITCHANGE, EN_CHANGE: begin SendMessage(GetParent(Dialog),WM_COMMAND,CBN_EDITCHANGE shl 16,Dialog); end; BN_CLICKED: begin case loword(wParam) of IDC_CLOSE_WPAR, IDC_CLOSE_LPAR, IDC_CLOSE_RES: ShowBlock(Dialog,loword(wParam)); else // from parameter and result SendMessage(GetParent(Dialog),WM_COMMAND,BN_CLICKED shl 16,Dialog); end; end; CBN_SELCHANGE: begin case loword(wParam) of IDC_C_SERVICE: FillTemplate(Dialog); end; end; end; end; else proc:=pointer(GetWindowLongPtrW(Dialog,GWLP_USERDATA)); result:=CallWindowProc(proc,Dialog,hMessage,wParam,lParam) end; end; function CreateServiceBlock(parent:HWND;x,y,width,height:integer;flags:dword=0):HWND; var hf:HFONT; ctrl,wnd,srv,srvs:HWND; proc:pointer; ApiCard:tmApiCard; rc,rc1:TRECT; dx,dy:integer; ux,uy:integer; h,bs:integer; begin hf:=SendMessageW(parent,WM_GETFONT,0,0); GetUnitSize(parent,ux,uy); // let think what x,y and width is dialog-related if height=0 then h:=100 else h:=height; SetRect(rc,x,y,x+width,y+h); dx:=rc.right-rc.left; result:=CreateWindowExW(WS_EX_CONTROLPARENT,'STATIC',nil,WS_CHILD+WS_VISIBLE, x,y,dx,rc.bottom-rc.top, parent,0,hInstance,nil); proc:=pointer(SetWindowLongPtrW(result,GWLP_WNDPROC,long_ptr(@DlgServiceProc))); SetWindowLongPtrW(result,GWLP_USERDATA,long_ptr(proc)); SendMessageW(result,WM_SETFONT,hf,0); dy:=0; // Service label rc.bottom:=12*uy div 8; srvs:=CreateWindowW('STATIC','Service:',WS_CHILD+WS_VISIBLE+SS_CENTERIMAGE+SS_LEFT, 0,dy,dx,rc.bottom, result,IDC_S_SERVICE,hInstance,nil); SendMessageW(srvs,WM_SETFONT,hf,0); inc(dy,rc.bottom+2); // Service name combobox rc.bottom:=14*uy div 8; srv:=CreateWindowW('COMBOBOX',nil,WS_CHILD+WS_VISIBLE+WS_VSCROLL+CBS_DROPDOWN+CBS_AUTOHSCROLL, 0,dy,dx,76, result,IDC_C_SERVICE,hInstance,nil); SendMessageW(srv,WM_SETFONT,hf,0); inc(dy,rc.bottom+2); MakeEditField(result,IDC_C_SERVICE); if (flags and ACF_BLOCK_EXPAND)<>0 then bs:=WS_CHILD+BS_AUTOCHECKBOX+BS_PUSHLIKE else bs:=WS_CHILD+WS_VISIBLE+BS_AUTOCHECKBOX+BS_PUSHLIKE; // wParam button+block rc.bottom:=11*uy div 8; ctrl:=CreateWindowW('BUTTON','wParam',bs, 0,dy,dx,rc.bottom, result,IDC_CLOSE_WPAR,hInstance,nil); SendMessageW(ctrl,WM_SETFONT,hf,0); if (flags and ACF_BLOCK_EXPAND)=0 then inc(dy,rc.bottom+4); wnd:=CreateParamBlock(result,0,dy,dx,flags); SetWindowLongPtrW(ctrl,GWLP_USERDATA,wnd); SetParamLabel(wnd,'wParam'); GetClientRect(wnd,rc1); if (flags and ACF_BLOCK_EXPAND)<>0 then inc(dy,rc1.bottom+8); // lParam button+block ctrl:=CreateWindowW('BUTTON','lParam',bs, 0,dy,dx,rc.bottom, result,IDC_CLOSE_LPAR,hInstance,nil); SendMessageW(ctrl,WM_SETFONT,hf,0); if (flags and ACF_BLOCK_EXPAND)=0 then inc(dy,rc.bottom+4); wnd:=CreateParamBlock(result,0,dy,dx,flags); SetWindowLongPtrW(ctrl,GWLP_USERDATA,wnd); SetParamLabel(wnd,'lParam'); if (flags and ACF_BLOCK_EXPAND)<>0 then inc(dy,rc1.bottom+8); // result button+block ctrl:=CreateWindowW('BUTTON','Result',bs, 0,dy,dx,rc.bottom, result,IDC_CLOSE_RES,hInstance,nil); SendMessageW(ctrl,WM_SETFONT,hf,0); if (flags and ACF_BLOCK_EXPAND)=0 then inc(dy,rc.bottom+4); wnd:=CreateResultBlock(result,0,dy,dx,flags); SetWindowLongPtrW(ctrl,GWLP_USERDATA,wnd); GetClientRect(wnd,rc); // autoresize panel if height=0 then begin if (flags and ACF_BLOCK_EXPAND)=0 then begin if rc1.bottom>rc.bottom then h:=rc1.bottom else h:=rc.bottom; end else begin h:=rc.bottom; end; MoveWindow(result,x,y,dx,dy+h,false); end; // additional ApiCard:=CreateServiceCard(result); ApiCard.FillList(srv); SetWindowLongPtrW(srvs,GWLP_USERDATA,long_ptr(ApiCard)); if (flags and ACF_BLOCK_EXPAND)=0 then ShowBlock(result,IDC_CLOSE_WPAR); end; procedure ClearServiceBlock(Dialog:HWND); begin if Dialog=0 then exit; SetDlgItemTextA(Dialog,IDC_C_SERVICE,''); SetEditFlags(GetDlgItem(Dialog,IDC_C_SERVICE),EF_SCRIPT,0); SetParamValue (GetWPar(Dialog),ACF_TYPE_NUMBER,nil); SetParamValue (GetLPar(Dialog),ACF_TYPE_NUMBER,nil); SetResultValue(GetRes (Dialog),ACF_TYPE_NUMBER); end; procedure SetServiceListMode(Dialog:HWND;mode:integer); var ApiCard:tmApiCard; begin if Dialog=0 then exit; ApiCard:=GetApiCard(Dialog); ApiCard.FillList(GetDlgItem(Dialog,IDC_C_SERVICE),mode); end; function SetSrvBlockValue(Dialog:HWND;const value:tServiceValue):boolean; begin if Dialog=0 then begin result:=false; exit; end; result:=true; if CB_SelectData(Dialog,IDC_C_SERVICE,Hash(value.service,StrLen(value.service)))<>CB_ERR then ReloadService(Dialog,value.service,false) else SetDlgItemTextA(Dialog,IDC_C_SERVICE,value.service); SetEditFlags(GetDlgItem(Dialog,IDC_C_SERVICE),EF_SCRIPT, ord((value.flags and ACF_FLAG_SCRIPT)<>0)); SetParamValue (GetWPar(Dialog),value.w_flags,value.wparam); SetParamValue (GetLPar(Dialog),value.l_flags,value.lparam); SetResultValue(GetRes (Dialog),value.flags); end; function GetSrvBlockValue(Dialog:HWND;var value:tServiceValue):boolean; var ApiCard:tmApiCard; begin if Dialog=0 then begin result:=false; exit; end; result:=true; ApiCard:=GetApiCard(Dialog); value.service:=ApiCard.NameFromList(GetDlgItem(Dialog,IDC_C_SERVICE)); GetParamValue(GetWPar(Dialog),value.w_flags,value.wparam); GetParamValue(GetLPar(Dialog),value.l_flags,value.lparam); value.flags:=GetResultValue(GetRes(Dialog)); if (GetEditFlags(Dialog,IDC_C_SERVICE) and EF_SCRIPT)<>0 then value.flags:=value.flags or ACF_FLAG_SCRIPT; end; procedure SetSrvBlockService(Dialog:HWND; service:PAnsiChar); begin if Dialog=0 then exit; ReloadService(Dialog,service,true); end; function GetSrvBlockService(Dialog:HWND):PAnsiChar; begin if Dialog=0 then begin result:=nil; exit; end; result:=GetDlgText(Dialog,IDC_C_SERVICE); end; //----- ServiceValue functions ----- procedure CopyServiceValue(var dst:tServiceValue; const src:tServiceValue); begin move(src,dst,SizeOf(tServiceValue)); StrDup(dst.service,dst.service); case dst.w_flags of ACF_TYPE_NUMBER, ACF_TYPE_STRING, ACF_TYPE_UNICODE: StrDupW(pWideChar(dst.wparam),pWideChar(dst.wparam)); ACF_TYPE_STRUCT : StrDup (pAnsiChar(dst.wparam),pAnsiChar(dst.wparam)); end; case dst.l_flags of ACF_TYPE_NUMBER, ACF_TYPE_STRING, ACF_TYPE_UNICODE: StrDupW(pWideChar(dst.lparam),pWideChar(dst.lparam)); ACF_TYPE_STRUCT : StrDup (pAnsiChar(dst.lparam),pAnsiChar(dst.lparam)); end; end; const iosection:PAnsiChar = '/service/'; ioflags :PAnsiChar = 'flags'; ioservice:PAnsiChar = 'service'; iowparam :PAnsiChar = 'wparam'; iolparam :PAnsiChar = 'lparam'; procedure SaveServiceValue(const data:tServiceValue; module,setting:PAnsiChar); var buf:array [0..127] of AnsiChar; p:PAnsiChar; begin p:=StrCopyE(StrCopyE(buf,setting),iosection); StrCopy(p,ioflags); DBWriteDWord (0,module,buf,data.flags); StrCopy(p,ioservice); DBWriteString (0,module,buf,data.service); StrCopy(p,iowparam); SaveParamValue(data.w_flags,data.wparam,module,buf); StrCopy(p,iolparam); SaveParamValue(data.l_flags,data.lparam,module,buf); end; procedure LoadServiceValue(var data:tServiceValue; module,setting:PAnsiChar); var buf:array [0..127] of AnsiChar; p:PAnsiChar; begin p:=StrCopyE(StrCopyE(buf,setting),iosection); StrCopy(p,ioflags); data.flags :=DBReadDWord (0,module,buf); StrCopy(p,ioservice); data.service:=DBReadString(0,module,buf); StrCopy(p,iowparam); LoadParamValue(data.w_flags,data.wparam,module,buf); StrCopy(p,iolparam); LoadParamValue(data.l_flags,data.lparam,module,buf); end; procedure ClearServiceValue(var data:tServiceValue); begin mFreeMem(data.service); ClearParam(data.w_flags,data.wparam); ClearParam(data.l_flags,data.lparam); FillChar(data,SizeOf(tServiceValue),0); end; //----- Service execute ----- const protostr=''; function ExecuteService(const service:tServiceValue; var data:tSubstData):boolean; var buf:array [0..255] of AnsiChar; lservice:PAnsiChar; lwparam,llparam:TLPARAM; wp,lp:PWideChar; res:int_ptr; begin result:=false; // Service name processing if (service.flags and ACF_FLAG_SCRIPT)<>0 then lservice:=ParseVarString(service.service,data.Parameter) else lservice:=service.service; StrCopy(buf,lservice); if (service.flags and ACF_FLAG_SCRIPT)<>0 then mFreeMem(lservice); if StrPos(buf,protostr)<>nil then if db_is_contact(data.Parameter)<>0 then StrReplace(buf,protostr,Proto_GetBaseAccountName(data.Parameter)) else Exit; if ServiceExists(buf) then begin result:=true; lwparam:=PrepareParameter(service.w_flags,TLPARAM(service.wparam),data); llparam:=PrepareParameter(service.l_flags,TLPARAM(service.lparam),data); res:=CallServiceSync(buf,lwparam,llparam); // ClearSubstData(data); DO NOT CLEAR!! (consist of input data) // result type processing case service.flags and ACF_TYPE_MASK of ACF_TYPE_STRING, ACF_TYPE_UNICODE: begin data.ResultType:=ACF_TYPE_UNICODE; if (service.flags and ACF_TYPE_MASK)=ACF_TYPE_STRING then AnsiToWide(pAnsiChar(res),pWideChar(data.LastResult),MirandaCP) else StrDupW(pWideChar(data.LastResult),pWideChar(res)); if (service.flags and ACF_FLAG_FREEMEM)<>0 then // Miranda Memory manager used mir_free(pointer(res)); end; ACF_TYPE_NUMBER: begin data.LastResult:=res; data.ResultType:=ACF_TYPE_NUMBER; end; ACF_TYPE_STRUCT: begin data.ResultType:=ACF_TYPE_UNICODE; if (service.w_flags and ACF_TYPE_MASK)=ACF_TYPE_STRUCT then begin wp:=GetStructureResult(lwparam); end else wp:=nil; lp:=nil; if (service.l_flags and ACF_TYPE_MASK)=ACF_TYPE_STRUCT then begin if wp=nil then lp:=GetStructureResult(llparam); end; if wp<>nil then PWideChar(data.LastResult):=wp else PWideChar(data.LastResult):=lp; end; end; ReleaseParameter(service.w_flags,lwparam); ReleaseParameter(service.l_flags,llparam); end; end; end.