Based on examples at for instance here, here, and here, I'm trying to include SVN revision info in a project. The result of a svn info call is stored in rev.txt (it's a plain ansi file). My revinfo.rc looks like this:
REV_TEXT TEXT rev.txt
My project looks like this:
unit rev;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm2 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
{$R revinfo.res}
procedure TForm2.Button1Click(Sender: TObject);
var
RS : TResourceStream;
MyStr : AnsiString;
begin
RS := TResourceStream.Create(hInstance, 'REV_TEXT', RT_RCDATA);
SetLength(MyStr, RS.Size);
RS.Read(MyStr[1], RS.Size);
RS.Free;
Memo1.Text := MyStr;
end;
end.
The project compiles, in other words, the resource file itself is located by the compiler (or perphaps it is the linker?). Anyway; when the statement TResourceStream.Create(hInstance, 'REV_TEXT', RT_RCDATA); is executed, I get an EResNotFound exception, complaining it can't find resource REV_TEXT. I can confirm that the resource file is compiled satisfactory, containing the content of the rev.txt text file. Are there anyone out there who're able to reproduce my troubles?
BTW: I've also tried to use the indexed version of the TResourceStream-constructor, but I don't know which index to use (tried 0, 1, and 2 to no avail).
I really appreciate your help! :)
The problem in your code is the line:
TResourceStream.Create(hInstance, 'REV_TEXT', RT_RCDATA);
You must call the TResourceStream.Create with the same type of the resource TEXT.
The following code should work:
var
RS : TResourceStream;
MyStr : AnsiString;
begin
RS := TResourceStream.Create(hInstance, 'REV_TEXT', 'TEXT');
try
SetLength(MyStr, RS.Size);
RS.Read(MyStr[1], RS.Size);
finally
RS.Free;
end;
end;
Related
I am porting a project to FMX (from VCL). I use a TSaveDialog with Filter for the file extensions, but when I change the extension the 'OnTypeChange' event does'nt fire, but the 'OnShow' event fires !
I tried TOpenDialog with the same problem.
Some informations :
Delphi Pro 10.3.1 (I tried Delphi 10.3.3)
Event 'OnFolderChange' does'nt fire.
Events 'OnClose' and 'OnShow' are OK.
Any idea ? Is there any option I missed ? Or a known bug ?
My test code : just a Form with a TButton and a TSaveDialog whith some code in the events to show if they are fired.
unit Unit1;
interface
uses
FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Controls.Presentation,
FMX.StdCtrls, System.Classes;
type
TForm1 = class(TForm)
SaveDialog1: TSaveDialog;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure SaveDialog1FolderChange(Sender: TObject);
procedure SaveDialog1TypeChange(Sender: TObject);
procedure SaveDialog1Close(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.SaveDialog1Close(Sender: TObject);
begin
Self.Caption := Self.Caption + ', Close';
end;
procedure TForm1.SaveDialog1FolderChange(Sender: TObject);
begin
Self.Caption := Self.Caption + ', Folder';
end;
procedure TForm1.SaveDialog1TypeChange(Sender: TObject);
begin
Self.Caption := Self.Caption + ', Change';
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Self.Caption := 'Start';
SaveDialog1.Filter := 'Applications (*.exe)|*.EXE|Text files (*.txt)|*.TXT';
SaveDialog1.Execute;
end;
end.
Thx
Although the OnFolderChange and OnTypeChange events are published and assignable in the TSaveDialog's Object Inspector these do nothing at all.
It is possible though to make these events work like in VCL by copying the source file FMX.Dialogs.Win.pas to your project folder and adding the relevant missing bits from the Vcl.Dialogs.pas source file, which include but not limited to:
References to FolderChange and TypeChange in TCustomFileDialog class.
Procedures OnFolderChangeEvent and OnTypeChangeEvent in TFileDialogWrapper class.
The whole TFileDialogEvents class.
Although these changes were tested with Delphi 10.3.3 the solution should be similar for Delphi 10.3.1 and even more recent versions as this unit hasn't changed much along time.
How can I save breakpoints using the Delphi IDE? I only know how to store the settings in a .dsk file.
I am using Delphi 2007.
I'm assuming from your mention of the .Dsk file that you are aware that the breakpoints are stored in there, but want to save them yourself for some reason. Of course, the easiest method of getting a list of saved breakpoints is simply to read them from the .Dsk file, but that assumes that it has been saved to disk, which usually
occurs when you close the project file.
You can write your own IDE plug-in to get a list of currently-set breakpoints
and save them in any way you want. The minimalist example below shows how to do this - see the GetBreakpoints method for details. To use this in the IDE, you would create a new package which requires
DesignIde.Dcp. Make sure that the output directory for the .Bpl file is either where
your 3rd-party .Bpls are stored on or is on your path. You can then install the
package in the IDE vie Install packages from the IDE's menu.
As you can see, it works by using the BorlandIDEServices interface in the ToolsAPI units to get an IOTADebuggerServices interface, and then uses that to iterate its SourceBkpts list and saves a number of properties of each IOTASourceBreakpoint in that list.
Note that
You can also retrieve a list of address breakpoints and save those in a similar fashion.
Both kinds of breakpoint interface in ToolsAPI have property setters as well as getters, so you could modify existing breakpoints in code and conceivably create new ones.
Code
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ToolsApi;
type
TBreakpointSaveForm = class(TForm)
Memo1: TMemo;
btnGetBreakpoints: TButton;
procedure btnGetBreakpointsClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
protected
public
procedure GetBreakpoints;
end;
var
BreakpointSaveForm: TBreakpointSaveForm;
procedure Register;
implementation
{$R *.DFM}
procedure TBreakpointSaveForm.GetBreakpoints;
var
DebugSvcs: IOTADebuggerServices;
procedure SaveBreakpoint(BreakPoint : IOTASourceBreakpoint);
begin
Memo1.Lines.Add('File: ' + Breakpoint.FileName);
Memo1.Lines.Add('LineNo: ' + IntToStr(Breakpoint.LineNumber));
Memo1.Lines.Add('Passcount: ' + IntToStr(Breakpoint.Passcount));
Memo1.Lines.Add('');
end;
procedure SaveBreakpoints;
var
i : Integer;
BreakPoint : IOTASourceBreakpoint;
begin
Memo1.Lines.Add('Source breakpoint count : '+ IntToStr(DebugSvcs.GetSourceBkptCount));
for i := 0 to DebugSvcs.GetSourceBkptCount - 1 do begin
Breakpoint := DebugSvcs.SourceBkpts[i];
SaveBreakpoint(Breakpoint);
end;
end;
begin
if not Supports(BorlandIDEServices, IOTADebuggerServices, DebugSvcs) then begin
ShowMessage('Failed to get IOTADebuggerServices interface');
exit;
end;
Memo1.Lines.Clear;
SaveBreakpoints;
end;
procedure Register;
begin
end;
initialization
BreakpointSaveForm := TBreakpointSaveForm.Create(Application);
BreakpointSaveForm.Show;
finalization
if Assigned(BreakpointSaveForm) then
BreakpointSaveForm.Free;
end.
procedure TBreakpointSaveForm.btnGetBreakpointsClick(Sender: TObject);
begin
GetBreakpoints;
end;
How to add support of HTML help files (.chm) on Delphi XE2? We need to use A-links (A-keywords) on HelpContext property of every control to lookup help pages. Delphi XE2 has native support of HTML help files by unit HTMLHelpViewer. But how to use it?
It's not hard with F1 jump to a context.
Select Edit1 and press F1 . Help opens and Overview.htm is shown.
Prerequisite.
Edit1 Help settings:
sample.chm source settings.
sample.ali
IDH_Overview=Overview.htm
IDH_welcom=FirstTopic.htm
IDH_UsingtheMenus=Overview.htm
sample.h
#define IDH_Creating_Projects_and_Topics 1005
#define IDH_Overview 1003
#define IDH_UsingtheMenus 1009
Unit1.pas
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, HTMLHelpViewer, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
HHALINKLOOKUP: TButton;
JumpAnchor: TButton;
Edit1: TEdit;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure HHALINKLOOKUPClick(Sender: TObject);
procedure JumpAnchorClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
hpPath : string;
link : HH_AKLINK;
procedure TForm1.FormCreate(Sender: TObject);
begin
hpPath := ExtractFilePath(Application.ExeName) +
'HelpFile\sample.chm';
Application.HelpFile := hpPath;
end;
procedure TForm1.HHALINKLOOKUPClick(Sender: TObject);
var
link : HH_AKLINK;
szUrl,szKey,szMsgText,szMsgTitle,szWindow : AnsiString;
begin
szKey := Edit1.Text; // 'UsingtheMenus';
szUrl :='Overview.htm';
szMsgText :='Error: Can''t find "'+Edit1.Text+'"!';
szMsgTitle :='Error: HH_ALINK_LOOKUP';
szWindow :='main';
with link do begin
cbStruct := sizeof(HH_AKLINK) ;
fReserved := False;
pszKeywords := PChar(szKey);
pszUrl := nil;
pszMsgText := PChar(szMsgText);
pszMsgTitle := PChar(szMsgTitle);
pszWindow := PChar(szWindow);
fIndexOnFail:= False;
end;
HtmlHelpW(0, hpPath+'>main', HH_DISPLAY_TOPIC, DWORD_PTR(nil));
HtmlHelpW(0, hpPath, HH_ALINK_LOOKUP, DWORD_PTR(#link));
end;
procedure TForm1.JumpAnchorClick(Sender: TObject);
begin
HtmlHelpW(0, hpPath+'::/Overview.htm#'+Edit1.Text+'>main', HH_DISPLAY_TOPIC, DWORD(nil));
end;
end.
Here is a ready to use sample.chm and the source Download
There is a trick how to easily, to jump, not only to the .htm file but jumps directly to an anchor.
Change sample.ali
IDH_Overview=Overview.htm
IDH_welcom=FirstTopic.htm
IDH_UsingtheMenus=Overview.htm#UsingtheMenus
Insert an anchor at the place, you want to jump to in Overview.htm
[...]
<A NAME="UsingtheMenus" </A>
<P><STRONG>Using the Menus and Toolbars</STRONG>
<P>The menus and toolbars provide a complete set of tools
[...]
Now it is possible with F1, jump directly to the desired point in overview.htm.
I suspect that to use A-links you need to do the following:
Assign an Application.OnHelp handler as described below.
Assign Application.HelpFile during program startup.
Call Application.HelpKeyword if you wish to invoke the help system with an A-link.
Set the HelpKeyword property for any GUI controls that you wish to respond to context sensitive F1 key presses.
The OnHelp handler looks like this:
function TMainForm.ApplicationHelp(Command: Word;
Data: THelpEventData; var CallHelp: Boolean): Boolean;
var
Link: THH_AKLink;
ALink: string;
begin
CallHelp := False;
Result := True;
//argh, WinHelp commands
case Command of
HELP_COMMAND:
begin
ZeroMemory(#Link, SizeOf(Link));
Link.cbStruct := SizeOf(Link);
ALink := PChar(Data); // we are going to re-purpose the keyword as an A-link
Link.pszKeywords := PChar(AnsiString(ALink)); // seems we have to pass a PAnsiChar ..
Link.fIndexOnFail := True;
HtmlHelp(GetDesktopWindow, Application.HelpFile, HH_ALINK_LOOKUP,
DWORD_PTR(#Link));
end;
end;
end;
The HtmlHelpViewer unit contains methods named LookupALink which do the same. But I don't see how they could ever be called.
The above approach is a little bit hacky because it interprets keywords as A-Links. If you want context sensitive help, I can't see what else you can do.
Not sure how Xe2 viewer works (I'm on 2007) but I just use Eric Granges port of the Microsoft HTML help API, which unsurprisingly, is called HTMLhelpAPI.pas.
You can call an Alink using the function
ChmShowTopic(const filename,atopic:string):HWND;
I've downloaded free DBX driver from here.
I am trying to make it work since two days now, without success.
Here is the snapshot of my code:
unit uMainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SqlExpr, WideStrings, DBXDynalink, DB;
type
TMainForm = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.Button1Click(Sender: TObject);
var C: TSQLConnection;
begin
C := TSQLConnection.Create(Self);
try
C.DriverName := 'FirebirdConnection';
C.LibraryName := 'dbxfb4d12.dll';
C.VendorLib := 'fbclient.dll';
C.GetDriverFunc := 'getSQLDriverFIREBIRD';
C.Params.Add('User_Name=SYSDBA');
C.Params.Add('Password=masterkey');
C.Params.Add('Database=C:\MyDB.fdb');
C.Open;
if C.Connected then
ShowMessage('Connection is active')
finally
C.Free;
end;
end;
After running the test I am receiving error: "Unable to load fbclient.dll(ErrorCode 22). It may be missing from the system path."
I have required libraries in my application path, I have them even in the System32 path. I am not using dbxdrivers.ini and dbxconnections.ini.
So what is going on here? I have Delphi 2009 with latest updates.
Thanks for your time.
Did you also try to put the fbclient.dll file in the same folder as the executable?
Sometimes it's necessary to have the fbclient.dll renamed to gds32.dll. It might do the trick.
I have the following sequence of commands in Delphi2010:
var netdir:string;
....
OpenDialog1.InitialDir:=netdir;
....
OpenDialog1.Execute...
....
GetDir(0,netdir);
....
After executing OpenDialog I should have in string netdir the directory where I finished
my OpenDialog.Execute. And in the next OpenDialog.Execute it should start from that
directory.
It works fine on XP, but not on Windows 7?
It always starts from directory where the program is installed.
Any idea what might be wrong?
Thanks.
Your question cannot be answered as it stands, because it lacks several crucial details.
Is netdir a global constant, or does it go out of scope every now and then?
Do you set netdir to something prior to OpenDialog1.Execute?
Is the question about what directory GetDir return (as your title suggests), or about how to make the open dialog remember the last visited directory (as the body matter suggests)?
I will assume that 1) netdir is a global constant, that 2) you do not set it initially, and that 3) you want the open dialog to remember the last visited folder. Thus you have something like
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm3 = class(TForm)
OpenDialog1: TOpenDialog;
procedure FormClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
var
netdir: string;
implementation
{$R *.dfm}
procedure TForm3.FormClick(Sender: TObject);
begin
OpenDialog1.InitialDir := netdir;
OpenDialog1.Execute;
GetDir(0, netdir);
end;
end.
Then the solution is to let Windows remember the directory for you, that is, simply do
procedure TForm3.FormClick(Sender: TObject);
begin
OpenDialog1.Execute;
end;
alone! But why doesn't your method work? Well, GetDir doesn't return what you want. If you need explicit control, do
procedure TForm3.FormClick(Sender: TObject);
begin
OpenDialog1.InitialDir := netdir;
OpenDialog1.Execute;
netdir := ExtractFilePath(OpenDialog1.FileName)
end;
If you not wan´t opendialog you can do as below to get dir under your program.
yourdir:=ExtractFilePath(Application.ExeName);
I have done it in Vista and it work.
This is the solution for the problem
openDialog1.Options := [ofFileMustExist];
if openDialog1.Execute then
begin
end;