2006. április 14., péntek
Load DOS text in a RichEdit
Problem/Question/Abstract:
Load OEM file (any DOS edited file) in a RichEdit.
Answer:
Use the following code, that translates the text through the OemToAnsiBuff function:
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
linea: PChar;
txt: TStringList;
begin
txt := TStringList.Create;
try
txt.LoadFromFile('c:\Fichero\a\leer.txt');
for i := 0 to txt.Count - 1 do
begin
linea := PChar(txt.strings[i]);
OemToAnsiBuff(linea, linea, strlen(linea));
end;
RichEdit1.Lines.AddStrings(txt);
finally
txt.Free;
end;
end;
2006. április 13., csütörtök
Implode / Explode methods like in PHP
Problem/Question/Abstract:
In Delphi you can also use the implode and explode methods from PHP:
Answer:
type
TDynStringArray = array of string;
function Implode(const Glue: string; const Pieces: array of string): string;
var
I: Integer;
begin
Result := '';
for I := 0 to High(Pieces) do
Result := Result + Glue + Pieces[I];
Delete(Result, 1, Length(Glue));
end;
function Explode(const Separator, S: string; Limit: Integer = 0): TDynStringArray;
var
SepLen: Integer;
F, P: PChar;
begin
SetLength(Result, 0);
if (S = '') or (Limit < 0) then
Exit;
if Separator = '' then
begin
SetLength(Result, 1);
Result[0] := S;
Exit;
end;
SepLen := Length(Separator);
P := PChar(S);
while P^ <> #0 do
begin
F := P;
P := AnsiStrPos(P, PChar(Separator));
if (P = nil) or ((Limit > 0) and (Length(Result) = Limit - 1)) then
P := StrEnd(F);
SetLength(Result, Length(Result) + 1);
SetString(Result[High(Result)], F, P - F);
F := P;
while (P^ <> #0) and (P - F < SepLen) do
Inc(P); // n�chsten Anfang ermitteln
end;
end;
2006. április 12., szerda
Debug your ISAPI applications on IIS 5
Problem/Question/Abstract:
Debug your ISAPI applications on IIS 5 without messing around with the registry. Just as simple as it should be!
Answer:
Start IIS WWW service;
Open Internet Services Manager and start your web site;
Open the properties sheet of your scripts directory;
Choose Aplication Protection = Low;
Click on Configuration button and choose the App Debugging tab;
Enable both Debugging Flags;
Close Internet Services Manager and stop IIS WWW service (do not stop your web site before stoping IIS);
Set your Delphi ISAPI Run Parameters as follows:
- host application: C:\WINNT\system32\inetsrv\inetinfo.exe (fix the path if necessary);
- parameters: -e w3svc;
That's it!
Now start your application inside Delphi IDE and it'll start IIS. Open your browser and go to your application. Delphi should start it and "say" it's running.
Good luck!
2006. április 11., kedd
How to read/ write a variable length string from/ to a TFileStream
Problem/Question/Abstract:
How to read/ write a variable length string from/ to a TFileStream
Answer:
Solve 1:
procedure WriteStringToFS(const s: string; const fs: TFileStream);
var
i: integer;
begin
i := 0;
i := Length(s);
if i > 0 then
fs.WriteBuffer(s[1], i);
end;
function ReadStringFromFS(const fs: TFileStream): string;
var
i: integer;
s: string;
begin
i := 0;
s := '';
fs.ReadBuffer(i, SizeOf(i));
SetLength(s, i);
fs.ReadBuffer(s, i);
Result := s;
end;
Solve 2:
You should be using TWriter and TReader. They make this kind of thing really simple to do. Create a stream, writer and reader object at the form level, then instantiate them in the OnCreate and destroy them in the OnDestroy event.
Stream := TMemoryStream.Create; {Or whatever kind of stream}
Writer := TWriter.Create(Stream, 1024);
Reader := TReader.Create(Stream, 1024);
Once that's done, try something similar to the following...
procedure TForm1.WriteStringToFS(const S: string; Writer: TWriter);
begin
try
Writer.WriteString(S);
except
raise;
end;
end;
function TForm1.ReadStringFromFS(Reader: TReader): string;
begin
try
Result := Reader.ReadString;
except
raise;
end;
end;
No need to save the length of the string because the writer do this automatically. The only caveat is that you need to be sure to create the stream first and to destroy it last.
2006. április 10., hétfő
How to extract coordinates from a region
Problem/Question/Abstract:
I am trying to do regioning backwards. I am writing an application that will read in a bitmap, allow the user to set a transparent colour, and then calculate the point set that would be needed to make that region transparent. I then want to supply the user with the coordinates as a set of coordinates, i.e. I want to extract it from a region format. Why? Because that's how Winamp takes the data in to make its custom shaped forms. But I can't seem to figure out how to pull the data out.
Answer:
One thing I found is that you must create a region prior to GetWindowRgn. I thought that one was created by default. I made a function that does what you need:
procedure TForm1.ShowRgnInfo(Rgn: HRGN);
type
RgnRects = array[0..1000] of TRect;
PRgnRect = ^RgnRects;
var
RgnData: PRgnData;
Size: DWORD;
i: Integer;
R: TRect;
RgnPtr: PRgnRect;
begin
Size := GetRegionData(Rgn, 0, nil);
Memo1.Lines.Add('Size = ' + IntToStr(Size));
GetMem(RgnData, Size);
GetRegionData(Rgn, Size, RgnData);
Memo1.Lines.Add('Number of Rectangles = ' + IntToStr(RgnData.rdh.nCount));
RgnPtr := @RgnData.Buffer;
for i := 0 to RgnData.rdh.nCount - 1 do
begin
R := RgnPtr[i];
Memo1.Lines.Add('Rect ' + IntToStr(i));
Memo1.Lines.Add(IntToStr(R.Left) + ', ' + IntToStr(R.Top) + ', ' +
IntToStr(R.Right) + ', ' + IntToStr(R.Bottom));
end;
end;
2006. április 9., vasárnap
Making a screen shot (Windows has trouble with big resolutions)
Problem/Question/Abstract:
I just want to give you an example of making a screen shot in "tiles" and pasting the results yourself.
Answer:
Sometimes you want to take a screen shot, however often Windows has trouble with big data amounts and becomes very slow. The simple solution is to make many small screen shots and paste the result together. It's not light speed, however often faster than taking the whole screen at once.
const
cTileSize = 50;
function TForm1.GetScreenShot: TBitmap;
var
Locked: Boolean;
X, Y, XS, YS: Integer;
Canvas: TCanvas;
R: TRect;
begin
Result := TBitmap.Create;
Result.Width := Screen.Width;
Result.Height := Screen.Height;
Canvas := TCanvas.Create;
Canvas.Handle := GetDC(0);
Locked := Canvas.TryLock;
try
XS := Pred(Screen.Width div cTileSize);
if Screen.Width mod cTileSize > 0 then
Inc(XS);
YS := Pred(Screen.Height div cTileSize);
if Screen.Height mod cTileSize > 0 then
Inc(YS);
for X := 0 to XS do
for Y := 0 to YS do
begin
R := Rect(
X * cTileSize, Y * cTileSize, Succ(X) * cTileSize,
Succ(Y) * cTileSize
);
Result.Canvas.CopyRect(R, Canvas, R);
end;
finally
if Locked then
Canvas.Unlock;
ReleaseDC(0, Canvas.Handle);
Canvas.Free;
end;
end;
2006. április 8., szombat
How to determine if a field's value has actually changed before posting the new value
Problem/Question/Abstract:
How to determine if a field's value has actually changed before posting the new value
Answer:
{ ... }
var
sBeforeText: string;
in the AfterEdit event of the table catch the value:
SBeforeText := DataSet.FieldByName('Category').AsString;
in the BeforePost or AfterPost Event(depending on your preference)you can compare the original with the current
if (sBeforeText <> DataSet.FieldByName('Category').AsString) then
ShowMessage('Different Values');
2006. április 7., péntek
How to create a Starfield Simulation
Problem/Question/Abstract:
How to create a Starfield Simulation
Answer:
procedure TForm1.Button1Click(Sender: TObject);
var
tmp: Integer;
begin
for tmp := 1 to Num_Stars do {Num_Stars is an Integer value}
Canvas.Pixels[Random(ClientWidth), Random(ClientHeight)] := clWhite;
end;
And you could get more fancy than that (i.e alter star color / greylevel for brightness, vary star
positions for galaxys).
2006. április 6., csütörtök
Add a password to several Paradox tables in one step
Problem/Question/Abstract:
How to add a password to several Paradox tables in one step
Answer:
procedure BDEProtectTable(ATable: TTable; const APassword: string);
var
CurPrp: CURProps;
hDB: hDBIdb;
TableDesc: CRTblDesc;
DoEncrypt: boolean;
bExcl, bOpen: boolean;
begin
Check(DBIGetCursorProps(ATable.Handle, CurPrp));
DoEncrypt := (APassword > '');
with ATable do
begin
bOpen := Active;
bExcl := Exclusive;
if Active and not Exclusive then
Close;
if not Exclusive then
Exclusive := True;
if not Active then
Open;
{supply nulls (=default) for every optional parameter:}
FillChar(TableDesc, SizeOf(CRTblDesc), 0);
{supply indispensable parameters:}
AnsiToNative(DBLocale, TableName, TableDesc.szTblName, DBIMAXTBLNAMELEN - 1);
TableDesc.szTblType := CurPrp.szTableType;
{supply parameters for our action here:}
AnsiToNative(DBLocale, APassword, TableDesc.szPassword, 255);
TableDesc.bProtected := DoEncrypt; {supply False to decrypt}
hDB := DBHandle;
Close;
{do the restructure:}
try
Check(DBIDoRestructure(hDB, 1, @TableDesc, nil, nil, nil, False));
finally
Exclusive := bExcl;
Active := bOpen;
end;
end;
end;
2006. április 5., szerda
Send a file from a TServerSocket to a TClientSocket
Problem/Question/Abstract:
How i can send a file from a TServerSocket to a TClientSocket?
Answer:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls;
type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
ServerSocket1: TServerSocket;
btnTestSockets: TButton;
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure btnTestSocketsClick(Sender: TObject);
private
FStream: TFileStream;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
iLen: Integer;
Bfr: Pointer;
begin
iLen := Socket.ReceiveLength;
GetMem(Bfr, iLen);
try
Socket.ReceiveBuf(Bfr^, iLen);
FStream.Write(Bfr^, iLen);
finally
FreeMem(Bfr);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FStream := nil;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if Assigned(FStream) then
begin
FStream.Free;
FStream := nil;
end;
end;
procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
if Assigned(FStream) then
begin
FStream.Free;
FStream := nil;
end;
end;
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
FStream := TFileStream.Create('c:\temp\test.stream.html', fmCreate or
fmShareDenyWrite);
end;
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Socket.SendStream(TFileStream.Create('c:\temp\test.html', fmOpenRead or
fmShareDenyWrite));
end;
procedure TForm1.btnTestSocketsClick(Sender: TObject);
begin
ServerSocket1.Active := True;
ClientSocket1.Active := True;
end;
end.
2006. április 4., kedd
Implement an inactivity timer with automatic logout
Problem/Question/Abstract:
Anyone have suggestions on how to implement an inactivity timer? My application has passwords for various functions, and I need to be able to automatically logout a user if they've been inactive for 10 minutes, etc.. I suppose I'd tie into the messaging queue, looking at keyboard and mouse events. The implementation should cover activity related to any form in my application, but not any activity outside the application.
Answer:
In your main form, add the integer variables "ShutdownCounter" and "ShutDownDelay". Add a TApplicationEvents and a TTimer control. Set the timer interval to, say, 5000 mSecs. In the form's OnCreate event handler, add:
{ ... }
{Set up the automatic log off routine. Get the users auto logoff time,
which defaults to 20 minutes. 0 is never autologoff}
shutDownDelay := UserIni.ReadInteger('Settings', 'Auto Shutdown Delay', 20);
shutDownDelay := shutDownDelay * 60;
ShutdownCounter := 0;
if shutDownDelay > 0 then
timShutDown.Enabled := true;
{Enable the timer if you want to use a timeout for this user}
This format allows you to add different logoff times for different users, or completely disable autologoff - I do this on my development system.
In the TApplicationEvents OnMessage event handler, add code to check for keypresses, or left mouse button clicks (or any other message you want to use to keep the app running). Whenever any of these messages are received by the application, reset the ShutDownCounter to zero.
procedure TfrmAutoProMain.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
case Msg.message of
WM_KEYDOWN, WM_LBUTTONDOWN:
ShutdownCounter := 0;
end;
end;
In the TTimer OnTimer event handler, add code to compare the current value of ShutDownCounter against the ShutDownDelay for this user. If the counter is larger than the delay, then we need to exit the application. In my apps, I actually show another window with a 30 second decrementing progress bar which gives the user notification that the app is about to shutdown, and gives him a chance to keep the app alive - that's the references to dlgAutoLogOff .
procedure TfrmAutoProMain.timShutDownTimer(Sender: TObject);
begin
Inc(ShutdownCounter, 5);
{Increase counter by 5 seconds (if TTimer interval was 5000)}
if ShutdownCounter >= shutDownDelay then
begin
timShutDown.Enabled := false;
{The next block handles a "last chance" warning dialog to allow the user
to stay alive}
dlgAutoLogOff := TdlgAutoLogOff.Create(self);
try
dlgAutoLogOff.Show;
repeat
Application.ProcessMessages;
until
(dlgAutoLogOff.ModalResult = mrOK) or (dlgAutoLogOff.ModalResult = mrAbort);
if dlgAutoLogOff.ModalResult = mrOK then
begin
ShutdownCounter := 0;
timShutDown.Enabled := true;
end
else
Application.Terminate;
finally
dlgAutoLogOff.Free;
end;
end;
end;
2006. április 3., hétfő
How to determine which combinations of rows and columns have been checked off in an array of TCheckBoxes
Problem/Question/Abstract:
I have a form with checkboxes in 8 rows and 7 columns. I want to be able to determine which combinations of rows and columns have been checked off. Is the best way to do this using a 2-D array? How would I declare this array for the checkboxes?
Answer:
FArray: array[0..7, 0..6] of TCheckBox;
You also you have to create Checkboxes at runtime, like:
FArray[i, j] := TCheckBox.Create(Self);
I would suggest to use the Tag property instead. Assign the same OnClick event handler to all checkboxes and code the Tag for each checkbox. Say 23 (second column, third row), you know like matrix indices in math:
....OnClick(Sender: TObject);
var
ATag: Integer;
begin
if (Sender is TComponent) then
begin
ATag := TComponent(Sender).Tag;
ShowMessage(Format('Column %d, Row %d', [ATag div 10, ATag mod 10]));
end;
end;
2006. április 2., vasárnap
How to identify detail tables linked to a master table
Problem/Question/Abstract:
How can I retrieve the name of the detail tables of some master table? How can I know if a table has a detail table linked? Is there any property or function in the table or query to get the details they have?
Answer:
One way to identify linked detail tables is to scan the form or data module's components array:
for I := 0 to Pred(Component.Count) do
if Components[I] is TTable then
if TTable(Components[I]).DataSource <> nil then
{ do whatever }
2006. április 1., szombat
How to embed binary data in an executable (3)
Problem/Question/Abstract:
Does anyone have experience using Delphi to create program that can create standalone exe that contains code and data like Picture2exe? This program creates a stand alone executable exe file that contains image and sound data that plays them in a slideshow. What is the approach and techniques used?
Answer:
Try this code where discclone.res includes the file you want to include:
procedure TMain.mnuCreateClick(Sender: TObject);
var
MyFile: TFileStream;
MyAppend: TMemoryStream;
begin
if diagOpenSelf.Execute then
begin
if diagCreateSelf.Execute then
begin
CopyFile(PChar(ExtractFilePath(ParamStr(0)) + '\Extractor.exe'),
PChar(diagCreateSelf.FileName), False);
{Create a filestream object for the extractor executable}
MyFile := TFileStream.Create(diagCreateSelf.FileName, $0002);
try
MyAppend := TMemoryStream.Create;
try
MyAppend.LoadFromFile(diagOpenSelf.FileName);
MyFile.Seek(0, soFromEnd);
MyFile.CopyFrom(MyAppend, 0);
MessageBox(0, 'File was successfully created.', 'File Created',
MB_OK + MB_ICONINFORMATION);
finally
MyAppend.Free;
end;
finally
MyFile.Free;
end;
end;
end;
end;
program Extractor;
{$R DiscClone.res}
uses
Windows, Classes, ShellAPI, Sysutils;
const
FileSize = 64512;
{Or 60416. You may have to change to this number to the size of the
compiled Extractor executable - minus the appended executable of course.}
var
{MyExtract: TFileStream;}
MyFile: TMemoryStream;
TempStream: TMemoryStream;
FileExe: string;
Buffer: array[0..260] of Char;
Count: DWord;
Buf: Pointer;
G: THandle;
Res: LongBool;
begin
{ ... }
{ask to make sure}
{ ... }
{check floppy in drive}
{ ... }
TempStream := TMemoryStream.Create;
{Create the memory stream which will hold a copy of this executable in memory}
MyFile := TMemoryStream.Create;
try
SetString(FileExe, Buffer, GetModuleFileName(0, Buffer,
SizeOf(Buffer))); {What is the name of this executable?}
MyFile.LoadFromFile(FileExe); {Load a copy of the executable into memory}
{A filestream which will eventually create the HelloWorld program}
// MyExtract := TFileStream.Create('dummy.floppy', fmCreate);
try
MyFile.Seek(FileSize, 0);
Move the stream pointer to the start of the appended executable}
{Copy the appended data to our filestream buffer - this creates the file}
// MyExtract.CopyFrom(MyFile, MyFile.Size - FileSize);
TempStream.CopyFrom(MyFile, MyFile.Size - FileSize);
finally
// MyExtract.Free; {Free the filestream object}
end;
{Tell the user that extraction went well and ask to run HelloWorld}
G := CreateFile('\\.\A:', GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
// F := CreateFile(PChar('\\.\' + location), GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
GetMem(Buf,1457664); {1457664}
// SetFilePointer(F, 0, nil, FILE_BEGIN);
// ReadFile(F, Buf^, 1457664, Count, nil);
// Buf:=@MyExtract; //new
WriteFile(G, Pointer(TempStream)^, 1457664, Count, nil);
// WriteFile(G, Buf^, 1457664, Count, nil);
// ShowMessage(IntToStr(GetLastError));
FreeMem(Buf);
// CloseHandle(F);
CloseHandle(G);
{ G := CreateFile(PChar('\\.\C:\Work\Boot\TestCenter\Fred.txt'),
GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);}
G := CreateFile('\\.\A:', GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
GetMem(Buf, 1474560);
TempStream.Position := 0;
TempStream.Read(Buf^, 1474560);
res := WriteFile(G, Buf^, 1474560, Count, nil);
if not res then
MessageBox(0, PChar(IntToStr(GetLastError)),
PChar(SysErrorMessage(GetLastError)),
MB_OK);
CloseHandle(G);
FreeMem(Buf);
// FlushFileBuffers(MyFileStream.Handle);
MessageBox(0, PChar(IntToStr(TempStream.size)), 'Extraction successful!',
MB_OK + MB_ICONQUESTION)
finally
{Free the memoerystream object}
MyFile.Free;
end;
TempStream.Free;
end.
Feliratkozás:
Bejegyzések (Atom)