|
WinAPI
Capture the minimize button, before application will be minimized
Call GetProcAddress procedure
Checking whether a form is still around
How to determine an existing instance of a program is already running
Intercept WM_KEYDOWN event
Popup menu by clicking left mouse button
Access icons in .exe-file
Own message handler
Keyboard routines
EnumChildWindows Example
Getting window handles from instance handle
Get line from TMemo
Previous Instance
EnumChildWindows - ExampleCode
Difference between Smart Callbacks and Dumb Callbacks
Is menu open
FindWindow
Minimize a non-delphi window from a delphi program
WinAPI functions
TMessage vs TMsg
Button does not respond to enter key
Simulating Key presses
Key presses / edit position
Avoiding close
Speaker Bleep
How to call a function with a TFarProc
Callback functions
Terminate vs. PostMessage(Handle, wm_Close, 0, 0)
How to detect program is already running
TPolygon Object OnClick algorithm question
Problems with GetSystemMetrics(SM_CYMENU)
Stuffing Keystrokes into buffer
Insert / overwrite
How can I trap a system error message
Find window problem
How do I disable mouse cursor
Mouse cursor position
Shift Tab don't activate onexit event
Task ID
Setting the active window
Updating Cursor immediately
Change System Menu
Move Mouse through Code
WinExec
How to drop down a combo box list
Capturing the Maximize message
Scroll Listbox programmatically
Moving the cursor only in the x-axis
Send Messages to a control
Previous Instance, FindWindow
Waiting for an exec'd application to complete
_hread
Manually drop-down a combobox
Imitating Key Strokes
Mouse control within and area of the screen
Need WinProc
Number of colors used in Windows
EnumWindows()
Undo in a memo field
Terminate all running applications
How to keep apps iconized
Trapping WM_ENDSESSION message
Restarting Windows
Automate memo or window scrolling
Virtual key values
Getting DOS and Windows version numbers
Flashing an applications's title bar and/or icon
Determining number of lines a memo can show
Exiting Windows from within a Delphi app
Simulate sending key to own application
ExitWindows
System Menu
GetModuleFileName
CM_MOUSELEAVE
Capture the minimize button, before application will be minimized
Question
Does anybody know how to capture the minimize button press and act on
it before it actually minimizes the form?
Answer
A:
You should intercept WM_SYSCOMMAND messages like this:
unit Unit1;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs;
type
TForm1 = class(TForm)
public
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.WMSysCommand;
begin
if (Msg.CmdType = SC_MINIMIZE) or
(Msg.CmdType = SC_MAXIMIZE) then
MessageBeep(0);
DefaultHandler(Msg);
end;
end.
Call GetProcAddress procedure
Question
I have to call GetProcAddress procedure, but I don't know how.
Answer
A:
First you need to declare a procedural data type. Here is a quick example
that should explain it. BTW you will need a procedural data type for all of
the different command lines you will be calling.
type
TMyProcType = function( X, Y: Integer ): Integer;
...
...
var
nHandle: THandle;
MyProcType: TMyProcType
begin
nHandle := LoadLibrary( 'MYDLL.DLL' );
if nHandle < 32 then
raise EDLLLoadError.Create( 'Cant load the sucker' );
@MyProcType := GetProcAddress( nHandle, 'MYFUNCNAME' );
{ Now call it like a function, ex:}
z := MyProcType( 10, 10 );
FreeLibrary( nHandle );
Checking whether a form is still around
Question
Checking whether a form is still around?
Answer
A:
Look in the API help under EnumChildWindows
It's prototype is:
(WndParent: HWnd; EnumFunc: TFarProc; lParam: LongInt): Boolean;
Use the application handle for WndParent.
EnumFunc which is written by you checks for the existence of the window -
remember to export it.
Also try the API function:
Function IsWindow(Wnd: HWnd): Boolean;
The IsWindow function determines whether the given window handle is valid.
How to determine an existing instance of a program is already running
Question
How can a Delphi program check if an existing instance of it is already
running?
Answer
A:
If hPrevInstance<>0 then Terminate;
As one of the first lines of the project source will terminate the instance of
the application just run if another is already running.
A:
Try this in the project source file:
{usual stuff at the top of the project source file
var hwnd: Word;
begin
if hPrevInst = 0 then
begin
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
begin
hwnd := FindWindow('TForm1', nil);
if (not IsWindowVisible(hwnd)) then
begin
ShowWindow(hwnd, sw_ShowNormal);
PostMessage(hwnd, wm_User, 0, 0);
end;
else
SetWindowPos(hwnd, HWND_TOP, 0,0,0,0,
SWP_NOSIZE or SWP_NOMOVE);
end;
end.
In the form's PAS file add a message response function for the wm_User
message.
{in the form declaration}
public
procedure WMUser(var msg: TMessage); message wm_User;
{in the implementation section}
procedure TForm1.WMUser(var msg: TMessage);
begin
Application.Restore;
end;
A:
if hprevinst <> 0 then begin
bringwindowtotop(findwindow('TForm1', nil));
halt;
end;
Application.CreateForm(TForm1, Form1);
Application.Run;
Intercept WM_KEYDOWN event
Question
I'm just writting a new component base od TCustomControl and I have
problems with intercepting KeyDown event.
I want to intercept VK_DOWN. The overriden KeyDown method is not
called when I press down arrow key (for other keys it's OK). The
same with intercepting WM_KEYDOWN method:
procedure WMKeyDown(var Message : TMessage); message WM_KEYDOWN;
Answer
A:
The VK_DOWN, VK_UP, and the VK_TAB can't be accessed by using KeyDown. Use
the 'OnMessage' event to handle those keys. The 'OnMessage' event gives you
the full message along with all it's parameters.
A:
What you need to do is override the KeyDown method of TCustomControl ie.
in the protected section of you new object type, insert this line:
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
then in your object's implementation you do something like:
procedure TMyObject.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited KeyDown(Key, Shift);
if (Key in [VK_UP, VK_DOWN, VK_NEXT, VK_PRIOR, VK_HOME, VK_END]) then
{do key movement work}
end;
A:
1. To write OnMessage hander for the Application
2. To intercept WM_GETDLGCODE message first and return DGLC_WANTARROWS.
The probles was that messages WM_KEYDOWN: VK_UP, VK_DOWN, VK_TAB are
not sent to the control as long as the control does not response
to WM_GETDLGCODE message.
Popup menu by clicking left mouse button
Question
I would like the popup menu to appear when the user clicks with the left
button.
Answer
A:
In your circumstances it might be a good idea to swap the left and
mouse right buttons. Use the following API call to do this
Function SwapMouseButton(Swap : Boolean) : Boolean;
Parameters - Swap : Non0Zero to swap buttons or zero to to restore
Returns a non-zero if meanings reversed; zero if not;
I would like the popup menu to appear when the user clicks with the left
button.
A:
How about setting the AutoPopup property to false, then on your form's
OnClick event call the Popup's Popup Method. Of course you could
leave AuotoPopup which would allow either button to do the trick.
Access icons in .exe-file
Question
I want to know if it is possible to access the icons that is stored in the
.exe of a file from a delphi form.
Answer
A:
Have a look at the ExtractIcon() API. Do note that the IconIndex
parameter is specified as being of Word type; but to get the
functionality of returning the total number of icons in the specified
file you're supposed to pass -1; you can do this by passing either $FFFF
or Word(-1).
Own message handler
Question
How do I write my own message handler within a base object.
The Main problem relates to unhooking the callbacks, documentation I had
recomended unhooking from outside the callback which mean't passing messsages
from the dll to the application.
Answer
A:
What you can do is create a message handle using RegisterWindowsMessage.
The code should look something like this:
StopMessage := RegsiterWindowsMessage('WM_STOP');
You should use RegisterWindowsMessage in both the DLL and in your application.
Then you can use StopMessage as the message type in a SendMessage or
PostMessage function call from the DLL. In your application you can trap
this message
by checking for StopMessage in your WndProc function like this:
procedure TMyForm.WndProc(Message : TMessage);
begin
if Message.Message = StopMessage then
begin
{ do processing for StopMessage here }
end;
end;
Keyboard routines
Question
Does anybody know if it is possible to distinguish between the right shift key
and the left shift key in Delphi?
Answer
A:
{ using this code you can determine which key is being pressed }
type
tkeyspressed = (kpRightShft, kpLeftShft, kpCtrl, kpAlt);
tkeyspset = set of tkeyspressed;
function getkeyshfstate : tkeyspset;
begin
result := mem[$40:$17]; { $40 is the famous bimodal segment/selector }
end;
{ ----------------------------------------- }
Use the code as a set. To know if the left shift is being pressed you do
...
if getkeyshfstate in [kpLeftShft] then
.....
.....
A:
Const
kpRightShft = 1
kpLeftShft = 1 shl 1;
kpInsertActive = 1 shl 7;
kpLeftCtrl = 1 shl 8;
kpLeftAlt = 1 shl 9;
kpSysReq = 1 shl 10;
kpNumLockOn = 1 shl 11;
function getkeyshfstate : word;
begin
result := memw[$40:$17]; { $40 is the famous bimodal segment/selector }
end;
This is how you use it now:
...
if getkeyshfstate and kpLeftShft <> 0 then
..... { Left Shift is pressed }
...
if getkeyshfstate and kpLeftCtrl <> 0 then
..... { Left Ctrl is pressed }
EnumChildWindows Example
Question
I've been trying to write a function to make finding child windows easier
using EnumChildWindows. I can't get it to work.
Answer
A:
I suggest that you do as follows. Please make shure that in the compiler
options you select smart callbacks ON. Or use the compiler directive as I
included it here.
{$K+} { smart callbacks on}
unit WndX;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs;
function FWC(P: integer; C: String; I: integer): integer;
function EnumChildProc(HWnd: integer; lParam: longint): Boolean;
function Left(inString : String; numChars : Byte) : String;
implementation
var
Counter : integer;
Cnt : Integer;
FWCWnd : integer;
CMatch : array[0..254] of char;
function EnumChildProc(HWnd: Integer; lParam: longint): Boolean; export; {
must be declared export }
var
ClsName : array[0..31] of char;
ClsLen : Integer;
begin
GetClassName(HWnd, ClsName, 31);
If strcomp(ClsName, CMatch) = 0 then
Counter := Counter + 1;
Result := Counter <> cnt;
if not result then
FWCWnd := HWnd;
end;
function FWC(P: integer; C: string; I: integer): integer;
begin
FWCWnd := 0;
strpcopy(CMatch, C); { convert from string to ASCIIZ }
Cnt := I;
EnumChildWindows(P, @EnumChildProc, 0); { no need for makeprocinstance! }
FWC := FWCWnd;
end;
end.
Getting window handles from instance handle
Question
I am trying to write a simple launcher app that launches a list of apps
when started, minimizes them all when minimized, and closes them all when
closed.
None of the messages for closing or minimizing will work off an instance
handle, which I get from WinExec.
Answer
A:
It's work, but you can do it in two steps. First you have to obtain the task
from the instance. To do so you can use toolhelp to walk the task list looking
for a task that has your instance.
Step two. A new walk. Once you have the task you call EnumTaskWindows to
walk the windows list until you find the one. It may be the first one.
In the second case you have to pass a pointer to your own walk function.
I hope this helps. But you will have to read in the WINAPI help section
looking for the data in the structures.
Get line from TMemo
Question
How do I know which line the cursor is on in a TMemo?
Answer
A:
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)
Lebel2.Caption := 'Position ' + IntToStr((Memo1.SelStart -
CharsBeforeLine) + 1);
end;
Previous Instance
Question
I have a program that is minimized. When I execute it again, it does not
run again, but, the first copy remains minimized.
Answer
A:
In your main form:
procedure TForm1.AppOnActivate(Sender: TObject);
begin
Self.WindowState := wsNormal;
{Self.Minimize1.Caption := 'Mi&nimize';
}
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
Application.OnActivate := AppOnActivate;
end;
In Your main unit:
begin
{ If there's another instance already running, activate that one and
terminate this one }
if HPrevInst <> 0 then begin
LoadPreviousInstance;
Exit;
End;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Then here is where the work is done - I know it is alot of code but
it will do the trick (the problem is that you have to activate the
application and then restore the form)
unit PrevInst;
interface
uses WinProcs, WinTypes, SysUtils;
type
PHWnd = ^HWnd;
{EnumFunc must be exported. It is used as the callback function for
the API call to EnumWindows}
function EnumFunc(Wnd : HWnd; TargetWindow : PHWnd): Bool; export;
procedure LoadPreviousInstance;
implementation
function EnumFunc(Wnd : HWnd; TargetWindow : PHWnd): Bool;
{Callback function for EnumWindows. EnumWindows passes the handle
(Wnd) of each open parent window (not children). }
var
ClassName : array [0..30] of char;
begin
Result := True;
if GetWindowWord(Wnd,GWW_HINSTANCE) = HPrevInst then begin
GetClassName(Wnd,ClassName,30);
if StrIComp(ClassName,'TApplication') = 0 then begin
{It is the window we want - assign it to TargetWindow}
TargetWindow^ := Wnd;
Result := False; {Stop enumeration - see EnumWindowsProc
in the API help}
end;
end;
end;
procedure LoadPreviousInstance;
var
PrevInstWnd : HWnd;
begin
PrevInstWnd := 0;
{Pass each open parent window's handle in turn to EnumFunc}
EnumWindows(@EnumFunc,Longint(@PrevInstWnd));
if PrevInstWnd <> 0 then {We have a handle to the previous
instance}
BringWindowToTop(PrevInstWnd); End;
end.
EnumChildWindows - ExampleCode
Question
EnumChildWindows - ExampleCode?
Answer
A:
I suggest you start with a hWnd of 0, meaning the screen. You can recurse from
there.
{$K+,F+} { IMPORTANT use smartcallbacks }
function EnumChilProc(hwnd: thandle; lparam: longint) : wordbool; export;
{ IMPORTANT use export }
begin
{ you are called here with hwnd = the child window
do what you want, store it in a tlist or array or whatever
lparam is an arbitrary parameter that you pass from EnumChildWindows
you may cast it to a tlist if you want
}
result := true; { return false if you want to abort the enumeration }
end;
{$F-}
Function myenum(parentwnd : thandle);
begin
enumchildwindows(parentwnd, @EnumChildProc, 0); {you may replace the
last 0 with any value that you want to send to lparam in the EnumChildProc}
end;
A:
This example sets the font of all child windows, but you can adapt this a lot of
different ways. I'm pretty sure your callback function cannot be a method in an
object (except possibly by making it a class method). The lParam argument is
user-definable. Notice that I used MakeLong to make a longint out of two words.
It is not mentioned in the Help, but is part of WinProcs. The following must
be compiled with $K+ (Smart Callbacks), which is global to each UNIT (at least
it was in BPW). If you don't want to use smart callbacks, you must declare a
variable of type TFarProc, and use MakeProcInstance and FreeProcInstance. See
second example. There are certain cases in which Smart callbacks are not
allowed, but EnumChildWindows is NOT one of them.
function SetChildWinFont(aWnd: hWnd; lParam: longint): Bool; export;
begin
SendMessage(aWnd, wm_SetFont, LoWord(lParam), HiWord(lParam));
SetChildWinFont := true;
end;
{$K+}
begin
EnumChildWindows(HWindow, TFarProc(@SetChildWinFont), MakeLong(aFont, 1));
end;
{$K-} or {$K+}
var
MyProc: TFarProc;
begin
MyProc := MakeProcInstance(@EnumChildWindows, hInstance);
EnumChildWindows(HWindow, MyProc, MakeLong(aFont, 1));
FreeProcInstance(MyProc);
end;
Difference between Smart Callbacks and Dumb Callbacks
Question
A Smart Callback is one in which you do not need to use MakeProcInstance.
MicroSoft docs generally all say that you have to use
MakeProcInstance/FreeProcInstance whenever you use a callback function of any
kind. A dumb callback (first time I've heard the term used), is the opposite,
i.e. you have to use MakeProcInstance and FreeProcInstance.
Answer
Borland tools are 'smart' and can get around that in many instances through the
use of Smart Callbacks. That is all you really need to know to use them. So
far as what's really going on, as I understand it, MakeProcInstance does a type
of thunking. "What's thunking?", you may ask. Kind of hard to explain, but
basically it places a layer of code between two modules in which one needs to
call the other, to 'translate' things. In this case, I think it mostly has to
do with properly setting the DS and SS registers upon entering and leaving the
callback function.
Is menu open
Question
Is there a (preferably non-Delphi specific) way to tell if the menu as a
whole is currently open/selected?
Answer
A:
{....}
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
item01: TMenuItem;
item11: TMenuItem;
Item21: TMenuItem;
private
{ Private declarations }
public
{----- HERE ------}
PROCEDURE WMMENUSELECT(VAR M: TWMMENUSELECT);MESSAGE WM_MENUSELECT;
end;
{...}
PROCEDURE Tform1.WMMENUSELECT(VAR M: TWMMENUSELECT);
begin
inherited;
{This beeps even if it is the sysmenu (control menu) and/or on any
selected item: }
{ messagebeep(MB_ICONASTERISk); }
{This beeps when mainmenu1 is opened, but only beeps on item[0]}
if M.menu=Mainmenu1.handle then
messagebeep(MB_ICONASTERISk);
end;
end.
FindWindow
Question
I need to pass 0 Long as one of the parameters in FindWindow.
Answer
A:
In Delphi, 0 can be a byte, integer, word, longint, real, double. But in this
case FindWindow is wanting a PChar type, which is essentially a pointer to an
array of char. Nil should work just fine; it works for me. For the second
parameter, I noticed that you're using double-quotes ["]. That is incorrect
syntax. In Delphi, strings are denoted by single-quotes [']. For instance,
try:
function FindaWin: hWnd;
begin
Result := FindWindow(nil, 'Title');
end;
By the way, a PChar is not compatible with a pascal string, but in the above
example, the compiler accepts the literal 'Title' as a PChar just fine. If you
wanted to write a function that would accept a pascal string and use it to call
FindWindow, you could do this:
function FindaWin(aName: string): hWnd;
var
aStr: array[0..255] of char;
begin
Result := FindWindow(nil, StrPCopy(aStr, aName));
end;
Minimize a non-delphi window from a delphi program
Question
I need to minimize a window from another program (non delphi) when
my program executes. Is there a way to send this window a message
to minimize itself?
Answer
A:
First you need to get the HWND (Window Handle see the WinAPI help) of the
window you want to close (The subject of another thread here.) Then try
this Windows API routine. SendMessage( hWnd, WM_SIZE, SIZE_MINIMIZED, 0);
This sends the message to the window in hWnd, that the user pressed
the minmize box or selected it from the system menu.
A:
A better solution is calling the Windows API function: CloseWindow(hWnd) -- or
ShowWindow(hWnd, SW_MINIMIZE);
WinAPI functions
Question
I'm having trouble figuring out how to use the functions that are listed in the
WinAPI Help file, and would appreciate any help that anyone has to offer ...
The specific function I am looking at is WinExec.
Answer
A:
To call Windows API functions like WinExec:
1. You need WinProcs (and often WinTypes) in the uses clause
of the unit from which you want to make the call.
2. If you want to supply a string constant as the actual
parameter where the formal parameter is PChar, you need to
check Extended syntax in the Options | Project [Compiler]
dialog (or alternatively use the {$X+} compiler directive at
the top of the unit concerned.
3. Then just code something like:
WinExec('Notepad', SW_ShowMaximized)
TMessage vs TMsg
Question
Code taht I got from the 'net uses TMessage, and it worked OK. Docs use TMsg,
and do not mention TMessage. What's the deal?
Answer
A:
Use TMessage for cracking messages passed to a window. TMsg is for certain API
calls such as PeekMessage, TranslateMessage, GetMessage, etc., in other words,
stuff that you probably won't be doing in a Delphi app. TMsg also includes info
about where the mouse cursor was at the time the message was generated, and a
time stamp.
Button does not respond to enter key
Question
I want to make a Button respond to pressing the Enter/Return key. Note the
following snippet.
buttonKeyPress(.....)
begin
if key = #13 then do SOMETHING;
else do SOMETHING ELSE;
end;
Using this programming, if the return key is pressed NOTHING happens.
The trace-over just skips it.
IF a key OTHER than the return key is pressed, then SOMETHING ELSE does
get done!?
Answer
A:
The reason for this is that TButton or TBitBtn uses the Windows standard button
control, which uses the Return key. To overcome this, you will need to create a
descendant of TButton and add a message handler for wm_GetDlgCode, like this:
type
TMyButton = class
protected
procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message wm_GetDlgCode;
end;
procedure TMyButton.WMGetDlgCode;
begin
inherited;
Msg.Result := Msg.Result or dlgc_WantReturn;
end;
See the WinAPI help file for further information on this message.
Simulating Key presses
Question
When my users enter a certain text box, I want conditional text to fill in
automatically. Let's use the following fictitious scenario.
In Edit1.Text the user fills in "CT" the state code for CT. Edit2 collects
phone number information. I know that "(203) " should be the first six
characters entered. So, using the OnEnter method of Edit2 I would like the
following to happen; the text value set to "(203) " and the cursor to
position itself at the end of those characters.
I imagine that there is an easy way to reposition a cursor in an edit box
that I do not know. If so, I'd appreciate hearing about it.
I figured I could use the following code (don't ask me why I figured this
would work ... it seems to be some vestigal memory from a something I
read or something.). In any case, it doesn't work. Any insights?
begin
Edit2.Text := '(203 )';
SendMessage(WM_CHAR,VK_END,0,0);
end;
Answer
A:
Try this:
begin
Edit2.Text := '(203 )';
Edit2.selStart:=Edit2.GetTextLen;
end;
Also, you might want to set Edit.AutoSelect to False, otherwise when a user tab
to this editBox, the text you inserted is selected, and if the user starts
typing it will be overwrited.
Key presses / edit position
Question
I imagine that there is an easy way to reposition a cursor in an edit box
that I do not know.
Answer
A:
Try this 2 Edit box sample below.
unit Cursor;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
procedure Edit1Change(Sender: TObject);
procedure Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
CurPos : integer;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Edit1Change(Sender: TObject);
begin
CurPos := Edit1.SelStart;
edit2.Text := IntToStr(CurPos);
end;
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
If Key = VK_LEFT then dec(CurPos);
if Key = VK_RIGHT then inc(CurPos); {RIGHT Arrow}
edit2.text := inttostr(CurPos);
end;
end.
Avoiding close
Question
I am writing an application that needs to to run continously, so if the user
clicks on the close button it should minimize. I tried to use the on close
event in the main form giving the value caNone and caMinimze to the var
parameter Action. However, the application quits.
Answer
A:
type
skAction = ( skfNone, skfClose, skfMinimize, skfMaximize, skfReload
);
procedure TSKDForm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
case FormAction of
skfNone :
begin
Action := caNone;
ShowWindow( Handle, SW_MINIMIZE );
Exit;
end;
skfClose :
begin
{ my clodr window code }
Exit;
end;
skfMinimize :
begin
Action := caMinimize;
Exit;
end;
end;
end;
Speaker Bleep
Question
Anybody know how to make the PC speaker bleep in Delphi, like when a user
types a wrong character?
Answer
A:
Try to take a look in the Windows API on-line help and search for
MessageBeep procedure...
Anyway, something like the following may be right for you:
uses WinProcs;
...
MessageBeep( -1 );
...
A:
If you use the WINDOS unit in your uses clause, you can do a standard Pascal
write of the BEL ASCII character to output:
Write(Chr(7))
I think it produces the rather prosaic BIOS type BEEP.
How to call a function with a TFarProc
Question
I gather I can use GetProcAddress to return a pointer to a procedure in a
.drv file. For example, ExtDeviceMode to get or change some printer settings.
Does anyone know how to use the pointer to call the function? I get a
type mismatch however I try.
Answer
A:
In the WinProcs unit, ExtDeviceMode is declared as a 'type' of procedure,
like this:
type
TExtDeviceMode = function(Wnd: HWnd; Driver: THandle;
var DevModeOutput: TDevMode; DeciveName, Port: PChar;
var DevModeInput: TDevMode; Profile: PChar; Mode: Word): Integer;
So, what you want is to declare a variable of that type, which will in
reality be a pointer, load the printer driver, and get the address to the
function, like this:
var
aModule: THandle;
ExtDeviceMode: TExtDeviceMode;
begin
aModule := LoadLibrary('HPPCL.DRV');
if DeviceModule < 32 then
raise Exception.Create('Can''t load printer driver');
try
@ExtDeviceMode := GetProcAddress(aModule, 'ExtDeviceMode');
if (@ExtDeviceMode = nil) then
raise Exception.Create('Can''t find ExtDeviceMode function');
ExtDeviceMode( ... );
finally
FreeLibrary(aModule);
end;
end;
Callback functions
Question
What is a callback function and is it supported by Delphi?
Answer
A:
A Callback function is a windows function that gets called every time
something happens. You could sorta say that message events are callback
functions, but they're not. You can do callback functions in delphi but i
wouldn't say it "supports" them. I.e. you have to declare callback
functions(the dec's are in winapi.hlp) the declarations and constants are
not in wintypes or winprocs etc. You also have to put callback functions
into a .dll i believe there a ways getting around that, but in the help it
says to put callback function code into a dll. Callback functions can do
lots of advanced windows things like hooks,subclassing other apps etc.
To subclass another app use setwindowlong(). You'll see help in winapi.hlp
To install hooks on certain things look up setwindowshookex() the VB
sendkeys function is an example of the wh_journalplayback hook.
Alot of these functions in my eyes are best used to make add on programs for
other programs. or to tell what's happening in another program. By
subclassing another program you can find out everything that is sent to it,
and handle its messages etc. An example could be you subclass aol or prodigy
chat and allow alias's and actions and such in the chatroom. (there'd be no
need to subclass mirc as it already supports 'em,just in case anybody didn't
like the example)
You can also do many other powerful things with hook/callback functions such as
Creating a win95 style taskbar for win 3.1
Finding out whats heading thru the comport
Make programs like interactive tutors that came with delphi
I can't really think of anything else offhand, if your trying to figure out
whether you need to or should use a callback function, let us know what
you're trying to do and somebody(probably not me) will know what the best
call is.
A:
Callback functions is procedures/functions that you use to notify (for
instance) something in your code. For example, imagine a procedure that
install a software in your hard disk. In the Install procedure, you may want
to update a gauge in your screen to tell the user how much of the installation
already has passed, right? So, you can pass a procedure in a parameter of the
Install procedure that points to another function that update this gauge. Too
confusing? An example:
Type
TGaugeUpdateFunc = procedure( pos : integer );
( ... )
procedure Install( GaugeFunc : TGaugeUpdateFunc; drive : byte );
var
Percent : integer;
begin
{ do some code here }
{ Update the gauge }
GaugeFunc( Percent );
end;
So, what this example tell us? It tell us that there is a private attribute
called FOnError that is a "callback" function. So, in your test function, if
a situation causes an error, you may call the OnError routine to signal that
an error happenned. The Assigned is nothing more than FOnError <> Nil.
Well, i think this may clear something in this topic. If not, or if i am
mistaken in something, tell me and we can debate on this more.
Terminate vs. PostMessage(Handle, wm_Close, 0, 0)
Question
Would someone care to elucidate on the differences and advantages or
disadvantages of closing applications with either of these two calls,
are they the same thing? Do they both clean up properly?
Answer
A:
Calling application.terminate sets the value of 'terminated', while
closing the window directly does not. If you're doing direct WM
posts, this lets you trap the event.
How to detect program is already running
Question
How do I prevent my program to run which is already running?
Answer
A:
Use the hPrevInst variable. If it is 0 then there is no previous instance
otherwise your app is already running somewhere.
So in your project file (Project1.DPR or similar) add an if statement like
IF hPrevInst <> 0 THEN BEGIN
Application.CreateForm(TForm1, Form1);
Application.Run;
END;
TPolygon Object OnClick algorithm question
Question
I would like to make a polygon object that will allow the user to draw a
multiple side free form polygon.
I'm wondering if anyone has any ideas on how to write an algorithm to detect
if the user has clicked inside of the polygon for an OnClick Event.
Answer
A:
Check out the 2 WinAPI functions CreatePolygonRgn() and PtInRegion().
These will give you the capability you need. If you happen to have a
Compuserve account of susbscribe to Delphi Informant there is code in
the most recent issue on how to set up odd shaped mouse hot spots and
demonstrates how to use the above to functions.
Problems with GetSystemMetrics(SM_CYMENU)
Question
I'm trying to capture the height of the menu bar using
GetSystemMetrics(SM_CYMENU). This works fine for a single-line
menu bar, which the WinApi help says it should. My problem occurs
when the window is shrunk horizontally until the once-single-line
menu has to double-up on itself, becoming a double-line menu.
How can I determine the total height of the menu bar?
Answer
A:
Check if TForm.ClientOrigin (or ClientRect) is moved wrt TForm.Top, e.g.
YDiff := ClientOrigin.Y - Top;
I find that this will become 42, 61, 80 with a wide enough menu to be
made into three lines. (Add 20 minus 1 for the border line which isn't there.)
Stuffing Keystrokes into buffer
Question
I need my application to be able to "stuff keystrokes" into the keyboard
buffer.
My application needs to be able to do this while minimzed and the
keystrokes should effect the active Window and appear "typed".
Answer
A:
{this proc interrogates the numlock key and sets the state}
{according to the value of bOn}
procedure TIndexForm.ToggleNumLockKey(bOn: Boolean);
var
KeyState : TKeyBoardState;
begin
GetKeyboardState( KeyState );
if bOn then KeyState[VK_NUMLOCK] := 1
else KeyState[VK_NUMLOCK] := 0;
SetKeyboardState( KeyState );
end;
Insert / overwrite
Question
I've looked through help files and vcl source code for
components, but I haven't found any information about toggling
between insert and overwrite modes in components. It seems
like a fairly easy thing to do (perhaps an api call?) but I'm
at a loss.
Answer
A:
Here are a couple of routines that should help. When
testing, you'll have to watch out for the Delphi IDE's own
use of Insert and Overwrite. I'm not sure whether that
setting is stored in the VK_INSERT entry of the Virtual key
code table or not (and it may be reset on a return to the
IDE).
Also, it goes without saying that many Delphi components
may well pay no attention to the setting of this key.
function LowOrderBitSet(Int: integer): boolean;
{----------------------------------------------------------------}
{ Tests whether the low order bit of the given integer is set. }
{----------------------------------------------------------------}
const
LowOrderBit = 0;
type
BitSet = set of 0..15;
begin
if LowOrderBit in BitSet(Int)
then LowOrderBitSet := true
else LowOrderBitSet := false;
end;
function InsertOn: boolean;
{----------------------------------------------------------------}
{ Returns the status of the Insert key. }
{----------------------------------------------------------------}
begin
if LowOrderBitSet(GetKeyState(VK_INSERT))
then InsertOn := true
else InsertOn := false
end;
procedure ToggleInsert;
{----------------------------------------------------------------}
{ Toggles the status of the Insert key. }
{----------------------------------------------------------------}
var
KeyBoardState: TKeyBoardState;
begin
GetKeyboardState(KeyBoardState);
if InsertOn
then KeyBoardState[VK_INSERT] := 0
else KeyBoardState[VK_INSERT] := 1;
SetKeyboardState(KeyBoardState);
end;
A:
The reason why the Delphi component doesn't support overwrite is that it is
simply using the multi-line edit control that is one of the standard Windows
controls, and it does not support this capability directly. However, there
is a simple technique that I got from one of the Borland SE's not too long
ago. Here's what you do:
1. Add a boolean variable to the private section of your form, and call it
InsertOn.
2. Add an 'OnCreate' event handler to the form, to initialize InsertOn to
TRUE.
3. Add a TLabel control to display whether insert is on or not (optional).
4. Add an 'OnKeyDown' event handler to your TMemo or TDBMemo control, and
insert the following code:
procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Key = vk_Insert) and (Shift = []) then
begin
InsertOn := not InsertOn;
if InsertOn then
Label1.Caption := 'Insert'
else
Label1.Caption := 'Overwrite';
end;
end;
5. Add an 'OnKeyPress' event handler to your TMemo control, and code it like
this:
procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
if (Memo1.SelLength = 0) and (not InsertOn) then
Memo1.SelLength := 1;
end;
What happens is, if InsertOn is TRUE, then it selects one character so that
when the key gets inserted, it will be overwritten. I think its a pretty
slick way to handle the problem. Wish I could take credit for it! Anyway,
this should take care of the problem.
I don't think there is any function called LowOrderBitSet in
Delphi--must have been his own function. Also, as far as I know, the Insert
key is not a toggle in the same sense that the caps lock or num lock keys
are. It is totally up to the app to decide what to do when it is pressed,
and if you want to make it toggle, you'll have to store the state of that
toggle yourself, the way I suggested (or some other way).
How can I trap a system error message
Question
I am writing an installation program for an application that I
have, but if the disk if not in the drive I get a system error
message [Cancel] [Retry], is it possible to trap this?
Answer
A:
function DisketteDriveReady (DisketteDrive: char): boolean;
{----------------------------------------------------------------}
{ Returns true if specified Diskette drive [A/a or B/b] is ready }
{ with a diskette inserted, otherwise false. From a Delphi-Talk }
{ posting by Per Ola Svensson }
{----------------------------------------------------------------}
var
Drive: byte;
SaveErrorMode: word;
begin
DisketteDriveReady := false; {until proven otherwise}
case DisketteDrive of
'A', 'a': Drive := 1;
'B', 'b': Drive := 2;
else Exit;
end; {case}
SaveErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
if DiskFree(Drive) <> -1 then
DisketteDriveReady := true;
SetErrorMode(SaveErrorMode);
end; {DisketteDriveReady}
Find window problem
Question
I am using FindWindow() to locate a window handle and I
am using PostMessage() to close the application.
The problem is that I can't seem to close Acrobat Reader
using FindWindow(nil, 'Acrobat Reader') and PostMessage()
whenever Acrobat Reader has a file opened.
Using winsight.exe, I noticed that Acrobat Reader changes
its classname and window title whenever a PDF file is
opened. How do I find Acrobat Reader's window handle and
send a message to close the application when the
classname and title change?
Answer
A:
You should use Getwindow() to cycle thru all the various windows and search
each one's
name for acrobat reader, although this sounds like a chore it's really not
too tough and happens instantaneously when you run the program.
Here's the code to do it :
(* Function to get the handle of Adobe Acrobat, could be applied to any
partial text window of a main program such as notepad, just change the
"Acrobat
Reader" to the appropriate thing you're looking for, it will return 0 if the
window
wasn't found will return the handle if it was found *)
Function GetAcrobatHwnd : word;
var
hwndx :word;
PString : Pchar;
txtlength : integer;
posit : byte;
begin{function}
hwndx := Getdesktopwindow;
GetWindow(hwndx,GW_CHild);
While not done do
begin
Txtlength := GetWindowText(hwndx,PString,255);
Posit := Pos("Acrobat Reader",Strpas(Pstring));
If Posit > 0 then (* Acrobat was found, make the result the handle *)
begin {if}
Result := hwndx;
done := true;
end;{if}
if hwndx = Getwindow(hwndx,GW_Hwndlast) then (* Acrobat Isn't Running *)
begin
Result := 0;
done := true;
end;
hwndx := GetWindow(hwndx,GW_HWNDNEXT);
end;{while}
end;{function GetAcrobatHwnd}
That function should cover it, let me know if you have any problems
How do I disable mouse cursor
Question
How do I disable mouse cursor on the image-component?
Answer
A:
You can also use the ShowCursor API Function set to false (-1). To enable
again call the function again with
True arguement (0).
But you must remember that the cursor will be unavailable to ALL windows
with this function! You must reset the
value if someone leaves the specific area of your Application that you want
the cursor disabled.
I would put it in the LostFocus event of my window or control or in test
cursor coords in the mousemove event to see if it
is out of the area. This is a little bit more work, but it lets Windows
handle the null cursor.
A:
I think that the simplest method to 'disable' the mouse is to create
a custom cursor wich is an empty image, then you assign this cursor
when the mouse is over the windowed control that you want (in your
case, a TImage component).
I use this technique to hide the mouse cursor in a program that
displays an animated image projected on a maxi-screen. Then I use a
right-click to show a menu that permits to re-display the cursor.
It works well and it's functional.
You should create a cursor with Resource Wokshop or similar resource
editors, and fit it in your RES. Then you must define a constant value
for your cursor that is greater then the standars Windows cursor
constant (for instance, 6 or 7):
const
crNullCursor = 6;
Then in the create event, load the cursor:
Screen.Cursors [crNullCursor] := LoadCursor (hInstance, 'EMPTY');
Assuming that 'EMPTY' is the name for your custom cursor in the RES.
Then you can toggle for different Windows and custom cursor on every
windowed control, assigning the proper Cursor property.
TImage1.Cursor := crNullCursor;
TImage1.Cursor := crDefault;
etc...
Mouse cursor position
Question
I'd like to be able to get the actual
mouse co-ordinates though and not have rely on a mousedown event to get
them. Anybody know how to do this? Example, I'd like to be able to have
a timer running and check the co-ordinates on a regular basis. I assume
some Windows API calls are required here.
Answer
A:
You can use a MouseMove event. For example:
Var
MyX, MyY : Integer;
Procedure Form1.Image1MouseMove(Sender : TObject...);
Var
MyPoint : TPoint;
Begin
If Timer1.Enabled Then
Begin
MyPoint.X:=X;
MyPoint.Y:=Y;
MyPoint:=ClientToScreen(MyPoint);
MyX:=MyPoint.X;
MyY:=MyPoint.Y
End
End;
May not be elegant, but should be workable.
Shift Tab don't activate onexit event
Question
I've the following problem: When an user presses Shift-Tab, in a edit-box,
I don't want the OnExit event to be activated, but how ?? Does anybody has a
solution for this problem.
Answer
A:
Perhaps you could use code something like this:
Form1.Canvas.StretchDraw(Rect(0,0, 50,50), Image1.Picture.Graphic);
The function Rect() will take two points (x,y, x,y) and turn them into
a var of type TRect. The method Form1.ClientRect, simply returns a
TRect structure that can be used by StretchDraw. (Check out the help
file for more details on these)
Here's a modified version, to stretch the bitmap from Image2 onto
Image1. (Try the code out, a blank form with 2 TImages and a TButton,
on which you can attach the following code, should work well ... :)
Image1.Picture.Bitmap.Canvas.StretchDraw(Rect(0,0, Image2.Width,
Image2.Height), Image2.Picture.Graphic);
To get the effect, a neat idea would be to make a scale factor, in
say, an edit box, ranging from 0.01 to 1. The code would then look
something along these lines:
procdure Button1.Click(Sender etc, can't remember the rest ... :(
var
x,y: Integer;
s: Double; {Scale / Magnification factor}
r: TRect;
begin
s := StrToFloat(Edit1.Text);
x := Trunc(Image2.Width * s + 0.5); {Scale and round off with 0.5}
y := Trunc(Image2.Height * s + 0.5);
r := Rect(0,0, x,y);
Image1.Picture.Bitmap.Canvas.StretchDraw(r, Image2.Picture.Graphic);
end;
Task ID
Question
I start a program with winexec and it gives me an instance. I need the task
handle (at least I think so) so I can reactivate it later if it still
exists(rather than starting another instance) I looked at
taskfirst/tasknext, but they are not working - I must not be initing the
structure properly but I can't figure out what i'm doing wrong. HELP!!!
basically, I want to start a program... later I may need it again... if it
is still running (ie the user has not closed it) then I would like to make
it active - if I have a task handle then I could:
PostMessage(HWND_BROADCAST,WM_ACTIVATEAPP,01,taskid);
right?
Answer
A:
First I did some tests in my machine. I arrived to the following litle program
which works perfectly well:
program CrtApp;
uses WinCrt, winprocs, wintypes, toolhelp, sysutils;
var
rslt : bool;
taskentry : ttaskentry;
begin
taskentry.dwsize := sizeof(taskentry);
rslt := taskfirst(@taskentry);
while rslt do begin
with taskentry do
writeln(format('Task: %6x Hinstance: %6x', [htask, hinst]));
if taskentry.hnext = 0 then
break;
rslt := TaskNext(@taskentry);
end;
end.
Based on that, I suggest you try the following.
uses winprocs, wintypes, toolhelp, sysutils;
...
{ for a given instance return the task. Return 0 if failure }
Function instancetotask(myinstance : thandle) : thandle;
var
temp : thandle;
rslt : bool;
taskentry : ttaskentry;
begin
result := 0
taskentry.dwsize := sizeof(taskentry);
rslt := taskfirst(@taskentry);
repeat
if not rslt then
exit;
if taskentry.hinst = myinstance then begin
result := taskentry.htask;
exit;
end;
if taskentry.hnext = 0 then
exit;
rslt := TaskNext(@taskentry);
until false;
end;
Setting the active window
Question
I am using a TTimer object to wait for an event and when that event occurs, I
want to display a dialog box to the user (probably something more elaborate
than MessageBox). But if my app is minimized or not the active window (for
example, if MS Word is the active app), my dialog box (or message box) does
not display. I know my TTimer event procedure is working because I hear the
MessageBeep(0) that I put in there before I show my dialog box.
Answer
A:
I have tried this using a form of my own design, and it pops up in
front of the running application without having to resort to any API
stuff. Here's my timer event; as you can see it's not anything
special:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
MyDialog.ShowModal;
end;
It shows me the dialog no matter the state of my application
(not focused, minimized, whatever).
Updating Cursor immediately
Question
For example, if I change my cursor to a waiting clock cursor before
some time-consuming operations is executed, why isn't my waiting clock
cursor activated immediately? It's only activated after the event!
Answer
A:
Begin
Try
Screen.Cursor:=crHourGlass;
ReportForm := TReportForm.Create(Application);
Screen.Cursor:=crDefault;
ReportForm.ShowModal;
ReportForm.Free;
Finally
Screen.Cursor:=crDefault;
end;
end;
Change System Menu
Question
How could I change the system menu so that it includes an item
like "register"?
Answer
A:
Here is a routine that should help:
procedure AppendToSystemMenu (Form: TForm;
Item: string; ItemID: word);
{----------------------------------------------------------------}
{ Appends menu item to end of system menu of specified form and }
{ to system menu of application's minimized icon. For separator }
{ bar, use '-' for the Item, and 0 for the ItemID. }
{----------------------------------------------------------------}
var
NormalSysMenu, MinimizedMenu: HMenu;
AItem: array[0..255] of Char;
PItem: PChar;
begin
NormalSysMenu := GetSystemMenu(Form.Handle, false);
MinimizedMenu := GetSystemMenu(Application.Handle, false);
if Item = '-' then
begin
AppendMenu(NormalSysMenu, MF_SEPARATOR, 0, nil);
AppendMenu(MinimizedMenu, MF_SEPARATOR, 0, nil);
end
else
begin
PItem := StrPCopy(@AItem, Item);
AppendMenu(NormalSysMenu, MF_STRING, ItemID, PItem);
AppendMenu(MinimizedMenu, MF_STRING, ItemID, PItem);
end
end; {AppendToSystemMenu}
To use the above routine, call it something like:
{ Add an item to the system menu: }
AppendToSystemMenu(MainForm, '-', 0); {Separator bar}
AppendToSystemMenu(MainForm, '&Please Register...', 99);
Application.OnMessage := MainForm.RegisterMsg;
(Slightly to my surprise the above 3 lines work OK from the
form's Create method).
Then supply whatever you want to do when the user selects
the new menu item in a method like:
procedure TMainForm.RegisterMsg (var Msg: TMsg;
var Handled: boolean);
begin
if Msg.Message = WM_SYSCOMMAND then
if Msg.wParam = 99 then
{Registration stuff}
end;
Move Mouse through Code
Question
How can you move the Mouse using code.
is there a global mouse variable?
maybe through application variable or screen variable
Is there delphi or do I have to use API what API would I use?
Can you restrict the range of the mouse? (so if you drag it out side of a
rectangle it just hangs out along the border)
Answer
A:
GetCursorPos and SetCursorPos (in Windows API) are very easy to use.
See ClipCursor in the on-line help.
WinExec
Question
wProg := WinExec('thingy.exe', SW_SHOW)
while (still_running(wProg))
Application.ProcessMessage;
...
I need this 'still_running' piece, any one have any ideas.
Answer
A:
still_running(wprog) == (GetModuleUsage(wprog) > 0)
But your own process could be terminated, so better use
repeat Application.ProcessMessages
until (GetModuleUsage(wProg) = 0) or Application.Terminated;
A:
Try this code:
var
ProgramHandle: Word;
PathName: PChar;
...
ProgramHandle := WinExec(PathName, SW_SHOWNORMAL);
While GetModuleUsage(ProgramHandle) <> 0 then
Application.ProcessMessage;
...
How to drop down a combo box list
Question
I have a drop down combo box on a form. I need to be able to drop the
list down programmatically when (if) the user types in to the edit part
of the combo box. I am aware that there is a Windows message to do this,
but how do I use it?
Answer
A:
The message is CB_SHOWDROPDOWN and to use it:
SendMessage(ComboBox1.Handle, CB_SHOWDROPDOWN, 1, 0) {Opens list}
SendMessage(ComboBox1.Handle, CB_SHOWDROPDOWN, 0, 0) {Closes list}
A:
Procedure THebEnhancedDBComboBox.ShowList;
begin
if GetWindowLong(Handle, gwl_Style) and cbs_DropDown = cbs_DropDown then
SendMessage(Handle, cb_ShowDropDown, 1, 0);
end;
{ Hides the list of an associated drop-down combobox. }
procedure THebEnhancedDBComboBox.HideList;
begin
if GetWindowLong(Handle, gwl_Style) and cbs_DropDown = cbs_DropDown then
SendMessage(Handle, cb_ShowDropDown, 0, 0);
end;
Capturing the Maximize message
Question
I need to intercept the maximize system message and change the size of my
form manually (it's got a funky size. It resembles Delphi's main form in
size and behavior). Right now, I have code in my OnResize event that
changes the size after the fact to what I want. This makes a nasty flash,
even on my DX4/100. This app is going to run on much slower machines (486
DX/33 or SX/25) and this flash as it redraws the form twice would be nasty
at that speed. I tried writing my own handler for it assigned it to message
SC_MAXIMIZE. This gave me a duplicate virtual method error (?).
Answer
A:
Respond to the WMGetMinMaxInfo message. Pretty simple, some example
code is below. You don't get the flash, it just restricts how far
you can drag window borders when resizing, maximising, etc. Set the
sizes to whatever you like.
private
{ Private declarations }
procedure WMGetMinMaxInfo( var Message :TWMGetMinMaxInfo ); message WM_GETMINMAXINFO;
procedure TCCentre.WMGetMinMaxInfo( var Message :TWMGetMinMaxInfo );
begin
with Message.MinMaxInfo^ do
begin
ptMaxSize.X := 640; {Width when maximized}
ptMaxSize.Y := 96; {Height when maximized}
ptMaxPosition.X := 0; {Left position when maximized}
ptMaxPosition.Y := 0; {Top position when maximized}
ptMinTrackSize.X := 500; {Minimum width}
ptMinTrackSize.Y := 96; {Minimum height}
ptMaxTrackSize.X := 640; {Maximum width}
ptMaxTrackSize.Y := 150; {Maximum height}
end;
Message.Result := 0; {Tell windows you have changed
minmaxinfo} inherited;
end;
Scroll Listbox programmatically
Question
I would like to scroll a list box programmatically by a button.
ie. when I click on the button, it's as though I've clicked on the
scrollbar arrow.
Answer
A:
Take a look at the LB_SETTOPINDEX Windows API message. Send it to the
desired listbox with the (zero-based) index in wParam.
Ex.
SendMessage(ListBox.Handle,lb_SetTopIndex,10,0);
This will make the eleventh item appear as the first visible item.
Moving the cursor only in the x-axis
Question
Does anyone know how to trap the movement of the mouse cursor, in
such a way that the programmer can specify that only the x coord will
change ?
I am currently looking at the OnMouseMove event, but can't seem to
find a way to specify the Y coord.
I need to be able to hold the cursor on a horizontal line and not
allow it to move in the y axis.
Answer
A:
In your OnMouseMove, go something like:
if (y<>0) and (lockY) then begin
GetMouseCoords(NewX,NewY);
NewY := NewY + y; {or should that be minus?}
SetMouseCoords(NewX,NewY);
end;
'lockY' is a variable you declare and set true when you want to do this
type of control.
Substitute the real functions that get and set the mouse co-ordinates in
the relevant spots.
Send Messages to a control
Question
How do I send a window message to a control? I want to send
LVM_EDITLABEL to a TListView. Or does anyone know of any other way to
"manually" start editing of a label in a TListView?
Answer
A:
Use the NotifyControls(LVM_EDITLABEL) or...
var
msg : TMessage;
begin
msg.msg := LVM_EDITLABEL;
msg.wParam := 0;
msg.lParam := 0;
msg.Result := 0;
broadcast(msg);
end;
please note that if you have a container such as a panel or page
control that contains other controls, the message won't be passed
through the container. You must code a message handler for each
container to receive and echo the message to the controls in that
container.
Previous Instance, FindWindow
Question
I'm having trouble detecting a previous instance of an application using
Delphi2.
Answer
A:
In Win32, hInstance doesn't work. Everytime you start an
application it has a complete and private address space that spans
4GB. So, if you launch a program twice, the second one doesn't know
about the previous one (as it is in a different virtual address
space). Again, all this is true only for 32-bit executables.
When you a launch 16 bit apps in Windows95 or WindowsNT, they all
share a common virtual machine, so you get instance handles. Since
you were compiling the app with Delphi 1.x, your code worked. Now in
the Delphi 2.0 you code is 'broken' beacuse your HPrevInst is always
zero. If you still want to find a previous 'instance' (sic), you'll
have to resort to a different technique like searching for the main
window of the application.
A:
Another solution is to create a memory mapped file from the first instance.
If the file already exists then you know another instance is running. I
don't have the Win32 API here, but if you search on "memory mapped file" you
should find it.
Waiting for an exec'd application to complete
Question
I'm looking for a component for Delphi 2.0 that will exec another
application and wait for it to complete. I found one for Delphi 1.0, but
since it lacked sources it does me no good at all.
Answer
function WinExecAndWait32(FileName:String; Visibility : integer):integer;
var
zAppName:array[0..512] of char;
zCurDir:array[0..255] of char;
WorkDir:String;
StartupInfo:TStartupInfo;
ProcessInfo:TProcessInformation;
begin
StrPCopy(zAppName,FileName);
GetDir(0,WorkDir);
StrPCopy(zCurDir,WorkDir);
FillChar(StartupInfo,Sizeof(StartupInfo),#0);
StartupInfo.cb := Sizeof(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := Visibility;
if not CreateProcess(nil,
zAppName, { pointer to command line string }
nil, { pointer to process security attributes }
nil, { pointer to thread security attributes }
false, { handle inheritance flag }
CREATE_NEW_CONSOLE or { creation flags }
NORMAL_PRIORITY_CLASS,
nil, { pointer to new environment block }
nil, { pointer to current directory name }
StartupInfo, { pointer to STARTUPINFO }
ProcessInfo) then Result := -1 { pointer to PROCESS_INF }
else begin
WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
GetExitCodeProcess(ProcessInfo.hProcess,Result);
end;
end;
A:
The following logic is fairly simple, but it works under both Delphi 1.0 and
2.0.
while FindWindow(NIL, ' 0 do
Application.ProcessMessages ;
MessageDlg('Done!', mtInformation, [mbOK], 0) ;
A:
And if you want to process other Windows messages while executing the program
change the WaitforSingleObject(ProcessInfo.hProcess,INFINITE); line to
while WaitForSingleObject(ProcessInfo.hProcess, 100) = WAIT_TIMEOUT do
Application.ProcessMessages;
_hread
Question
Can someone tell me how I would go about using the _hread win api with
delphi. Apparently it is not in the WinProcs unit. Might the
function be in a differnt unit? I can use the _lread, _lwrite, ...,
but I want to be able to read the data into global mem in one pass.
Answer
_hread isn't declared in any Delphi file. You should declare it by
yourself using:
function _hread(FileHandle: Integer; Buffer: PChar; Bytes: LongInt):
LongInt; far; external 'KERNEL';
in your PAS file. It is also used internally in Delphi's function
FileRead. You can try FileOpen,FileRead and FileClose.
Manually drop-down a combobox
Question
Does anybody know a way of manually dropping down a combobox? In my
app I want the user to be able to type a value into a combobox. In the
OnExit event the value is to be validated and if it's not valid, the
dropdownlist of the combobox must appear. I don't want to use the
csDropDown style, because I want the user to be able to type the
value. The only problem is how to programmatically have the combobox
show its dropdown list.
Answer
SendMessage(DBComboBox1.Handle,CB_SHOWDROPDOWN,1,0);
Imitating Key Strokes
Question
Is there an easy way in Delphi to imitate keystrokes on a keyboard.
Answer
You can send a message to the window that must handle the key, like:
PostMessage(FWinControl.Handle, WM_KEYDOWN, VK_BACK, 1966081);
Mouse control within and area of the screen
Question
Anybody know if there is a way to limit mouse movement so that
the mouse can not be moved outside of a TPanel. I am trying to
write a system that requires no mouse movement outside the
upper left corner of the screen.
Answer
Use the ClipCursor API function. The only trick with it is to
notice that its parameter is not a simple TRect but a pointer
to a TRect, so you will have to use something like:
var
MyRect: TRect;
...
ClipCursor(@MyRect);
Also, remember to set the cursor free again at some stage with
ClipCursor(nil);
Need WinProc
Question
The reason I need access to the WinProc is because I need to register
a custom Windows and Message and provide a message handler for this
message. Is there some other way to do this within a component
without requiring a WinProc.
Answer
There should be no reason why you cant do the RegisterMessage during the
TComponent
Create method, just OverRide it. Also if all you are doing is posting the Same
Message to yourself all the time and not to other windows there is no
requirement to register the message
all you have to is define it so that your app knows what is. you can do that
by making it a Const eg. MyMessage : WM_User + 1; {always start from WM_User
plus what ever number}
Or in your MessageHandler Just test for it
eg if WM_User + 1 then.
As for the Message handler the code below should help you out.
constructor YourComp.Create(AOwner: TComponent);
begin
Inherited Create;
{hself is a variable defined in your private area}
hSelf := AllocateHwnd(OnMyMessage);
end;
procedure YourComp.OnMyMessage(var Msg: TMessage);
begin
case Msg.Msg of
WM_User + 1: begin
ShowMessage('Got WM_User+1');
end;
WM_User + 2: begin
ShowMessage('Got WM_User+2');
end;
end;
end;
destructor YourComp.Destroy;
begin
{Ensuring the handle we have allocated is de allocated}
DeAllocatehWnd(hSelf);
Inherited Destroy;
end;
Number of colors used in Windows
Question
How to make sure that windows is running at least using 256 colors video mode in
delphi program ?
So our program will not run in 16 colors.
Answer
Try this piece of code:
hDC := GetDC(0);
Bits := GetDeviceCaps(hDC, CAPS_BITSPIXEL);
PLANES := GetDeviceCaps (hDC, CAPS_PLANES);
DrvColours := (Bits * PLANES);
DrvColours := APowerB(2, DrvColours);
ReleaseDC (0, hDC);
EnumWindows()
Question
Can someone pass any information, or source along regarding
EnumWindows. Running D1.
Answer
ENumWindows is described in D1's on-line WinAPI
help, but you'll get much more helpful answers if you are more
specific about what you are trying to achieve.
As an example here is a bit if code that uses EnumWindows to
locate a window containing a specified string in its title:
{function FindWindowHandle (HuntFor: string): HWnd;}
{----------------------------------------------------------------}
{ Hunts for a parent window with title containing the HuntFor }
{ string. Returns the window handle or 0 if none found. }
{----------------------------------------------------------------}
{ The following indented code is logically a part of }
{ FindWindowHandle but is placed here above the real }
{ FindWindowHandle function heading as Borland do not }
{ allow nesting of callback functions. }
{-----------------------------------------------------}
type
PHuntRec = ^THuntRec;
THuntRec = record
HuntingFor: string;
WindowFound: HWnd;
end;
function EnumWindowsFunc (WindowHandle: HWnd;
lParam: Longint): WordBool; export;
{-----------------------------------------------------}
{ Callback function used by FindWindowHandle. }
{-----------------------------------------------------}
var
ATitle: array[0..255] of Char;
begin
GetWindowText(WindowHandle, PChar(@ATitle), 255);
if StrHas(PHuntRec(lParam)^.HuntingFor,
StrPas(PChar(@ATitle))) then
begin
PHuntRec(lParam)^.WindowFound := WindowHandle;
EnumWindowsFunc := false; {stop looking}
end
else
EnumWindowsFunc := true {continue looking}
end; {EnumWindowsFunc}
function FindWindowHandle (HuntFor: string): HWnd;
var
Proc: TFarProc;
HuntRec: PHuntRec;
begin
GetMem(HuntRec, SizeOf(THuntRec));
HuntRec^.HuntingFor := HuntFor;
HuntRec^.WindowFound := 0;
Proc := MakeProcInstance(@EnumWindowsFunc, HInstance);
EnumWindows(Proc, Longint(HuntRec));
FreeProcInstance(Proc);
FindWindowHandle := HuntRec^.WindowFound;
FreeMem(HuntRec, SizeOf(THuntRec));
end; {FindWindowHandle}
Undo in a memo field
Question
How can I do undo in a memo?
Answer
If you have a pop-up menu in a TMemo, and put shortcuts
on it for the Cut,Copy, Paste, then you can handle those
events, and call CuttoClipBoard, CopytoClipBoard, etc.
However, if you put an Undo option onto your pop-up menu
(normally Ctrl-Z) how do you instruct the TMemo to do the Undo?
If the built-in undo is sufficient, you can get it easier than
a Ctrl+Z:
Memo1.Perform(EM_UNDO, 0, 0);
To check whether undo is available so as to enable/disable
an undo menu item:
Undo1.Enabled := Memo1.Perform(EM_CANUNDO, 0, 0) <> 0;
Terminate all running applications
Question
How to terminate all running applications?
Answer
{
A word of caution, before you run this for the first time, make sure
that you save it and anything else that may have some pending data.
}
procedure TForm1.ButtonKillAllClick(Sender: TObject);
var
pTask : PTaskEntry;
Task : Bool;
ThisTask: THANDLE;
begin
GetMem (pTask, SizeOf (TTaskEntry));
pTask^.dwSize := SizeOf (TTaskEntry);
Task := TaskFirst (pTask);
while Task do
begin
if pTask^.hInst = hInstance then
ThisTask := pTask^.hTask
else
TerminateApp (pTask^.hTask, NO_UAE_BOX);
Task := TaskNext (pTask);
end;
TerminateApp (ThisTask, NO_UAE_BOX);
end;
How to keep apps iconized
Question
How to keep applications iconized?
Answer
1. You must set WindowState to wsMinimized in the form's properties.
2. In the private section of the form object's declaration, put:
PROCEDURE WMQueryOpen(VAR Msg : TWMQueryOpen); message WM_QUERYOPEN;
3. In the implementation section, put this method:
PROCEDURE TForm1.WMQueryOpen(VAR Msg : TWMQueryOpen);
begin
Msg.Result := 0;
end;
That's it! The form will always remain iconic.
Trapping WM_ENDSESSION message
Question
How to trap WM_ENDSESSION message?
Answer
The problem seems to be that when you close down Windows, it will first
send a WM_QueryEndSession message to all running top-level windows. This
is handled and processed correctly by the TForm object in VCL.
Then assuming that all applications indicated that it was ok to close down,
Windows will send WM_EndSession messages to all windows. This message is
not handled by VCL. The application is simply brought down with a bang.
No windows are closed, no destructor called and no exit procedures called.
The solution is to handle the WM_EndSession message yourself. There are
several ways of handling messages in Delphi, but the only reliable way
of handling the WM_ENDSESSION is to use the HookWindow method of
Application.
In the message handler, check to see if the message is a WM_ENDSESSION.
If so, we should close down the application. We could have called the
Close method of the main window, but the Windows API documentation states
that the system might go down anytime after return from the WM_ENDSESSION,
and a posted WM_QUIT message might never arrive to the application.
The solution is to simply call Halt instead. This will call all registred
exit procedures, including the ones in Controls and DB units. These will
free the application and screen objects and take the BDE down correctly.
A simple example follows:
unit Tst2u;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Grids, DBGrids, DB, DBTables;
type
TForm1 = class(TForm)
DataSource1: TDataSource;
Table1: TTable;
DBGrid1: TDBGrid;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
function HookProc(var Message: TMessage): boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
const
FlagFileName = 'C:\Flag.Fil';
procedure CreateFlagFile;
var
F: System.Text;
begin
System.Assign(F, FlagFileName);
System.Rewrite(F);
Writeln(F, 'This is a dummy flag file');
System.Close(F);
end;
procedure KillFlagFile;
var
F: File;
begin
System.Assign(F, FlagFileName);
System.Erase(F);
end;
procedure MyExitProc; far;
begin
KillFlagFile;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.HookMainWindow(HookProc);
end;
function TForm1.HookProc(var Message: TMessage): boolean;
begin
Result := false;
if Message.Msg = WM_EndSession then
begin
if WordBool(Message.wParam) then
begin
{ Windows is closing down - clean up!! }
{ This should execute all ExitProcs, close windows and call destructors... }
Halt; { This works! }
{ This should close things down properly,
but do we have enough time to handle any posted messages before Windows
is already down?? This will result in a PostQuitMessage that might
never arrive!}
{ Close;} { This doesn't always work - avoid it }
end;
end;
end;
initialization
CreateFlagFile;
AddExitProc(MyExitProc);
end.
This unit demonstrates that the exit procedures are called when closing
the app normally and when closing down Windows and using HookMainWindow.
Without the HookMainWindow call, the exit proc will not be called. This
is specially important for DB applications. Without the Halt, LCK files
will not be deleted, buffers might not be flushed, changes posted and
so on.
Restarting Windows
Question
How to restart Windows?
Answer
There are two documented functions in the Windows API for restarting
Windows: ExitWindows(), and ExitWindowsExec(). (See the Windows API help
for details on both.) A common misconception is that the Program Manager DDE
macro call "[Reload()]" is for restarting Windows; it is not!
The call ExitWindows( 0, EW_RESTARTWINDOWS ) is _supposed_ to shut down
Windows, then bring it back up. I've had no luck, though, from inside a
Delphi app. It just shuts down Windows and gives me a DOS prompt.
ExitWindowsExec was built so that you could shut down Windows, execute a DOS
app (to replace Windows-critical DLL's, for example), and then bring Windows
hack up. I have discovered that you simply need to pass a bad executable
name, and ExitWindowsExec performs exactly as ExitWindows was supposed to!
For example, the last few lines of an installation application may be:
if (MessageDlg( 'The installation was successful! You must now ' +
'restart Windows. Do this now?', mtInformation,
[mbYes, mbNo], 0) = mrYes) then begin
ExitWindowsExec( BOGUS_EXE, Nil );
end;
where BOGUS_EXE is declared something like
const
BOGUS_EXE = 'zyxwvuts.exe';
Automate memo or window scrolling
Question
How to automate memo or window scrolling?
Answer
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key = VK_F8 then
SendMessage(Memo1.Handle, { HWND of the Memo Control }
WM_VSCROLL, { Windows Message }
SB_PAGEDOWN, { Scroll Command }
0) { Not Used }
else if Key = VK_F7 then
SendMessage(Memo1.Handle, { HWND of the Memo Control }
WM_VSCROLL, { Windows Message }
SB_PAGEUP, { Scroll Command }
0); { Not Used }
end;
Virtual key values
Question
Answer
vk_LButton = $01;
vk_RButton = $02;
vk_Cancel = $03;
vk_MButton = $04; { NOT contiguous with L & RBUTTON }
vk_Back = $08;
vk_Tab = $09;
vk_Clear = $0C;
vk_Return = $0D;
vk_Shift = $10;
vk_Control = $11;
vk_Menu = $12;
vk_Pause = $13;
vk_Capital = $14;
vk_Escape = $1B;
vk_Space = $20;
vk_Prior = $21;
vk_Next = $22;
vk_End = $23;
vk_Home = $24;
vk_Left = $25;
vk_Up = $26;
vk_Right = $27;
vk_Down = $28;
vk_Select = $29;
vk_Print = $2A;
vk_Execute = $2B;
vk_SnapShot = $2C;
vk_Copy = $2C not used by keyboards }
vk_Insert = $2D;
vk_Delete = $2E;
vk_Help = $2F;
vk_A thru vk_Z are the same as their ASCII equivalents: 'A' thru 'Z' }
vk_0 thru vk_9 are the same as their ASCII equivalents: '0' thru '9' }
vk_NumPad0 = $60;
vk_NumPad1 = $61;
vk_NumPad2 = $62;
vk_NumPad3 = $63;
vk_NumPad4 = $64;
vk_NumPad5 = $65;
vk_NumPad6 = $66;
vk_NumPad7 = $67;
vk_NumPad8 = $68;
vk_NumPad9 = $69;
vk_Multiply = $6A;
vk_Add = $6B;
vk_Separator = $6C;
vk_Subtract = $6D;
vk_Decimal = $6E;
vk_Divide = $6F;
vk_F1 = $70;
vk_F2 = $71;
vk_F3 = $72;
vk_F4 = $73;
vk_F5 = $74;
vk_F6 = $75;
vk_F7 = $76;
vk_F8 = $77;
vk_F9 = $78;
vk_F10 = $79;
vk_F11 = $7A;
vk_F12 = $7B;
vk_F13 = $7C;
vk_F14 = $7D;
vk_F15 = $7E;
vk_F16 = $7F;
vk_F17 = $80;
vk_F18 = $81;
vk_F19 = $82;
vk_F20 = $83;
vk_F21 = $84;
vk_F22 = $85;
vk_F23 = $86;
vk_F24 = $87;
vk_NumLock = $90;
vk_Scroll = $91;
Getting DOS and Windows version numbers
Question
How can I get the Windows or DOS version numbers?
Answer
The API call GetVersion will do it, but the information is
encrypted into a longint. Here is how to get and decrypt the information:
Type
TGetVer = record
WinVer,
WinRev,
DosRev,
DosVer: Byte;
end;
const
VerStr = '%d.%d';
procedure TForm1.Button1Click(Sender: TObject);
var
AllVersions: TGetVer;
begin
AllVersions := TGetVer(GetVersion);
Edit1.Text := Format(VerStr, [AllVersions.WinVer, AllVersions.WinRev]);
Edit2.Text := Format(VerStr, [AllVersions.DOSVer, AllVersions.DOSRev]);
end;
Note1: The values that windows displays for the versions and the values
that it returns through its API call are not always the same. e.g. The
workgroup version displays as 3.10 rather than 3.11.
Note2: Win32 applications should call GetVersionEx rather than GetVersion.
DISCLAIMER: You have the right to use this technical information
subject to the terms of the No-Nonsense License Statement that
you received with the Borland product to which this information
pertains.
Flashing an applications's title bar and/or icon
Question
How can I make the title of my app flash? I want to be able to notify the user
that a process is completed while the app is minimized or maximized.
Answer
It's easy... use the FlashWindow API function. FlashWindow accepts two
parameters. The first is the handle of the window to flash (i.e., change its
status from active to inactive, or vice versa). The second is a boolean
indicating whether to flash the window (True) or return it to its original
state (False).
The best way to use FlashWindow is in conjunction with a timer. The following
syntax in your timer's OnTimer event handler will flash the current window:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
FlashWindow(Handle, True) ;
end;
However, if your application is minimized and you want the icon to flash, you
need to make a slightly different call to FlashWindow. Instead, you would pass
the handle of your application (the global Application variable), which manages
the icon.
procedure TForm1.Timer1Timer(Sender: TObject);
begin
FlashWindow(Application.Handle, True) ;
end;
Of course, you can make both calls together without any ill effects.
Determining number of lines a memo can show
Question
How can I tell how many lines a memo is capable of showing?
Answer
Here is the short and elegant way that works (most of the
time):
function TForm1.MemoLinesShowing(memo: TMemo): integer;
var
R: TRect;
begin
Memo.Perform(EM_GETRECT, 0, Longint(@R));
Result := (R.Bottom - R.Top) div Canvas.TextHeight('XXX');
end;
The problem with this code is that the TForm and the TMemo must
both be using the same font. If the fonts are different, then
the calculations are not accurate.
You have to retrieve the font height by selecting it into a
device context. The reason you cannot use the font Height
provided by Delphi is because Delphi caches the font infomation
but doesn't acutally select the font into the DC (canvas) until
it is actually going to draw something. This occurs in the
painting event of the memo.
To get around this problem, you can get the memo's device
context using the Windows API and get the font information
from the device context to calculate the text height.
The function below illustrates this process:
function TForm1.MemoLinesShowingLong(Memo: TMemo): integer;
Var
Oldfont: HFont; {the old font}
DC: THandle; {Device context handle}
i: integer; {loop variable}
Tm: TTextMetric; {text metric structure}
TheRect: TRect;
begin
DC := GetDC(Memo.Handle); {Get the memo's device context}
try
{Select the memo's font}
OldFont := SelectObject(DC, Memo.Font.Handle);
try
GetTextMetrics(DC, Tm); {Get the text metric info}
Memo.Perform(EM_GETRECT, 0, longint(@TheRect));
Result := (TheRect.Bottom - TheRect.Top) div
(Tm.tmHeight + Tm.tmExternalLeading);
finally
SelectObject(DC, Oldfont); {Select the old font}
end;
finally
ReleaseDC(Memo.Handle, DC); {Release the device context}
end;
end;
Exiting Windows from within a Delphi app
Question
How to exiting Windows from within a Delphi app?
Answer
There are occasionally situations where you may need to force the user to exit
or restart Windows from within your Delphi app. It can be done fairly easily.
The syntax varies dependent upon whether you are using Windows 3.x or
Windows 95/NT. If you are using Windows 3.x, you will want to use the
ExitWindows API function. ExitWindows accepts two parameters. The second
parameter must always be zero. The first parameter can be zero, which will
exit Windows, or either of the following two self-explanatory constants:
ew_RebootSystem or ew_RestartWindows. (Note that this is the opposite of what
the Windows API help file tells you, namely, that the first parameter should
always be zero. Do not be fooled!)
If you are using Windows 95/NT, you should use the similar but different
ExitWindowsEx API function. Like ExitWindows, ExitWindowsEx also accepts two
parameters, the second of which must always be zero. To reboot the system and
restart, pass ewx_Reboot as the first parameter. You may also pass ewx_PowerOff
to shut down the system. You may also combine one of those two parameters with
ewx_Force, which forces all processes to terminate without user interaction
(i.e., even if they do not respond, shut them down without giving the user the
customary #no response# dialog). NOTE: The ExitWindows function does exist in
Windows 95/NT, but it can only be used to log off the current user.
ExitWindowsEx is far more flexible.
Additional Windows 95/NT Information: If you want your app to be able to shut
down or restart Windows, it must have the SE_SHUTDOWN_NAME privilege enabled.
(I found this to be the case by default, but as they say, your mileage may vary.)
This can be accomplished by using the AdjustTokenPrivileges API function, which
is fully documented in the Win32 Programmer's Reference which accompanies
Delphi 2.0.
Simulate sending key to own application
Question
I've a situation where I need to simulate as though the user
has pressed a RETURN key on my application.
Answer
You can send a message to the window that must handle the key, like:
PostMessage(FWinControl.Handle, WM_KEYDOWN, VK_BACK, 0);
for the backspace case.
ExitWindows
Question
Does anyone know how to access the function ExitWindows in
User.exe. I would like to use this function to restart windows
without restarting the computer.
Answer
Here are examples of how to restart Windows and also how to
reboot the system:
procedure TMainForm.RestartWindowsBtnClick(Sender: TObject);
begin
if not ExitWindows(EW_RestartWindows, 0) then
ShowMessage('An application refused to terminate');
end;
procedure TMainForm.RebootSystemBtnClick(Sender: TObject);
begin
if not ExitWindows(EW_RebootSystem, 0) then
ShowMessage('An application refused to terminate');
end;
The ExitWindows function has always been wrongly documented -
Microsoft got it wrong in their documents and every one else
followed along with the incorrect info. I believe the correct
definition is:
function ExitWindows (dwReturnCode: Longint;
Reserved: Word): Bool;
System Menu
Question
How do you add something to the system menu, say something
like an about command or something of the the type.
Answer
A:
Here's a procedure that will do it:
procedure AppendToSystemMenu (Form: TForm;
Item: string; ItemID: Word);
{----------------------------------------------------------------}
{ Appends menu item to end of system menu of specified form and }
{ to system menu of application's minimized icon. To append a }
{ separator bar start the item with '-' (and use 0 for ItemID). }
{----------------------------------------------------------------}
var
NormalSysMenu, MinimizedMenu: HMenu;
AItem: array[0..255] of Char;
PItem: PChar;
begin
NormalSysMenu := GetSystemMenu(Form.Handle, false);
MinimizedMenu := GetSystemMenu(Application.Handle, false);
if StartsWith('-', Item) then
AppendMenu(NormalSysMenu, MF_SEPARATOR, 0, nil);
AppendMenu(MinimizedMenu, MF_SEPARATOR, 0, nil);
end
else
begin
PItem := StrPCopy(PChar(@AItem), Item);
AppendMenu(NormalSysMenu, MF_STRING, ItemID, PItem);
AppendMenu(MinimizedMenu, MF_STRING, ItemID, PItem);
end
end; {AppendToSystemMenu}
The StartsWith function that is used above is defined:
function StartsWith (const StartString, theString: string)
: Boolean;
{----------------------------------------------------------------}
{ Tests whether or not theString starts with the StartString. }
{ N.B. Case sensitive. }
{----------------------------------------------------------------}
begin
if Copy(theString, 1, length(StartString)) = StartString then
StartsWith := True
else
StartsWith := False
end; {StartsWith}
A:
Create a new form and add the following:
type
TForm1 = class(TForm)
private
{ Private declarations }
public
procedure WinMsgHandler( var Msg : TMsg; var Handled : Boolean );
{ Public declarations }
end;
const
WM_ABOUT = WM_USER + 1; { About message }
IMPLEMENTATION
procedure TForm1.WinMsgHandler( var Msg : TMsg; var Handled : Boolean );
begin
If Msg.Message = WM_SYSCOMMAND then
begin
if Msg.wParam = WM_ABOUT then Showmessage('Hello World!!');
end;
end;
In the forms create method you should add the following:-
Application.OnMessage := WinMsgHandler; {Use my message handler}
AppendMenu( GetSystemMenu( Self.Handle, False ),
MF_SEPARATOR, 0, ''); {Append our new value}
AppendMenu( GetSystemMenu( Self.Handle, False ), MF_BYPOSITION,
WM_ABOUT, '&Hello' );
A:
unit Sysmenuu;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure AppOnMessage(VAR Msg: TMsg; VAR Handled: Boolean);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
CONST SC_UDF = $EFF0;
procedure TForm1.FormCreate(Sender: TObject);
begin
AppendMenu(GetSystemMenu(Handle, False), { API call; see API Help }
MF_STRING, SC_UDF, '&About');
AppendMenu(GetSystemMenu(Application.Handle, False),
MF_STRING, SC_UDF, '&About');
Application.OnMessage := AppOnMessage;
end;
procedure TForm1.AppOnMessage(VAR Msg: TMsg; VAR Handled: BOolean);
VAR
Hf, Ha : hMenu;
Checkd : Boolean;
CONST
NuFlag : ARRAY[Boolean] OF Word = (MF_CHECKED, MF_UNCHECKED);
NuHWnd : ARRAY[Boolean] OF HWnd = (HWND_TOPMOST, HWND_NOTOPMOST);
BEGIN
IF Msg.Message <> WM_SYSCOMMAND THEN Exit;
IF Msg.wParam AND $FFF0 <> SC_UDF THEN Exit;
{ show your About Dialog }
END;
end.
GetModuleFileName
Question
If I'm using GetModuleFileName, I can't get it working. I'm assuming that
the problem is the hInstance in the first parameter. So let's say I wanted
to get the Module filename of the SysListView32....on my computer, it
has the handle of 168 all the time, so I'm assuming it doesn't change, so this
is my code basically:
stuff := GetWindowLong(168, GWL_hINSTANCE);
GetModuleFileName(stuff, buf, 100);
where buf is pchar...
Now what's the problem here? I get the hInstance don't I? Why isn't this
working?
Answer
procedure TForm1.Button1Click(Sender: TObject);
var
szFileName : array[0..49] of char;
szModuleName : array[0..19] of char;
iSize : integer;
begin
StrPCopy(szModuleName, 'NameOfModule');
iSize := GetModuleFileName(GetModuleHandle(szModuleName),szFileName,
SizeOf(szFileName));
if iSize > 0 then
ShowMessage('Full path name is : ' + StrPas(szFileName))
else
ShowMessage('Path of module not found');
end;
CM_MOUSELEAVE
Question
I was wondering if there is a Windows message that is sent to a component
when a mouse is moved over it and when the mouse is moved out from it's
space. For example, when the mouse moves over a TPanel and also when the
mouse leaves the TPanel.
Answer
You can also take advantage of two Delphi predefined messages,
CM_MOUSEENTER and CM_MOUSELEAVE. Below is a brief piece of code showing
one way to do it. I have tried it and it worked fine with TSpeedButtons. It
should normally work with TPanels as well. Try it yourself!
unit SomeForm;
interface
type
TSomeForm = class(TForm)
private
procedure CMMouseEnter(var Msg: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
end;
implementation
procedure TSomeForm.CMMouseEnter(var Msg: TMessage);
var
anObject : TObject;
begin
{ anObject is the control over which the mouse is right now }
anObject := TObject(Msg.lParam);
if anObject <> nil then begin
{ First, you must find WHICH is the control under the mouse cursor, }
{ then, determine what action to do, etc... }
end;
end;
procedure TSomeForm.CMMouseLeave(var Msg: TMessage);
begin
{ anObject is the control which the mouse has just gone out of }
anObject := TObject(Msg.lParam);
if anObject <> nil then begin
{ First, you must find WHICH is the control }
{ the mouse cursor has just left, }
{ then, determine what action to do, etc... }
end;
end;
end.
|