Link to home
Start Free TrialLog in
Avatar of Mark Brady
Mark BradyFlag for United States of America

asked on

Return 'Filename' from windows explorer context menu

I have added an item to the windows context menu (right click on any file);
When clicked, my application opens so this is ok.

I need to know how to display the path and filename of the file that was right clicked on, so my application can deal with it.

Eg:      I have added 'Your File Path is '     to the right click context menu from my application,  This works fine.

           When I click on the context menu item 'Your File Path is'    it opens my application.  

           I want a procedure/ Function to do the following:

          ShowMessage (YourFilePath);

Please can someone show me how to get the filepath [eg:]  ('c:\test.txt')  from the file that was clicked in windows and return it to my program ?

Now here is the longer version :

When right clicking on any file in windows explorer the context menu has a choice that is ''Your File Path is'.   // I have achieved this.

When you click on it, my application is started //  I have achieved this

Here is where I need help !

I need to know how my application will know WHICH file was clicked on ?
It should return the full filepath including filename so my application can work with it.

The registry key I have added for context menu is......

C:\Documents and Settings\Spider\Desktop\program test\maxenc.exe "%1"

What does the "%1" mean and how can I modify this to open the file that was clicked ?

Thanks in advance.

Elvin

ASKER CERTIFIED SOLUTION
Avatar of 2266180
2266180
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Mark Brady

ASKER

Hi Ciuly

I tried that code in my application.  Where should I execute it ?  OnFormCreate ?   I just tried it as a separate procedure and selected a file in Windows Explorer, then swapped to my application and ran the procedure but it always has a paramcount <1 so it's not recognising that a file has been selected in windows.

Can you maybe show me a small example ?

Thanks
Elvin
Ciuly

I got it working by changing your line

//  if paramcount>1 then

to

if paramcount>0 then

Now it works and returns the path and filename to the application.  Was that a typo or is there something I should know about paramcount ?

Now that it is working, perhaps you could give advise on how to achieve this...

If a user right clicks on a file with a certain extention [eg] '.lok' then how to add to context another entry of say.... 'Unlock'          So my application will know which procedure to carry out depending on the file extention that was loaded into the application.

Elvin
>> Now it works and returns the path and filename to the application.

well, that's not what you wanted, is it? yuo wanted to have the filename passed as the parameter, which will normally reside in paramstr(1).

paramcount returns the number of parameters. if paramcount =0, it means there are no parameters. paramstr returns the values of the parameter, OR, if the index is 0, returns the application path/name.

since your applicaiton is not beeing executed with a parameter, why did you enter in the registry the %1? makes no sense.

I am guessing you are doing this all wrong. bulding a context menu handler requires knowledge of COM. I thought you already have it, given the way you presented your problem by everything "working". but if you don't even know what paramcount and paramstr are ... that means I'm in for a lot more pain than initially thought.

so, let's make this easier for both of us. here is a nice article with a context menu handler: http://www.delphi3000.com/articles/article_2926.asp?SK=
works for one selected file.
if you look for function TContextMenu.IShellExtInit_Initialize you will see there how he gets the selected filename. if you need the extension, use extractfileext function.

if you will still encouter problems, post the entire project in a zip somewhere and post the link here. In this case, I think I'd rather see what you do and not assume anything :)
Sorry buddy what I meant to say was if I select a single file then run your example code, it was not returning the filename.  I figured out that your line paramcount>1 was looking for more than 1 perameter when there was only 1 perameter.  I changed it to >0 so it would recognise the file that was selected.

Am I confused ?   Probabaly but it worked once I changed it.

//  Here is the form data

object Form1: TForm1
  Left = 0
  Top = 0
  VertScrollBar.Visible = False
  BorderIcons = []
  BorderStyle = bsNone
  ClientHeight = 95
  ClientWidth = 202
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  OnShow = FormShow
  PixelsPerInch = 96
  TextHeight = 13
  object Label2: TLabel
    Left = 379
    Top = 464
    Width = 3
    Height = 13
  end
  object Label1: TLabel
    Left = 8
    Top = 8
    Width = 4
    Height = 16
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clTeal
    Font.Height = -13
    Font.Name = 'Tahoma'
    Font.Style = [fsBold]
    ParentFont = False
  end
end

// And the unit

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, registry;

const
  DirExtensionKey = 'Directory\shell\encrypt';
  FileExtensionKey = '*\shell\';
  SubKey = '\command';
  ContextName= 'Lock-Unlock File';

  type
  TForm1 = class(TForm)
    Label2: TLabel;
    Label1: TLabel;
    procedure Lock(Sender: TObject);
    procedure Unlock(Sender: TObject);
    procedure AddEntryToExplMenu(Adding:boolean);
    procedure FormCreate(Sender: TObject);
    procedure GetFileName(Sender: TObject);
    procedure FormShow(Sender: TObject);




  private
    { Private declarations }
  public

end;
var
  Form1: TForm1;
  FileSelected : TFilename;

implementation

{$R *.dfm}

procedure TForm1.GetFileName(Sender: TObject);
var
Filename, ext : string;

begin
if paramcount>0 then
Filename := (paramstr(1))
else
exit;
label1.Caption := (Filename);
ext := extractFileExt (Filename);
if ext = '.loc' then
Unlock(sender)
else
lock(Sender);
end;

function ReverseFileBytes(const Infile, OutFile: String): Boolean;
var
FileRead, FileWrite: TFileStream;
FileSize, i, x,z: Integer;
bt: Byte;
psw : string;
label pswcheck;

begin
Result := False;
pswcheck :
psw := inputbox ('Enter a password','Password','');

z := 32 - length(psw);
for i := 1 to z do
psw := psw + ' ';

FileRead := TFileStream.Create(InFile, fmOpenRead or fmShareDenyWrite);
try
  FileWrite := TFileStream.Create(OutFile, fmCreate or fmOpenWrite or fmShareDenyWrite);
  FileSize := FileRead.Size;
  if FileSize < 1 then Exit;

  FileWrite.Seek(0, soFromBeginning);
  FileWrite.write(psw[1], 32);


  for i := 1 to FileSize do
    begin
    FileRead.Seek(-i, soFromEnd);
    FileRead.Read(bt, 1);
    FileWrite.Write(bt,1);
    end;


  Result := True;
  finally
  FreeAndNil(FileRead);
  FreeAndNil(FileWrite);
  end;
end;

function UnlockFile(const Infile, OutFile: String): Boolean;
var
FileRead, FileWrite: TFileStream;
FileSize, i, x: Integer;
bt: Byte;
psw,password : string;
label NoCanDo;
begin
Result := False;

FileRead := TFileStream.Create(InFile, fmOpenRead or fmShareDenyWrite);

setlength(psw,32);
  FileRead.Seek(0, soFromBeginning);
  FileRead.read(psw[1], length(psw));

  NoCanDo :
  password := inputbox ('Enter the password','Password','');
  if password = '' then
  Goto NoCanDo;
  if password <> (trim(psw)) then
  begin
    FileRead.Free;
    exit;
  end;

  try
  FileWrite := TFileStream.Create(OutFile, fmCreate or fmOpenWrite or fmShareDenyWrite);
  FileSize := FileRead.Size;
  if FileSize < 1 then Exit;

      for i := 1 to FileSize - 32 do
    begin
    FileRead.Seek(-i, soFromEnd);
    FileRead.Read(bt, 1);
    FileWrite.Write(bt,1);
    end;


  Result := True;
  finally
  FreeAndNil(FileRead);
  FreeAndNil(FileWrite);
  end;
end;


PROCEDURE TForm1.AddEntryToExplMenu(Adding:boolean);
var
  reg: TRegistry;
begin
  try
    reg := TRegistry.Create;
  except
    Exit;
  end;
  if Adding then
    with reg do
    begin
      RootKey := HKEY_CLASSES_ROOT;
      OpenKey(FileExtensionKey, Adding);
      WriteString('', ContextName);
      CloseKey;
      OpenKey(FileExtensionKey + ContextName+SubKey, Adding);
      WriteString('', ParamStr(0) + ' "%1"');
      CloseKey;
    end
  else
    with reg do
    begin
      RootKey := HKEY_CLASSES_ROOT;
      DeleteKey(FileExtensionKey + ContextName);
      CloseKey;
    end;
  reg.Free;
END;



Procedure TForm1.Lock(Sender: TObject);
var
fname, ext, realname,s : string;
i,x : integer;
begin
fname := label1.caption;
if Fname = '' then
exit;
realname := ExtractFileName(fname);

if ReverseFileBytes(fname, Realname + '.loc') then
  ShowMessage('The file has been Locked');

end;


Procedure TForm1.Unlock(Sender: TObject);
var
fname, ext, realname,s : string;
i,x : integer;
begin
fname := label1.caption;
if Fname = '' then
exit;
ext := ExtractFileExt(fname);
realname := ExtractFileName(fname);

x := pos('.loc',realname);
for I := 1 to x-1 do
begin
s := s + realname[i];
end;
if UnlockFile(fname, s) then
  ShowMessage('The file has been Unlocked');

end;


procedure TForm1.FormCreate(Sender: TObject);
begin
AddEntryToExplMenu(true);
GetFileName(sender);
end;


procedure TForm1.FormShow(Sender: TObject);
begin
close;
end;

end.


// This should be a console app but I haven't worked that out to do yet ?
yep. that was my mistake explaining. it's >=1, you're right. then I read "Now it works and returns the path and filename to the application. " and thought you meant
"Now it works and returns the path and filename of the application". guess I wasn't woken up fully :D

then we go to the next stage:

"If a user right clicks on a file with a certain extention [eg] '.lok' then how to add to context another entry of say.... 'Unlock'          So my application will know which procedure to carry out depending on the file extention that was loaded into the application."

in order to be able to achieve this, you must write a COM class which will be a context menu handler. just in teh link I gave you on delphi3000.zom. there is no way around it. basically, when the context menu is created, explorer will call some methods in your com class which will tell it IF to create any menues, and what menues to create depending on the selected object (file, directory, etc)

so you need to make it a COM object, which basically means that you will not be able to make it a console application.
it won't be any kind of aplication, it will be a dll. refer to that article for more info.
Thanks Ciuly

I'm going to accept your first answer (even though there was a typo) as I now have this working to my satisfaction.  I read the info in your link but considering it is a large process just to add one more command to the context menu, I have rewritten my app code so it looks for the file extention and processes the file according to what the extention is.  Only one entry in the context menu 'Lock-Unlock'

When that is clicked it runs my app and either locks or unlocks the file that was selected.  

I was prefering to have this as a console app as I have nothing on the form and the form is never displayed but for now I will deal with closing the app on formshow.

I will rerad more on console app;ications and modify my code to suit later.

Thanks for your help buddy....

Elvin
I can work with what you gave me even though there was a typo I worked it out.  Thanks for the answer Ciuly
for a small mistake, a typo, you give me a B grade? very nice. well, if you think that an A grade is given only for a perfect, flawless answer, then I think, no, I KNOW, that you are now the 12th person on my blacklist: which means that I will no longer answer your questions.

have a nice one.

PS: no need to answer, I unsubscribed from this question.