Solved

Command Line

Posted on 2001-07-05
36
214 Views
Last Modified: 2010-04-06
I once thought this was a simple exercise in cutting strings, but only now I started to comprehend how sophisticated this combina is.

OK, I have a command line string of an application (many, actually - TStrings, but I process them uno by uno). I need to strip them off their parameters and unify them (i.e. UpperCase(ExtractShortPathName())   ).

I use this function, and it is rather good, but it only works for 70 percent of the cases, the others seem to slip away. I have broken my head trying to find a common pattern to all the command line, but could not distinguish more than I already did(without actually searching for the files).

Function StripParams(Path:String):string;
Const
PossibleParams='/*?"><|';
var
Temp:String;
Posit,i:integer;
begin
  Temp:=Path;
    For i:=1 to Length(PossibleParams) do
      begin
        Posit:=pos(PossibleParams[i],Temp);
        if posit>0 then
          Temp:=Copy(Temp,1,Posit-1);
      end;
    //Maybe in Windows or Windows system directory and path not given?
    If ExtractFilePath(Temp)='' then
      begin
        if FileExists(MainForm.WinDir+Temp) then
          Temp:=MainForm.WinDir+Temp
        else if FileExists(MainForm.SysDir+Temp)then
          Temp:=MainForm.SysDir+Temp;
      end;
    Temp:=UpperCase(ExtractShortPathName(Temp));
   Result:=Temp;
end;



Here are some strings that slipped away(taken from my registry autorun section for sake of testing):

Rundll32.exe powrprof.dll,LoadCurrentPwrScheme
"C:\Program Files\Common Files\Symantec Shared\Script Blocking\SBServ.exe" -reg



Alright, as you see this func is far from perfect (the number 70 is just an estimate) so all suggestions for improvement would be welcome.
0
Comment
Question by:duke_n
  • 16
  • 11
  • 8
  • +1
36 Comments
 
LVL 1

Expert Comment

by:bnemmers
ID: 6257408
Duke,

Have you look at two function
FindCmdLineSwitch and ParamStr in Sysutils.pas and System.pas
0
 
LVL 1

Author Comment

by:duke_n
ID: 6257474
this is no good.
'-' and ' ' can be part of a file or dir name also!
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6257493
Then the job will be impossible. How do you know if -reg is a file/dir or a switch?
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6257499
And if a file or dir has a ' ', it must be between double-quotes.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6257530
if I use you string as parameter and use this code

var i: Integer;
begin
  for i := 0 to ParamCount do
    Memo1.Lines.Add(Format('ParamStr(%d) = %s', [i, ParamStr(i)]));

I get this output:

ParamStr(0) = C:\WINDOWS\DESKTOP\PARAMS\PROJECT1.EXE
ParamStr(1) = Rundll32.exe
ParamStr(2) = powrprof.dll,LoadCurrentPwrScheme
ParamStr(3) = C:\Program Files\Common Files\Symantec Shared\Script Blocking\SBServ.exe
ParamStr(4) = -reg


A lot easier to handle IMHO.
0
 
LVL 1

Author Comment

by:duke_n
ID: 6258466
wait a second.
doesn't paramstr get the parameter string of the current application?

are you saying there is a way to apply it to an abstract string(Remember-I am not getting those command line strings as my command line param - but rather from inside the GUI)?
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6258516
ParamStr(0) and Application.ExeNam contain the current app (see my previous comment).
0
 
LVL 1

Author Comment

by:duke_n
ID: 6258663
Yes, but I do not get these stringss into my app command line param (look MY previous comment :)  )
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6258689
I'm using these functions which work fine for me. Hmmm... They need my unit madStrings, which is available for free from my homepage. It's inside the "madBasic" package.

function ExtractExefile(pathWithPara: string) : string;
var c1 : cardinal;
begin
  result := pathWithPara;
  c1 := 0;
  repeat
    c1 := PosChars([' ','"'], result, c1 + 1);
    if (c1 > 0) and (result[c1] = '"') then
      c1 := PosStr('"', result, c1 + 1);
  until (c1 = 0) or (result[c1] = ' ');
  if c1 > 0 then Delete(result, c1, maxInt);
  KillChar(result, '"');
  TrimStr(result);
end;

function ExtractParameters(pathWithPara: string) : string;
var c1 : cardinal;
begin
  result := pathWithPara;
  c1 := 0;
  repeat
    c1 := PosChars([' ','"'], result, c1 + 1);
    if (c1 > 0) and (result[c1] = '"') then
      c1 := PosStr('"', result, c1 + 1);
  until (c1 = 0) or (result[c1] = ' ');
  if c1 > 0 then result := RetTrimStr(RetDelete(result, 1, c1))
  else           result := '';
end;

Regards, Madshi.

http://www.madshi.net
http://help.madshi.net/Data/madStringsUnit.htm
0
 
LVL 1

Author Comment

by:duke_n
ID: 6258807
Dude, your page has quite a design.
Bene, I will check it out.
0
 
LVL 1

Author Comment

by:duke_n
ID: 6258861
nope, both functions return '' in 100% of the cases.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6259099
What!? I can't believe that! I just tested it again and it works perfectly!

Try this:

MessageBox(0, pchar(ExtractExeFile(cmdLine)), 'our exe', 0);

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6259104
Please recheck it, I'm absolutely sure that my functions do work correctly... Thank you...
0
 
LVL 1

Author Comment

by:duke_n
ID: 6259285
Oh, right :)
I forgot to do a lil' thing there.


However your function does not work always.
I keep getting 'C:\Program' out of everything from C:\program files\something
0
 
LVL 1

Author Comment

by:duke_n
ID: 6259297
I got an idea.
we can combine our 2 functions so that if mine returns bad stuff then we use yours and vise versa.
0
 
LVL 13

Accepted Solution

by:
Epsylon earned 100 total points
ID: 6259380
I've rewritten the ParamStr and ParamCount function:


function GetParamStr(P: PChar; var Param: string): PChar;
var
  Len: Integer;
  Buffer: array[0..4095] of Char;
begin
  while True do
  begin
    while (P[0] <> #0) and (P[0] <= ' ') do Inc(P);
    if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
  end;
  Len := 0;
  while (P[0] > ' ') and (Len < SizeOf(Buffer)) do
    if P[0] = '"' then
    begin
      Inc(P);
      while (P[0] <> #0) and (P[0] <> '"') do
      begin
        Buffer[Len] := P[0];
        Inc(Len);
        Inc(P);
      end;
      if P[0] <> #0 then Inc(P);
    end else
    begin
      Buffer[Len] := P[0];
      Inc(Len);
      Inc(P);
    end;
  SetString(Param, Buffer, Len);
  Result := P;
end;

function ParamCountEx(command: String): Integer;
var
  P: PChar;
  S: string;
begin
  P := GetParamStr(PChar(command), S);
  Result := 0;
  while True do
  begin
    P := GetParamStr(P, S);
    if S = '' then Break;
    Inc(Result);
  end;
end;

function ParamStrEx(Index: Integer; command: String): string;
var
  P: PChar;
  Buffer: array[0..260] of Char;
begin
  P := PChar(command);
  while True do
  begin
    P := GetParamStr(P, Result);
    if (Index = 0) or (Result = '') then Break;
    Dec(Index);
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
    s: String;
begin
  s := 'Rundll32.exe powrprof.dll,LoadCurrentPwrScheme "C:\Program Files\Common Files\Symantec Shared\Script Blocking\SBServ.exe" -reg';
  for i := 0 to ParamCountEx(s) do
    Memo1.Lines.Add(ParamStrEx(i, s));
end;
0
 
LVL 1

Author Comment

by:duke_n
ID: 6259950
Epsylon, the effectiveness of your string is exactly like madshi's. If a path has a space in it(i.e. Program Files), the path is whacked.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6259966
It works fine here as long as the entire path is between "".
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 13

Expert Comment

by:Epsylon
ID: 6259979
There is no other way to know these part belong together without some pre-knowledge.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6260065
Epsylon is right. But what you could do is this:

Check whether the exe returned by Epsylons or my function does exist (GetFileAttributes(...) <> dword(-1)). If yes, you're done. If not, append the first parameter to the exefile. Does it exist now? If yes, you're done. If not, append the second parameter to the exefile and so on...

Regards, Madshi.
0
 
LVL 1

Author Comment

by:duke_n
ID: 6260437
hmmm.
That is not a foolproof situation either. there could be a file or folder named c:\program .......


but I see that this is the best we can have.
OK, it is obvious how one appends later params with Epsylon's function, but it is not obvious how to do so with madshi's.

so I give Epsylon the pts.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6260561
ok
0
 
LVL 1

Author Comment

by:duke_n
ID: 6260590
sorry, mate.
the bloody comp has stuck.
I will accept in a sec :)
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6260633
Thanks  :o)
0
 
LVL 1

Author Comment

by:duke_n
ID: 6261434
Oops, haha, when I checked it, the idea didn't work :)

here is what I do:
    For i:=0 to ParamCountEx(Path) do
      if not FileExists(Temp) then
        Temp:=Temp+ParamStrEx(i,Path);


The reason it doesn't work is that it cuts out the param modifiers:
'C:\Program Files'='C:\Program'+'Files'='C:\ProgramFiles'.

so we are back where we were (My function up there ^ still is more effective, I think)
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6262369
Madshi, did you get a notification of duke_n last comment? I didn't. There seems to be a major bug in EE  :o((((
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6262378
duke_n, I'm puzzled... it cuts out param modifiers?
0
 
LVL 1

Author Comment

by:duke_n
ID: 6262408
I mean spaces,slashes and stuff.
does it not?
:)
0
 
LVL 1

Author Comment

by:duke_n
ID: 6262409
ah, the bug you've mentioned seems to be far worse.
did you know that I cannot see this question in my asked Qs list??
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6262422
Wow, just now I got notification about 2 comments. So I lost at least 3 notifications...   :-(
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6262430
About the problem: An ugly but possible solution would be this:

procedure SplitToExeFileAndParams(cmdLine: string; var exeFile, params: string);
var i1 : integer;
begin
  i1 := Length(ParamStrEx(1, cmdLine));
  while (i1 < Length(cmdLine)) and (not FileExists(Copy(cmdLine, 1, i1)) do
    inc(i1);
  exeFile := Copy(cmdLine, 1, i1);
  params  := Copy(cmdLine, i1 + 1, maxInt);
end;

Regards, Madshi.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 6262434
> did you know that I cannot see this question in my asked Qs list??

Now you mention it, I've have that too.

EE is doomed! They don't fix anything.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6262435
Ehm, the first code line should be this of course:

 i1 := Length(ParamStrEx(0, cmdLine));
0
 
LVL 1

Author Comment

by:duke_n
ID: 6262618
Yeah, they should hire us-fine programmers :)
0
 
LVL 1

Author Comment

by:duke_n
ID: 6262927
Madshi, this doesn't work(on the same stuff that my function doesn't work).

You know what, never mind. I see that my function was better than I thought it to be :)

I guess I will just leave it as it is
0
 
LVL 1

Author Comment

by:duke_n
ID: 6262931
And Epsylon, I think that EE has a special topic section for bug reports(that was a pretty smart thing to do for them, hehe).

I don't think that reporting these bugs in the Delphi section will get the Fixers' attention.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
How to run this video in webbrowse ? 2 68
Save pdf file to other location 3 72
find a node in VST 2 46
select query - oracle 16 81
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now