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;
Related
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;
RESOLVED
Just update Windows 10 and the problem disappears
I have an old program developed with Delphi 7 and uses TComPort for serial communication.
On windows 10 TComPort wrong to enumerate the ports, it does not return the port number.
The program works perfectly from windows xp to windows 8.1 u1
So there is an incompatibility between Windows 10 and TComPort, setting the compatibility, or by running the program as an administrator does not change anything.
How can I fix?
I have to use another library for serial communication?
Here's a test I've done
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, CPort;
type
TForm1 = class(TForm)
ComPort1: TComPort;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var List:TStringList;
sPortName:String;
I:integer;
begin
List := TStringList.Create;
try
EnumComPorts( List );
For I := 0 to List.Count-1 do
begin
sPortName := Trim(List[I]);
Memo1.Lines.Add(sPortName);
end;
finally
List.Free;
end;
end;
end.
This is the result
The string "sPortName" is 3 characters long.
I have had issues in the past with TComPort returning port names. TComPort is working fine for me here with Windows 10. I have found it is necessary to use Trim() on each returned port name since #0 characters can get returned at the end of the port name. You do not provide any useful debugging info but this may be contributing to your issue. The solution is simple. I do:
List := TStringList.Create;
try
EnumComPorts( List );
For I := 0 to List.Count-1 do
begin
sPortName := Trim(List[I]);
<<< do something with sPortName >>>
end;
finally
List.Free;
end;
I'm developing a DLL file that will be loaded by my EXE... So the EXE will call the first DLL procedure and when this procedure get loaded I want to keep it openned even if the EXE get closed. The example is, I have a DLL with timer showing a 'Hello World' message.
DLL Code:
uses
SysUtils,
Classes,
Dialogs,
ExtCtrls;
{$R *.res}
type
TMyTimer = Class(TTimer)
public
procedure OnMyTimer(Sender: TObject);
end;
procedure DllMessage; export;
var
MyTimer: TMyTimer;
begin
MyTimer := TMyTimer.Create(nil);
MyTimer.Interval := 10000;
MyTimer.OnTimer := MyTimer.OnMyTimer;
end;
procedure TMyTimer.OnMyTimer(Sender: TObject);
begin
ShowMessage('Hello World');
end;
exports DllMessage;
begin
end.
The EXE is loading like this:
procedure DllMessage; external 'Message.dll'
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
DllMessage;
end;
When I close the EXE I want the DLL keep running and showing the message every 10 seconds... Is that possible?
DLLs are loaded into processes and cannot exist without a process to host them. So what you ask is not possible.
If you want to close your process, but continue to execute code, you will need to start a new and separate process to execute that code.
u need Atach a A DLL to another process,
and hook ur code to execute on your processs !
this method is called Dll Injection and Code Hook,
easy ways using madcodehook component
athttp://www.madshi.net/
example injection
http://help.madshi.net/DllInjecting.htm
example code hooking
http://help.madshi.net/ApiCodeHooking.htm
or
creanting ur ways
http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
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;
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
unit unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,FileCtrl,omnixml,omnixmlutils;
type
TForm1 = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
procedure olddiris(name:string);
procedure GetPath(name:string);
{ Public declarations }
end;
var
Form1: TForm1;
olddir: string; //global variable.
implementation
{$R *.dfm}
procedure Tform1.olddiris(name:string);
begin
if name = 'trick' then
olddir:= 'c:\program files'+name;
end;
procedure Tform1.GetPath(name:string);
var
options : TSelectDirOpts;
begin
OldDirIs(name); //returns olddir
if SelectDirectory(OldDir,options,0) then
ShowMessage('i got it');
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
getpath('trick');
end;
end.
Options is TSelectDirOpts = set of TSelectDirOpt;
TSelectDirOpt Standard is {TSelectDirOpt = (
sdAllowCreate,
sdPerformCreate,
sdPrompt
)
gFindDirs is a simple variable that keeps the Name nothing else so i erase it.
The setPath(gFindDirs) just forget it ok i replace it with a simple massage..
When I run it i get an error: the "class Estringlist.error: List index out of bounds(0)";
I try this with the component jvselectdirectory of jvcl library but I get the same thing...
in jvselectdirectory if I left it empty it goes me to the default application folder...
Here is all the program... push the button get the name turn into an existing directory i create before and try to open it with the selectdirectory that's it i get the above error...
FULL CODE nothing else create a form and put a button one event onclick().
Oops Sorry i fix it.... The rush to fix it wrong copy paste...
Help...
var
olddir: string; //global variable
procedure olddiris(name:string);
begin
if name = 'trick' then
olddir:= 'c:\program files\'+name;
end;
procedure MyGetPath(name:string);
var
options : TSelectDirOpts;
begin
OldDirIs(name); //returns olddir
if FileCtrl.SelectDirectory(OldDir,options,0) then
ShowMessage('i got it');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Mygetpath('trick');
end;
This code runs without error... (Note: changed GetPath -> MyGetPath; added "\" to 'c:\program files') If the problem still exists, look elsewhere in you code or post more code/info.
You should replace your code with
procedure GetPath(name:string);
var
options : TSelectDirOpts;
begin
FixedOldDirIs(name); //returns olddir
gFindDirs := name;
if FixedSelectDirectory(OldDir,options,0) then
FixedSetPath(gFindDirs);
end;
That should do the trick (if I understand your question correctly...)