|
Windows
Detecting Win95 Vs W3.X
Getting large text from TClipboard
Long file names from Win95 DirListbox
Application.Title font color
Application to tile on windows desktop
Change wallpaper bitmap
Obtaining Windows Version
Creating and selecting palettes
Loading a listbox with program groups
System colors
Under Win95?
Knowing that Windows is exiting
Screen Saver Register
Hiding apps from taskbar
Reading from Registry
User Name in Windows95 with Delphi 2.0
How to Draw Template Thumbnails
List of opened applications and files
Screen Resolution
Registry and TStrings
Get Windows directory
Detecting Win95 Vs W3.X
Question
Does anyone know a quick way of detecting whether or not an application si
running on win 95 or Win3.x?
Answer
A:
I don't have Win 95 so I can't say what it will return, but the Windows API
function GetVersion returns the Windows (and DOS) version number (it's in
Delphi help). I'm running Windows for Workgroups under DOS 6.22, and this is
what I get back (Windows 3.1 gives me the same thing, I don't know how to
distinguish between 3.1 and 3.11):
var
x: longint;
begin
x := GetVersion;
integer(x shr 24) --> gives me 6, the DOS major version
integer((x shr 16) and $ff) --> gives me 22, the DOS minor version
integer((x shr 8) and $ff) --> gives me 10, the Windows minor version
integer(x and $ff) --> gives me 3, the Windows major version
A:
Here's a unit I whipped together the other day in an attempt to do this. It
just checks the WINVER.EXE file for the version of the product it is shipped
with. If there's an "official" way to detect Win 3.x/95, I'd like to know.
unit Testvsn;
interface
uses
SysUtils, WinTypes, WinProcs, VER;
procedure DoIt;
implementation
procedure DoIt;
var
VIHandle : LongInt;
VSize : LongInt;
VData : Pointer;
VVers : Pointer;
Len : Word;
OutStr : String;
begin
VSize := GetFileVersionInfoSize('WINVER.EXE', VIHandle);
If VIHandle = 0
Then OutStr := 'Windows Version : Unknown L1'
Else
Begin
GetMem(VData, VSize);
Try
If not GetFileVersionInfo('WINVER.EXE', VIHandle, VSize, VData)
Then OutStr := 'Windows Version : Unknown L2'
Else
If not VerQueryValue(VData,'\',VVers,Len)
Then OutStr := 'Windows Version : Unknown L3'
Else
With TVS_FIXEDFILEINFO(VVers^) do
OutStr := 'Windows Version : ' +
IntToStr((dwProductVersionMS and $FFFF0000) shr 16) +
'.' +
IntToStr(dwProductVersionMS and $0000FFFF);
Finally
FreeMem(VData, VSize);
End;
End;
OutStr := OutStr + chr(0);
MessageBox(0,@OutStr[1],'Windows Version Test',MB_OK or MB_ICONINFORMATION);
end;
begin
DoIt;
end.
A:
Uses the GetVersion API to determin the version of windows.
TYPE ver = RECORD
wmaj : byte;
wmin : byte;
dmin : byte;
dmaj : byte;
END;
VAR Version : ver;
BEGIN
Version:=getversion;
{for windows 95 Version.wmaj = 3
Version.wmin = 95;}
Getting large text from TClipboard
Question
How get a large text from TClipboard?
Answer
A:
var
Buffer: PChar;
MyHandle : THandle;
TextLength : Integer;
begin
MyHandle := Clipboard.GetAsHandle(CF_TEXT);
Buffer := GlobalLock(MyHandle);
If Buffer = Nil then
begin
GlobalUnlock(MyHandle);
exit;
end;
TextLength := StrLen(buffer); {since buffer is of type PChar,
all the functions applicable to PChar can be applied}
Long file names from Win95 DirListbox
Question
How do I get the long path string from a TDirectoryListbox in Win95 instead
of the 'hybrid' string that includes a tilde (~) character and a number?
Answer
A:
Delphi 16 in principle doesn't deal with longfilenames. But you can do it
yourself.
If you are familiar with assembly language get the M$ book "Programmer's
Guide to Microsoft Windows 95". Look in page 520 for the new DOS function
Find First File (with long filenames). It returns a WIN32_Find_Data record with
the long and short filenames.
From what I see you can pass either one and you get back both. You have to
code it as a simple
assembler routine into your code.
It's too much to give you an example here, but if you get the book you should be
on your way. Please keep in mind that you send and receive ASCIIZ strings,
not pascal strings.
Application.Title font color
Question
Is there a way to change the color of the application's title font?
Answer
A:
You can change all windows title font colors, but not your windows title font
color. This is a windows limitation.
It is possible to create a hot spot caption and add a label to it.
If you would like to create a custom captionless and borderless form that is
movable and resizable at runtime.
Application to tile on windows desktop
Question
How can I get my Application to tile with the other windows app's currently on
the Windows Desktop? (ie using the Tile button of Task Manager). Delphi apps
don't behave the way they should).
Answer
A:
type
TForm1 = class(TForm)
{ ..... }
procedure AppOnMessage(var Msg: TMsg; var Handled: Boolean);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppOnMessage;
ShowWindow(Handle, CmdShow);
end;
procedure TForm1.AppOnMessage(var Msg: TMsg; var Handled: Boolean);
var
WindowPosp : ^TWindowPos;
begin
with Msg do
if Message = WM_WINDOWPOSCHANGED then begin
WindowPosP := pointer(lparam);
with WindowPosP^ do begin
left := X;
Top := Y;
width := cx;
Height := cy;
end;
end;
end; { AppOnMessage }
end.
I tried it with Tile and Cascade in my Window 95 setup and it works great.
By the way the ShowWindow call that you mention is not to fix a bug. Delphi,
like Visual Basic has an invisible application form, distinct from the
main form.
Change wallpaper bitmap
Question
I want to change wallpaper (win95 desktop) bitmaps run-time.
How can i do it?
Answer
A:
The same way as in Win31 - using the SystemParametersInfo API call.
SystemParametersInfo(SPI_SETDESKWALLPAPER,0,pBitMap,SPIF_UPDATEINIFILE +
SPIF_SENDWININICHANGE);
This I do in one of my apps, and the app has quite successfully run
under Win31 and Win95
Obtaining Windows Version
Question
Does anyone have any code handy for determining the version
of Windows? I'm pretty sure it's got something to do with
the GetVersion API, but I can't seem to figure out the
bitwise operations in Delphi to determine it in a LongInt!
Answer
A:
Here's a short program that demonstrates GetVersion.
program Winvrsn;
uses
WinTypes,
WinProcs,
SysUtils;
var
WinVersion : Word;
DosVersion : Word;
VersionString : String;
begin
WinVersion := GetVersion and $0000FFFF;
DosVersion := (GetVersion and $FFFF0000) shr 16;
VersionString := 'DOS : ' + IntToStr(Hi(DOSVersion)) + '.' + IntToStr(Lo(DOSVersion)) + #13 +
'Windows : '+ IntToStr(Lo(WinVersion)) + '.' + IntToStr(Hi(WinVersion)) + #0;
MessageBox(0, @VersionString[1],'Version Information', MB_ICONINFORMATION or MB_OK)
end.
A:
I don't know for certain what result to expect since WfW is not on my machine
anymore, but how about giving this snippet a try and let me know what
happens? It "cheats" by getting the version info from WINVER.EXE. For
Windows 95 it reads "4.00", for Windows 3.1 it says "3.10".
var
VIHandle : LongInt;
VSize : LongInt;
VData : Pointer;
VVers : Pointer;
Len : Word;
OutStr : String;
begin
VSize := GetFileVersionInfoSize('WINVER.EXE', VIHandle);
If VIHandle = 0
Then OutStr := 'Windows Version : Unknown L1'
Else
Begin
GetMem(VData, VSize);
Try
If not GetFileVersionInfo('WINVER.EXE', VIHandle, VSize, VData)
Then OutStr := 'Windows Version : Unknown L2'
Else
If not VerQueryValue(VData,'\',VVers,Len)
Then OutStr := 'Windows Version : Unknown L3'
Else
With TVS_FIXEDFILEINFO(VVers^) do
OutStr := 'Windows Version : ' +
IntToStr((dwProductVersionMS and $FFFF0000) shr 16) +
'.' +
IntToStr(dwProductVersionMS and $0000FFFF) + #0;
Finally
FreeMem(VData, VSize);
End;
End;
MessageBox(0,@OutStr[1],'Windows Version Test',MB_OK or MB_ICONINFORMATION);
end;
Creating and selecting palettes
Question
How do you create and use a Palette in Delphi. According to the help fn I
think you should use the CreatePalette and SetPaletteEntries and RealizePalette
but how?
Answer
A:
Below are functions that help to create a palette (an identity
palette, BTW) from an array of RGBQuads (such as you would find in
the palette section of a .BMP file). I stole this from the WinG
documentation, and converted it to Delphi. First call
ClearSystemPalette, then you can get an identity palette by calling
CreateIdentityPalette.
If you plan to try palette animation, work in a 256-color mode, and
change all the PC_NOCOLLAPSE entries below to PC_RESERVED.
Besides creating the palette, the other pieces to the puzzle are
1. Override the form's GetPalette method, so that it returns the
new palette.
2. Select and realize the new palette just before you paint.
OldPal := SelectPalette(Canvas.Handle, NewPalette, False);
RealizePalette(Canvas.Handle);
{ Do your painting here }
SelectPalette(Canvas.Handle, OldPal, False);
3. Remember to release the palette when you are done using
DeleteObject
4. If you are used to using the RGB function to get color values, use
the PaletteRGB function in its place.
function CreateIdentityPalette(const aRGB; nColors : Integer) : HPALETTE;
type
QA = Array[0..255] of TRGBQUAD;
var
Palette : PLOGPALETTE;
PalSize : Word;
ScreenDC : HDC;
I : Integer;
nStaticColors : Integer;
nUsableColors : Integer;
begin
PalSize := SizeOf(TLOGPALETTE) + SizeOf(TPALETTEENTRY) * 256;
GetMem(Palette, PalSize);
try
with Palette^ do
begin
palVersion := $0300;
palNumEntries := 256;
ScreenDC := GetDC(0);
try
{ For SYSPAL_NOSTATIC, just copy the color table into a PALETTEENTRY
array and replace the first and last entries with black and white }
if (GetSystemPaletteUse(ScreenDC) = SYSPAL_NOSTATIC)
then
begin
{ Fill in the palette with the given values, marking each
with PalFlag }
{$R-}
for i := 0 to (nColors-1) do
with palPalEntry[i], QA(aRGB)[I] do
begin
peRed := rgbRed;
peGreen := rgbGreen;
peBlue := rgbBlue;
peFlags := PC_NOCOLLAPSE;
end;
{ Mark any unused entries with PalFlag }
for i := nColors to 255 do
palPalEntry[i].peFlags := PC_NOCOLLAPSE;
{ Make sure the last entry is white --
This may replace an entry in the array!}
I := 255;
with palPalEntry[i] do
begin
peRed := 255;
peGreen := 255;
peBlue := 255;
peFlags := 0;
end;
{ And the first is black --
This may replace an entry in the array!}
with palPalEntry[0] do
begin
peRed := 0;
peGreen := 0;
peBlue := 0;
peFlags := 0;
end;
{$R+}
end
else
begin
{ For SYSPAL_STATIC, get the twenty static colors into the
array, then fill in the empty spaces with the given color
table }
{ Get the static colors from the system palette }
nStaticColors := GetDeviceCaps(ScreenDC, NUMRESERVED);
GetSystemPaletteEntries(ScreenDC, 0, 256, palPalEntry);
{$R-}
{ Set the peFlags of the lower static colors to zero }
nStaticColors := nStaticColors shr 1;
for i:= 0 to (nStaticColors-1) do
palPalEntry[i].peFlags := 0;
{ Fill in the entries from the given color table}
nUsableColors := nColors - nStaticColors;
for I := nStaticColors to (nUsableColors-1) do
with palPalEntry[i], QA(aRGB)[i] do
begin
peRed := rgbRed;
peGreen := rgbGreen;
peBlue := rgbBlue;
peFlags := PC_NOCOLLAPSE;
end;
{ Mark any empty entries as PC_NOCOLLAPSE }
for i := nUsableColors to (255-nStaticColors) do
palPalEntry[i].peFlags := PC_NOCOLLAPSE;
{ Set the peFlags of the upper static colors to zero }
for i := (256 - nStaticColors) to 255 do
palPalEntry[i].peFlags := 0;
end;
finally
ReleaseDC(0, ScreenDC);
end;
end;
{ Return the palette }
Result := CreatePalette(Palette^);
finally
FreeMem(Palette, PalSize);
end;
end;
procedure ClearSystemPalette;
var
Palette : PLOGPALETTE;
PalSize : Word;
ScreenDC : HDC;
I : Word;
const
ScreenPal : HPALETTE = 0;
begin
PalSize := SizeOf(TLOGPALETTE) + SizeOf(TPALETTEENTRY) * 255; {256th = [0] }
GetMem(Palette, PalSize);
try
FillChar(Palette^, PalSize, 0);
Palette^.palVersion := $0300;
Palette^.palNumEntries := 256;
{$R-}
For I := 0 to 255 do
With Palette^.palPalEntry[I] do
peFlags := PC_NOCOLLAPSE;
{$R+}
{ Create, select, realize, deselect, and delete the palette }
ScreenDC := GetDC(0);
try
ScreenPal := CreatePalette(Palette^);
if ScreenPal <> 0
then
begin
ScreenPal := SelectPalette(ScreenDC,ScreenPal,FALSE);
RealizePalette(ScreenDC);
ScreenPal := SelectPalette(ScreenDC,ScreenPal,FALSE);
DeleteObject(ScreenPal);
end;
finally
ReleaseDC(0, ScreenDC);
end;
finally
FreeMem(Palette, PalSize);
end;
end;
Loading a listbox with program groups
Question
So my question is, how can I load a list box with all existing
program groups on a system?
Answer
A:
I am not sure if this approach will be helpful if the application
that ran before yours added any groups. i.e. whether groups get
written to disk immediately, or only on exit from Windows.... You
can try it out... if it works, great.... if not, and if you would
like some programmatic control, here is some code that I pulled out
of one of my programs...
------code---------
Procedure TProgMan.ReadGroups;
Var
GroupData : PChar;
TmpStr : String;
i : integer;
begin
GroupData := FDDEClient.RequestData('Groups');
FGroupsList.Clear;
FNumGroups := 0; {assume there are no groups! }
if GroupData = nil then
exit
else
begin
i := 0;
TmpStr := '';
While GroupData[i] <> #0 do
begin
if GroupData[i] = #13 then
begin
FGroupsList.Add(TmpStr);
TmpStr := '';
i := i + 1; {skip the #10 char}
end
else
TmpStr := TmpStr + GroupData[i];
i := i + 1;
end;
end;
StrDispose(GroupData);
end;
------------code ends-----------------
Here, FGroupsList is of type TStringlist.... therefore, you may
substitute it with Listbox.Items as easily.
A:
....
var
Groups: PChar;
begin
if not DDEClient.SetLink('ProgMan','PROGMAN') then
MessageDlg('Link with ProgMan NOT established.', mtInformation, [mbOK], 0);
DDEClient.OpenLink;
Groups:=DDEClient.RequestData('GROUPS');
ComboBox1.Items.SetText(Groups);
strDispose(groups);
DDEClient.CloseLink;
end;
.....
this code will get existing progMan groups names. and put it into a comboBox ( to let the
user select...)
Note, you don't have to allocate memory for the Groups variable, the API function
RequestData is doing this. but you have to dispose of it when through.
Of course you have to put a DDEClient component on your form.
System colors
Question
I need to emulate the color selection options of control panel... I looked
up the setsyscolor procedure, but though it seems to cause a global repaint,
it seems to have no effect... is it no longer supported? should I instead
change the win.ini (or is it system.ini - sorry - can't remember right now.)
If I change these values will programs update - or do they have to be
notified in some way?
Answer
A:
procedure TMainForm.Button4Click(Sender: TObject);
var
nColorIndex: array [1..2] of integer;
nColorValue: array [1..2] of longint;
begin
nColorIndex[1]:=COLOR_ACTIVECAPTION;
nColorIndex[2]:=COLOR_BTNFACE;
nColorValue[1]:=clBlue;
nColorValue[2]:=clRed;
SetSysColors(2,nColorIndex,nColorValue);
PostMessage(HWND_BROADCAST,WM_SYSCOLORCHANGE,0,0);
end;
Under Win95?
Question
How do I know if I am under Windows95?
Answer
A:
Try the windows function "getversion". Here is an example:
versNr := LoWord(GetVersion); {Windows-Versionsnr}
str(lobyte(versNr),Version);
str(hibyte(versNr), Dummy);
if (version = '3') and (dummy = '10') then
version := '3.10/3.11'
else
version := version + '.' +Dummy;
If Win95 is installed dummy returns 95. Version returns 3.
A:
Use the getVersion API call as follows:
vers: longint;
vers := GetVersion;
{if you're certain you're running Windows 3.xx or 95, then use this:}
if ((vers shr 8) and $ff) = 95 then
Win 95
else
Win 3.xx;
{if you could be running Windows 2.xx or 1.xx, then use this first:}
if ((vers and $ff) = 3) then
Win 3.xx or Win 95
else
Win 2.xx or Win 1.xx;
You might want to use ">=" instead of "=" to cover Win 96, etc.
Knowing that Windows is exiting
Question
I have been looking for a way to know how to differentiate between my app
closing on the users request and when Windows is closing my app because of
Windows shutting down.
Is there an easy way out, or do I have to write an event handler for the
TApplication object to look at the messages from Windows ?
Answer
A:
Windows sends a message (WM_QUERYENDSESSION) to every active
application when the user tries to shut down Windows. If your
program responds with a non-zero value, then Windows will close it.
If you program returns a 0, that tells Windows not to shut down. The
DefWindowProc returns a non-zero value for you. You can write a
message handler for this message for this message that will keep
Windows from shutting down if your program is active.
Screen Saver Register
Question
How do I register my Screen saver so Windows picks it up in the control
panel Desktop Dialog. The Application Name begins with SCRNSAVE and it
still does not register.
Answer
A:
a) In the project file (*.dpr) add '{$D SCRNSAVE } after the
uses clause.
b) On the main form, turn off the border and icon controls. In the
activate method set the form left and top to 0, and set the Windowstate
to wsMaximize.
c) In the form create method, set the application.OnMessage to a method
that controls the deactivation of the screen saver. Set the
application.OnIdle method to whatever display method for the saver.
d) In the form create method the command line should be tested for /c and
/s. These are the command line parameters windows uses to define whether
the screensaver should run or configure. (/c is for configuration)
e) Compile the program, and rename the .exe to .scr. Move it to the
windows directory, and it should show up in the control panel.
Hiding apps from taskbar
Question
Anyone can tell me how to remove an Application Icon & Title from the taskbar?
Answer
ShowWindow(Application.Handle, SW_HIDE);
Reading from Registry
Question
I have some problems with reading from registry.
Does any one have a clue about solving this problem?
I get Acces Violation with the following code:
Var
Registry: TRegistry;
Listan:TStrings;
begin
Listan.create;
Registry := TRegistry.Create;
try
Registry.RootKey := HKey_Classes_Root;
Registry.GetKeynames(Listan);
ComboBox1.Items.AddStrings(Listan);
finally
Registry.Free;
end;
end;
Answer
Try the following. Important is the OPENKEY!
procedure TForm1.FormCreate(Sender: TObject);
Var
Registry: TRegistry;
Listan:TStringList; // **************
begin
Listan := TStringList.create; // **************
Registry := TRegistry.Create;
try
Registry.RootKey := HKey_Classes_Root;
Registry.OpenKey('',False); // **************
Registry.GetKeynames(Listan);
ComboBox1.Items := Listan; // **************
finally
Registry.Free;
end;
end;
User Name in Windows95 with Delphi 2.0
Question
I am trying to get the username of the active user in a Windows 95, using
Delphi 2.0.
Answer
function GetUserName : string;
var
sNetUserName : DbiUserName;
begin
{ Get the user name. }
if DbiGetNetUserName(sNetUserName) = DBIERR_NONE then
Result := StrPas(sNetUserName)
else
Result := '';
end;
How to Draw Template Thumbnails
Question
I'm trying to find out how to draw a thumbnail representation of a
word processing template (for example, a WordPerfect .WPT or a
Microsoft Word .DOT) on a form. When I select an item from a
listbox, I want a thumnail of the corresponding file to be displayed on the
form.
Answer
If you mean associated icon, then you can use this:
IconIndex := 0;
Image1.Picture.Icon.Handle := ExtractAssociatedIcon( hInstance, PChar(
'c:\FileName.doc' ), IconIndex );
List of opened applications and files
Question
How to get a list of registered files and their extensions?
Answer
To get a list of the applications and their extensions for opening up
files in Windows95 do the following:
1. Open new application
2. Put a Memo component on the form, about 3 inches wide or so
3. Clear out the memo1 lines
4. Add a FormShow event and put in the following code:
procedure TForm1.FormShow(Sender: TObject);
var K: TRegIniFile;
i: Integer;
Extensions: TStringList;
begin
K := TRegIniFile.Create('');
K.RootKey := HKEY_LOCAL_MACHINE;
K.OpenKey('SOFTWARE\MicroSoft\Windows\CurrentVersion\Extensions',
False);
Extensions := TStringList.Create;
K.GetValueNames(Extensions);
for i := 0 to Extensions.Count-1 do
Memo1.Lines.Add(Extensions.Strings[i]
+ ' = ' +
K.ReadString('', Extensions.Strings[i], ''));
Extensions.Free;
K.Free;
end;
Screen Resolution
Question
When I run a program on my computer everything looks fine, but when I
run it on my other computer, with a higher screen resilotion it looks
totaly different. How can I get it to look the same in any resolution.
Answer
Borland's document ti2861 gave some mileage..and I give it to you with
some of my modifications..here is:
TI2861 - Form display with different screen resolutions.
Product: Delphi
Version: All
Platform: Windows/Win32
When designing forms, it is sometimes helpful to write the code
so that the screen and all of its objects are displayed at the
same size no matter what the screen resolution is. Here is
some code to show how that is done:
implementation
const
ScreenWidth: LongInt = 640; {I designed my form in 640x480 mode.}
ScreenHeight: LongInt = 480;
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
scaled := true;
if (screen.width <> ScreenWidth) then
begin
height := longint(height) * longint(screen.height) div ScreenHeight;
width := longint(width) * longint(screen.width) div ScreenWidth;
scaleBy(screen.width, ScreenWidth);
end;
end;
Then, you will want to have something that checks to see that
the font sizes are OK. You can iterate over each child
control's font to adjust its size as necessary. This can be
done as follows:
type
TFooClass = class(TControl); { needed to get at protected }
{ font property }
var
i,NewFormWidth,OldFormWidth : integer;
begin
NewFormWidth := GetsystemMetrics(0); <-- gives you your window's width
OldFormWidth := 640; <-- This is my resolution
for i := ControlCount - 1 downto 0 do
TFooClass(Controls[i]).Font.Size :=
(NewFormWidth div OldFormWidth) *
TFooClass(Controls[i]).Font.Size;
end;
This will calculate all your fonts, objects that are on your forms...
Note: The following are issue to bear in mind when scaling
Delphi applications (forms) on different screen resolutions:
* Decide early on in the form design stage whether you're
going to allow the form to be scaled or not. The advantage of
not scaling is that nothing changes at runtime. The
disadvantage of not scaling is that nothing changes at runtime
(your form may be far too small or too large to read on some
systems if it is not scaled).
* If you're NOT going to scale the form, set Scaled to False.
* Otherwise, set the Form's Scaled property to True.
* Set AutoScroll to False. AutoScroll = True means 'don't
change the form's frame size at runtime' which doesn't look
good when the form's contents do change size.
* Set the form's font to a scaleable TrueType font, like
Arial. MS San Serif is an ok alternate, but remember that it
is still a bitmapped font. Only Arial will give you a font
within a pixel of the desired height. NOTE: If the font used
in an application is not installed on the target computer, then
Windows will select an alternative font within the same font
family to use instead. This font may not match the same size
of the original font any may cause problems.
* Set the form's Position property to something other than
poDesigned. poDesigned leaves the form where you left it at
design time, which for me always winds up way off to the left
on my 1280x1024 screen - and completely off the 640x480 screen.
* Don't crowd controls on the form - leave at least 4 pixels
between controls, so that a one pixel change in border
locations (due to scaling) won't show up as ugly overlapping
controls.
* For single line labels that are alLeft or alRight aligned,
set AutoSize to True. Otherwise, set AutoSize to False.
* Make sure there is enough blank space in a label component
to allow for font width changes - a blank space that is 25% of
the length of the current string display length is a little too
much, but safe. (You'll need at least 30% expansion space for
string labels if you plan to translate your app into other
languages) If AutoSize is False, make sure you actually set
the label width appropriately. If AutoSize is True, make sure
there is enough room for the label to grow on its own.
* In multi-line, word-wrapped labels, leave at least one line
of blank space at the bottom. You'll need this to catch the
overflow when the text wraps differently when the font width
changes with scaling. Don't assume that because you're using
large fonts, you don't have to allow for text overflow -
somebody else's large fonts may be larger than yours!
* Be careful about opening a project in the IDE at different
resolutions. The form's PixelsPerInch property will be
modified as soon as the form is opened, and will be saved to
the DFM if you save the project. It's best to test the app by
running it standalone, and edit the form at only one
resolution. Editing at varying resolutions and font sizes
invites component drift and sizing problems.
* Speaking of component drift, don't rescale a form multiple
times, at design time or a runtime. Each rescaling introduces
roundoff errors which accumulate very quickly since coordinates
are strictly integral. As fractional amounts are truncated
off control's origins and sizes with each successive
rescaling, the controls will appear to creep northwest and get
smaller. If you want to allow your users to rescale the form
any number of times, start with a freshly loaded/created form
before each scaling, so that scaling errors do not accumulate.
* Don't change the PixelsPerInch property of the form, period.
* In general, it is not necessary to design forms at any
particular resolution, but it is crucial that you review their
appearance at 640x480 with small fonts and large, and at a
high-resolution with small fonts and large before releasing
your app. This should be part of your regular system
compatibility testing checklist.
* Pay close attention to any components that are essentially
single-line TMemos - things like TDBLookupCombo. The Windows
multi-line edit control always shows only whole lines of text
- if the control is too short for its font, a TMemo will show
nothing at all (a TEdit will show clipped text). For such
components, it's better to make them a few pixels too large
than to be one pixel too small and show not text at all.
* Keep in mind that all scaling is proportional to the
difference in the font height between runtime and design time,
NOT the pixel resolution or screen size. Remember also that
the origins of your controls will be changed when the form is
scaled - you can't very well make components bigger without
also moving them over a bit.
Registry and TStrings
Question
I want to save the contents of a string list to the registry (and later read
it back). It looks like the ReadSectionValues method of TRegIniFile may
read back the list.
Answer
If anyone is interested, the code that I used to write (and read) a
TStringList to the Registry is:
{Save a list of strings to the registry.
It will write each string as a key,value with the key being the index of
each string element and the value being the key.
}
procedure TDPRegistry.SaveStringListInRegistry(_RootKey: HKEY;
_Localkey: String; Strings: TStrings);
var
TR: TRegIniFile;
LStringIndex: Integer;
begin
TR := TRegIniFile.Create('');
try
case _RootKey of { default is RootKey=HKEY_CURRENT_USER }
HKEY_CLASSES_ROOT,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS,
HKEY_PERFORMANCE_DATA,
HKEY_CURRENT_CONFIG,
HKEY_DYN_DATA : TR.RootKey := _RootKey;
end; {end case _RootKey}
TR.EraseSection(_Localkey); {make sure no entries for this section/key}
with TRegistry(TR) do begin
if OpenKey(_Localkey,true) then begin
try
for LStringIndex := 0 to Strings.Count - 1 do begin
WriteString (IntToStr(LStringIndex), Strings[LStringIndex]);
end; {for each string in the list}
finally
CloseKey;
end; {try finally}
end; {if OpenKey}
end; {with TRegistry(TR)}
finally
TR.Free;
end; {try finally}
end;
{Get list of strings from registry.}
procedure TDPRegistry.GetStringListFromRegistry(_RootKey: HKEY;
_Localkey: String; Strings: TStrings);
var
TR: TRegIniFile;
LStringIndex: Integer;
RegKeyInfo : TRegKeyInfo;
begin
Strings.Clear; {start with no elements in string list}
TR := TRegIniFile.Create('');
try
case _RootKey of { default is RootKey=HKEY_CURRENT_USER }
HKEY_CLASSES_ROOT,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS,
HKEY_PERFORMANCE_DATA,
HKEY_CURRENT_CONFIG,
HKEY_DYN_DATA : TR.RootKey := _RootKey;
end;
{ TR.ReadSectionValues(_Localkey, Strings); doesn't work nicely because
returns strings as "1=Value", "2=Value"...}
with TRegistry(TR) do begin
if OpenKey(_Localkey,true) then begin
try
if (GetKeyInfo(RegKeyInfo)) then begin
for LStringIndex := 0 to RegKeyInfo.NumValues - 1 do begin
Strings.Add(ReadString(IntToStr(LStringIndex)));
end; {for each value associated with this key}
end; {got key information}
finally
CloseKey;
end; {try finally}
end; {if OpenKey}
end; {with TRegistry(TR)}
finally
TR.Free;
end; {try finally}
end;
Get Windows directory
Question
How to retrieve Windows directory?
Answer
{this code finds the windows directory on the click of a button}
procedure TForm1.Button1Click(Sender: TObject);
var
buf : array[0..200] of char;
pc : Pchar;
str : string;
x : integer;
begin
pc := @buf[0];
x := getwindowsdirectory(pc, 199);
str := strpas(pc);
writeln(str); { output c:\windows}
writeln(x); { output 10}
end;
|