• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 233
  • Last Modified:

mail clients installed on system

using this article:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_adv/registeringapps.asp

i've written this code...

type
  PMailClient = ^TMailClient;
  TMailClient = record
    display : String;
    exeName : String;
    icon : HICON;
  end;

procedure GetMailPrograms;
var
  reg : TRegistry;
  names,shellOpen : string;
  exeName : string;
  canonicalName : string;
  canonicalNamesList : TStringList;
  mailClient : PMailClient;
  i : integer;
begin
  canonicalNamesList := TStringList.Create;
  canonicalNamesList.Clear;
  try
    reg := TRegistry.Create;
    reg.RootKey := HKEY_LOCAL_MACHINE;

    names := 'Software\Clients\Mail';
    if reg.OpenKey(names, false) then
    begin
      reg.GetKeyNames(canonicalNamesList);
      reg.CloseKey;

      for i := 0 to canonicalNamesList.Count - 1 do
      begin
        canonicalName := names + '\' + canonicalNamesList[i];
        if reg.OpenKey(canonicalName, false) then
        begin
          new(mailClient);
          mailClient.display := reg.ReadString('');
          reg.CloseKey;

          shellOpen := canonicalName + '\shell\open\command';
          if reg.OpenKey(shellOpen, false) then
          begin
            exeName := reg.readString('');
            mailClient.exeName := exeName;
            reg.CloseKey;
          end;

          MailClients.Add(mailClient);

        end;
      end;
    end;
  finally
    reg.Free;
  end;
  canonicalNamesList.Free;
end;

so, this grabs the mail clients installed just fine. but i'm tryint to do a bit more,

1) i want to get the default icon... this isn't working so well. i want to grab it as HICON
2) most of these "shell open" commands are formatted in such a way that ShellExecute won't run them..

example: rundll32.exe "%ProgramFiles%\INTERN~1\hmmapi.dll",OpenInboxHandler

can anyone complete this code for me???

i think Delphi not knowing what to do with %ProgramFiles% is the biggest problem, but just don't know the clean way to code this.
0
gwarguitar
Asked:
gwarguitar
  • 4
  • 3
  • 2
1 Solution
 
pcsentinelCommented:
Yes Delphi wont understand %Programs%, you need to substituts this for the program files folder

to do this add ActiveX and ShlObj to your uses clause then add the followinf 3 functions

function PidlToPath(IdList: PItemIdList): string;
begin
  SetLength(Result, MAX_PATH);
  if SHGetPathFromIdList(IdList, PChar(Result)) then
        SetLength(Result, StrLen(PChar(Result)))
  else
    Result := '';
end;

function PidlFree(var IdList: PItemIdList): Boolean;
var
  Malloc: IMalloc;
begin
  Result := False;
  if IdList = nil then
    Result := True
  else
  begin
    if Succeeded(SHGetMalloc(Malloc)) and (Malloc.DidAlloc(IdList) > 0) then
    begin
      Malloc.Free(IdList);
      IdList := nil;
      Result := True;
    end;
  end;
end;

function GetProgramsFolder: string;
var
  FolderPidl: PItemIdList;
begin
  if Succeeded(SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, FolderPidl)) then
  begin
    Result := PidlToPath(FolderPidl);
    PidlFree(FolderPidl);
  end
  else
    Result := '';
end;

The last function returns the item you want.

Then do a string replace as below

function StrReplace(Source, FindStr, ReplStr: string): string;
var
      li:integer;
begin
  Result := Source;
  li := Pos(FindStr,Source);
  if li > 0 then
  begin
    Delete(Result,li,Length(FindStr));
    Insert(ReplStr,Result,li);
  end;
end;

and do

label1.caption:=strreplace('%ProgramFiles%\INTERN~1\hmmapi.dll','%ProgramFiles%',GetDocumentsFolder);

this gives you the full path to your object

regards
0
 
pcsentinelCommented:
To get the icon you can use extracticon()

add shellapi to your uses clause and use

extracticon(HINSTANCE,pChar(strreplace('%ProgramFiles%\INTERN~1\hmmapi.dll','%ProgramFiles%',GetDocumentsFolder)),1);

regards
0
 
Russell LibbySoftware Engineer, Advisory Commented:

Actually, when reading from a REG_EXPAND_SZ value you should be using the environment to replace the values. The %value% may not just be ProgramFiles, it could also be WinDir, or any other path that is set in the environment.

It would be better to us a function like below when expanding the value:

function ExpandString(Value: String): String;
var  dwNewSize:     Integer;
     dwDefSize:     Integer;
begin

  // Set default length of result
  dwDefSize:=1024;

  // Allocate result size
  SetLength(result, dwDefSize);

  // Expand the environment strings
  dwNewSize:=ExpandEnvironmentStrings(PChar(Value), @result[1], dwDefSize);

  // Make sure the buffer was large enough
  if (dwNewSize > dwDefSize) then
  begin
     // Allocate buffer
     SetLength(result, dwNewSize);
     // Expand the environment strings
     dwNewSize:=ExpandEnvironmentStrings(PChar(Value), @result[1], dwNewSize);
  end;

  // Trim result to actual size
  SetLength(result, dwNewSize);

end;

And usage example:

 ShowMessage(ExpandString('%ProgramFiles%\Testing'));


Regards,
Russell


0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
gwarguitarAuthor Commented:
yeah! expandString seems to do it.

what about grabbing the arguments from there, though?
i just dont get how windows reads this..

the icon thing works that way, but the index isn't always 1... they throw it in there on the end, but it's all non standard, it kind of sucks. hehe
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Parsing args..

function ParseCommand(Command: String; List: TStrings): Integer;
var  lpszStr:       PChar;
     lpBuffer:      Array [0..4095] of Char;
     dwLength:      Integer;
begin

  // Check the list
  if Assigned(List) then
  begin
     // Lock update
     List.BeginUpdate;
     try
        // Clear the list
        List.Clear;
        // Check Command string
        if (Length(Command) > 0) then
        begin
           // Get pointer to start of string
           lpszStr:=PChar(Command);
           //  Parse the command string into individual pieces
           while (lpszStr^ > #0) do
           begin
              // Skip leading spaces (all chars below space as well as comma)
              while True do
              begin
                 while (lpszStr^ > #0) and ((lpszStr^ <= #32) or (lpszStr^ = ',')) do Inc(lpszStr);
                 if (lpszStr^ = '"') and (lpszStr[1] = '"') then
                    Inc(lpszStr, 2)
                 else
                    break;
              end;
              dwLength:=0;
              while (lpszStr^ > ' ') and (lpszStr^ <> ',') and (dwLength < SizeOf(lpBuffer)) do
              begin
                 if lpszStr^ = '"' then
                 begin
                    Inc(lpszStr);
                    while (lpszStr^ <> #0) and (lpszStr^ <> '"') do
                    begin
                       lpBuffer[dwLength]:=lpszStr^;
                       Inc(lpszStr);
                       Inc(dwLength);
                    end;
                    if (lpszStr^ > #0) then Inc(lpszStr);
                 end
                 else
                 begin
                    lpBuffer[dwLength]:=lpszStr^;
                    Inc(lpszStr);
                    Inc(dwLength);
                 end;
              end;
              // Null terminate the buffer
              lpBuffer[dwLength]:=#0;
              // Add param to the list
              List.Add(lpBuffer);
           end;
        end;
     finally
        // Unlock the list
        List.EndUpdate;
     end;
  end
  else
     // Parsed zero params
     result:=0;

end;

function ExpandString(Value: String): String;
var  dwNewSize:     Integer;
     dwDefSize:     Integer;
begin

  // Set default length of result
  dwDefSize:=1024;

  // Allocate result size
  SetLength(result, dwDefSize);

  // Expand the environment strings
  dwNewSize:=ExpandEnvironmentStrings(PChar(Value), @result[1], dwDefSize);

  // Make sure the buffer was large enough
  if (dwNewSize > dwDefSize) then
  begin
     // Allocate buffer
     SetLength(result, dwNewSize);
     // Expand the environment strings
     dwNewSize:=ExpandEnvironmentStrings(PChar(Value), @result[1], dwNewSize);
  end;

  // Trim result to actual size
  SetLength(result, dwNewSize);

end;

procedure TForm1.Button1Click(Sender: TObject);
var  list:          TStringList;
     szCommand:     String;
     szProgram:     String;
     dwIcon:        Integer;
begin

  szCommand:=ExpandString('rundll32.exe "%ProgramFiles%\INTERN~1\hmmapi.dll",OpenInboxHandler');

  // Create the list for results
  list:=TStringList.Create;
  try
     // Parse the command line into params
     ParseCommand(szCommand, list);
     // Display text
     ShowMessage(list.Text);
     // SAMPLE handling. This is not meant to be ALL INCLUSIVE, for as you have already said, this tends to
     // be non-standard
     if (list.Count > 0) then
     begin
        // Check first param. Either the program or rundll32.exe
        if (CompareText('rundll32.exe', list[0]) = 0) then
        begin
           // Better be a second param
           if (list.Count > 1) then
              szProgram:=list[1]
           else
              szProgram:=EmptyStr;
        end
        else
           // Module is the first item
           szProgram:=list[0];
        // Do whatever checking you need to do to get the icon (not sure without an example to go by)
        // Dummy the number to zero
        dwIcon:=0;
     end
     else
        szProgram:=EmptyStr;
     // Extract the icon
     if (Length(szProgram) > 0) then
     begin
        // Example of getting default icon
        Application.Icon.Handle:=ExtractIcon(hInstance, PChar(szProgram), 0);
     end;
  finally
     // Free the list
     FreeAndNil(list);
  end;

end;
0
 
gwarguitarAuthor Commented:
woohoo! right on, thanks!!! you never fail to impress me :)

one thing,

  ShellExecute(hInstance,'open',PChar(szProgram),PChar(szCommand),nil,0);


that doesn't work in the above example.... the hotmail one...
0
 
gwarguitarAuthor Commented:
wait.. i think i read that wrong. hehe

command is the full string...
err... i'm retarded :)
0
 
gwarguitarAuthor Commented:
score! winexec works fine with expand string.. i'll just use it!

thanks a lot!
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Glad it works. If you need to parse just the program / command line, then you could update the parsing routine to just split it once. The reason I split all pieces is because I though it would make it easier for you to extract the icon information (plus you asked how to split the command).

If you want an example of the updated routine, then just say the word

Regards,
Russell
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 4
  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now