Files associated to which program?

Hi, all

How do I know from inside a regular non-elevated exe clarion program, to which program is associated a given file extension? For example, I want to use Shellexecute to open a JPG, but before that I want to know if the JPG extension is associated with MSPaint or any other program, to execute different code previous to the call.

Kind regards,
Jorge Lavera

FindExecutable

Search for that and read MSDN there are other ways

HINSTANCE FindExecutableA(
  [in]           LPCSTR lpFile,
  [in, optional] LPCSTR lpDirectory,
  [out]          LPSTR  lpResult
);

This should be close for Clarion map

FindExecutable PROCEDURE( |
       *CSTRING lpFile, |
      <*CSTRING lpDirectory>, |
       *CSTRING  OutResult |
       ),LONG,PASCAL,RAW,DLL(1),NAME('FindExecutableA') ! Returns  HINSTANCE >=33 indicates Success

Error 31 for No Assoc seems likely. There’s are the same as Shell Execute

SE_ERR_FNF  Equate(2) !The specified file was not found.
SE_ERR_PNF  Equate(3) !The specified path is invalid.
SE_ERR_ACCESSDENIED  Equate(5) !The specified file cannot be accessed.
SE_ERR_OOM  Equate(8) !The system is out of memory or resources.
SE_ERR_NOASSOC  Equate(31) !There is no association for the specified file type with an executable file.

Thank you! that worked perfectly.

This is in a legacy program.
In the global embeds, inside the global map:

    MODULE('shell32.dll')
        FindExecutableA(*cstring,*cstring,*cstring),LONG, PASCAL, RAW, NAME('FindExecutableA')
    END

Several sources recommend to use FindExecutableW instead of FindExecutableA, don’t bother, it doesn’t work with Clarion.
You will need some local variabes:

l:File                      CSTRING(2049)
l:Directory                 CSTRING(2049)
l:Result                    CSTRING(2049)
L:Executable                STRING(256)
L:Status                    LONG

And, assign your variables to the call:

L:File = clip(YourfFlenameOnly)
L:directory = clip(YourPathOnly)
L:Status = FindExecutableA(L:File,L:Directory,L:Result) 
L:Executable = st.FilenameOnly(L:Result)

I used Capesoft’s StringTheory to quickly get the filename only, from the result, as it is returned with fully path. You can, of course, use your own code or other tool for that.

That’s it!
Then you can, for example:

if lower(clip(L:Executable)) = 'mspaint.exe' then
    !Do whatever
end

Kind regards,
Jorge Lavera

1 Like

The W affix/suffix is used to denote Wide Char aka Unicode, and the A is used to denote Ansi aka Windows Code Page.

Most of the time you’ll be using A suffix API’s, but some Windows API’s only exist in a W suffix form, so besides using that W suffix API you’ll also have to use API’s to convert the Unicode string back to Ansi and vice versa as described here:

Dot Net is similiar with the A & W suffixes.

In previous versions of .NET, both the CoreCLR and Mono runtimes add an A or W suffix to the export name during export discovery for P/Invokes on all platforms.

In .NET 5 and later versions, an A or W suffix is added to the export name during export discovery on Windows only. On Unix platforms, the suffix is not added. The semantics of both runtimes on the Windows platform remain unchanged.

The File Name is simply after the Last Backslash, if there is one.

It’s not well known but INSTRING(,,-1,End Len) can search in Reverse with a Step of -1 and Start at the End of the String i.e. its SIZE() or LEN(). Code below finds the Last Backslash.

    L:Executable = L:Result
    LastBS=INSTRING('\',L:Executable,-1,SIZE(L:Executable))  !Find \program.exe after c:\path
    L:Executable=SUB(L:Executable,LastBS+1,999)

For a CSTRING the LEN() is correct to avoid possible garbage after the Chr(0) that SIZE() would search:


    LastBS=INSTRING('\',L:Result,-1,LEN(L:Result))  !Find \program.exe after c:\path
    L:Executable=SUB(L:Result,LastBS+1,999)
1 Like