{$include compilers.inc} unit wrapper; interface uses windows; function CreateHiddenWindow(proc:pointer=nil):HWND; function DoInitCommonControls(dwICC:dword):boolean; function GetScreenRect:TRect; procedure SnapToScreen(var rc:TRect;dx:integer=0;dy:integer=0{; minw:integer=240;minh:integer=100}); function GetDlgText(Dialog:HWND;idc:integer;getAnsi:boolean=false):pointer; overload; function GetDlgText(wnd:HWND;getAnsi:boolean=false):pointer; overload; function StringToGUID(const astr:PAnsiChar):TGUID; overload; function StringToGUID(const astr:PWideChar):TGUID; overload; // Comboboxes function CB_SelectData(cb:HWND;data:lparam):LRESULT; overload; function CB_SelectData(Dialog:HWND;id:cardinal;data:lparam):LRESULT; overload; function CB_GetData (cb:HWND;idx:integer=-1):LRESULT; function CB_SetData (cb:HWND;data:lparam;idx:integer=-1):LRESULT; function CB_AddStrData (cb:HWND;astr:PAnsiChar;data:lparam=0;idx:integer=-1):HWND; overload; function CB_AddStrData (Dialog:HWND;id:cardinal;astr:PAnsiChar;data:lparam=0;idx:integer=-1):HWND; overload; function CB_AddStrDataW(cb:HWND;astr:PWideChar;data:lparam=0;idx:integer=-1):HWND; overload; function CB_AddStrDataW(Dialog:HWND;id:cardinal;astr:PWideChar;data:lparam=0;idx:integer=-1):HWND; overload; // CommCtrl - ListView Procedure ListView_GetItemTextA(list:HWND;i:WPARAM;iSubItem:integer;pszText:pointer;cchTextMax:integer); Procedure ListView_GetItemTextW(list:HWND;i:WPARAM;iSubItem:integer;pszText:pointer;cchTextMax:integer); function LV_GetLParam (list:HWND;item:integer=-1):LRESULT; function LV_SetLParam (list:HWND;lParam:LPARAM;item:integer=-1):LRESULT; function LV_ItemAtPos(list:HWND;pt:TPOINT;var subitem:dword):integer; overload; function LV_ItemAtPos(list:HWND;x,y:integer;var subitem:dword):integer; overload; procedure LV_SetItem (list:HWND;str:PAnsiChar;item:integer;subitem:integer=0); procedure LV_SetItemW(list:HWND;str:PWideChar;item:integer;subitem:integer=0); function LV_MoveItem(list:HWND;direction:integer;item:integer=-1):integer; function LV_GetColumnCount(list:HWND):LRESULT; function LV_CheckDirection(list:HWND):integer; // bit 0 - can move up, bit 1 - down // CommDLG - Dialogs function ShowDlg (dst:PAnsiChar;fname:PAnsiChar=nil;Filter:PAnsiChar=nil;open:boolean=true):boolean; function ShowDlgW(dst:PWideChar;fname:PWideChar=nil;Filter:PWideChar=nil;open:boolean=true):boolean; procedure GetUnitSize(wnd:HWND; var baseUnitX, baseUnitY: integer); implementation uses messages,common,commctrl,commdlg; const EmptyGUID:TGUID = '{00000000-0000-0000-0000-000000000000}'; {$IFNDEF FPC} const LVM_SORTITEMSEX = LVM_FIRST + 81; {$ENDIF} {$IFNDEF DELPHI_7_UP} const SM_XVIRTUALSCREEN = 76; SM_YVIRTUALSCREEN = 77; SM_CXVIRTUALSCREEN = 78; SM_CYVIRTUALSCREEN = 79; {$ENDIF} //----- Hidden Window functions ----- const HWND_MESSAGE = HWND(-3); const hiddenwindow:HWND = 0; hwndcount:integer=0; function HiddenWindProc(wnd:HWND; msg:uint;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall; begin if msg=WM_CLOSE then begin dec(hwndcount); if hwndcount>0 then // not all references gone begin result:=0; exit end else hiddenwindow:=0 end; result:=DefWindowProcW(wnd,msg,wParam,lParam); end; function CreateHiddenWindow(proc:pointer=nil):HWND; begin if proc=nil then begin if hiddenwindow<>0 then begin result:=hiddenwindow; inc(hwndcount); // one reference more end else begin result:=CreateWindowExW(0,'STATIC',nil,0, 1,1,1,1,HWND_MESSAGE,0,hInstance,nil); if result<>0 then SetWindowLongPtrW(result,GWL_WNDPROC,LONG_PTR(@HiddenWindProc)); hiddenwindow:=result; end end else begin result:=CreateWindowExW(0,'STATIC',nil,0, 1,1,1,1,HWND_MESSAGE,0,hInstance,nil); if result<>0 then SetWindowLongPtrW(result,GWL_WNDPROC,LONG_PTR(proc)); end; end; //----- End of hidden window functions ----- function DoInitCommonControls(dwICC:dword):boolean; var ICC: TInitCommonControlsEx; begin if dwICC=0 then dwICC:=ICC_STANDARD_CLASSES or ICC_WIN95_CLASSES; ICC.dwSize:= Sizeof(ICC); ICC.dwICC := dwICC; result:=InitCommonControlsEx(ICC); end; function GetScreenRect:TRect; begin result.left := GetSystemMetrics( SM_XVIRTUALSCREEN ); result.top := GetSystemMetrics( SM_YVIRTUALSCREEN ); result.right := GetSystemMetrics( SM_CXVIRTUALSCREEN ) + result.left; result.bottom:= GetSystemMetrics( SM_CYVIRTUALSCREEN ) + result.top; end; procedure SnapToScreen(var rc:TRect;dx:integer=0;dy:integer=0{; minw:integer=240;minh:integer=100}); var rect:TRect; begin rect:=GetScreenRect; if rc.right >rect.right then rc.right :=rect.right -dx; if rc.bottom>rect.bottom then rc.bottom:=rect.bottom-dy; if rc.left 1 then begin mGetMem(PAnsiChar(result),a); SendMessageA(wnd,WM_GETTEXT,a,lparam(result)); end; end else begin a:=SendMessageW(wnd,WM_GETTEXTLENGTH,0,0)+1; if a>1 then begin mGetMem(PWideChar(result),a*SizeOf(WideChar)); SendMessageW(wnd,WM_GETTEXT,a,lparam(result)); end; end; end; function GetDlgText(Dialog:HWND;idc:integer;getAnsi:boolean=false):pointer; begin result:=GetDlgText(GetDlgItem(Dialog,idc),getAnsi); end; //----- Combobox functions ----- function CB_SelectData(cb:HWND;data:lparam):LRESULT; overload; var i:integer; begin result:=CB_ERR; for i:=0 to SendMessage(cb,CB_GETCOUNT,0,0)-1 do begin if data=lparam(SendMessage(cb,CB_GETITEMDATA,i,0)) then begin result:=i; break; end; end; result:=SendMessage(cb,CB_SETCURSEL,result,0); end; function CB_SelectData(Dialog:HWND;id:cardinal;data:lparam):LRESULT; overload; begin result:=CB_SelectData(GetDlgItem(Dialog,id),data); end; function CB_GetData(cb:HWND;idx:integer=-1):LRESULT; begin if idx<0 then idx:=SendMessage(cb,CB_GETCURSEL,0,0); if idx<0 then result:=0 else result:=SendMessage(cb,CB_GETITEMDATA,idx,0); end; function CB_SetData(cb:HWND;data:lparam;idx:integer=-1):LRESULT; begin if idx<0 then idx:=SendMessage(cb,CB_GETCURSEL,0,0); if idx<0 then result:=0 else result:=SendMessage(cb,CB_SETITEMDATA,idx,0); end; function CB_AddStrData(cb:HWND;astr:PAnsiChar;data:lparam=0;idx:integer=-1):HWND; begin result:=cb; if idx<0 then idx:=SendMessageA(cb,CB_ADDSTRING,0,lparam(astr)) else idx:=SendMessageA(cb,CB_INSERTSTRING,idx,lparam(astr)); SendMessageA(cb,CB_SETITEMDATA,idx,data); end; function CB_AddStrData(Dialog:HWND;id:cardinal;astr:PAnsiChar;data:lparam=0;idx:integer=-1):HWND; begin result:=CB_AddStrData(GetDlgItem(Dialog,id),astr,data,idx); end; function CB_AddStrDataW(cb:HWND;astr:PWideChar;data:lparam=0;idx:integer=-1):HWND; begin result:=cb; if idx<0 then idx:=SendMessageW(cb,CB_ADDSTRING,0,lparam(astr)) else idx:=SendMessageW(cb,CB_INSERTSTRING,idx,lparam(astr)); SendMessage(cb,CB_SETITEMDATA,idx,data); end; function CB_AddStrDataW(Dialog:HWND;id:cardinal;astr:PWideChar;data:lparam=0;idx:integer=-1):HWND; begin result:=CB_AddStrDataW(GetDlgItem(Dialog,id),astr,data,idx); end; function StringToGUID(const astr:PAnsiChar):TGUID; var i:integer; begin result:=EmptyGUID; if StrLen(astr)<>38 then exit; result.D1:=HexToInt(PAnsiChar(@astr[01]),8); result.D2:=HexToInt(PAnsiChar(@astr[10]),4); result.D3:=HexToInt(PAnsiChar(@astr[15]),4); result.D4[0]:=HexToInt(PAnsiChar(@astr[20]),2); result.D4[1]:=HexToInt(PAnsiChar(@astr[22]),2); for i:=2 to 7 do begin result.D4[i]:=HexToInt(PAnsiChar(@astr[21+i*2]),2); end; end; function StringToGUID(const astr:PWideChar):TGUID; var i:integer; begin result:=EmptyGUID; if StrLenW(astr)<>38 then exit; result.D1:=HexToInt(PWideChar(@astr[01]),8); result.D2:=HexToInt(PWideChar(@astr[10]),4); result.D3:=HexToInt(PWideChar(@astr[15]),4); result.D4[0]:=HexToInt(PWideChar(@astr[20]),2); result.D4[1]:=HexToInt(PWideChar(@astr[22]),2); for i:=2 to 7 do begin result.D4[i]:=HexToInt(PWideChar(@astr[21+i*2]),2); end; end; //----- ListView functions ----- Procedure ListView_GetItemTextA(list:HWND;i:WPARAM;iSubItem:integer;pszText:pointer;cchTextMax:integer); Var lvi:LV_ITEMA; Begin lvi.iSubItem :=iSubItem; lvi.cchTextMax:=cchTextMax; lvi.pszText :=pszText; SendMessageA(list,LVM_GETITEMTEXT,i,LPARAM(@lvi)); end; Procedure ListView_GetItemTextW(list:HWND;i:WPARAM;iSubItem:integer;pszText:pointer;cchTextMax:integer); Var lvi:LV_ITEMW; Begin lvi.iSubItem :=iSubItem; lvi.cchTextMax:=cchTextMax; lvi.pszText :=pszText; SendMessageW(list,LVM_GETITEMTEXT,i,LPARAM(@lvi)); end; procedure LV_SetItem(list:HWND;str:PAnsiChar;item:integer;subitem:integer=0); var li:LV_ITEMA; begin // zeromemory(@li,sizeof(li)); li.mask :=LVIF_TEXT; li.pszText :=str; li.iItem :=item; li.iSubItem:=subitem; SendMessageA(list,LVM_SETITEMA,0,lparam(@li)); end; procedure LV_SetItemW(list:HWND;str:PWideChar;item:integer;subitem:integer=0); var li:LV_ITEMW; begin // zeromemory(@li,sizeof(li)); li.mask :=LVIF_TEXT; li.pszText :=str; li.iItem :=item; li.iSubItem:=subitem; SendMessageW(list,LVM_SETITEMW,0,lparam(@li)); end; function LV_GetLParam(list:HWND;item:integer=-1):LRESULT; var li:LV_ITEMW; begin if item<0 then begin item:=SendMessage(list,LVM_GETNEXTITEM,-1,LVNI_FOCUSED); if item<0 then begin result:=-1; exit; end; end; li.iItem :=item; li.mask :=LVIF_PARAM; li.iSubItem:=0; if SendMessageW(list,LVM_GETITEMW,0,lparam(@li))=0 then result:=-1 else result:=li.lParam; end; function LV_SetLParam(list:HWND;lParam:LPARAM;item:integer=-1):LRESULT; var li:LV_ITEMW; begin if item<0 then begin item:=SendMessage(list,LVM_GETNEXTITEM,-1,LVNI_FOCUSED); if item<0 then begin result:=-1; exit; end; end; li.iItem :=item; li.mask :=LVIF_PARAM; li.lParam :=lParam; li.iSubItem:=0; SendMessageW(list,LVM_SETITEMW,0,windows.lparam(@li)); result:=lParam; end; function LV_ItemAtPos(list:HWND;Pt:TPOINT;var subitem:dword):integer; var HTI:LV_HITTESTINFO; begin HTI.pt.x := pt.X; HTI.pt.y := pt.Y; SendMessage(list,LVM_SUBITEMHITTEST,0,lparam(@HTI)); Result :=HTI.iItem; if @subitem<>nil then subitem:=HTI.iSubItem; end; function LV_ItemAtPos(list:HWND;x,y:integer;var subitem:dword):integer; overload; var HTI:LV_HITTESTINFO; begin HTI.pt.x := x; HTI.pt.y := y; SendMessage(list,LVM_SUBITEMHITTEST,0,lparam(@HTI)); Result :=HTI.iItem; if @subitem<>nil then subitem:=HTI.iSubItem; end; function LV_Compare(lParam1,lParam2,param:LPARAM):integer; stdcall; var olditem,neibor:integer; begin result:=lParam1-lParam2; neibor :=hiword(param); olditem:=loword(param); if neibor>olditem then begin if (lParam1=olditem) and (lParam2<=neibor) then result:=1; end else begin if (lParam2=olditem) and (lParam1>=neibor) then result:=1; end; end; function LV_MoveItem(list:HWND;direction:integer;item:integer=-1):integer; begin if ((direction>0) and (item=(SendMessage(list,LVM_GETITEMCOUNT,0,0)-1))) or ((direction<0) and (item=0)) then begin result:=item; exit; end; if item<0 then item:=SendMessage(list,LVM_GETNEXTITEM,-1,LVNI_FOCUSED); SendMessageW(list,LVM_SORTITEMSEX,wparam(item)+(wparam(item+direction) shl 16),lparam(@LV_Compare)); result:=item+direction; end; function LV_GetColumnCount(list:HWND):LRESULT; begin result:=SendMessage(SendMessage(list,LVM_GETHEADER,0,0),HDM_GETITEMCOUNT,0,0); end; function LV_CheckDirection(list:HWND):integer; var i,cnt{,selcnt}:integer; stat,first,last,focus: integer; begin first :=-1; last :=-1; focus :=-1; cnt :=SendMessage(list,LVM_GETITEMCOUNT,0,0)-1; // selcnt:=SendMessage(list,LVM_GETSELECTEDCOUNT,0,0); for i:=0 to cnt do begin stat:=SendMessage(list,LVM_GETITEMSTATE,i,LVIS_SELECTED or LVIS_FOCUSED); if (stat and LVIS_SELECTED)<>0 then begin if (stat and LVIS_FOCUSED)<>0 then focus:=i; if first<0 then first:=i; last:=i; end; end; result:=0; if focus<0 then focus:=first; if focus>=0 then result:=result or ((focus+1) shl 16); if first>0 then // at least one selected and not first begin result:=(result or 1){ or (first+1) shl 16}; end; if (last>=0) and (lastdst then StrCopy(dst,fname); // lpstrInitialDir:=dst; if Filter<>nil then begin lpstrDefExt:=StrEnd(Filter)+1; inc(lpstrDefExt,2); // skip "*." end; lpStrFile :=dst; lpStrFilter:=Filter; NMaxFile :=511; Flags :=OFN_EXPLORER or OFN_OVERWRITEPROMPT;// or OFN_HIDEREADONLY; end; if open then result:=GetOpenFileNameA({$IFDEF FPC}@{$ENDIF}NameRec) else result:=GetSaveFileNameA({$IFDEF FPC}@{$ENDIF}NameRec); end; function ShowDlgW(dst:PWideChar;fname:PWideChar=nil;Filter:PWideChar=nil;open:boolean=true):boolean; var NameRec:OpenFileNameW; begin if dst=nil then begin result:=false; exit; end; FillChar(NameRec,SizeOf(NameRec),0); with NameRec do begin LStructSize:=SizeOf(NameRec); if fname=nil then dst[0]:=#0 else if fname<>dst then StrCopyW(dst,fname); // lpstrInitialDir:=dst; if Filter<>nil then begin lpstrDefExt:=StrEndW(Filter)+1; inc(lpstrDefExt,2); // skip "*." end; lpStrFile :=dst; lpStrFilter:=Filter; NMaxFile :=511; Flags :=OFN_EXPLORER or OFN_OVERWRITEPROMPT;// or OFN_HIDEREADONLY; end; if open then result:=GetOpenFileNameW({$IFDEF FPC}@{$ENDIF}NameRec) else result:=GetSaveFileNameW({$IFDEF FPC}@{$ENDIF}NameRec) end; procedure GetUnitSize(wnd:HWND; var baseUnitX, baseUnitY: integer); var dc :HDC; hfo :HFONT; tm :TTEXTMETRIC; size:TSIZE; tmp :PWideChar; begin dc:=GetDC(wnd); hfo:=SelectObject(dc,SendMessage(wnd,WM_GETFONT,0,0)); GetTextMetrics(dc,tm); tmp:='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; GetTextExtentPoint32W(dc,tmp,52,size); SelectObject(dc,hfo); ReleaseDC(wnd,dc); baseUnitX:=(size.cx div 26+1) div 2; baseUnitY:=tm.tmHeight; end; end.