[Оглавление] [1] [2] [3] [4] [5] [6] [7]
Лениво пользовать семафоры, покажу на именованных мутексах (семафоры с двумя состояниями).
Unit OneInstance32; interface implementation uses Forms; var g_hAppMutex: THandle; function OneInstance: boolean; var g_hAppCritSecMutex: THandle; dw: Longint; begin g_hAppCritSecMutex := CreateMutex( nil, true, PChar(Application.Title + '.OneInstance32.CriticalSection') ); // if GetLastError - лениво писать g_hAppMutex := CreateMutex( nil, false, PChar(Application.Title + 'OneInstance32.Default') ); dw := WaitForSingleObject( g_hAppMutex, 0 ); Result := (dw <> WAIT_TIMEOUT); ReleaseMutex( g_hAppCritSecMutex ); // необязательно вследствие последующего закрытия CloseHandle( g_hAppCritSecMutex ); end; initialization g_hAppMutex := 0; finalization if LongBool( g_hAppMutex ) then begin ReleaseMutex( g_hAppMutex); // необязательно CloseHandle( g_hAppMutex ); end; end.
ShellExecute("mailto:writer@coolware.com");
ShellExecute("http://coolware.com");
procedure TLine.CMHitTest(var Message: TWMNCHitTest);
begin
if PointInLineReg(Message.XPos, Message.YPos) then
Message.Result:=1 else
Message.Result:=0;
end;
unit PrtRichU;
interface
uses SysUtils, Windows, Classes, ComCtrls, RichEdit, Printers;
procedure PrintRichEdit(const Caption: string;
const RichEdt: TRichEdit);
implementation
procedure PrintRichEdit(const Caption: string;
const RichEdt: TRichEdit);
var
Range: TFormatRange;
LastChar, MaxLen, LogX, LogY, OldMap: Integer;
begin
FillChar(Range, SizeOf(TFormatRange), 0);
with Printer, Range do
begin
BeginDoc;
hdc := Handle;
hdcTarget := hdc;
LogX := GetDeviceCaps(Handle, LOGPIXELSX);
LogY := GetDeviceCaps(Handle, LOGPIXELSY);
if IsRectEmpty(RichEdt.PageRect) then
begin
rc.right := PageWidth * 1440 div LogX;
rc.bottom := PageHeight * 1440 div LogY;
end
else begin
rc.left := RichEdt.PageRect.Left * 1440 div LogX;
rc.top := RichEdt.PageRect.Top * 1440 div LogY;
rc.right := RichEdt.PageRect.Right * 1440 div LogX;
rc.bottom := RichEdt.PageRect.Bottom * 1440 div LogY;
end;
rcPage := rc;
Title := Caption;
LastChar := 0;
MaxLen := RichEdt.GetTextLen;
chrg.cpMax := -1;
OldMap := SetMapMode(hdc, MM_TEXT);
SendMessage(RichEdt.Handle, EM_FORMATRANGE, 0, 0);
try repeat
chrg.cpMin := LastChar;
LastChar := SendMessage(RichEdt.Handle, EM_FORMATRANGE, 1,
Longint(@Range));
if (LastChar < MaxLen) and (LastChar <> -1) then NewPage;
until (LastChar >= MaxLen) or (LastChar = -1);
EndDoc;
finally
SendMessage(RichEdt.Handle, EM_FORMATRANGE, 0, 0);
SetMapMode(hdc, OldMap);
end;
end;
end;
end.
и главное печатает.
procedure TForm2.DrawShadows(WDepth, HDepth : Integer);
var
Dst, RgnBox : TRect;
hOldDC : HDC;
OffScreen : TBitmap;
Pattern : TBitmap;
Bits : array[0..7] of WORD;
begin
Bits[0]:=$0055;
Bits[1]:=$00aa;
Bits[2]:=$0055;
Bits[3]:=$00aa;
Bits[4]:=$0055;
Bits[5]:=$00aa;
Bits[6]:=$0055;
Bits[7]:=$00aa;
hOldDC:=Canvas.Handle;
Canvas.Handle:=GetWindowDC(Form1.Handle);
OffsetRgn(ShadeRgn, WDepth, HDepth);
GetRgnBox(ShadeRgn, RgnBox);
Pattern:=TBitmap.Create;
Pattern.ReleaseHandle;
Pattern.Handle:=CreateBitmap(8, 8, 1, 1, @(Bits[0]));
Canvas.Brush.Bitmap:=Pattern;
OffScreen:=TBitmap.Create;
OffScreen.Width:=RgnBox.Right-RgnBox.Left;
OffScreen.Height:=RgnBox.Bottom-RgnBox.Top;
Dst:=Rect(0, 0, OffScreen.Width, OffScreen.Height);
OffsetRgn(ShadeRgn, 0, -RgnBox.Top);
FillRgn(OffScreen.Canvas.Handle, ShadeRgn, Canvas.Brush.Handle);
OffsetRgn(ShadeRgn, 0, RgnBox.Top);
// BitBlt работает быстрее CopyRect
BitBlt(OffScreen.Canvas.Handle, 0, 0, OffScreen.Width, OffScreen.Height,
Canvas.Handle, RgnBox.Left, RgnBox.Top, SRCAND);
Canvas.Brush.Color:=clBlack;
FillRgn(Canvas.Handle, ShadeRgn, Canvas.Brush.Handle);
BitBlt(Canvas.Handle, RgnBox.Left, RgnBox.Top, OffScreen.Width,
OffScreen.Height, OffScreen.Canvas.Handle, 0, 0, SRCPAINT);
OffScreen.Free;
Pattern.Free;
OffsetRgn(ShadeRgn, -WDepth, -HDepth);
ReleaseDC(Form1.Handle, Canvas.Handle);
Canvas.Handle:=hOldDC;
end;
Комментарии :procedure TMainForm.SetBands(AControls: array of TWinControl;
ABreaks: array of boolean);
var i: integer;
begin
with CoolBar do begin
for i:=0 to High(AControls) do
begin
if Bands.Count=succ(i) then TCoolBand.Create(Bands);
with Bands[succ(i)] do begin
if Assigned(Control) then Control.Hide;
MinHeight:=AControls[i].Height;
Break:=ABreaks[i];
Control:=AControls[i];
Control.Show;
Visible:=true;
end
end;
for i:=High(AControls)+2 to pred(Bands.Count) do Bands[i].Free
end
end;
иprocedure TMsgForm.FormActivate(Sender: TObject); begin MainForm.SetBands([ToolBar],[false]) end;Пpимечание:
TMainForm
...
object SpeedBar: TPanel
...
Align = alTop
BevelOuter = bvNone
object ToolBar: TPanel
...
Align = alLeft
BevelOuter = bvNone
end
object RxSplitter1: TRxSplitter
...
ControlFirst = ToolBar
ControlSecond = ChildBar
Align = alLeft
BevelOuter = bvLowered
end
object ChildBar: TPanel
....
Align = alClient
BevelOuter = bvNone
end
end
TMdiChild {пpоподитель всех остальных}
...
object pnToolBar: TPanel
...
Align = alTop
BevelOuter = bvNone
Visible = False
end
procedure TMDIForm.FormActivate(Sender: TObject);
begin
pnToolBar.Parent:=MainForm.ChildBar;
pnToolBar.Visible:=True;
end;
procedure TMDIForm.FormDeactivate(Sender: TObject);
begin
pnToolBar.Visible:=false;
pnToolBar.Parent:=self
{pnToolBar.Visible:=false}
end;
type
StrRec = record
allocSiz: Longint;
refCnt: Longint;
length: Longint;
end;
От себя добавлю:Тепеpь подpобнее о счетчике ссылок. Я уже говоpил, что пpи пpисваивании копиpования не пpоисходит, а только увеличивается счетчик. Когда он уменьшается? Hу, очевидно, когда в pезультате опеpации значение стpоки меняется, то для стаpого значения счетчик уменьшается. Это понятно. Более непонятно, когда освобождаются значения, на котоpые ссылаются поля некого класса. Это пpоисходит в System.TObject.FreeInstance пpи вызове _FinalizeRecord, а инфоpмация беpется из vtInitTable (кстати, здесь же очищаются Variant). Еще более непонятно, когда освобождаются пеpеменые String, котоpые описаны как локальные в пpоцедуpах/функциях/методах. Здесь pаботает компилятоp, котоpые вставляет эти неявные опеpации в код этой функции.
Тепеpь о типе PString. Hа самом деле пеpеменные этого типа указывают на такие же значения, как и LongString, но для пеpеменных этого типа для всех опеpаций по созданию/копиpованию/удалению нужно помнить об этих самых счетчиках ссылок. Иногда без этого типа не обойтись. Вот опеpации для этого типа (sysutils.pas):
{ String handling routines }
{ NewStr allocates a string on the heap. NewStr is provided for backwards
compatibility only. }
function NewStr(const S: string): PString;
{ DisposeStr disposes a string pointer that was previously allocated using
NewStr. DisposeStr is provided for backwards compatibility only. }
procedure DisposeStr(P: PString);
{ AssignStr assigns a new dynamically allocated string to the given string
pointer. AssignStr is provided for backwards compatibility only. }
procedure AssignStr(var P: PString; const S: string);
Можно отметить, что: явно задать использование long strings можно декларацией
var sMyLongString: AnsiString; // long dinamically allocated string sMyWideString: WideString; // wide string (UNICODE) sMyShortString1: ShortString; // old-style string sMyShortString2: String[255]; // old-style string, no more than 255 chars
(c) Max Rusov. All rights reserved:
function LocalAddr(Proc :Pointer) :TMethod; assembler;
asm
mov Result.Data, EBP
mov Result.Code, Proc
end;
function TMyList.ForEach(Proc :TMethod) :Integer;
type
EnumProc = procedure(Index :Integer; Item :Pointer; var More :Boolean);
var
I :Integer;
More :Boolean;
Tmp :Pointer;
begin
Result := -1;
More := True;
for I := 0 to Count - 1 do begin
{Вызываем локальную процедуру...}
Tmp := Proc.Data; asm push Tmp end;
EnumProc(Proc.Code)(I, List^[I], More);
asm pop ECX end;
if not More then begin
Result := I;
Exit;
end;
end;
end;
В принципе, здесь можно без Tmp - сразу Push Proc.Data. о иногда - в
других enumertor'ах кодогенератор глючит. Так что, для надежности...
Использование:
function Present(AList :TList; AItem :Pointer) :Boolean;
procedure Compare(Index :Integer; Item :Pointer; var More :Boolean);
begin
More := Item <> AItem;
end;
begin
Result := AList.ForEach(LocalAddr(@Compare)) <> -1;
end;
(Для тех кто в танке: Это пример, IndexOf не предлагать!)
procedure TForm1.Button1Click(Sender: TObject);
procedure madd(s:string);
begin
memo1.lines.add(s);
end;
VAR
ppmalloc:imalloc;
id:ishellfolder;
pi:pitemidlist;
lpname:tstrret;
begin
if succeeded(shgetspecialfolderlocation(0,CSIDL_PROGRAMS,pi)) then <<<<<<<
begin
madd('Succeeded programs location');
if succeeded(shgetdesktopfolder(id)) then
begin
madd('Succeeded get desktop folder');
if succeeded(id.getdisplaynameof(pi,0,lpname)) then
begin
madd('Succeeded get display name');
if lpname.uType=2 then madd(lpname.cstr);
end;
end
else
madd('UnSucceeded get display name');
end
else
madd('UnSucceeded get desktop folder');
end
else
madd('UNSucceeded programs location');
end;
Грубо говоря, это аналог TDC из OWL. Те операции, которые нельзя выполнить с помощью методов TCanvas, можно выполнить с помощью WinAPI. Для этого у обьектов класса TCanvas имеется свойство Handle - это и есть Хэндл Дисплейного Контекста ОС Windows (HDC), который необходим графическим функциям WinAPI.
Если свойство Canvas недоступно, Вы можете достучаться до него созданием потомка и переносом этого свойства в раздел Public.
{ Example. We recommend You to create this component through Component Wizard.
In Delphi 1 it can be found as 'File|New Component...', and can be found
as 'Component|New Component...' in Delphi 2 or above. }
type
TcPanel = class(TPanel)
public
property Canvas;
end;
У меня есть маленькое замечание.
Если у объекта нет свойства Canvas (у TDBEdit, вpоде-бы нет), по кpайней меpе в D3 можно использовать класс TControlCanvas. Пpимеpное использование:
var cc: TControlCanvas; ... cc := TControlCanvas.Create; cc.Control := youControl; ...и далее как обычно можно использовать методы Canvas.
{ Example }
begin
iScreenWidth := Screen.Width;
end;
Заодно и другие, например, Fonts и Cursors.
{ Example }
procedure TForm1.OnClick(ASender: TObject);
var
btnTemp: TButton;
begin
{ Creating }
btnTemp := TButton.Create(Self);
{ You can use 'with btnTemp do' operator below }
{ Inserting to Form }
btnTemp.Parent := Self;
{ Initialization }
btnTemp.Caption := 'I''m glad to see You';
btnTemp.SetBounds(20, 20, 80, 20);
{ You must define this event handler named 'OnBtnTempClick' }
btnTemp.OnClick := OnBtnTempClick;
{ Ready to show }
btnTemp.Visible := true;
{ Done. }
end;
procedure SetNodeState(node :TTreeNode; Flags: Integer); var tvi: TTVItem; begin FillChar(tvi, Sizeof(tvi), 0); tvi.hItem := node.ItemID; tvi.mask := TVIF_STATE; tvi.stateMask := TVIS_BOLD or TVIS_CUT; tvi.state := Flags; TreeView_SetItem(node.Handle, tvi); end;И вызываем:
SetNodeState(TreeView1.Selected, TVIS_BOLD); // Текст жиpным SetNodeState(TreeView1.Selected, TVIS_CUT); // Иконкy бледной (Ctrl+X) SetNodeState(TreeView1.Selected, TVIS_BOLD or TVIS_CUT); // Текст жиpным SetNodeState(TreeView1.Selected, 0); // Hи того, ни дpyгого
Когда-то (мечтательно закатив глаза в потолок) в API было еще и TVIS_DISABLE.
Снесли собаки. А pекомендyемyю стилистикy yпотpебления этого добpа смотpи в MS
Internet News.