HomePage Delphi Library Shopping
Windows
windows23 From: [email protected] (Sundial Services)
In article <[email protected]> Jean-Luc Nicoulin <[email protected]> writes: I get the message 'Data segment too large'. What is the matter and what can I do to solve the problem ?
In a Windows 3.1 application, three major data-areas share one(!) 64K memory segment: t he stack, the Windows 'local heap', and the data-segment containing all globals and initialized constants. This area can become used up extremely quickly.
Consequently, W3.1 applications store almost -nothing- in the stack or in a global. Rather, they store -pointers- to them. This is why, in Delphi, 'an object is a pointer.'
What you have to do is to comb your application looking for large globals and to move those into a common data block which your program allocates on startup (as an object) and destroys when done. You can see a lot about what's in the data segment by setting the 'linker map' to 'detailed' and looking for the 'DATA' segment. Whatever's in that segment is going to be trying to occupy space in the lower part of that 64K-memory segment.
Paul S. Knapp wrote: > > Does anyone know how to make as Delphi app read the Run Minimized > checkbox in the Windows 3.1 or 3.11 StartUp Group. > > I cannot get my application to run minimized when this checkbox is > checked. I would like to be able to give my users the option of > starting the application in their startup group, in either maximized or > minimized mode. Every Windows application I have ever used is able to > start in the mode selected by the checkbox in the Startup Group. I > assume Delphi applications should be able to as well, but so far I a > haven't found a way. > > Thanks in advance for your advice > Paul Knapp
Hi Paul!
Use WinProcs unit and after created main form add call ShowWindow.
You can use HInstance, HPrevInst, CmdShow and CmdLine global variables.
program Project1;
uses
WinProcs, {*** use WinProcs}
Forms,
Unit1 in 'UNIT1.PAS' {Form1};
{$R *.RES}
begin
Application.CreateForm(TForm1, Form1);
ShowWindow(Form1.handle, CmdShow);
Application.Run;
end.
From: Ken Kyler <[email protected]>
Here's and example, it's taken from
Rubenking, Neil (1996). _Delphi Programming Problem Solver_. Foster City, CA: IDG Books. ISBN:1-56884-795-5.
unit Unit1;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
ShowHow : word ;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
var
SUI : TStartupInfo ;
begin
if CmdShow = SW_SHOWDEFAULT then
begin
GetStartupInfo( SUI ) ;
ShowHow := SUI.wShowWindow ;
end
else
ShowHow := CmdShow ;
if ShowHow = SW_SHOWMAXIMIZED then
WindowState := wsMaximized ;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
case ShowHow of
SW_SHOWMINIMIZED,
SW_MINIMIZE,
SW_SHOWMINNOACTIVE :
Application.Minimize ;
end ;
end;
end.
From: [email protected] (Andreas Viebke)
This works with NT 4 and Delphi 2.01. It took me one and a half hours to find out: Make your project code look like this:
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Form1.Show;
Application.Minimize;
Application.Run;
end.
It seems to be important that neither OnCreate nor OnShow is disturbed by a procedure that changes a window's state.
From: [email protected] (Abel du Plessis)
I need to start my form minimized, unfortunetly it doesn't work. When I set the WindowState property of the main form to wsMinimized and run it, the form minimizes onto Win95 desktop instead of the taskbar how it properly should. Does anyone know how to fix this bug?
There was an article in The Delphi Magazine, Issue 19, March 1997 - the Delphi Clinic section which explained the problem.
Here is my adaptation of the fix:
unit Foobar;
interface
type
TfrmFoobar = class(TForm);
procedure DoRestore(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
procedure TfrmUVChannel.FormCreate(Sender: TObject);
begin
//Assign a temporary event handler for when the app gets restored
Application.OnRestore := DoRestore;
Application.Minimize;
end;
procedure TfrmFoobar.DoRestore(Sender: TObject);
begin
Application.ShowMainForm := True;
//Restore the application
Perform(wm_SysCommand, sc_Restore, 0);
//Ensure all components draw properly
Show;
//Disconnect this event handler so it will not be called again
Application.OnRestore := nil;
end;
initialization
//Hide the minimized main form for now
Application.ShowMainForm := False;
end.
From: [email protected] (John Crane)
Sharing Memory Mapped Files... Check out the following code:
var
HMapping: THandle;
PMapData: Pointer;
const
MAPFILESIZE = 1000;
procedure OpenMap;
var
llInit: Boolean;
lInt: Integer;
begin
HMapping := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, MAPFILESIZE, pchar('MY MAP NAME GOES HERE'));
// Check if already exists
llInit := (GetLastError() <> ERROR_ALREADY_EXISTS);
if (hMapping = 0) then begin
ShowMessage('Can''t Create Memory Map');
Application.Terminate;
exit;
end;
PMapData := MapViewOfFile(HMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if PMapData = nil then begin
CloseHandle(HMapping);
ShowMessage('Can''t View Memory Map');
Application.Terminate;
exit;
end;
if (llInit) then begin
// Init block to #0 if newly created
memset(PMapData, #0, MAPFILESIZE);
end;
end;
procedure CloseMap;
begin
if PMapData <> nil then begin
UnMapViewOfFile(PMapData);
end;
if HMapping <> 0 then begin
CloseHandle(HMapping);
end;
end;
Any two or more applications or DLLs may obtain pointers to the same physical block of memory this way. PMapData will point to a 1000 byte buffer in this example, this buffer being initialized to #0's the first time in. One potential problem is synchronizing access to the memory. You may accomplish this through the use of mutexes. Here's an example of that:
{ Call LockMap before writing (and reading?) to the memory mapped file. Be sure to call UnlockMap immediately when done updating. }
var
HMapMutex: THandle;
const
REQUEST_TIMEOUT = 1000;
function LockMap:Boolean;
begin
Result := true;
HMapMutex := CreateMutex(nil, false, pchar('MY MUTEX NAME GOES HERE'));
if HMixMutex = 0 then begin
ShowMessage('Can''t create map mutex');
Result := false;
end else begin
if WaitForSingleObject(HMapMutex,REQUEST_TIMEOUT) = WAIT_FAILED then begin
// timeout
ShowMessage('Can''t lock memory mapped file');
Result := false;
end;
end;
end;
procedure UnlockMap;
begin
ReleaseMutex(HMixMutex);
CloseHandle(HMixMutex);
end;
Please excuse my unnecessary begin..end's. I come from a Clipper background, and I prefer to see my logic blocks capped off with end's - easier to follow.
From: "Neil Clayton" <[email protected]>
Rainer Perl <[email protected]> wrote in article > I have a question to the Shell_NotifyIcon function: > I can add an icon to the taskbar > I can modify an icon > I can delete an icon. > What I can't do: I can't receive Messages from the Icon!!
To receive messages you must add the NIF_MESSAGE flag to your notify structure and tell it what message to send and to which window. This is the code that I use:
procedure TMainForm.UpdateTaskBar; // update the win95 taskbar icon area
var
NotifyData: TNotifyIconData;
begin
With NotifyData do // set up the data structure
begin
cbSize := SizeOf(TNotifyIconData);
Wnd := MyForm.Handle;
uID := 0;
uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP; // ... the aspects to modify ...
uCallbackMessage := WM_MY_MESSAGE; // ... the message to send back to us ...
hIcon := hMyIcon;
szTip := 'Tool Tip To Display'; // ... and the tool tip
end;
Shell_NotifyIcon(dwMessage, @NotifyData); // now do the update
end;
WM_MYMESSAGE is a user defined message. Usually defined as:
const WM_MYMESSAGE = WM_USER + <some number - can be zero>;
From: [email protected] (Chris Randall)
"J.J. Bakker" <[email protected]> wrote: >Does anyone know the answer, I', trying to make an app that has an icon in the notification area with a popupmenu. However the application is still visible on the taskbar. Using Application.ShowMainForm:=False; is not enough. >
I have run into the same problem but found the answer. This little bit of code works great.
procedure TMainForm.FormCreate(Sender: TObject); begin Application.OnMinimize:=AppMinimize; Application.OnRestore:=AppMinimize; Application.Minimize; AppMinimize(@Self); end; procedure TMainForm.AppMinimize(Sender: TObject); begin ShowWindow(Application.Handle, SW_HIDE); end;
From: "James D. Rofkar" <jim_rofkar%[email protected]>
JAAD wrote:
>
> I want to make a Delphi-Form to REALLY stay on top, But not only within it own application (thats simpel)
No I want it to stay on top even when I am using for instance EXCEL.
>
Try using the Windows API function SetWindowPos(). Something like...
with MyForm do
SetWindowPos(Handle,
HWND_TOPMOST,
Left,
Top,
Width,
Height,
SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
You may need to call this function in your Form's OnShow(), OnDeactivate(), and OnActivate() event handlers.
From: "James D. Rofkar" <jim_rofkar%[email protected]>
Robert Copier wrote: > Is there a way to hide the Windows 95 statusbar when i start my application made in delphi 2.01. When the user close the application the statusbar must become visible again.
I'm guessing you're referring to the Windows 95 taskbar and system tray window, and not a statusbar. The answer: Sure you can! And what a cool idea! Here's how:
TForm1 = class(TForm)
...
private
hTaskBar: HWND;
...
end;
hTaskBar := FindWindow('Shell_TrayWnd', nil);
ShowWindow(hTaskBar, SW_HIDE);
ShowWindow(hTaskBar, SW_SHOW);
"Earl F. Glynn" <[email protected]>
PROCEDURE HideWin95TaskBar;
VAR
WindowHandle: hWnd;
BEGIN
{Hide the Windows 95 Taskbar}
WindowHandle := FindWindow('Shell_TrayWnd', '');
IF WindowHandle <> 0
THEN ShowWindow(WindowHandle, SW_HIDE)
END {HideWin95TaskBar};
PROCEDURE ShowWin95TaskBar;
VAR
WindowHandle: hWnd;
BEGIN
{Allow the Windows 95 Taskbar to appear}
WindowHandle := FindWindow('Shell_TrayWnd', '');
IF WindowHandle <> 0
THEN ShowWindow(WindowHandle, SW_RESTORE)
END {ShowWin95TaskBar};
From: "Chami" <[email protected]>
> I need to have a form in my application that zooms to half of > the screen when the Maximize button is pressed, not to full > screen. >
you could handle the WM_GETMINMAXINFO message from your form.
for example, add the following declaration to the protected section of your form (interface):
procedure _WM_GETMINMAXINFO( var mmInfo : TWMGETMINMAXINFO ); message wm_GetMinMaxInfo;
then define (implementation) the above message handler as follows (TForm1 being the name of your form of course):
procedure TForm1._WM_GETMINMAXINFO( var mmInfo : TWMGETMINMAXINFO );
begin
// set the position and the size of your form when maximized:
with mmInfo.minmaxinfo^ do
begin
ptmaxposition.x := Screen.Width div 4;
ptmaxposition.y := Screen.Height div 4;
ptmaxsize.x := Screen.Width div 2;
ptmaxsize.y := Screen.Height div 2;
end;
end;
From: [email protected]
Check the API help In the WINPROCS unit try the function GetVersion: LongInt;
The GetVersion function retrieves the current version numbers of the Windows and MS-DOS operation systems.
NOTE there is a error in the orginal API documentation, the major/minor Win version are reversed!
As I have used it:
Windows 3.1 show up as 3.1, WIN95 shows up as 3.95
Note For windows 95 and higher use the function GetVersionEx
The following code comes from Loyds Help File (it can be found on most delphi web pages). I haven't tried it but I will use it in one of my apps as soon as I get the bitmap from the client. let me know if it works for you.
unit Unit1;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Bitmap: TBitmap;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
Bitmap := TBitmap.Create;
Bitmap.LoadFromFile('C:\WINDOWS\cars.BMP');
end;
procedure TForm1.FormPaint(Sender: TObject);
var
X, Y, W, H: LongInt;
begin
with Bitmap do begin
W := Width;
H := Height;
end;
Y := 0;
while Y < Height do begin
X := 0;
while X < Width do begin
Canvas.Draw(X, Y, Bitmap);
Inc(X, W);
end;
Inc(Y, H);
end;
end;
end.
From: "Dirk Faber " <[email protected]>
Rob Wilson <[email protected]> wrote > Does anyone know how I can change the wallpaper at runtime using a > filename that I specifiy?
procedure ChangeWallpaper(bitmap: string); {bitmap contains filename: *.bmp}
var pBitmap : pchar;
begin
bitmap:=bitmap+#0;
pBitmap:=@bitmap[1];
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pBitmap, SPIF_UPDATEINIFILE);
end;
> Also, is there a way of saving it to the INI file for next session?
[LastUsedBitmap] LUBitmap= c:\mybitmap.bmp
procedure WriteToIniFile(bitmap : string);
var MyIniFile : TInifile;
begin
MyIniFile := Tinifile.Create( 'c:\Bitmap.ini' );
MyIniFile.WriteString( 'LastUsedBitmap', 'LUBitmap', bitmap);
MyIniFile.Free;
end;
procedure ReadFromIniFile(var bitmap: string);
var MyIniFile : TInifile;
begin
MyIniFile := Tinifile.Create( 'c:\Bitmap.ini' );
bitmap:= MyIniFile.ReadString('LastUsedBitmap', 'LUBitmap');
MyIniFile.Free;
end;Christian Piene Gundersen <[email protected]>
This is a rather complicated matter, so if it isn't vital to your application, I suggest that you spend your time better than digging into it. However, I'll try to point you in the right direction.
The windows 32 operating system is based on a shell which uses virtual folders, like 'my computer', 'desktop' and 'recycle bin'. Some of these folders are part of the physical file system. That is they have a corresponding directory in the file system. This is the case with 'desktop' and 'recycle bin'. These directories can be used as InitialDir for the TOpenDialog, but first you have to get their physical location, which can be different on different computers. To get the physical location of these folders, you have to use some special API calls (see example below). Other folders, like 'my computer' and 'printers' are not part of the file system - they are only virtual. I've noticed that you can browse to these folders using the TOpenDialog, but I don't think they can be used as InitialDir.
Virtual folders are (a bit simplified) of the type SHITEMID (item identifier). They are normally accessed using pointers to item identifiers list (PIDL). To get the PIDL of a special folder, you can use the SHGetSpecialFolder function. The physical location of the corresponding directory can then be obtained by passing the PIDL to the GetPathFromIDList function. If the folder is part of the file system, the function will return the path as a string (which can be used as InitialDir). But if you want the OpenDialog to start in a folder that is only virtual (like 'my computer'), you'll have to make it accept a PIDL as InitialDir, which I don't think it will. My guess is that the TOpenDialog uses PIDLs when browsing, but only accepts physical directories as InitialDir.
Here is an example that shows how to get the 'recent documents' path and use it as InitialDir:
procedure TForm1.Button1Click(Sender: TObject); var PIDL: Pointer; Path: LPSTR; const CSIDL_RECENT = $0008; begin Path := StrAlloc(MAX_PATH); SHGetSpecialFolderLocation(Handle, CSIDL_RECENT, @PIDL); if SHGetPathFromIDList(PIDL, Path) then // returns false if folder isn't part of file system begin OpenDialog1.InitialDir := Path; OpenDialog1.Execute; end; StrDispose(Path); end;
I think you'll have to write a wrapper for these API calls. They are found in shell32.dll. The best advice I can give you if you want to dig into this is to study the ShlObj.h file. I don't program in C myself, but I found it very useful.
Some constants you may need:
CSIDL_DESKTOP = $0000; CSIDL_PROGRAMS = $0002; CSIDL_CONTROLS = $0003; CSIDL_PRINTERS = $0004; CSIDL_PERSONAL = $0005; CSIDL_STARTUP = $0007; CSIDL_RECENT = $0008; CSIDL_SENDTO = $0009; CSIDL_BITBUCKET = $000a; CSIDL_STARTMENU = $000b; CSIDL_DESKTOPDIRECTORY = $0010; CSIDL_DRIVES = $0011; // My Computer CSIDL_NETWORK = $0012; CSIDL_NETHOOD = $0013; CSIDL_FONTS = $0014; CSIDL_TEMPLATES = $0015;
"Greg Peterson" <[email protected]>
Try this:
FUNCTION SmallFonts : BOOLEAN;
{returns TRUE if small fonts are set, FALSE if using Large Fonts }
VAR
DC : HDC; { used to check for number of colors available }
BEGIN
DC := GetDC(0);
Result := (GetDeviceCaps(DC, LOGPIXELSX) = 96);
{ LOGPIXELSX will = 120 if large fonts are in use }
ReleaseDC(0, DC);
END;
Gene Eighmy <[email protected]>
> > When my programs run on systems with small fonts, I > often get strange output. Labels too small to hold all > the text, leaving the right, or the bottom, unshown, for > instance. StringGrid's which don't align as expected. >
Try this. This will rescale both the form size and also reform small vs. large fonts. Call it in Form.FormCreate. Hope this helps.
unit geScale;
interface
uses Forms, Controls;
procedure geAutoScale(MForm: TForm);
implementation
Type
TFooClass = class(TControl); { needed to get at protected }
{ font property }
procedure geAutoScale(MForm: TForm);
const
cScreenWidth :integer = 800;
cScreenHeight:integer = 600;
cPixelsPerInch:integer= 96;
cFontHeight:integer = -11; {Design-time value of From.Font.Height}
var
i: integer;
begin
{
IMPORTANT!! : Set Scaled Property of TForm to FALSE with Object Inspector.
The following routine will scale the form such that it looks the same
regardless of the screen size or pixels per inch. The following section
determines if the screen width differs from the design-time screen size.
If it differs, Scaled is set true and component positions are rescaled such
that they appear in the same screen location as the design-time location.
}
if (Screen.width &;lt> cScreenWidth)or(Screen.PixelsPerInch <> cPixelsPerInch) then
begin
MForm.scaled := TRUE;
MForm.height := MForm.height * screen.Height DIV cScreenHeight;
MForm.width := MForm.width * screen.width DIV cScreenWidth;
MForm.ScaleBy(screen.width, cScreenWidth);
end;
{
This section determines if the run-time font size differs from the design-
time font size. If the run-time pixelsperinch differs form the design-time
pixelsperinch, the fonts must be rescaled in order for the form to appear
as designed. Scaling is calculated as the ratio of the design-time font.height
to run-time font.height. Font.size will not work as it may equal the design-
time value yet appear physically larger crowding and overrunning other
components. For instance, a form designed in 800x600 small fonts
has a font.size of 8. When you run the form on in 800x600 large fonts,
font.size is also 8 but the text is noticably larger than when run in small
font mode. This scaling will make them both appear to be the same size.
}
if (Screen.PixelsPerInch <> cPixelsPerInch) then
begin
for i := MForm.ControlCount - 1 downto 0 do
TFooClass(MForm.Controls[i]).Font.Height :=
(MForm.Font.Height div cFontHeight) *
TFooClass(MForm.Controls[i]).Font.Height;
end;
end;
end.
A: Here is WindowRestorer - a window size and state restorer
DESCRIPTION: Ever notice how professional programs seem to remember in what condition and location you left them and their child windows? Ever notice how most RAD apps don't? You can take that ragged edge off your program with this unit. It Allows apps to save the location, size, and state of windows so that when the user reopens them, they will look as the user left them.
USE: Put WINRSTOR in the uses of clause of your main form and any forms that will be saving or restoring their own state, size, or location. (If you will be doing all the saving and restoring using WinSaveChildren and WinRestoreChildren from the main form, you only need reference it in the main form's uses clause.)
In MainForm.Create, initialize the global WinRestorer object as follows (it's already declared in this file, but needs to be allocated):
GlobalWinRestorer := TWinRestorer.create( Application, TRUE, WHATSAVE_ALL);
Which is the same as:
GlobalWinRestorer := TWinRestorer.create( Application, TRUE, [location, size, state]);
Then, in MainForm.Destroy, deallocate the global WinRestorer object as follows:
GlobalWinRestorer.free;
A good place to save a form's status is in the queryclose event or else attached to a button or menu item. I usually create an item in the File Menu captioned 'Save &Workspace' which does:
GlobalWinRestorer.SaveChildren(Self, [default]);
And under main form's Close event I put:
GlobalWinRestorer.SaveWin(Self, [WHATSAVE_ALL]);
I have tended to restore the children's status in their own show events like this:
GlobalWinRestorer.RestoreWin(Self, [default]);
though I am moving toward putting in the main form's show event:
GlobalWinRestorer.RestoreWin(Self, [default]); GlobalWinRestorer.RestoreChildren(Self, [default]);
HINTS: If you set TForm.Position to poScreenCenter or anything fancy, this unit won't do what you expect. poDesigned seems to work fairly well. I could have raised an exception if you try to set top and left of a poScreenCentere'd form, but then you have to be careful using WinRestoreChildren. I opted not to check the position property and leave that up to individual developers.
unit WinRstor;
INTERFACE
USES SysUtils, Forms;
TYPE {=============================================================}
{------------------------------------------------------------------
Windows restorer object class and related types.
-------------------------------------------------------------------}
EWinRestorer = class( Exception);
TWhatSave = (default, size, location, state);
STWhatSave = set of TWhatSave;
TWinRestorer = class(TObject)
protected
mIniFile: string;
mIniSect: string[80];
mIsInitialized: boolean;
mDefaultWhat: STWhatSave;
public
constructor Create( TheApp: TApplication;
LocalDir: boolean; DefaultWhatSave: STWhatSave);
{If localDir is true, ini dir is the app dir. Else, ini dir is the windows dir.}
procedure SaveWin(TheForm: TForm; What: STWhatSave);
procedure SaveChildren(TheMDIForm: TForm; What: STWhatSave);
procedure RestoreWin( TheForm: TForm; What: STWhatSave);
procedure RestoreChildren(TheMDIForm: TForm; What: STWhatSave);
property IniFileName: string read mIniFile;
end;
CONST
WHATSAVE_ALL = [size, location, state];
VAR
GlobalWinRestorer: TWinRestorer;
IMPLEMENTATION
Uses IniFiles;
constructor TWinRestorer.create;
var fname, path: string[100];
begin
inherited create;
{Calculate ini file name}
if default in DefaultWhatSave then
raise EWinRestorer.create(
'Attempt to initialize default window position paramaters with set ' +
' containing [default] item. ' +
'Default params may contain only members of [size, location, state]. ')
else mDefaultWhat := DefaultWhatSave;
fname := ChangeFileExt( ExtractFileName( TheApp.exeName), '.INI');
if LocalDir then begin {parse out path and add to file name}
path := ExtractFilePath(TheApp.exeName);
if path[length(path)] <> '\' then
path := path + '\';
fname := path + fname;
end;
{fill object fields}
mIniFile := fname;
mIniSect := 'WindowsRestorer';
{It'd be nice to write some notes to a section called [WinRestorer Notes]}
end;
procedure TWinRestorer.RestoreWin;
var FormNm, SectionNm: string[80]; ini: TIniFile;
n,l,t,w,h: integer; {Left, Top Width, Height}
begin
ini := TIniFile.create( mIniFile);
TRY
SectionNm := mIniSect;
FormNm := TheForm.classname;
if default in What then What := mDefaultWhat;
{Update Window State if Necessary}
if state in What then
n := ini.ReadInteger( SectionNm, FormNm + '_WindowState', 0);
case n of
1: TheForm.WindowState := wsMinimized;
2: TheForm.WindowState := wsNormal;
3: TheForm.WindowState := wsMaximized;
end;
{Update Size and Location if necessary.}
with TheForm do begin l:=left; t:=top; h:=height; w:=width; end; {Save current vals.}
if size in What then begin
w := ini.ReadInteger( SectionNm, FormNm + '_Width', w);
h := ini.ReadInteger( SectionNm, FormNm + '_Height', h);
end;
if location in What then begin
t := ini.ReadInteger( SectionNm, FormNm + '_Top', t);
l := ini.ReadInteger( SectionNm, FormNm + '_Left', l);
end;
TheForm.SetBounds(l,t,w,h);
FINALLY
ini.free;
END;
end;
procedure TWinRestorer.RestoreChildren;
var i: integer;
begin
if TheMDIForm.formstyle <> fsMDIForm then
raise EWinRestorer.create('Attempting to save window sizes of children for a non MDI parent window.')
else
for i := 0 to TheMDIForm.MDIChildCount - 1 do
RestoreWin( TheMDIForm.MDIChildren[i], what);
end;
procedure TWinRestorer.SaveWin;
var FormNm, SectionNm: string[80]; w : STWhatsave; ini: TIniFile;
begin
ini := TIniFile.create( mIniFile);
TRY
SectionNm := mIniSect;
FormNm := TheForm.ClassName;
if default in What then w := mDefaultWhat else w := mDefaultWhat;
if size in w then begin
ini.WriteInteger( SectionNm, FormNm + '_Width', TheForm.Width);
ini.WriteInteger( SectionNm, FormNm + '_Height', TheForm.Height);
end;
if location in w then begin
ini.WriteInteger( SectionNm, FormNm + '_Top', TheForm.Top);
ini.WriteInteger( SectionNm, FormNm + '_Left', TheForm.Left);
end;
if state in w then
case TheForm.WindowState of
wsMinimized: ini.WriteInteger( SectionNm, FormNm + '_WindowState', 1);
wsNormal: ini.WriteInteger( SectionNm, FormNm + '_WindowState', 2);
wsMaximized: ini.WriteInteger( SectionNm, FormNm + '_WindowState', 3);
end;
FINALLY
ini.free;
END;
end;
procedure TWinRestorer.SaveChildren;
var i: integer;
begin
if TheMDIForm.formstyle <> fsMDIForm then
raise EWinRestorer.create('Attempting to restore window sizes of children for a non MDI parent window.')
else
for i := 0 to TheMDIForm.MDIChildCount - 1 do
SaveWin( TheMDIForm.MDIChildren[i], what);
end;
INITIALIZATION
END.
{ This code came from Lloyd's help file! }
From: Allan Carlton <[email protected]>
In each language version of Windows the 'StartUp' folder has als a different name. Is there any way to determine the correct name of this folder ??
There is an entry in the registry under:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Start Menu
Which might give you the info you need
From: "HIKI Takehito" <[email protected]>
Is there a function or API call to find the boot drive?
I found it in the Registry.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup
"BootDir" value may be BootDrive.
From: "Eric Lawrence" <[email protected]>
SetSystemModalWindow(Form1.handle);
From: "David Zajac" <[email protected]> Hope this helps:
unit Unit1;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
private
AppInst: THandle;
AppWind: THandle;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
uses ShellAPI;
procedure SendShift(H: HWnd; Down: Boolean);
var vKey, ScanCode, wParam: Word;
lParam: longint;
begin
vKey:= $10;
ScanCode:= MapVirtualKey(vKey, 0);
wParam:= vKey or ScanCode shl 8;
lParam:= longint(ScanCode) shl 16 or 1;
if not(Down) then lParam:= lParam or $C0000000;
SendMessage(H, WM_KEYDOWN, vKey, lParam);
end;
procedure SendCtrl(H: HWnd; Down: Boolean);
var vKey, ScanCode, wParam: Word;
lParam: longint;
begin
vKey:= $11;
ScanCode:= MapVirtualKey(vKey, 0);
wParam:= vKey or ScanCode shl 8;
lParam:= longint(ScanCode) shl 16 or 1;
if not(Down) then lParam:= lParam or $C0000000;
SendMessage(H, WM_KEYDOWN, vKey, lParam);
end;
procedure SendKey(H: Hwnd; Key: char);
var vKey, ScanCode, wParam: Word;
lParam, ConvKey: longint;
Shift, Ctrl: boolean;
begin
ConvKey:= OemKeyScan(ord(Key));
Shift:= (ConvKey and $00020000) <> 0;
Ctrl:= (ConvKey and $00040000) <> 0;
ScanCode:= ConvKey and $000000FF or $FF00;
vKey:= ord(Key);
wParam:= vKey;
lParam:= longint(ScanCode) shl 16 or 1;
if Shift then SendShift(H, true);
if Ctrl then SendCtrl(H, true);
SendMessage(H, WM_KEYDOWN, vKey, lParam);
SendMessage(H, WM_CHAR, vKey, lParam);
lParam:= lParam or $C0000000;
SendMessage(H, WM_KEYUP, vKey, lParam);
if Shift then SendShift(H, false);
if Ctrl then SendCtrl(H, false);
end;
function EnumFunc(Handle: HWnd; TF: TForm1): Bool; Far;
begin
TF.AppWind:= 0;
if GetWindowWord(Handle, GWW_HINSTANCE) = TF.AppInst then
TF.AppWind:= Handle;
result:= (TF.AppWind = 0);
end;
procedure TForm1.Button1Click(Sender: TObject);
var Text: Array[0..255] of char;
begin
AppInst:= ShellExecute(Handle, 'open', 'notepad.exe', nil, '', SW_NORMAL);
EnumWindows(@EnumFunc, longint(self));
AppWind:= GetWindow(AppWind, GW_CHILD);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
SendKey(AppWind, 'T');
SendKey(AppWind, 'e');
SendKey(AppWind, 's');
SendKey(AppWind, 't');
end;
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if AppWind <> 0 then SendKey(AppWind, Key);
end;
end.
Can anybody out there send me some basic stuff about Windows Messages related to Delphi. All this WM_*** stuff is getting on my nerves, since I can't understand it.
[Jim Stanley, [email protected]]
All the Windows messages are listed in the Windows API help in your Delphi help topics. (I'm using D1, assume the same for future versions).
The WM_ (and other) messages are essential to the way Windows works. You're well aware that Delphi is primarily an *event-driven* system; all those OnKeyPress, OnThis, OnThat methods. If you have the VCL source code, you'll find in there somewhere that those event handler methods are designed to *receive* particular Windows messages (and there are some threads in here showing how you can subclass a component and "teach" it to respond to other messages as well). Windows is constantly sending out those messages in response to actions performed by the user, and it's the business of the Delphi app (and of all Windows apps) to intercept them and handle them in ways you decide. Delphi puts a wrapper over most of the message system by creating the event handlers for components described above.
In addition to recieving those messages, you can also *send* them as well. There are a couple of ways to work this: check out SendMessage and PostMessage (both native Win API functions), as well as the Delphi Perform method. The first two require you to use the Handle parameter of the component you're sending the message to, while Perform is a method belonging to that component. The messages go into the standard Windows message queue and are processed like every other message.
Here's a trivial example: I want (for some bizarre reason) to insert a 'y' character whenever I type a '4' in a TMemo. [Think of automatically inserting a begin-end block or a closing parenthesis.) Now I could do a lot with the Memo's Lines property, but that gets pretty complex. A much simpler way of going about it is:
procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = '4' then
SendMessage(Memo1.Handle, WM_CHAR, Word('y'), 0);
end;
Another example is something we were doing here at Jacobs that used a lot of combo boxes. We wanted them to automatically drop down when the user pressed a key, which is (unfortunately) not standard behavior. Here's what we did:
procedure TFormEffortRates.ComboBoxMaterialKeyDown(Sender: TObject; var
Key: Word;
Shift: TShiftState);
var iShowing : integer;
{ other code, then... }
begin
{ This tells you whether the combo is already dropped }
iShowing := SendMessage((Sender as TComboBox).Handle, CB_GETDROPPEDSTATE, 0, 0);
if iShowing = 0 then
{ drop the combo box }
SendMessage((Sender as TComboBox).Handle, CB_SHOWDROPDOWN, 1,0);
end;
Another good example is getting the line and column from a TMemo. You have to go into the API to do it. Here's a (not particularly efficient - no flames please!!) method of determining them:
function TMDIChild.GetMemoColumn(const TheMemo : TMemo) : integer;
begin
Result := TheMemo.SelStart -
(SendMessage(TheMemo.Handle, EM_LINEINDEX,
GetMemoLine(TheMemo), 0));
end;
function TMDIChild.GetMemoLine(const TheMemo : TMemo) : integer;
begin
Result := SendMessage(TheMemo.Handle, EM_LINEFROMCHAR,
TheMemo.SelStart, 0);
end;
Again, all these messages can be found in your API help. The instructions for using them are a little vague, but I'm sure everyone will be glad to help you should you need it.
In short, API messages provide you with a way to fine-tune your applications to respond in exactly the way you want them to. I would consider it an advanced Delphi topic, but it sounds like one you're more than ready for.
Can anyone tell me of a way or a component or whatever else that will allow delphi 2 or 3 to place a button on the task bar much like what PowerDesk 2.0 Toolbar does.
Here are the code snipits to do just that!
// This needs to be in your public declarations @ the top of the pas file procedure TForm1.IconCallBackMessage( var Mess : TMessage ); message WM_USER + 100;
procedure TForm1.FormCreate(Sender: TObject);
var
nid : TNotifyIconData;
begin
with nid do
begin
cbSize := SizeOf( TNotifyIconData );
Wnd := Form1.Handle;
uID := 1;
uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;
uCallbackMessage := WM_USER + 100;
hIcon := Application.Icon.Handle;
szTip := 'This is the hint!';
end;
Shell_NotifyIcon( NIM_ADD, @nid );
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
nid : TNotifyIconData;
begin
with nid do
begin
cbSize := SizeOf( TNotifyIconData );
Wnd := Form1.Handle;
uID := 1;
uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;
uCallbackMessage := WM_USER + 100;
hIcon := Application.Icon.Handle;
szTip := 'This is the hint!';
// All the above is probably not needed.
end;
Shell_NotifyIcon( NIM_DELETE, @nid );
end;
procedure TForm1.IconCallBackMessage( var Mess : TMessage );
var
sEventLog : String;
begin
case Mess.lParam of
// Do whatever you wish here. For example popup up a menu on a right click.
WM_LBUTTONDBLCLK : sEventLog := 'Left Double Click';
WM_LBUTTONDOWN : sEventLog := 'Left Down';
WM_LBUTTONUP : sEventLog := 'Left Up';
WM_MBUTTONDBLCLK : sEventLog := 'M Dbl';
WM_MBUTTONDOWN : sEventLog := 'M D';
WM_MBUTTONUP : sEventLog := 'M U';
WM_MOUSEMOVE : sEventLog := 'movement';
WM_MOUSEWHEEL : sEventLog := 'Wheel';
WM_RBUTTONDBLCLK : sEventLog := 'r dbl';
WM_RBUTTONDOWN : sEventLog := 'r down';
WM_RBUTTONUP : sEventLog := 'r up';
end;
end;
From: "Hiki Takehito" <[email protected]>
>Anyone know how to put a Delphi application inside the Control Panel?
If you use Delphi3, add Cpl unit at dpr file.
I show you a sample code. -----------
library Project1; {Change "program" to "library"}
uses
Cpl, {use Cpl unit}
Windows,
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
procedure ExecuteApp;
begin
Application.Initialize;
Application.CreateForm(TForm1,Form1);
Application.Run;
end;
{A callback function to export at Control Panel}
function CPlApplet(hwndCPl: THandle; uMsg: DWORD;
lParam1, lParam2: LongInt):LongInt;stdcall;
var
NewCplInfo:PNewCplInfo;
begin
Result:=0;
case uMsg of
{Initialization.Return True.}
CPL_INIT:
Result:=1;
{Number of Applet.}
CPL_GETCOUNT:
Result:=1;
{Transporting informations of this Applet to the Control Panel.}
CPL_NEWINQUIRE:
begin
NewCplInfo:=PNewCplInfo(lParam2);
with NewCplInfo^ do
begin
dwSize:=SizeOf(TNewCplInfo);
dwFlags:=0;
dwHelpContext:=0;
lData:=0;
{An icon to display on Control Panel.}
hIcon:=LoadIcon(HInstance,'MAINICON');
{Applet name}
szName:='Project1';
{Description of this Applet.}
szInfo:='This is a test Applet.';
szHelpFile:='';
end;
end;
{Executing this Applet.}
CPL_DBLCLK:
ExecuteApp;
else Result:=0;
end;
end;
{Exporting the function of CplApplet}
exports
CPlApplet;
begin
end.
To use this, change the extention from "dll" to "cpl". And put into the System folder.
Applet means a piece of Control Panel.Display,Fonts,Mouse,System are all Applets.
From: Jeremy Collins <[email protected]>
Basically, you need to add two keys to the registry under HKEY_CLASSES_ROOT. Say your extension in ".ext", then the first key you add is the extension itself:
HKEY_CLASSES_ROOT\ .ext\
and set the "default" string value of this key to an "internal name" for your file type - for example MyApp.Document:
HKEY_CLASSES_ROOT\
.ext\
Default = "MyApp.Document"
You then create another key with this name:
HKEY_CLASSES_ROOT\ MyApp.Document\
Create a sub-key of this called "shell", a sub-key of *this* called "open" and a further sub-key of "open" called "command". The default value uder this key is the location and name of your your application folled by "%1" which represents the filename parameter that Windows will pass to your executable:
HKEY_CLASSES_ROOT\
MyApp.Document\
shell\
open\
command\
Default = "C:\myapp\myapp.exe %1"
You can do this in code with the TRegistry object, or use InstallShield, which can make registry changes for you. I'd advise doing both, in case the user trashes your registry entry. From: "Rodney E Geraghty" &tt;[email protected]>
The easiest way I've found to do this is to modify the Extensions section of the win.ini file that is located in the Windows directory. This also works under Win 95 and will update the registry automatically under Win95. Look at the extensions section of the win.ini to see the format you have to use. Put IniFiles in your uses clause and then use something like this:
var
INIFile: TIniFile;
begin
try
INIFile := TInifile.Create('WIN.INI');
INIFile.WriteString('Extensions','txt','c:\windows\notepad.exe ^.txt');
finally
INIFile.Free;
end;
end;
This would associate *.txt files with Windows Notepad. If you had an app named MyApp in the c:\MyApps directory and your extension was *.MAP then you would change it like this:
var
INIFile: TIniFile;
begin
try
INIFile := TInifile.Create('WIN.INI');
INIFile.WriteString('Extensions','map','c:\myapps\myapp.exe ^.map');
finally
INIFile.Free;
end;
end;
This will work in both Win 3.11 and Win 95 and saves you from having to modify the Reqistry under Win 95. Not sure about Win NT (or Win95b) since I don't have a test machine available. Note that this is only the first part of the solution though since it will open the associated application but it won't load the file you clicked. To do this you have to read ParamStr(1), which would hold the full path of the file you clicked, and run the file name through your file opening routine.
From: "Carsten Paasch" <[email protected]>
Use this proc. to hide the start button:
procedure hideStartbutton(visi:boolean);
Var
Tray, Child : hWnd;
C : Array[0..127] of Char;
S : String;
Begin
Tray := FindWindow('Shell_TrayWnd', NIL);
Child := GetWindow(Tray, GW_CHILD);
While Child <> 0
do Begin
If GetClassName(Child, C, SizeOf(C)) > 0
Then Begin
S := StrPAS(C);
If UpperCase(S) = 'BUTTON'
then begin
// IsWindowVisible(Child)
startbutton_handle:=child;
If Visi
then ShowWindow(Child, 1)
else ShowWindow(Child, 0);
end;
End;
Child := GetWindow(Child, GW_HWNDNEXT);
End;
End;
Please email me and tell me if you liked this page.
Last modified 04/09/1998 11:27:51