Saturday, December 22, 2007
Connect to Firebird 1.5 database on Windows Vista using Local Protocol
Using Local Protocol to connect to Firebird database no longer works in Windows Vista when we install firebird server using setup file's default configuration.
Using local connection is convenient and fast if we perform GBAK, GFIX, QLI operation compare to TCP/IP connection.
To configure Firebird 1.5 works with windows vista for local connection, install the firebird server to run as application instead of service:
I haven't try using local connection for Firebird 2.x install on windows vista. Some suggest that changing IPCName in firebird.conf works even running firebird as service.
Saturday, December 08, 2007
Create a I/O redirection console application
Typical DOS application that may perform great function are GREP, MORE, SORT. These functions chain together via command redirection operators may perform complex operations. Here is a simple application written by Delphi to show how to deal with I/O redirection:
program pipe; {$APPTYPE CONSOLE} var S: string; F: TextFile; begin AssignFile(F, ''); Reset(F); while not Eof(F) do begin Readln(F, s); Writeln(s); Flush(F); end; CloseFile(F); end.
Scrolling TMemo and TRichEdit control at runtime
Here is the code to scroll TMemo control to bottom at runtime:
var M: TWMVScroll; begin M.Msg := WM_VSCROLL; M.ScrollCode := SB_BOTTOM; Memo1.Dispatch(M); end;As such, we may use the code above to perform various kind scrolling operation during runtime:
{ Scroll Bar Commands } {$EXTERNALSYM SB_LINEUP} SB_LINEUP = 0; {$EXTERNALSYM SB_LINELEFT} SB_LINELEFT = 0; {$EXTERNALSYM SB_LINEDOWN} SB_LINEDOWN = 1; {$EXTERNALSYM SB_LINERIGHT} SB_LINERIGHT = 1; {$EXTERNALSYM SB_PAGEUP} SB_PAGEUP = 2; {$EXTERNALSYM SB_PAGELEFT} SB_PAGELEFT = 2; {$EXTERNALSYM SB_PAGEDOWN} SB_PAGEDOWN = 3; {$EXTERNALSYM SB_PAGERIGHT} SB_PAGERIGHT = 3; {$EXTERNALSYM SB_THUMBPOSITION} SB_THUMBPOSITION = 4; {$EXTERNALSYM SB_THUMBTRACK} SB_THUMBTRACK = 5; {$EXTERNALSYM SB_TOP} SB_TOP = 6; {$EXTERNALSYM SB_LEFT} SB_LEFT = 6; {$EXTERNALSYM SB_BOTTOM} SB_BOTTOM = 7; {$EXTERNALSYM SB_RIGHT} SB_RIGHT = 7; {$EXTERNALSYM SB_ENDSCROLL} SB_ENDSCROLL = 8;
Friday, December 07, 2007
Capture the output of console process and display on your GUI application
I use GBAK.EXE to perform backup and restore operation of Firebird database in my GUI application design. The reason I use GBAK instead of firebird service manager is I can perform remote backup and restore operation via TCP/IP network without transferring the backup file to firebird server first.
However, as GBAK is a console utility, It display the output to STDOUT or STDERR. There is no easy way to capture the output while the console process is running. We need to invoke windows API to perform the task. We may use CreatePipe and CreateProcess to redirect the STDxxx handles and use ReadFile to capture the output in our GUI application.
Here are some references that may helps:
- Microsoft knowledge base: How to spawn console processes with redirected standard handles
- Borland newsgroup: Catch console output in real time
Child processes that use such C run-time functions as printf() and fprintf() can behave poorly when redirected. The C run-time functions maintain separate IO buffers. When redirected, these buffers might not be flushed immediately after each IO call. As a result, the output to the redirection pipe of a printf() call or the input from a getch() call is not flushed immediately and delays, sometimes-infinite delays occur. This problem is avoided if the child process flushes the IO buffers after each call to a C run-time IO function. Only the child process can flush its C run-time IO buffers. A process can flush its C run-time IO buffers by calling the fflush() function.I face this problem if I use GBAK to perform a lengthy backup and restore operation via this approach. The GUI application always stop half way in unforeseen point although it will finish the operation at last. There isn't any response from the ReadFile when it hang some where. I suspect it was due the GBAK utility written didn't perform flush as described.
Friday, November 02, 2007
Enumerate Optional Parameters of TClientDataSet instance
We may use GetOptionalParam and SetOptionalParam methods to access the optional parameters in TClientDataSet instance. However, if we do not know ahead of what parameters are available, these 2 methods serve no purpose to enumerate a list of available parameters.
Unit DBClient.pas defines the following:
type TCustomClientDataSet = class(TWideDataSet) private FDSBase: IDSBase; protected property DSBase: IDSBase read FDSBase write FDSBase; end; TClientDataSet = class(TCustomClientDataSet) end;Unit DSInst.pas defines the following:
DSProps = packed record szName : MIDASPATH; { Name, if any } iFields : Integer; { Number of columns } iRecBufSize : Integer; { Size of record buffer } iBookMarkSize : Integer; { Size of bookmark } bReadOnly : LongBool; { Dataset is not updateable } iIndexes : Integer; { Number of indexes on dataset } iOptParams : Integer; { Number of optional parameters } bDelta : LongBool; { This is a delta dataset } iLCID : Integer; { Language used } iUnused : packed array[0..7] of Integer; { Reserved } end; function GetOptParameter( { Returns optional parameter (unknown to dataset) } iNo : LongWord; { Number 1..iOptAttr } iFldNo : LongWord; { 0 if not field attribute } var ppName : Pointer; { returns ptr to name } var piType : LongWord; { returns type } var piLen : LongWord; { returns length } var ppValue : Pointer { returns ptr to value } ): DBResult; stdcall;We may attempt to use the above definition to enumerate a list of available optional parameters in TClientDataSet instance. Before we proceed, there is an obstacle to solve. The DSBase property is protected. To overcome it, we can define a class helper function to access the protected property.
type TClientDataSetHelper = class helper for TClientDataSet public function GetDSBase: IDSBase; end; function TClientDataSetHelper.GetDSBase: IDSBase; begin Result := DSBase; end;The following code shows how to retrieve available optional params.
var D: TClientDataSet; p: DSProps; pName, pValue: PChar; pType, pLen: LongWord; iResult: word; begin D := TClientDataSet.Create(nil); try D.FieldDefs.Add('Name', ftString, 20); D.CreateDataSet; D.SetOptionalParam('Param1', 'FirstValue', True); D.SetOptionalParam('Param2', 'SecondValue', True); ZeroMemory(@p, SizeOf(p)); D.GetDSBase.GetProps(p); Assert(p.iOptParams = 2); pName := nil; pValue := nil; iResult := D.GetDSBase.GetOptParameter(1, 0, pointer(pName), pType, pLen, pointer(pValue)); Assert(iResult = 0); Assert(string(pName) = 'Param1'); Assert((pType and dsTypeBitsMask) shr dsSizeBitsLen = dsfldZSTRING); Assert(pLen = 11); Assert(string(pValue) = 'FirstValue'); pName := nil; pValue := nil; iResult := D.GetDSBase.GetOptParameter(2, 0, pointer(pName), pType, pLen, pointer(pValue)); Assert(iResult = 0); Assert(string(pName) = 'Param2'); Assert((pType and dsTypeBitsMask) shr dsSizeBitsLen = dsfldZSTRING); Assert(pLen = 12); Assert(string(pValue) = 'SecondValue'); finally D.Free; end; end;
Friday, October 26, 2007
Understand HANDLE allocated to Delphi Packages in Windows environment
We may seldom need to deal with Windows API when using Delphi VCL to develop a Win32 application. The most common information we may want to retrieve is the file name of the main executable in runtime. In this case, we use
MyExeFileName := ParamStr(0);Delphi packages (.bpl) itself are a better windows .DLL. We may use it like normal windows .DLL file but it is more than that. Here are some useful tricks when work with dynamic packages. HINSTANCE HINSTANCE is a cardinal variable available at runtime. It will always return the module handle allocated by windows depends on where the current execution point is. For example, if current code is at the main .exe, the HINSTANCE will return handle of the .exe module. If current code is at .bpl package, the HINSTANCE will return handle of the .bpl package. GetModuleHandle You may use GetModuleHandle to retrieve the handle of known .exe or .bpl file name. For example,
hExe := GetModuleHandle(PAnsiChar('main.exe'))will return the handle of main.exe module.
hBPL := GetModuleHandle(PAnsiChar('package.bpl'))will return the handle of package.bpl package. If we pass a NULL parameter to the function,
hNULL := GetModuleHandle(nil)It will always return the handle of main executable even if current execution point is in a package. Thus, hNULL and hEXE should have same value. You may now understand what is the value returned by LoadPackage and the value required by UnloadPackage. Both values are handle allocated by windows. So,
m := LoadPackage('package.dll'); hBPL := GetModuleHandle(PAnsiChar('package.dll')); Assert(m = hBPL); // must be equal UnloadPackage(bBPL);To test if current execution point is at main executable, you may use
if HINSTANCE = GetModuleHandle(nil) then // in main executable else // in a package or dll moduleGetModuleName GetModuleName(hEXE) will return the main executable file name. It should be same as ParamStr(0). GetModuleName(hBPL) will return the package file name. GetModuleName(HINSTANCE) will return the current module name (either Main executable or package) depends on where the current execution point is.
Thursday, October 25, 2007
Make non TWinControl descendant response to windows messages
Although using SendMessage and PostMessage isn't a good practice in OO design. However, I do need it in some situation.
All the while I wrote TWinControl descendant to handle the custom messages:
W := TWinControl_Descendant.Create(nil);
W.Parent := Application.MainForm;
PostMessage(W.Handle, 10000, 0, 0);
I got to set the Parent for the instance else the handle won't be allocated. It is troublesome if the application I wrote isn't a window form application.
I raise a post in codegear newsgroup "borland.public.delphi.vcl.components.using.win32" of title "Is that possible to allocate windows handle to TObject direct descendant" and get some great replies. The TTimer component in Delphi VCL already is a good example of how to make a non TWinControl descendant response to windows messages. I then write a prototype to try out and it work as expected.
type
TMyObject =class
(TObject)private
FHandle: THandle;procedure
WndProc(var
Message: TMessage);public
procedure
AfterConstruction;override
;procedure
BeforeDestruction;override
;property
Handle: THandleread
FHandle;end
;procedure
TMyObject.AfterConstruction;begin
inherited
; FHandle := AllocateHWnd(WndProc);end
;procedure
TMyObject.BeforeDestruction;begin
inherited
; DeallocateHWnd(FHandle);end
;procedure
TMyObject.WndProc(var
Message: TMessage);begin
if
Message.Msg = 10000then
ShowMessage('Message received'
)else
Message.Result := DefWindowProc(FHandle, Message.Msg, Message.wParam, Message.lParam);end
;var
C: TMyObject;begin
C := TMyObject.Create;try
SendMessage(C.Handle, 10000, 0, 0);finally
C.Free;end
;end
;
Wednesday, October 24, 2007
Improve the loading speed of Delphi application built with runtime package
I just come across with the article The ultimate Delphi IDE start-up hack
When we use SysUtils.LoadPackage in Delphi, the following procedure will be invoked:
If we are very sure that our .bpl packages has no duplicate unit name, we may safely ignore the call to "CheckForDuplicateUnits" procedure. It should improve the loading speed of your Delphi application that built with runtime packages.procedure
InitializePackage(Module: HMODULE; AValidatePackage: TValidatePackageProc);type
TPackageLoad =procedure
;var
PackageLoad: TPackageLoad;begin
CheckForDuplicateUnits(Module, AValidatePackage); @PackageLoad := GetProcAddress(Module,'Initialize'
);//Do not localize
if
Assigned(PackageLoad)then
PackageLoadelse
raise
EPackageError.CreateFmt(sInvalidPackageFile, [GetModuleName(Module)]);end
;
Monday, September 24, 2007
How to install Firebird ODBC Drivers
The Firebird ODBC drivers may obtain from http://www.firebirdsql.org/
I haven't try the Windows Full Install .exe file yet. The following are steps for manual installation.
The following files are needed:
- IscDbc.dll
- OdbcJdbc.dll
- OdbcJdbcSetup.dll
- OdbcJdbc.chm
cd c:\temp %windir%\system32\RegSvr32.EXE .\OdbcJdbcSetup.dllManual Uninstall
cd c:\temp %windir%\system32\RegSvr32.EXE /u .\OdbcJdbcSetup.dllAlways set full path for RegSvr32.EXE and always set .\ before OdbcJdbcSetup.dll After finish install, you may go to Control Panel | Administrative Tools | Data Sources (ODBC) | Drivers to make sure the Firebird ODBC Driver has installed.
Sunday, September 23, 2007
Problems running a "LARGE" win32 application compiled by Delphi in Windows 98
Windows 98 kernel is not NT kernel. There are limitations on the application resource (*.RES) size and EXE file size.
Application Resource Size
If you encounter:
- "There is not enough free momory to run this program. Quit one or more programs, and then try again" OR
- "There is not enough memory to start "MyApp.EXE". Quit some programs, and then try again.
- "A device attached to the system is not functioning" OR
- The MyApp.EXE is linked to missing export MyPackage.BPL:@MyUnit@TMyClass@...
Tuesday, September 11, 2007
Using TPopupMenu control in Delphi
Imagine a form that has several controls. If we right click on the control especially controls like TEdit or TMemo, a default popup menu will shown on screen with common clipboard operations like cut, copy, paste and etc.
However, if we
- Drop a TPopupMenu component on the form
- Defines some menu items for the TPopupMenu component
- Bind the TPopupMenu component to the Form (TForm.PopupMenu)
- Compile and Run the application
- Right Click on Form show the TPopupMenu component
- Right Click on controls show the default popup menu
- Trap the TForm.OnMouseDown event
- Trap the TForm.OnContextPopup event
procedure TForm1.AfterConstruction; begin Self.PopupMenu.AutoPopup := False; end; procedure TForm1.FormContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); var C: TControl; P: TPoint; begin Handled := False; C := ControlAtPos(MousePos, True, True, True); if C = nil then begin P := ClientToScreen(MousePos); Self.PopupMenu.Popup(P.X, P.Y); Handled := True; end; end;
Sunday, September 02, 2007
Install and Configure Fedora Core 7
I love the distribution of Fedora Core 7 in DVD ISO format. Once download it, I can mount the ISO file access the contents of the FC7 files.
There are plenty of installation methods. The most usual method I used is FTP or HTTP installation. To start the installation, I burn the diskboot.img to a USB flash drive (using dd - diskdump utility). The PC must support USB flash drive boot. Once up, the installation is easy and straight.
With the help of virtual machine and ISO, I can setup my Fedora Core on virtual machine running on windows OS (2000, XP or Vista). Then I can setup FTP or HTTP server on virtual machine to serve as installation server. I then use the USB flash drive to boot the machine that support USB flash drive booting and start installing my Fedora Core remotely. This installation method is clean and easy, I only require a working TCP network environment. No DVD RW-Device and no wasting of a DVD-R disc. Help to save the earth, huh.
However, there is a PXE installation that I haven't have time to explore it yet.
The linux OS evolve in last 10 years. There are plenty of new things to learn and research. Some things that I used in last 10 years wasn't exist anymore. Especially for user like me who still use the bash shell to configure the linux OS instead of GNOME X-Windows.
Logical Volume Management (LVM)
I am not familiar with LVM and do not know why Fedora partition my hard drive LVM instead of the Primary partition that I am familiar with. The first problem I found it hard to use the LVM is it is not easy to mount a file system on LVM partition. If all mounted LVM has same logical volme name, I have problem to manage the LVM. Instead, I have to rename it or use the UUID of LVM.
SELINUX
I am not familiar with SELINUX, I turn it off usually.
TELNET
Telnet no longer come with Fedora since FC 6. It make us difficult to access the linux machine on windows desktop. To overcome this, I have to find a SSH client.
SSH Client for Windows - Tera Terms Pro
It is fast and easy.
YUM
YUM allows me to download and install RPMs from internet. It help to resolve the package dependencies.
XINETD
xinetd service wasn't come with FC7. I do not know if they have alternative ways. However, CVS service needs it. I YUM the xinetd to install it.
SAMBA
Samba that come with FC7 now use database to store user name and password instead of smbpasswd by default.
Firebird 2.01
Firebird 2.0.1 needs compat-libstdc++-33 package
X-Windows
I used to access my fedora machine on my windows desktop. However, I always need to find X-Windows Client and configure my x-server to make both able to communicate with X-DMCP. It seems VNC is a new new ways to access.
Subscribe to:
Posts (Atom)