Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: Identifying target file from within default program


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 13 - Last Post: Jan 16, 2018 2:01 PM Last Post By: Paolo Valle Threads: [ Previous | Next ]
Keith Mylon

Posts: 2
Registered: 4/22/02
Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 21, 2017 10:56 AM
I have written a small program and have set it to be the default for a file type. Within the program, how do I find the name of the file which I am being asked to process (i.e. the file which a user double-clicked in Windows Explorer)? I am using Win7, but the most generic answer would be the best. Thanks.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 21, 2017 11:16 AM   in response to: Keith Mylon in response to: Keith Mylon
Keith Mylon wrote:

I have written a small program and have set it to be the default for
a file type. Within the program, how do I find the name of the file
which I am being asked to process (i.e. the file which a user
double-clicked in Windows Explorer)?

That depends on how exactly you registered your app, but the typical
scenario is to have the filename passed to the app via the command-line
when the app is started. In that case, you can use the RTL's
ParamCount() and ParamStr() functions to read the command-line
parameters.

--
Remy Lebeau (TeamB)
Keith Mylon

Posts: 2
Registered: 4/22/02
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 30, 2017 2:05 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
That depends on how exactly you registered your app, but the typical
scenario is to have the filename passed to the app via the command-line
when the app is started. In that case, you can use the RTL's
ParamCount() and ParamStr() functions to read the command-line
parameters.

--
Remy Lebeau (TeamB)
I changed the default program (Start/Default programs/Set associations) for an existing file type (.xls) to set my program as the default for opening that type. It launches my program, but does not seem to offer any command-line parameters, so I can not see how to tell what file was double-clicked. Setting file associations does not seem to offer any options for using parameters. Any further insight would be welcome, thanks.
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 30, 2017 4:21 AM   in response to: Keith Mylon in response to: Keith Mylon
El 30/12/2017 a las 11:05, Keith Mylon escribió:
Remy Lebeau (TeamB) wrote:
That depends on how exactly you registered your app, but the typical
scenario is to have the filename passed to the app via the command-line
when the app is started. In that case, you can use the RTL's
ParamCount() and ParamStr() functions to read the command-line
parameters.

--
Remy Lebeau (TeamB)
I changed the default program (Start/Default programs/Set associations) for an existing file type (.xls) to set my program as the default for opening that type. It launches my program, but does not seem to offer any command-line parameters, so I can not see how to tell what file was double-clicked. Setting file associations does not seem to offer any options for using parameters. Any further insight would be welcome, thanks.


When a user double-clicks the .xls file, the system executes the application and normally passes the file path to the
file as a parameter of the command line.

You should check for parameters on the command line by calling the ParamCount function and, if there are any, obtain the
file path by calling the ParamStr function.

You can do it in the application's startup or in the OnCreate event of the main form:

procedure TForm1.FormCreate(Sender: TObject);
var
   FileName: String;
begin
   if ParamCount>= 1 then
   begin
     FileName:= ParamStr(1);
     // Use FileName as needed
   end;
 
end;
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 4, 2018 12:49 PM   in response to: Antonio Estevez in response to: Antonio Estevez
Antonio Estevez wrote:

When a user double-clicks the .xls file, the system executes the
application and normally passes the file path to the file as a
parameter of the command line.

Again, that depends on the particular way in which the file extension
is registered. Executing the app with the filename as a command-line
parameter is the typical way, but it is not the only way.

You should check for parameters on the command line by calling the
ParamCount function and, if there are any, obtain the file path by
calling the ParamStr function.

You can do it in the application's startup or in the OnCreate event
of the main form:

Since command-line parameters are accessible globally, you are not
limited to just those two specific locations. You can call the Param
functions at any time from any code you want.

if ParamCount>= 1 then
begin
FileName:= ParamStr(1);
// Use FileName as needed
end;

Just be careful using the Param functions, as they both assume the
first command-line parameter is the filename of the calling process,
which is TYPICALLY BUT NOT ALWAYS TRUE!

--
Remy Lebeau (TeamB)
Paolo Valle

Posts: 39
Registered: 8/31/07
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 6, 2018 10:03 AM   in response to: Antonio Estevez in response to: Antonio Estevez
You suggest to put the code in the formCreate evnt, but which even it is triggered if the program is already running ?

thank you in advance.

Antonio Estevez wrote:
El 30/12/2017 a las 11:05, Keith Mylon escribió:
Remy Lebeau (TeamB) wrote:
That depends on how exactly you registered your app, but the typical
scenario is to have the filename passed to the app via the command-line
when the app is started. In that case, you can use the RTL's
ParamCount() and ParamStr() functions to read the command-line
parameters.

--
Remy Lebeau (TeamB)
I changed the default program (Start/Default programs/Set associations) for an existing file type (.xls) to set my program as the default for opening that type. It launches my program, but does not seem to offer any command-line parameters, so I can not see how to tell what file was double-clicked. Setting file associations does not seem to offer any options for using parameters. Any further insight would be welcome, thanks.


When a user double-clicks the .xls file, the system executes the application and normally passes the file path to the
file as a parameter of the command line.

You should check for parameters on the command line by calling the ParamCount function and, if there are any, obtain the
file path by calling the ParamStr function.

You can do it in the application's startup or in the OnCreate event of the main form:

procedure TForm1.FormCreate(Sender: TObject);
var
   FileName: String;
begin
   if ParamCount>= 1 then
   begin
     FileName:= ParamStr(1);
     // Use FileName as needed
   end;
 
end;
Douglas Rudd

Posts: 314
Registered: 5/16/97
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 8, 2018 12:30 AM   in response to: Paolo Valle in response to: Paolo Valle
Paolo Valle wrote:
You suggest to put the code in the formCreate evnt, but which even it is triggered if the program is already running ?

thank you in advance.
You mean if the program is already running and the user double-clicks on a .xls file?

The new parameter will only come when your program first starts.
I think Windows will start up another instance of your program.

Then how do you get the parameter over to the first instance?
When the second instance starts it will have to save the parameter it received and send it to the first instance and the then shut down the second instance.

How do you send it to the first instance? Probably with Windows SendMessage.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 8, 2018 11:47 AM   in response to: Douglas Rudd in response to: Douglas Rudd
Douglas Rudd wrote:
You mean if the program is already running and the user double-clicks on a .xls file?

The new parameter will only come when your program first starts.
I think Windows will start up another instance of your program.

By default, yes, if the file extension is registered to pass the filename as
a command-line value. But like I said, that is not the only way to setup a
file extension. For instance, you can register a file extension in such a way
that Windows will send the new filename to an existing instance of the
program (if one is already running) via DDE or ActiveX/COM instead. This
is the preferred solution for single-instance applications, instead of using
SendMessage() to send the filename from a new instance to a window of
an existing instance.

--
Remy Lebeau (TeamB)
Paolo Valle

Posts: 39
Registered: 8/31/07
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 9, 2018 9:33 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I would like to implement;
- double click on file and run the exe to open it (if the exe is not already running) : this was done with the suggestion here given via ParamCount and ParamStr
- double click on file and open it in the exe already running (duplicate exe run is not allowed in my case)
- drag and drop the file (or link to the file) on the running exe

any example of how implement last two cases ?

thank you in advance

Remy Lebeau (TeamB) wrote:
Douglas Rudd wrote:
You mean if the program is already running and the user double-clicks on a .xls file?

The new parameter will only come when your program first starts.
I think Windows will start up another instance of your program.

By default, yes, if the file extension is registered to pass the filename as
a command-line value. But like I said, that is not the only way to setup a
file extension. For instance, you can register a file extension in such a way
that Windows will send the new filename to an existing instance of the
program (if one is already running) via DDE or ActiveX/COM instead. This
is the preferred solution for single-instance applications, instead of using
SendMessage() to send the filename from a new instance to a window of
an existing instance.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 9, 2018 11:38 AM   in response to: Paolo Valle in response to: Paolo Valle
Paolo Valle wrote:

- double click on file and run the exe to open it (if the exe is
not already running) : this was done with the suggestion here given
via ParamCount and ParamStr

- double click on file and open it in the exe already running
(duplicate exe run is not allowed in my case)

That is best handled using DDE or COM instead of command-line
parameters. Let DDE/COM launch the EXE if it is not already running
(since they have to register themselves with the OS anyway) and pass
the filename to the existing DDE/COM server for you.

If you don't want to go that route, then register the file extension to
use command-line parameters, and then code the app to look for an
existing instance and if found then send the filename to that existing
instance using any IPC mechanism you want.

- drag and drop the file (or link to the file) on the running
exe

That requires implementing the COM IDropTarget interface and
associating with your window(s) at runtime.

https://blogs.msdn.microsoft.com/oldnewthing/20100503-00/?p=14183

Anders Melander wrote a Drag&Drop component library for Delphi that
implement this for you (see the TDropFileTarget component):

http://melander.dk/delphi/dragdrop/

The benefit of this approach is that IDropTarget can also handle the
double-click action as well, by implementing a COM server in the app
and have it implement IDropTarget, and then register that COM object's
CLSID in the Registry as the DropTarget for the file extension. That
way, when double-clicking the file, COM will check if the app is
already running, start it if needed, and then pass the filename to
IDropTarget. Doing this, it is possible to use the same IDropTarget
instance for both double-clicking and drag&drop.

--
Remy Lebeau (TeamB)
Paolo Valle

Posts: 39
Registered: 8/31/07
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 11, 2018 12:56 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
many thanks for this information...

Anders Melander wrote a Drag&Drop component library for Delphi that
implement this for you (see the TDropFileTarget component):

http://melander.dk/delphi/dragdrop/

The benefit of this approach is that IDropTarget can also handle the
double-click action as well, by implementing a COM server in the app
and have it implement IDropTarget, and then register that COM object's
CLSID in the Registry as the DropTarget for the file extension. That
way, when double-clicking the file, COM will check if the app is
already running, start it if needed, and then pass the filename to
IDropTarget. Doing this, it is possible to use the same IDropTarget
instance for both double-clicking and drag&drop.

--
Remy Lebeau (TeamB)
Paolo Valle

Posts: 39
Registered: 8/31/07
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 16, 2018 2:01 PM   in response to: Paolo Valle in response to: Paolo Valle
Paolo Valle wrote:
many thanks for this information...

surprisingly the drag-and-drop of data file on the exe link on desktop works without ant further coding (Windows 10) !

Anders Melander wrote a Drag&Drop component library for Delphi that
implement this for you (see the TDropFileTarget component):

http://melander.dk/delphi/dragdrop/

The benefit of this approach is that IDropTarget can also handle the
double-click action as well, by implementing a COM server in the app
and have it implement IDropTarget, and then register that COM object's
CLSID in the Registry as the DropTarget for the file extension. That
way, when double-clicking the file, COM will check if the app is
already running, start it if needed, and then pass the filename to
IDropTarget. Doing this, it is possible to use the same IDropTarget
instance for both double-clicking and drag&drop.

--
Remy Lebeau (TeamB)
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 8, 2018 4:37 AM   in response to: Paolo Valle in response to: Paolo Valle
Paolo Valle wrote:
You suggest to put the code in the formCreate evnt, but which even it is triggered if the program is already running ?

thank you in advance.

If the file extension is registered to execute the application with the file path as a command-line parameter the system will create a new instance of the application.

The application should check if another instance is already running and, if so, it should communicate with the other instance, send the file path and terminate itself.

This can be done, for example, by sending the WM_COPYDATA message to the window of the first instance.

The following application has a form with a PageControl. Every time the application is executed by passing the path of a file a new tab is created.

// Project source (.dpr)
begin
  if not InitAppInstance(TFormFileLoaderMain, 
                         'Unique Identifier For This Application') then Exit;
 
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TFormFileLoaderMain, FormFileLoaderMain);
  Application.Run;
end.

unit FileLoaderMain;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls;
 
type
  TFormFileLoaderMain = class(TForm)
    PageControl: TPageControl;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure WMCopyData(var Message: TWMCopyData); message WM_COPYDATA;
 
    procedure OpenFile(FileName:String);
  public
    { Public declarations }
  end;
 
var
  FormFileLoaderMain: TFormFileLoaderMain;
 
function InitAppInstance(WindowClass: TClass; Identifier: PChar): Boolean;
 
implementation
 
{$R *.dfm}
 
var
  AppMutex: THandle;
  OpenFileName: String;
  WM_OPEN_FILE: Cardinal;
 
function InitAppInstance(WindowClass: TClass; Identifier: PChar): Boolean;
var
  HWnd: THandle;
  Data: TCopyDataStruct;
begin
  Result:= True;
 
  if ParamCount>= 1 then
  begin
    OpenFileName:= ParamStr(1);
  end;
 
  AppMutex:= CreateMutex(nil, False, Identifier);
  if (AppMutex= 0) or (GetLastError= ERROR_ALREADY_EXISTS) then
  begin
    if Length(OpenFileName)> 0 then
    begin
      HWnd:= FindWindow(PChar(WindowClass.ClassName), nil);
      if HWnd<> 0 then
      begin
        Data.dwData:= WM_OPEN_FILE;
        Data.cbData:= Length(OpenFileName)*SizeOf(Char);
        Data.lpData:= PChar(OpenFileName);
        SendMessage(HWnd, WM_COPYDATA, 0, LPARAM(@Data));
      end;
    end;
    Result:= False;
  end;
end;
 
procedure TFormFileLoaderMain.FormCreate(Sender: TObject);
begin
  if Length(OpenFileName)> 0 then
  begin
    OpenFile(OpenFileName);
    OpenFileName:= EmptyStr;
  end;
end;
 
procedure TFormFileLoaderMain.WMCopyData(var Message: TWMCopyData);
var
  FileName: String;
  Data: PCopyDataStruct;
begin
  Data:= Message.CopyDataStruct;
  if Data.dwData= WM_OPEN_FILE then
  begin
    SetString(FileName, PChar(Data.lpData), Data.cbData div SizeOf(Char));
    OpenFile(FileName);
 
    if WindowState= wsMinimized then
      WindowState:= wsNormal;
    Application.BringToFront;
  end;
end;
 
procedure TFormFileLoaderMain.OpenFile(FileName:String);
var
  Tab: TTabSheet;
begin
  Tab:= TTabSheet.Create(Self);
  Tab.PageControl:= PageControl;
  Tab.Caption:= ExtractFileName(FileName);
 
end;
 
initialization
   WM_OPEN_FILE:= RegisterWindowMessage('WM_MY_OPEN_FILE');
 
end.
Robert Triest

Posts: 687
Registered: 3/24/05
Re: Identifying target file from within default program  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 8, 2018 4:34 AM   in response to: Keith Mylon in response to: Keith Mylon
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02