mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-03 03:49:35 +01:00
use double buffering when painting winxp themed controls (issue #1425)
git-svn-id: trunk@8243 -
This commit is contained in:
parent
258a8704a3
commit
9391fe1f6c
@ -103,18 +103,44 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
type
|
type
|
||||||
TEraseBkgndCommand = (ecDefault, ecNoMsg);
|
TEraseBkgndCommand = (ecDefault, ecDiscard, ecDiscardNoRemove);
|
||||||
const
|
const
|
||||||
EraseBkgndStackMask = $3;
|
EraseBkgndStackMask = $3;
|
||||||
EraseBkgndStackShift = 2;
|
EraseBkgndStackShift = 2;
|
||||||
var
|
var
|
||||||
EraseBkgndStack: dword = 0;
|
EraseBkgndStack: dword = 0;
|
||||||
|
|
||||||
|
{$ifdef MSG_DEBUG}
|
||||||
|
function EraseBkgndStackToString: string;
|
||||||
|
var
|
||||||
|
I: dword;
|
||||||
|
begin
|
||||||
|
SetLength(Result, 8);
|
||||||
|
for I := 0 to 7 do
|
||||||
|
Result[8-I] := char(ord('0') + ((EraseBkgndStack shr (I*2)) and $3));
|
||||||
|
end;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
procedure PushEraseBkgndCommand(Command: TEraseBkgndCommand);
|
procedure PushEraseBkgndCommand(Command: TEraseBkgndCommand);
|
||||||
begin
|
begin
|
||||||
|
{$ifdef MSG_DEBUG}
|
||||||
|
case Command of
|
||||||
|
ecDiscard: DebugLn(MessageStackDepth,
|
||||||
|
' *forcing next WM_ERASEBKGND to discard message');
|
||||||
|
ecDiscardNoRemove: DebugLn(MessageStackDepth,
|
||||||
|
' *forcing next WM_ERASEBKGND to discard message, no remove');
|
||||||
|
end;
|
||||||
|
DebugLn(MessageStackDepth, ' *erasebkgndstack: ', EraseBkgndStackToString);
|
||||||
|
{$endif}
|
||||||
EraseBkgndStack := (EraseBkgndStack shl EraseBkgndStackShift) or dword(Ord(Command));
|
EraseBkgndStack := (EraseBkgndStack shl EraseBkgndStackShift) or dword(Ord(Command));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
DoubleBufferDC: HDC = 0;
|
||||||
|
DoubleBufferBitmap: HBITMAP = 0;
|
||||||
|
DoubleBufferBitmapWidth: integer = 0;
|
||||||
|
DoubleBufferBitmapHeight: integer = 0;
|
||||||
|
|
||||||
function CheckMouseMovement: boolean;
|
function CheckMouseMovement: boolean;
|
||||||
// returns true if mouse did not move between lmousebutton down
|
// returns true if mouse did not move between lmousebutton down
|
||||||
var
|
var
|
||||||
@ -233,17 +259,20 @@ Var
|
|||||||
|
|
||||||
procedure SendPaintMessage;
|
procedure SendPaintMessage;
|
||||||
var
|
var
|
||||||
DC, MemDC: HDC;
|
DC: HDC;
|
||||||
MemBitmap, OldBitmap : HBITMAP;
|
DoubleBufferBitmapOld: HBITMAP;
|
||||||
|
PaintRegion: HRGN;
|
||||||
PS : TPaintStruct;
|
PS : TPaintStruct;
|
||||||
MemWidth: Integer;
|
|
||||||
MemHeight: Integer;
|
|
||||||
PaintMsg: TLMPaint;
|
PaintMsg: TLMPaint;
|
||||||
ORect: TRect;
|
ORect: TRect;
|
||||||
|
WindowOrg: Windows.POINT;
|
||||||
|
ParentPaintWindow: HWND;
|
||||||
|
WindowWidth, WindowHeight: Integer;
|
||||||
parLeft, parTop: integer;
|
parLeft, parTop: integer;
|
||||||
useDoubleBuffer: boolean;
|
useDoubleBuffer: boolean;
|
||||||
parentPaint: boolean;
|
|
||||||
isNotebook: boolean;
|
isNotebook: boolean;
|
||||||
|
isNativeControl: boolean;
|
||||||
|
lNotebookFound: boolean;
|
||||||
begin
|
begin
|
||||||
// note: ignores the received DC
|
// note: ignores the received DC
|
||||||
// do not use default deliver message
|
// do not use default deliver message
|
||||||
@ -257,59 +286,101 @@ Var
|
|||||||
GetClassName(Window, winClassName, 20);
|
GetClassName(Window, winClassName, 20);
|
||||||
isNotebook := TWin32WidgetSet(WidgetSet).ThemesActive and
|
isNotebook := TWin32WidgetSet(WidgetSet).ThemesActive and
|
||||||
CompareMem(@winClassName, @TabControlClsName, High(TabControlClsName)+1);
|
CompareMem(@winClassName, @TabControlClsName, High(TabControlClsName)+1);
|
||||||
parentPaint := WindowInfo^.isTabPage or (WindowInfo^.hasTabParent and (WParam <> 0));
|
isNativeControl := not CompareMem(@winClassName, @ClsName, High(ClsName)+1);
|
||||||
|
ParentPaintWindow := 0;
|
||||||
|
// if hasTabParent and not isTabPage then background will be drawn in
|
||||||
|
// WM_ERASEBKGND and WM_CTLCOLORSTATIC for native controls
|
||||||
|
// sent by default paint handler
|
||||||
|
if WindowInfo^.isTabPage or (WindowInfo^.hasTabParent
|
||||||
|
and (not isNativeControl or (WParam <> 0))) then
|
||||||
|
begin
|
||||||
|
ParentPaintWindow := Window;
|
||||||
|
lNotebookFound := false;
|
||||||
|
while (ParentPaintWindow <> 0) and not lNotebookFound do
|
||||||
|
begin
|
||||||
|
// notebook is parent of window that has istabpage
|
||||||
|
if GetWindowInfo(ParentPaintWindow)^.isTabPage then
|
||||||
|
lNotebookFound := true;
|
||||||
|
ParentPaintWindow := Windows.GetParent(ParentPaintWindow);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
// if painting background of some control for tabpage, don't handle erase background
|
// if painting background of some control for tabpage, don't handle erase background
|
||||||
// in parent of tabpage
|
// in parent of tabpage
|
||||||
if WindowInfo^.isTabPage then
|
if WindowInfo^.isTabPage then
|
||||||
begin
|
PushEraseBkgndCommand(ecDiscard);
|
||||||
{$ifdef MSG_DEBUG}
|
|
||||||
writeln(MessageStackDepth, ' *forcing next WM_ERASEBKGND to disable message');
|
|
||||||
{$endif}
|
|
||||||
PushEraseBkgndCommand(ecNoMsg);
|
|
||||||
end;
|
|
||||||
|
|
||||||
// paint optimizations for controls on a tabpage
|
|
||||||
if WindowInfo^.hasTabParent and (WParam = 0) and not WindowInfo^.isTabPage then
|
|
||||||
begin
|
|
||||||
// if this is a groupbox in a tab, then the next erasebackground is for
|
|
||||||
// drawing the background of the caption, send paint message then
|
|
||||||
// update: tgroupbox does not have csOpaque, so it gets painted
|
|
||||||
|
|
||||||
|
|
||||||
// if need to start paint, paint by calling parent, and we have no
|
|
||||||
// controls, is a native control, use default win32 painting to avoid flicker
|
|
||||||
if (lWinControl.ControlCount = 0)
|
|
||||||
and not CompareMem(@winClassName, @ClsName, High(ClsName)+1) then
|
|
||||||
begin
|
|
||||||
// optimization: no child controls -> default painting
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// check if double buffering is requested
|
// check if double buffering is requested
|
||||||
useDoubleBuffer := (WParam = 0) and lWinControl.DoubleBuffered;
|
useDoubleBuffer := (WParam = 0) and (lWinControl.DoubleBuffered
|
||||||
|
or TWin32WidgetSet(WidgetSet).ThemesActive);
|
||||||
|
{$ifdef MSG_DEBUG}
|
||||||
|
if useDoubleBuffer and (DoubleBufferDC <> 0) then
|
||||||
|
begin
|
||||||
|
DebugLn('ERROR: RECURSIVE PROBLEM! DOUBLEBUFFERED PAINT');
|
||||||
|
useDoubleBuffer := false;
|
||||||
|
end;
|
||||||
|
{$endif}
|
||||||
if useDoubleBuffer then
|
if useDoubleBuffer then
|
||||||
begin
|
begin
|
||||||
DC := Windows.GetDC(0);
|
DoubleBufferDC := Windows.CreateCompatibleDC(0);
|
||||||
GetWindowSize(Window, MemWidth, MemHeight);
|
GetWindowSize(Window, WindowWidth, WindowHeight);
|
||||||
MemBitmap := Windows.CreateCompatibleBitmap(DC, MemWidth, MemHeight);
|
if (DoubleBufferBitmapWidth < WindowWidth) or (DoubleBufferBitmapHeight < WindowHeight) then
|
||||||
Windows.ReleaseDC(0, DC);
|
begin
|
||||||
MemDC := Windows.CreateCompatibleDC(0);
|
DC := Windows.GetDC(0);
|
||||||
OldBitmap := Windows.SelectObject(MemDC, MemBitmap);
|
if DoubleBufferBitmap <> 0 then
|
||||||
PaintMsg.DC := MemDC;
|
Windows.DeleteObject(DoubleBufferBitmap);
|
||||||
|
DoubleBufferBitmapWidth := WindowWidth;
|
||||||
|
DoubleBufferBitmapHeight := WindowHeight;
|
||||||
|
DoubleBufferBitmap := Windows.CreateCompatibleBitmap(DC, WindowWidth, WindowHeight);
|
||||||
|
Windows.ReleaseDC(0, DC);
|
||||||
|
end;
|
||||||
|
DoubleBufferBitmapOld := Windows.SelectObject(DoubleBufferDC, DoubleBufferBitmap);
|
||||||
|
PaintMsg.DC := DoubleBufferDC;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$ifdef MSG_DEBUG}
|
||||||
|
if useDoubleBuffer then
|
||||||
|
DebugLn(MessageStackDepth, ' *double buffering on DC: ', IntToHex(DoubleBufferDC, 8))
|
||||||
|
else
|
||||||
|
DebugLn(MessageStackDepth, ' *painting, but not double buffering');
|
||||||
|
{$endif}
|
||||||
|
|
||||||
WinProcess := false;
|
WinProcess := false;
|
||||||
try
|
try
|
||||||
if WParam = 0 then
|
if WParam = 0 then
|
||||||
begin
|
begin
|
||||||
|
// ignore first erase background on themed control, paint will do everything
|
||||||
|
if TWin32WidgetSet(WidgetSet).ThemesActive then
|
||||||
|
PushEraseBkgndCommand(ecDiscardNoRemove);
|
||||||
DC := Windows.BeginPaint(Window, @PS);
|
DC := Windows.BeginPaint(Window, @PS);
|
||||||
|
if TWin32WidgetSet(WidgetSet).ThemesActive then
|
||||||
|
EraseBkgndStack := EraseBkgndStack shr EraseBkgndStackShift;
|
||||||
|
if useDoubleBuffer then
|
||||||
|
begin
|
||||||
|
PaintRegion := CreateRectRgn(0, 0, 1, 1);
|
||||||
|
if GetRandomRgn(DC, PaintRegion, SYSRGN) = 1 then
|
||||||
|
begin
|
||||||
|
// winnt returns in screen coordinates
|
||||||
|
// win9x returns in window coordinates
|
||||||
|
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||||||
|
begin
|
||||||
|
WindowOrg.X := 0;
|
||||||
|
WindowOrg.Y := 0;
|
||||||
|
Windows.ClientToScreen(Window, WindowOrg);
|
||||||
|
OffsetRgn(PaintRegion, -WindowOrg.X, -WindowOrg.Y);
|
||||||
|
end;
|
||||||
|
SelectClipRgn(DoubleBufferDC, PaintRegion);
|
||||||
|
end;
|
||||||
|
// a copy of the region is selected into the DC, so we
|
||||||
|
// can free our region immediately
|
||||||
|
DeleteObject(PaintRegion);
|
||||||
|
end;
|
||||||
end else begin
|
end else begin
|
||||||
DC := WParam;
|
DC := WParam;
|
||||||
|
PaintRegion := 0;
|
||||||
end;
|
end;
|
||||||
if parentPaint then
|
if ParentPaintWindow <> 0 then
|
||||||
GetWin32ControlPos(Window, GetParent(Window), parLeft, parTop);
|
GetWin32ControlPos(Window, ParentPaintWindow, parLeft, parTop);
|
||||||
if not GetLCLClientBoundsOffset(lWinControl, ORect) then
|
if not GetLCLClientBoundsOffset(lWinControl, ORect) then
|
||||||
begin
|
begin
|
||||||
ORect.Left := 0;
|
ORect.Left := 0;
|
||||||
@ -322,11 +393,15 @@ Var
|
|||||||
PaintMsg.DC := DC;
|
PaintMsg.DC := DC;
|
||||||
if not WindowInfo^.hasTabParent and not isNotebook then
|
if not WindowInfo^.hasTabParent and not isNotebook then
|
||||||
lWinControl.EraseBackground(PaintMsg.DC);
|
lWinControl.EraseBackground(PaintMsg.DC);
|
||||||
if parentPaint then
|
if ParentPaintWindow <> 0 then
|
||||||
begin
|
begin
|
||||||
|
{$ifdef MSG_DEBUG}
|
||||||
|
DebugLn(MessageStackDepth, ' *painting background by sending paint message to parent window ',
|
||||||
|
IntToHex(Window, 8));
|
||||||
|
{$endif}
|
||||||
// tabpage parent and got a dc to draw in, divert paint to parent
|
// tabpage parent and got a dc to draw in, divert paint to parent
|
||||||
MoveWindowOrgEx(PaintMsg.DC, -parLeft, -parTop);
|
MoveWindowOrgEx(PaintMsg.DC, -parLeft, -parTop);
|
||||||
SendMessage(GetParent(Window), WM_PAINT, PaintMsg.DC, 0);
|
SendMessage(ParentPaintWindow, WM_PAINT, PaintMsg.DC, 0);
|
||||||
MoveWindowOrgEx(PaintMsg.DC, parLeft, parTop);
|
MoveWindowOrgEx(PaintMsg.DC, parLeft, parTop);
|
||||||
end;
|
end;
|
||||||
if (WParam = 0) or not WindowInfo^.hasTabParent then
|
if (WParam = 0) or not WindowInfo^.hasTabParent then
|
||||||
@ -336,20 +411,20 @@ Var
|
|||||||
MoveWindowOrgEx(PaintMsg.DC, -ORect.Left, -ORect.Top);
|
MoveWindowOrgEx(PaintMsg.DC, -ORect.Left, -ORect.Top);
|
||||||
end;
|
end;
|
||||||
if useDoubleBuffer then
|
if useDoubleBuffer then
|
||||||
Windows.BitBlt(DC, 0, 0, MemWidth, MemHeight, MemDC, 0, 0, SRCCOPY);
|
Windows.BitBlt(DC, 0, 0, WindowWidth, WindowHeight, DoubleBufferDC, 0, 0, SRCCOPY);
|
||||||
if WParam = 0 then
|
if WParam = 0 then
|
||||||
Windows.EndPaint(Window, @PS);
|
Windows.EndPaint(Window, @PS);
|
||||||
finally
|
finally
|
||||||
if useDoubleBuffer then
|
if useDoubleBuffer then
|
||||||
begin
|
begin
|
||||||
SelectObject(MemDC, OldBitmap);
|
SelectObject(DoubleBufferDC, DoubleBufferBitmapOld);
|
||||||
|
DeleteDC(DoubleBufferDC);
|
||||||
|
DoubleBufferDC := 0;
|
||||||
// for debugging purposes: copy rendered bitmap to clipboard
|
// for debugging purposes: copy rendered bitmap to clipboard
|
||||||
// Windows.OpenClipboard(0);
|
// Windows.OpenClipboard(0);
|
||||||
// Windows.EmptyClipboard;
|
// Windows.EmptyClipboard;
|
||||||
// Windows.SetClipboardData(CF_BITMAP, MemBitmap);
|
// Windows.SetClipboardData(CF_BITMAP, DoubleBufferBitmap);
|
||||||
// Windows.CloseClipboard;
|
// Windows.CloseClipboard;
|
||||||
DeleteDC(MemDC);
|
|
||||||
DeleteObject(MemBitmap);
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -851,7 +926,7 @@ Begin
|
|||||||
// need to draw transparently, draw background
|
// need to draw transparently, draw background
|
||||||
GetWin32ControlPos(LParam, Window, P.X, P.Y);
|
GetWin32ControlPos(LParam, Window, P.X, P.Y);
|
||||||
MoveWindowOrgEx(WParam, -P.X, -P.Y);
|
MoveWindowOrgEx(WParam, -P.X, -P.Y);
|
||||||
SendMessage(Window, WM_PAINT, WParam, 0);
|
SendPaintMessage;
|
||||||
MoveWindowOrgEx(WParam, P.X, P.Y);
|
MoveWindowOrgEx(WParam, P.X, P.Y);
|
||||||
LMessage.Result := GetStockObject(HOLLOW_BRUSH);
|
LMessage.Result := GetStockObject(HOLLOW_BRUSH);
|
||||||
SetBkMode(WParam, TRANSPARENT);
|
SetBkMode(WParam, TRANSPARENT);
|
||||||
@ -978,24 +1053,39 @@ Begin
|
|||||||
WM_ERASEBKGND:
|
WM_ERASEBKGND:
|
||||||
Begin
|
Begin
|
||||||
eraseBkgndCommand := TEraseBkgndCommand(EraseBkgndStack and EraseBkgndStackMask);
|
eraseBkgndCommand := TEraseBkgndCommand(EraseBkgndStack and EraseBkgndStackMask);
|
||||||
EraseBkgndStack := EraseBkgndStack shr EraseBkgndStackShift;
|
{$ifdef MSG_DEBUG}
|
||||||
if (eraseBkgndCommand <> ecNoMsg) and not WindowInfo^.hasTabParent then
|
case eraseBkgndCommand of
|
||||||
|
ecDefault: DebugLn(MessageStackDepth, ' *command: default');
|
||||||
|
ecDiscardNoRemove, ecDiscard: DebugLn(MessageStackDepth, ' *command: completely ignore');
|
||||||
|
end;
|
||||||
|
DebugLn(MessageStackDepth, ' *erasebkgndstack: ', EraseBkgndStackToString);
|
||||||
|
{$endif}
|
||||||
|
if eraseBkgndCommand <> ecDiscardNoRemove then
|
||||||
|
EraseBkgndStack := EraseBkgndStack shr EraseBkgndStackShift;
|
||||||
|
if eraseBkgndCommand in [ecDiscard, ecDiscardNoRemove] then
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if not WindowInfo^.hasTabParent then
|
||||||
begin
|
begin
|
||||||
if TWin32WidgetSet(WidgetSet).ThemesActive and WindowInfo^.isGroupBox
|
if TWin32WidgetSet(WidgetSet).ThemesActive and WindowInfo^.isGroupBox
|
||||||
and (lWinControl <> nil) then
|
and (lWinControl <> nil) then
|
||||||
begin
|
begin
|
||||||
// Groupbox (which is a button) doesn't erase it's background properly; force repaint
|
// Groupbox (which is a button) doesn't erase it's background properly; force repaint
|
||||||
lWinControl.EraseBackground(WParam);
|
lWinControl.EraseBackground(WParam);
|
||||||
|
LMessage.Result := 1;
|
||||||
end else begin
|
end else begin
|
||||||
LMessage.Msg := LM_ERASEBKGND;
|
LMessage.Msg := LM_ERASEBKGND;
|
||||||
LMessage.WParam := WParam;
|
LMessage.WParam := WParam;
|
||||||
LMessage.LParam := LParam;
|
LMessage.LParam := LParam;
|
||||||
end;
|
end;
|
||||||
end else begin
|
end else begin
|
||||||
if WindowInfo^.hasTabParent and ((lWinControl = nil)
|
if (lWinControl = nil) or not (csOpaque in lWinControl.ControlStyle) then
|
||||||
or not (csOpaque in lWinControl.ControlStyle)) then
|
begin
|
||||||
SendPaintMessage;
|
SendPaintMessage;
|
||||||
LMessage.Result := 1;
|
LMessage.Result := 1;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
WinProcess := false;
|
WinProcess := false;
|
||||||
End;
|
End;
|
||||||
@ -1710,7 +1800,8 @@ End;
|
|||||||
function WindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
|
function WindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
|
||||||
LParam: Windows.LParam): LResult; stdcall;
|
LParam: Windows.LParam): LResult; stdcall;
|
||||||
begin
|
begin
|
||||||
writeln(MessageStackDepth, 'WindowProc called for window=', window,' msg=', WM_To_String(msg),' wparam=', wparam, ' lparam=',lparam);
|
DebugLn(MessageStackDepth, 'WindowProc called for window=', IntToHex(Window, 8),' msg=',
|
||||||
|
WM_To_String(msg),' wparam=', IntToHex(WParam, 8), ' lparam=', IntToHex(lparam, 8));
|
||||||
MessageStackDepth := MessageStackDepth + ' ';
|
MessageStackDepth := MessageStackDepth + ' ';
|
||||||
|
|
||||||
Result := RealWindowProc(Window, Msg, WParam, LParam);
|
Result := RealWindowProc(Window, Msg, WParam, LParam);
|
||||||
|
|||||||
@ -125,10 +125,6 @@ Type
|
|||||||
TimerFunc: TFNTimerProc; // owner function to handle timer
|
TimerFunc: TFNTimerProc; // owner function to handle timer
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// In the way that ScrollWindow is implemented at Windows unit
|
|
||||||
// It's not possible to pass a pointer as argument
|
|
||||||
// which prevents the use of nil
|
|
||||||
function ScrollWindow(hWnd:HWND; XAmount:longint; YAmount:longint;lpRect,lpClipRect:LPRECT):WINBOOL; external 'user32' name 'ScrollWindow';
|
|
||||||
var
|
var
|
||||||
// FTimerData contains the currently running timers
|
// FTimerData contains the currently running timers
|
||||||
FTimerData : TList; // list of PWin32Timerinfo
|
FTimerData : TList; // list of PWin32Timerinfo
|
||||||
|
|||||||
@ -145,6 +145,9 @@ Const
|
|||||||
// for calendar control
|
// for calendar control
|
||||||
MCN_FIRST = (0-750); // monthcal
|
MCN_FIRST = (0-750); // monthcal
|
||||||
MCN_SELCHANGE = (MCN_FIRST + 1);
|
MCN_SELCHANGE = (MCN_FIRST + 1);
|
||||||
|
|
||||||
|
// for GetRandomRgn
|
||||||
|
SYSRGN = 4;
|
||||||
|
|
||||||
// missing listview macros
|
// missing listview macros
|
||||||
function ListView_GetHeader(hwndLV: HWND): HWND;
|
function ListView_GetHeader(hwndLV: HWND): HWND;
|
||||||
@ -160,11 +163,16 @@ function ListView_SetHoverTime(hwndLV: HWND; dwHoverTimeMs: DWORD): DWORD;
|
|||||||
Function GetAncestor(Const HWnd: HWND; Const Flag: UINT): HWND; StdCall; External 'user32';
|
Function GetAncestor(Const HWnd: HWND; Const Flag: UINT): HWND; StdCall; External 'user32';
|
||||||
{ Get information about combo box hwndCombo and place in pcbi }
|
{ Get information about combo box hwndCombo and place in pcbi }
|
||||||
Function GetComboBoxInfo(Const hwndCombo: HWND; pcbi: PCOMBOBOXINFO): BOOL; StdCall; External 'user32';
|
Function GetComboBoxInfo(Const hwndCombo: HWND; pcbi: PCOMBOBOXINFO): BOOL; StdCall; External 'user32';
|
||||||
|
function GetRandomRgn(aHDC: HDC; aHRGN: HRGN; iNum: longint): longint; stdcall; external 'gdi32';
|
||||||
|
|
||||||
{ Functions allocate and dealocate memory used in ole32 functions
|
{ Functions allocate and dealocate memory used in ole32 functions
|
||||||
e.g. BrowseForFolder dialog functions}
|
e.g. BrowseForFolder dialog functions}
|
||||||
function CoTaskMemAlloc(cb : ULONG) : PVOID; stdcall; external 'ole32.dll' name 'CoTaskMemAlloc';
|
function CoTaskMemAlloc(cb : ULONG) : PVOID; stdcall; external 'ole32.dll' name 'CoTaskMemAlloc';
|
||||||
procedure CoTaskMemFree(pv : PVOID); stdcall; external 'ole32.dll' name 'CoTaskMemFree';
|
procedure CoTaskMemFree(pv : PVOID); stdcall; external 'ole32.dll' name 'CoTaskMemFree';
|
||||||
|
// In the way that ScrollWindow is implemented at Windows unit
|
||||||
|
// It's not possible to pass a pointer as argument
|
||||||
|
// which prevents the use of nil
|
||||||
|
function ScrollWindow(hWnd:HWND; XAmount:longint; YAmount:longint;lpRect,lpClipRect:LPRECT):WINBOOL; external 'user32' name 'ScrollWindow';
|
||||||
|
|
||||||
{ Miscellaneous functions }
|
{ Miscellaneous functions }
|
||||||
{ Convert string Str to a PChar }
|
{ Convert string Str to a PChar }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user