2008. december 31., szerda
Convert 8 or 16 bit color images to 32 bit
Problem/Question/Abstract:
How do I convert a 8 bit color image or a 16 bit color image to 32 bits of color? In my case, I have files with 8bit or 16bit images which I read using scanline. So I have one or two bytes determining the pixel color. What I want to do is still read one or two bytes for each pixel, for either the 8bit or the 16bit, but convert it to 32 bits on display.
Answer:
I think you mean 8 or 16 bit per pixel, not 8 or 16 per sample. You must divide the 8 bit and the 16 bit. 8 bit is a indexed image (palette image). The pixel value is an index in a color table (palette). You need a pointer to this color table and get the color from this table. 16 bit is an RGB image, the pixel directly contains the color data. Unfortunately, you must determine the pixel mask. On Win9x the data can be 5 bit blue, 6 bit green, 5 bit red or 5 bit blue, 5 bit green, 5 bit red (bit 15 is unused). On WinNT or later the data can be stored in other combinations, but this is unlikely.
From a own project to convert such pixel data:
function DIB555ToBGR(Value: DWord): DWord; assembler;
asm
{blue}
mov ecx, eax
shl eax, 3
mov edx, eax
and eax, $0000F8
shr ecx, 2
and ecx, $000007
or eax, ecx
{green}
shl edx, 3
mov ecx, edx
and edx, $00F800
or eax, edx
shr edx, 5
and edx, $000700
or eax, edx
{red}
shl ecx, 3
and ecx, $F80000
or eax, ecx
shr ecx, 5
and ecx, $070000
or eax, ecx
end;
function DIB565ToBGR(Value: DWord): DWord; assembler;
asm
{blue}
mov ecx, eax
shl eax, 3
mov edx, eax
and eax, $0000F8
shr ecx, 2
and ecx, $000007
or eax, ecx
{green}
shl edx, 2
mov ecx, edx
and edx, $00FC00
or eax, edx
shr edx, 6
and edx, $000300
or eax, edx
{red}
shl ecx, 3
and ecx, $F80000
or eax, ecx
shr ecx, 5
and ecx, $070000
or eax, ecx
end;
However, I think you should simple use TBitmap.PixelFormat:
PixelFormat := pf32Bit;
This sets the bitmap to 32 Bit.
On the other side, you can directly display the 8 or 16 bit bitmap, the WinAPI convert the bitmap to the correct format.
2008. december 30., kedd
Coloring Cells in a StringGrid / DBGrid
Problem/Question/Abstract:
StringGrids / DBGrids with colored cells looks very nice and you can inform the user about importent data inside the Grid.
Answer:
Unfortunately you can't use the same method for coloring StringGrids and DBGrids. So first let's have a look to the StringGrid:
1. StringGrid
Use the "OnDrawCell"-event to make your StringGrids colorful! The following Code shows how to give your Grid a red background color. The second column will be colored with green background.
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
const //define your color here. Of course you
//can use default colors too.
clPaleGreen = TColor($CCFFCC);
clPaleRed = TColor($CCCCFF);
begin
//Does the cell have the focus you have to paint it with other colors
if (gdFocused in State) then
begin
StringGrid1.Canvas.Brush.Color := clBlack;
StringGrid1.Canvas.Font.Color := clWhite;
end
else //Does the cell have NOT the focus you can use
//your personal colors here
if ACol = 2 //the second Column should be
{//green, the other cells red } then
StringGrid1.Canvas.Brush.color := clPaleGreen
else
StringGrid1.canvas.brush.Color := clPaleRed;
//Now Paint the cells, but only, if the cell isn't the Title- Row/Column
//This of course depends whether you have title-Row/Columns or not.
if (ACol > 0) and (ARow > 0) then
begin
//Painting the Background
StringGrid1.canvas.fillRect(Rect);
//Painting the Text. Here you can improve the code with
// using alignment and so on.
StringGrid1.canvas.TextOut(Rect.Left, Rect.Top, StringGrid1.Cells[ACol, ARow]);
end;
end;
If you want to colorize your cells depending on values in the cells you can replace the 3 lines (if Acol = 2 ......) with something like this
if StringGrid1.Cells[ACol, ARow] = 'highlight it' then
StringGrid1.Canvas.Brush.color := clPalered
else
StringGrid1.canvas.brush.Color := clwhite;
But now lets coloring DBGrids:
2. DBGrid
It's much easier to give color to DBGrids. Here you have to use the "OnDrawColumnCell"-Event. The following example is coloring the Cells of Column "Status" when the value is not "a".
If you want to color the whole line you only have to delete the "If..." statement (see below)
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn;
State: TGridDrawState);
const
clPaleGreen = TColor($CCFFCC);
clPaleRed = TColor($CCCCFF);
begin
if Column.FieldName = 'Status' then //Remove this line, if you want
//to highlight the whole line
if Column.Field.Dataset.FieldbyName('Status').AsString <> 'a' then
if (gdFocused in State) {//does the cell have the focus? } then
dbgrid1.canvas.brush.color := clBlack //focused
else
dbgrid1.canvas.brush.color := clPaleGreen; //not focused
//Now let's paint the cell using a Default-Method:
dbgrid1.DefaultDrawColumnCell(rect, DataCol, Column, State)
end;
2008. december 29., hétfő
How to draw text on the Windows taskbar
Problem/Question/Abstract:
Does anyone know how to write a text on the main taskbar in Win95 using Delphi 3.0?
Answer:
This modified splash procedure that I use draws text directly on the Start button. Perhaps it helps. I normally use it to draw splash text directly on screen. To do that, use DC:= GetDC(0):
procedure TForm1.Button1Click(Sender: TObject);
var
DC: hDC;
Size: TSize;
Font: hFont;
const
DispText = 'Test';
begin
DC := GetDC(GetDlgItem(FindWindow(PChar('Shell_TrayWnd'), nil), $130));
ShowMessage(IntToStr(GetDlgItem(FindWindow(PChar('Shell_TrayWnd'), nil), $130)));
SetBkMode(DC, TRANSPARENT);
Font := CreateFont(12, 10, 0, 0, 1000, 0, 0, 0, ANSI_CHARSET, OUT_DEVICE_PRECIS,
CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, 'ARIAL');
SelectObject(DC, Font);
SetTextColor(DC, RGB(128, 128, 0));
GetTextExtentPoint(DC, PChar(DispText), Length(DispText), Size);
TextOut(DC, 0, 0, PChar(DispText), Length(DispText));
DeleteObject(Font);
ReleaseDC(GetDlgItem(FindWindow(PChar('Shell_TrayWnd'), nil), $130), DC);
end;
2008. december 28., vasárnap
How to use a TImage as the background for a TDBGrid
Problem/Question/Abstract:
I would like to have a DBGrid on a form that contains a bitmap and have the text in the cells of the grid float on the bitmap. I've tried using SetBKMode but apparently I'm using it incorrectly. Is there a separate canvas for each cell as well as the grid itself?
Answer:
Place a TImage on a form or create it off-screen and put the following (untested) code in the OnDrawColumnCell event of the grid:
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
w, h: Integer;
begin
with DBGrid1.Canvas do
begin
w := Rect.Right - Rect.Left;
h := Rect.Bottom - Rect.Top;
BitBlt(DBGrid1.Canvas.Handle, Rect.Left, Rect.Top, w, h,
Image1.Picture.Bitmap.Canvas.Handle, Rect.Left, Rect.Top, SRCCOPY);
Brush.Style := bsClear;
TextOut(Rect.left, Rect.Top, Column.Field.AsString);
end;
end;
2008. december 27., szombat
Return identity id from insert_SQL
Problem/Question/Abstract:
How can i obtain the value of the identity column in a table, when inserting a record with a INSERT SQL statement.
Answer:
Found the following note when surfing several sql-dba website forums:
You can use the SET NOCOUNT statement. SET NOCOUNT ON will prevent SQL Server from telling you how many rows each statement affected. SET NOCOUNT OFF will return SQL Server back to it's default setting. The variable @@ROWCOUNT will always contain the number of rows affected by the previous statement regardless of the setting of NOCOUNT
do use this statement to obtain the value of the inserted id:
whe have a table called TheTable with fields:
Field_ID (identity column)
Field001 (varchar)
Field002 (int)
Set Nocount on
Insert TheTable (Field001, Field002)
VALUES ('ABC', 1)
select IdentityInsert=@@identity
set nocount off
Example usage:
I have an order table with the primary order data, and a related table called orderdetails with the orderdetails per primary order data. The primary order table contains a key, field OrderID, of type identity-column autoincrement start at 0 and increment with 1. The table orderdetails contains the orderId as foreign key.
Case asp e-business website:
The visitor wants to checkout the order wich is composed. Now fire the insert sql to insert a record in the primary order table, using the script in this article to obtain the order id. With the obtained order id fire the several sql_inserts into the the order details table.
Tested with sqlserver 7, ado, d5, asp
2008. december 26., péntek
Create a Menu from XML-File
Problem/Question/Abstract:
How can you build up the content of e.g. a TMainMenu from a XML-File?
Perhaps you have a program which also includes an administration part for a database, but only some users should be able to see and use this administration part. Why don't create a XML-File, which contains the menu of the program. When the program starts, it builds its menu from this XML-File. And only the people who should be able to see and use the administration part get the XML-File which contains it, all other users have a file without this part.
This way it's very hard for hackers to get into the administration part.
And when you even encrypt your XML-File, it should nearly unpossible.
But how can we do this?
Answer:
A special feature of the code below: You only need to specify the Name of the procedure which then
will be attached to a OnClick handler (but all this procedures MUST be public)
At first, insert this code in your mainform and add a TMainMenu (without any content) and a TXMLDocument to your form.
procedure TMainForm.CreateMenuFromXMLFile;
function Get_Int(S: string): Integer;
begin
Result := 0;
try
Result := StrToInt(S);
except
end;
end;
procedure AddRecursive(Parent: TMenuItem; Item: IXMLNode);
var
I: Integer;
Node: TMenuItem;
Child: IXMLNode;
Address: TMethod;
begin
Node := TMenuItem.Create(Parent);
if (Uppercase(Item.Attributes['CAPTION']) <> 'SEPERATOR') then
begin
Node.Caption := Item.Attributes['CAPTION'];
if (Uppercase(Item.Attributes['ID']) <> 'NONE') then
begin
Address.Code := MethodAddress(Item.Attributes['ID']);
Address.Data := Self;
if (Item.ChildNodes.Count - 1 < 0) then
Node.OnClick := TNotifyEvent(Address);
end;
if (Uppercase(Item.Attributes['SHORTCUT']) <> 'NONE') then
Node.ShortCut := TextToShortCut(Item.Attributes['SHORTCUT']);
Node.Checked := (Item.Attributes['CHECKED'] = '1');
end
else
Node.Caption := '-';
Node.Visible := (Item.Attributes['VISIBLE'] = '1');
if Parent <> nil then
Parent.Add(Node)
else
MainMenu.Items.Add(Node);
for I := 0 to Item.ChildNodes.Count - 1 do
begin
Child := item.ChildNodes[i];
if (Child.NodeName = 'ENTRY') then
AddRecursive(Node, Child);
end;
end;
var
Root: IXMLMENUType;
Parent: TMenuItem;
I: Integer;
Child: IXMLNode;
begin
XMLDocument.FileName := ExtractFilePath(Application.ExeName) + XMLFile;
if not FileExists(XMLDocument.FileName) then
begin
MessageDlg('Menu-XML-Document not found!', mtError, [mbOK], 0);
Halt;
end;
XMLDocument.Active := True;
Screen.Cursor := crHourglass;
try
Root := GetXMLMenu(XMLDocument);
Parent := nil;
for I := 0 to Root.ChildNodes.Count - 1 do
begin
Child := Root.ChildNodes[i];
if (Child.NodeName = 'ENTRY') then
AddRecursive(Parent, Child);
end;
finally
Screen.Cursor := crDefault;
end;
end;
This was the first step.
You also need the encapsulation of the XML-File.
( Save the code below as unit and add it to your program.
Created with Delphi6 -> New -> XML Data Binding Wizard )
{***************************************************}
{ }
{ Delphi XML-Datenbindung }
{ }
{ Erzeugt am: 27.06.2002 13:25:01 }
{ }
{***************************************************}
unit XMLMenuTranslation;
interface
uses xmldom, XMLDoc, XMLIntf;
type
{ Forward-Deklarationen }
IXMLMENUType = interface;
IXMLENTRYType = interface;
{ IXMLMENUType }
IXMLMENUType = interface(IXMLNode)
['{8F36F5E2-834F-41D9-918F-9B1A441C9074}']
{ Zugriff auf Eigenschaften }
function Get_ENTRY: IXMLENTRYType;
{ Methoden & Eigenschaften }
property ENTRY: IXMLENTRYType read Get_ENTRY;
end;
{ IXMLENTRYType }
IXMLENTRYType = interface(IXMLNode)
['{AD85CD05-725E-40F8-A8D7-D6EC05FD4360}']
{ Zugriff auf Eigenschaften }
function Get_CAPTION: WideString;
function Get_VISIBLE: Integer;
function Get_ID: Integer;
function Get_ENTRY: IXMLENTRYType;
procedure Set_CAPTION(Value: WideString);
procedure Set_VISIBLE(Value: Integer);
procedure Set_ID(Value: Integer);
{ Methoden & Eigenschaften }
property Caption: WideString read Get_CAPTION write Set_CAPTION;
property Visible: Integer read Get_VISIBLE write Set_VISIBLE;
property ID: Integer read Get_ID write Set_ID;
property ENTRY: IXMLENTRYType read Get_ENTRY;
end;
{ Forward-Deklarationen }
TXMLMENUType = class;
TXMLENTRYType = class;
{ TXMLMENUType }
TXMLMENUType = class(TXMLNode, IXMLMENUType)
protected
{ IXMLMENUType }
function Get_ENTRY: IXMLENTRYType;
public
procedure AfterConstruction; override;
end;
{ TXMLENTRYType }
TXMLENTRYType = class(TXMLNode, IXMLENTRYType)
protected
{ IXMLENTRYType }
function Get_CAPTION: WideString;
function Get_VISIBLE: Integer;
function Get_ID: Integer;
function Get_ENTRY: IXMLENTRYType;
procedure Set_CAPTION(Value: WideString);
procedure Set_VISIBLE(Value: Integer);
procedure Set_ID(Value: Integer);
public
procedure AfterConstruction; override;
end;
{ Globale Funktionen }
function GetXMLMENU(Doc: IXMLDocument): IXMLMENUType;
function LoadMENU(const FileName: WideString): IXMLMENUType;
function NewMENU: IXMLMENUType;
implementation
{ Globale Funktionen }
function GetXMLMENU(Doc: IXMLDocument): IXMLMENUType;
begin
Result := Doc.GetDocBinding('MENU', TXMLMENUType) as IXMLMENUType;
end;
function LoadMENU(const FileName: WideString): IXMLMENUType;
begin
Result := LoadXMLDocument(FileName).GetDocBinding('MENU', TXMLMENUType) as
IXMLMENUType;
end;
function NewMENU: IXMLMENUType;
begin
Result := NewXMLDocument.GetDocBinding('MENU', TXMLMENUType) as IXMLMENUType;
end;
{ TXMLMENUType }
procedure TXMLMENUType.AfterConstruction;
begin
RegisterChildNode('ENTRY', TXMLENTRYType);
inherited;
end;
function TXMLMENUType.Get_ENTRY: IXMLENTRYType;
begin
Result := ChildNodes['ENTRY'] as IXMLENTRYType;
end;
{ TXMLENTRYType }
procedure TXMLENTRYType.AfterConstruction;
begin
RegisterChildNode('ENTRY', TXMLENTRYType);
inherited;
end;
function TXMLENTRYType.Get_CAPTION: WideString;
begin
Result := ChildNodes['CAPTION'].Text;
end;
procedure TXMLENTRYType.Set_CAPTION(Value: WideString);
begin
ChildNodes['CAPTION'].NodeValue := Value;
end;
function TXMLENTRYType.Get_VISIBLE: Integer;
begin
Result := ChildNodes['VISIBLE'].NodeValue;
end;
procedure TXMLENTRYType.Set_VISIBLE(Value: Integer);
begin
ChildNodes['VISIBLE'].NodeValue := Value;
end;
function TXMLENTRYType.Get_ID: Integer;
begin
Result := ChildNodes['ID'].NodeValue;
end;
procedure TXMLENTRYType.Set_ID(Value: Integer);
begin
ChildNodes['ID'].NodeValue := Value;
end;
function TXMLENTRYType.Get_ENTRY: IXMLENTRYType;
begin
Result := ChildNodes['ENTRY'] as IXMLENTRYType;
end;
end.
Finally, I'll show you an example for the XML-File.
The Procedure Name is assigned to the ID which then will be called.
<?xml version="1.0" encoding="ISO-8859-1"?>
<MENU>
<ENTRY CAPTION="Datei" VISIBLE="1" ID="None" SHORTCUT="None" CHECKED="0">
<ENTRY CAPTION="Beenden" VISIBLE="1" ID="CloseProgram" SHORTCUT="Strg+X" CHECKED="0"></ENTRY>
</ENTRY>
<ENTRY CAPTION="Anzeige" VISIBLE="1" ID="None" SHORTCUT="None" CHECKED="0">
<ENTRY CAPTION="Toolbar" VISIBLE="1" ID="ShowToolbar" SHORTCUT="None" CHECKED="1"></ENTRY>
<ENTRY CAPTION="Seperator" VISIBLE="1"></ENTRY>
<ENTRY CAPTION="Optionen" VISIBLE="1" ID="ShowOptionen" SHORTCUT="Strg+O" CHECKED="0"></ENTRY>
</ENTRY>
<ENTRY CAPTION="News" VISIBLE="1" ID="None" SHORTCUT="None" CHECKED="0">
<ENTRY CAPTION="Refresh" VISIBLE="1" ID="RefreshAll" SHORTCUT="F5" CHECKED="0"></ENTRY>
<ENTRY CAPTION="Seperator" VISIBLE="1"></ENTRY>
<ENTRY CAPTION="Administration" VISIBLE="1" ID="None" SHORTCUT="None" CHECKED="0">
<ENTRY CAPTION="neue Nachricht hinzuf�gen" VISIBLE="1" ID="NewMarkedNews" SHORTCUT="Strg+N" CHECKED="0"></ENTRY>
<ENTRY CAPTION="markierte Nachricht bearbeiten" VISIBLE="1" ID="EditMarkedNews" SHORTCUT="Strg+E" CHECKED="0"></ENTRY>
<ENTRY CAPTION="markierte Nachricht l�schen" VISIBLE="1" ID="DeleteMarkedNews" SHORTCUT="None" CHECKED="0"></ENTRY>
<ENTRY CAPTION="Seperator" VISIBLE="1"></ENTRY>
<ENTRY CAPTION="Film hinzuf�gen" VISIBLE="1" ID="AddMPG" SHORTCUT="None" CHECKED="0"></ENTRY>
<ENTRY CAPTION="markierten Film l�schen" VISIBLE="1" ID="DeleteMPG" SHORTCUT="None" CHECKED="0"></ENTRY>
</ENTRY>
</ENTRY>
<ENTRY CAPTION="Hilfe" VISIBLE="1" ID="None" SHORTCUT="None" CHECKED="0">
<ENTRY CAPTION="LogView" VISIBLE="1" ID="ShowLog" SHORTCUT="Strg+L" CHECKED="0"></ENTRY>
<ENTRY CAPTION="eMail schreiben" VISIBLE="1" ID="WriteEMail" SHORTCUT="None" CHECKED="0"></ENTRY>
<ENTRY CAPTION="Seperator" VISIBLE="1"></ENTRY>
<ENTRY CAPTION="�ber" VISIBLE="1" ID="About" SHORTCUT="None" CHECKED="0"></ENTRY>
</ENTRY>
</MENU>
The first Node should be <MENU> ... </MENU>
There you can the use <ENTRY ...></ENTRY>. When you write another entry before the Entry-Endtag, this will be a submenu item.
The parameters for ENTRY are:
CAPTION - this is the string which is displayed in the Menu. If this string is "Seperator", a Seperator will be insert
VISIBLE - when zero, the MenuItem will be generated but not displayed
ID - this is None for nothing or the Name of the procedure to call when the Item is clicked (BUT BE CAREFUL: THIS PROCEDURE MUST BE PUBLIC!)
SHORTCUT - None for nothing or e.g. Ctrl+X (read the Delphi-Help for 'TextToShortCut' to understand this)
CHECKED - when not zero, the MenuItem will be checked
2008. december 25., csütörtök
How to track a TEdit at an OnExit event
Problem/Question/Abstract:
I'm getting a trouble with an special event inside a OnExit event. I need to know at OnExit of a TEdit Control, when the user clicks a button such as the Cancel button. The user may exit the TEdit just with a correct data or when the Cancel Button was clicked. How can I track this?
Answer:
Assuming that "BlockExit" is a global variable or field of your form:
procedure TForm1.FormCreate(Sender: TObject);
begin
BlockExit := false;
end;
procedure TForm1.Edit1Exit(Sender: TObject);
begin
BlockExit := (Edit1.Text <> 'OK');
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if BlockExit then
begin
Beep;
Beep;
MessageDlg('Wrong data in Edit1', mtError, [mbOK], -1);
Edit1.SetFocus;
CanClose := false;
end
else
CanClose := true;
end;
procedure TForm1.btnCancelClick(Sender: TObject);
begin
BlockExit := false;
Close;
end;
procedure TForm1.btnOKClick(Sender: TObject);
begin
Close;
end;
2008. december 24., szerda
How to determine the caret position in a TMemo
Problem/Question/Abstract:
How to determine the caret position in a TMemo
Answer:
You can use the Windows API messages EM_LINEFROMCHAR and EM_LINEINDEX to determine the current line and offset within that line (starting from SelStart).
var
LineNum: longint;
CharsBeforeLine: longint;
begin
LineNum := SendMessage(Memo1.Handle, EM_LINEFROMCHAR, Memo1.SelStart, 0);
CharsBeforeLine := SendMessage(Memo1.Handle, EM_LINEINDEX, LineNum, 0);
Label1.Caption := ' Line ' + IntToStr(LineNum + 1);
Label2.Caption := ' Position ' + IntToStr((Memo1.SelStart - CharsBeforeLine) + 1);
end;
2008. december 23., kedd
Select first five records from table
Problem/Question/Abstract:
How to select first five records from table
Answer:
I know that SQL looks like easy thing but sometimes we face some problems, try this solvation.
SELECT TOP 5 Field1, Field2, ....FROM Table1...
2008. december 22., hétfő
Check if Internet Explorer is running and get the source of the page that is displayed
Problem/Question/Abstract:
I need to identify if IE is already running on the machine, and if so, read the source of the HTML being displayed
Answer:
{ ... }
uses
SHDocVw, MSHtml;
{ ...}
var
ShellWindows: IShellWindows;
Browser: IWebBrowser2;
i: integer;
Doc: IHTMLDocument2;
{ ...}
{ Use ShellWindows to get the active browser window }
ShellWindows := CoShellWindows.Create;
for i := 0 to ShellWindows.Count - 1 do
begin
if Supports(ShellWindows.Item(i), IWebBrowser2, Browser) then
begin
Doc := Browser.Document as IHTMLDocument2;
Memo1.Clear;
Memo1.Lines.Add(Doc.body.innerText);
{ ...}
2008. december 21., vasárnap
Copy directory structures
Problem/Question/Abstract:
How to copy directory structures
Answer:
Solve 1:
The most appropriate way would be with the SHFileOperation API call. This is a snippet of a demo I have written for this. You should be able to see the functionality.
procedure TForm1.SHFileOperationCopy(sFrom, sTo, STitle: string);
var
lpFileOp: TSHFILEOPSTRUCT;
op, flag: Integer;
begin
case rgOP.ItemIndex of
0: op := FO_COPY;
1: op := FO_DELETE;
2: op := FO_MOVE;
3: op := FO_RENAME;
end;
flag := 0;
if AllowUndo.Checked then
flag := flag or FOF_ALLOWUNDO;
if ConfirmMouse.checked then
flag := flag or FOF_CONFIRMMOUSE;
if FilesOnly.checked then
flag := flag or FOF_FILESONLY;
if NoConfirm.Checked then
flag := flag or FOF_NOCONFIRMATION;
if NoConfirmMkdir.Checked then
flag := flag or FOF_NOCONFIRMMKDIR;
if RenameColl.Checked then
flag := flag or FOF_RENAMEONCOLLISION;
if Silent.Checked then
flag := flag or FOF_SILENT;
if SimpleProgress.Checked then
flag := flag or FOF_SIMPLEPROGRESS;
with lpFileOp do
begin
Wnd := Form1.Handle;
wFunc := op;
pFrom := pChar(sFrom);
pTo := pChar(sTo);
fFlags := Flag;
hNameMappings := nil;
lpszProgressTitle := pChar(sTitle);
end;
if (SHFileOperation(lpFileOp) <> 0) then
ShowMessage('Error processing request.');
if lpFileOp.fAnyOperationsAborted then
ShowMessage('Operation Aborted');
end;
Solve 2:
Here is desired function - with recursion:
function copyfilesindir(const source, dest, mask: string; subdirs: Boolean): Boolean;
var
ts: TSearchRec;
function filewithpath(const dir, file: string): string;
begin
if (length(dir) > 0) and (copy(dir, length(dir), 1) <> '\') then
result := dir + '\' + file
else
result := dir + file;
end;
begin
result := directoryexists(dest);
if not result then
result := createdir(dest);
if not result then
exit;
if findfirst(filewithpath(source, mask), faanyfile, ts) = 0 then
repeat
if not ((ts.name = '.') or (ts.name = '..')) then
begin
if ts.Attr and fadirectory > 0 then
begin
if subdirs then
result := copyfilesindir(filewithpath(source, ts.name),
filewithpath(dest, ts.name), mask, subdirs);
end
else
result := copyfile(pchar(filewithpath(source, ts.name)),
pchar(filewithpath(dest, ts.name)), false);
if not result then
break;
end;
until
findnext(ts) <> 0;
findclose(ts);
end;
2008. december 20., szombat
How to convert UNIX time to TDateTime and vice versa
Problem/Question/Abstract:
There is a date/ time format that I'm trying to translate, but I can't find anything that could match. This example is 2000-12-20 around 22:15. Integer: 977347109, Hex: 3A412225. Anyone know how to translate it?
Answer:
The value is a Unix Time, defined as seconds since 1970-01-01T00:00:00,0Z. Important is the Letter Z, you live in Sweden, in consequence you must add 1 hour for StandardDate and 2 hours for DaylightDate to the date. The infos you can get with GetTimeZoneInformation. But you must determine, which Bias (Standard or Daylight) is valid for the date (in this case -60). You can convert the date value with the function below.
The Date for 977347109 is 2000-12-20T22:18:29+01:00.
const
UnixDateDelta = 25569; { 1970-01-01T00:00:00,0 }
SecPerMin = 60;
SecPerHour = SecPerMin * 60;
SecPerDay = SecPerHour * 24;
MinDayFraction = 1 / (24 * 60);
{Convert Unix time to TDatetime}
function UnixTimeToDateTime(AUnixTime: DWord; ABias: Integer): TDateTime;
begin
Result := UnixDateDelta + (AUnixTime div SecPerDay) { Days }
+ ((AUnixTime mod SecPerDay) / SecPerDay) { Seconds }
- ABias * MinDayFraction { Bias to UTC in minutes };
end;
{Convert Unix time to String with locale settings}
function UnixTimeToStr(AUnixTime: DWord; ABias: Integer): string;
begin
Result := FormatDateTime('ddddd hh:nn:ss', UnixTimeToDateTime(AUnixTime, ABias));
end;
{Convert TDateTime to Unix time}
function DateTimeToUnixTime(ADateTime: TDateTime; ABias: Integer): DWord;
begin
Result := Trunc((ADateTime - UnixDateDelta) * SecPerDay) + ABias * SecPerMin;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
Label1.Caption := UnixTimeToStr(977347109, -60);
end;
2008. december 19., péntek
Create without worrying of destroy a component
Problem/Question/Abstract:
How can I prevent resources leak.
Answer:
Make use of Interface characteristic where when the reference goes out of scope it will free itself.
type
IAutoClean = interface
['{61D9CBA6-B1CE-4297-9319-66CC86CE6922}']
end;
TAutoClean = class(TInterfacedObject, IAutoClean)
private
FObj: TObject;
public
constructor Create(AObj: TObject);
destructor Destroy; override;
end;
implementation
constructor TAutoClean.Create(AObj: TObject);
begin
FObj := AObj;
end;
destructor TAutoClean.Destroy;
begin
FreeAndNil(FObj);
inherited;
end;
Application....
procedure TForm1.Button1Click(Sender: TObject);
var
a: IAutoClean;
//must declare as local variable, so when this procedure finished, it's out of scope
o: TOpenDialog; //any component
begin
o := TOpenDialog.Create(self);
a := TAutoClean.Create(o);
if o.Execute then
ShowMessage(o.FileName);
end;
2008. december 18., csütörtök
Achieve Record locking with MSSQL 7 or later
Problem/Question/Abstract:
How would you like to be able to determine if a record has been locked in MSSQL Server and not get that annoying 'Record has been changed by another User' when you finally try to post your changes? There is an easy approach (quite easy) but it has to be implemented programatically.
Answer:
For every record you want to lock to this:
Create a global temporary table that is named after the table on which the record is, together with the Unique Id of the table. For example, if you have a table named customers, with a unique id field called Uid and you want to lock the record with uid=14, create the table using this query:
Create table ##Customers14 (id int null)
When you want to unlock the record just drop that table:
Drop table ##Customers14
Now lets say that another user wants to use the same record. His client program tries to create the same global temporary table, but fails with an exception, because no two global temporary tables can have the same name. Trap the exception in a try-except clause and you are home free.
TIPS.
Use this only for SQLServer 7 and above. SQL 6.5 and below have a terrible way of handling Temprorary tables that gives a lot of overhead.
You can create any kind of collumn in your temporary table, so you can have info like what time the record was locked and by what user.
Never use this approach if there is a chance someone will forget his computer open on a record for hours, and that computer is located lets say 100 miles from the server!!!
If the connection is lost by lets say an application error, the table is automatically droped by the SQL Server.
If the computer shutsdown by a power failure, the SQL Server waits for about 15 minutes and then drops the temporary table, or if the computer logs on again the table is droped automatically.
If you don't want to have to handle an exception you can also check for the existance of the Temporary table in the Master database.
Feliratkozás:
Bejegyzések (Atom)