From: info@sundialservices.com (Sundial Services)
In article <325B6BAB.7096@hec.unil.ch> Jean-Luc Nicoulin <Jean-Luc.Nicoulin@hec.unil.ch> 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 <ken@kyler.com>
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.
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.
From: abeldup@unison.co.za (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.
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: johnnysc@ix.netcom.com (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" <100101.602@compuserve.com>
Rainer Perl <Rainer.Perl@iddc.via.at> 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: gt6298d@prism.gatech.edu (Chris Randall)
"J.J. Bakker" <J.J.Bakker@stud.rgl.ruu.nl> 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%lotusnotes1@instinet.com>
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%lotusnotes1@instinet.com>
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);
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" <72223.10@compuserve.com>
> 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: mdiluglio@aol.com
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 " <d.j.faber@student.utwente.nl>
Rob Wilson <wilson@pelops.compd.com> 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 <j.c.p.gundersen@jusstud.uio.no>
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;
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" <maxint@cwnet.com>
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 <eighmy@scott.net>
> > 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.
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);
GlobalWinRestorer := TWinRestorer.create( Application, TRUE, [location, size, state]);
GlobalWinRestorer.free;
GlobalWinRestorer.SaveChildren(Self, [default]);
GlobalWinRestorer.SaveWin(Self, [WHATSAVE_ALL]);
GlobalWinRestorer.RestoreWin(Self, [default]);
GlobalWinRestorer.RestoreWin(Self, [default]); GlobalWinRestorer.RestoreChildren(Self, [default]);
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.
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
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
SetSystemModalWindow(Form1.handle);
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, Jim.Stanley@jacobs.com]
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;
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;
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;
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.[Joolz@emarkt.com]
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;
>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.
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;gerarod@ibm.net>
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.
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;