October 30, 2025, 05:15:07 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Question about my code using the System or ShellExecute Commands

Started by Del, September 16, 2008, 04:37:07 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Del

Firstly I would like to thank people so far with the help I have had and used from within the forums.
New to Emergence from Visual Basic environment so generally learning to translate VB thinking to this one.
I am creating an executable that can be called by giving the 2 parameters of the file extension and the file name.
like -- >
Quote"OpenExtApp.exe" MSG "S:\Application Development\OpenExtApp\0032738.MSG"
There are reasons for needing to be given the extension rather than just pulling it from the file but that is superfluos

My code is as follows - yes it is messy :) first attempt and I will comment and clean it up once I can stop making changes to it.
Quote
DECLARE "shell32.dll", CommandLineToArgv alias CommandLineToArgvW(lpCmdLine:STRING, pNumArgs:WORD),POINTER
DECLARE "kernel32.dll",GetCommandLine alias GetCommandLineW(),STRING
DECLARE "kernel32.dll",GlobalFree(hMem:UINT),INT
DECLARE IMPORT,WideCharToMultiByte(codepage:UINT,dwFlags:UINT,lpWideStr:POINTER,cchWideStr:INT,lpMultiByteStr:POINTER,cchMultiByte:INT,lpDefaultChar:POINTER,lpUsedDefault:POINTER),INT
CONST CP_ACP = 0

' Parameter 1 - Extension
' Parameter 2 - Filename to be opened

DEF Args[50]:String
DEF NumArgs:INT

DEF pszArglist:pointer
DEF strTemp:WORD
DEF nArgs:WORD
DEF pszArglist1:pointer
DEF strTemp1:WORD
DEF nArgs1:WORD
DEF I:INT
DEF ExtParam:STRING
DEF FileParam:STRING 
DEF AppPath:STRING
DEF iStat as UINT
DEF strA:STRING
DEF strB:STRING
DEF strC:STRING
DEF strD:STRING
DEF strE:STRING
DEF strF:STRING
DEF AppExe:STRING

$include "Registry.inc"

pszArglist = CommandLineToArgv(GetCommandLine(), &nArgs)
Buffer = ""
IF nArgs=3 THEN
   WideCharToMultiByte(CP_ACP,0,*<STRING>*<POINTER>(pszArglist+(4)),-1,ExtParam,254,NULL,NULL)
   WideCharToMultiByte(CP_ACP,0,*<STRING>*<POINTER>(pszArglist+(8)),-1,FileParam,254,NULL,NULL)
   WideCharToMultiByte(CP_ACP,0,*<STRING>*<POINTER>(pszArglist+(0)),-1,AppExe,254,NULL,NULL)
   strA =RegGetValue("HKEY_CLASSES_ROOT\\."+ExtParam)
   strB=RegGetValue("HKEY_CLASSES_ROOT\\" + strA + "\\shell\\Open\\command")
   iStat = INSTR(strB,"%1")-1
   strC = LEFT$(strB,iStat) + FileParam + RIGHT$(strB,LEN(strB)-iStat-2)
   ParseString(strC)
   
   strD = Args[1]

   strE = RIGHT$(strC,LEN(strC)-LEN(strD))
   strF = LEFT$(strC,LEN(strD))
iStat = ShellExecute(strF,strE, "", "open", 5)
END IF
END



Sub ParseString(CmdLine:STRING)
   DEF aChar: STRING 
   DEF aString:STRING
   DEF escBackslash:INT
   DIM inQuote:INT
   DIM I:INT

   NumArgs=0
   If LEN(CmdLine)>0 then
      escBackSlash=0
      inQuote=0
      aString =""
      For I=1 to LEN(CmdLine)
         aChar = MID$(CmdLine,I,1)
         Select aChar
            Case Chr$(34)
               IF inQuote=1 THEN
                  inQuote = 0
               ELSE
                  inQuote = 1
               ENDIF
               aString = aString + aChar               
            Case " "
               If inQuote=0 THEN
                  NumArgs = NumArgs + 1
                  Args[NumArgs]=aString
                  aString = ""
               ELSE
                  aString = aString + aChar                  
               ENDIF
               escBackSlash=0
            DEFAULT
               aString = aString + aChar
               escBackSlash=0
         ENDSELECT
      NEXT I
      if aString<>"" THEN
         NumArgs = NumArgs + 1
         Args[NumArgs]=aString
         aString = ""
      ENDIF
   ENDIF
EndSub





'===============================================================================
'
' Description:      Attempts to shell execute (launch via the shell) an operation on a file or command.
' Syntax:           UINT iResult = ShellExecute(sFileOrCommand, sParam="", sWorkDir="", sType="Open", iShowFlag=5)
' Parameter(s):     sFileOrCommand - string, filename or command name to execute
'               sParam - optional string, parameter for the file or command (default = "")
'               sWorkDir - optional string, working directory for file or command (default = "")
'               sType - optional string, the verb specifying the type of context operation to perform (default = "open")
'                     Some working examples are "open", "explore", "edit", "print", "properties", etc.
'               iShowFlag - optional integer indicating how Windows should display the executed process (default = SW_SHOW = 5)
'                     Some possible values:
'                        0 = SW_HIDE (the window/process is launched invisibly, and is activated)
'                        2 = SW_SHOWMINIMIZED (minimized at launch)
'                        3 = SW_MAXIMIZE (shown, maximized at launch, and activated)
'                        4 = SW_SHOWNOACTIVATE (shown, but not activated)
'                        5 = SW_SHOW (shown, activated, displayed in last used size & position)
' Requirement(s):   Emergence Basic (any version)
' Return Value(s):  On Success - Returns instance handle of launched process (a UINT > 32)
'                   On Failure - Returns a UINT value less than or equal to 32
'                  Some possible returned errors:
'                     2 = SE_ERR_FNF (file not found)
'                     3 = SE_ERR_PNF (path not found)
'                     5 = SE_ERR_ACCESSDENIED (access denied)
'                     8 = SE_ERR_OOM (out of memory)
'                     11 = ERROR_BAD_FORMAT (invalid EXE file or error in EXE image)
'                     26 = SE_ERR_SHARE (a sharing violation occured)
'                     27 = SE_ERR_ASSOCINCOMPLETE (incomplete or invalid file association)
'                     28 = SE_ERR_DDETIMEOUT (DDE timeout)
'                     29 = SE_ERR_DDEFAIL (DDE transaction failed)
'                     30 = SE_ERR_DDEBUSY (DDE busy)
'                     31 = SE_ERR_NOASSOC (no association for file extension)
'                     32 = SE_ERR_DLLNOTFOUND (DLL not found)
' Author(s):        SEO <locodarwin at yahoo dot com>
' Note(s):          This routine does not perform internal error checking and instead relies upon error checking provided
'               by the ShellExecuteA() WinAPI function.
'
'               Be careful when using a iShowFlag of 0, as the process you've launched will then be invisible and will
'               have to be terminated through task manager (or programmatically) if it does not terminate itself.
'
'               Also, the string value for sType represents verbs that are possible for that file, in context.  Using
'               a verb that doesn't apply to the file or command launched will result in an error.  Windows will do its
'               best to infer what you mean in all cases, based on file associations and file types.
'
'===============================================================================
Sub ShellExecute(sFileOrCommand as STRING, Opt sParam as STRING, Opt sWorkDir as STRING, Opt sType="Open" as STRING, Opt iShowFlag=5 as INT), UINT
   
   DECLARE IMPORT, ShellExecuteA(hwnd as UINT, pOp as POINTER, pFile as POINTER, pParam as POINTER, pDir as POINTER, nShow as INT), UINT
   
   UINT iRet
   iRet = ShellExecuteA(0, sType, sFileOrCommand, sParam, sWorkDir, iShowFlag)
   Return iRet
EndSub


and from this I end up with a command line this
Quote%SystemRoot%\System32\rundll32.exe "%ProgramFiles%\Windows Photo Gallery\PhotoViewer.dll", ImageView_Fullscreen S:\Application Development\OpenExtApp\0032385.TIF

When used directly from a command prompt works perfectly but when applied to the ShellExecute it does nothing
If anyone could help it would be greatly appreciated
TIA


sapero

Dello Del, I see you have an envinronment variable in the command line. When you run it from the command prompt, the shell parser does expand all envinronment variables before continuing.
There is special function for this: ExpandEnvironmentStrings

declare import, ExpandEnvironmentStringsA(string source, string destination, int destSize),int

' paste this before ShellExecute to expand envinronment variables from sFileOrCommand to new, dynamic string pszCommandLine
pointer pszCommandLine
int requiredSize

' this dummy call to ExpandEnvironmentStrings will return lenght of expanded sFileOrCommand
requiredSize = ExpandEnvironmentStringsA(sFileOrCommand, pszCommandLine, 0) + 1

' allocate new memory for expanded sFileOrCommand
pszCommandLine = new(char, requiredSize)
' todo: check if pszCommandLine is NULL

' expand it now
ExpandEnvironmentStringsA(sFileOrCommand, pszCommandLine, requiredSize) /*should return requiredSize*/

' todo: expand also sParam and sWorkDir if needed

' your code with small modification - replaced sFileOrCommand with pszCommandLine
iRet = ShellExecuteA(0, sType, *<STRING>pszCommandLine, sParam, sWorkDir, iShowFlag)

' free memory
delete pszCommandLine
'delete pszParam
'delete pszWorkDir


Here is an helper function:
sub ExpandEnv(string toexpand),heap
heap expanded
int requiredSize

requiredSize = ExpandEnvironmentStringsA(toexpand, *<STRING>expanded, 0) + 1
expanded = AllocHeap(requiredSize)
ExpandEnvironmentStringsA(toexpand, *<STRING>expanded, requiredSize)
return expanded
endsub

'usage:
iRet = ShellExecuteA(0, sType, ExpandEnv(sFileOrCommand), ExpandEnv(sParam), ExpandEnv(sWorkDir), iShowFlag)


If you are sure the expanded string will be not longer than N characters, use an istring[N] instead pointer + new + delete.
Or, if you know the target exe is located in system-known directory (like system32, windows, %path%, your exe {current} dir) do not use folders, simply pass the program  name. You can also omit the extension if you are targeting an exe:
rundll32 parameters
rundll32 xvid.ax,Configure


edit: replaced 'byte' from Aurora with 'char' ;D

Del

Thanks for your help
Here is the code before I comment and finalise it...

QuoteDECLARE "kernel32",Sleep(dwMilliseconds:INT)
DECLARE "Shell32",FindExecutable Alias FindExecutableA(lpFile:String,lpDirectory:String,lpResult:String), Int
DECLARE "kernel32",GetTempPath Alias GetTempPathA (nBufferLength:INT,lpBuffer:String),Int
DECLARE "kernel32",GetTempFileName Alias GetTempFileNameA (lpszPath:String,lpPrefixString:String,wUnique:INT,lpTempFileName:String),INT
DECLARE "shell32.dll", CommandLineToArgv alias CommandLineToArgvW(lpCmdLine:STRING, pNumArgs:WORD),POINTER
DECLARE "kernel32.dll",GetCommandLine alias GetCommandLineW(),STRING
DECLARE "kernel32.dll",GlobalFree(hMem:UINT),INT
DECLARE IMPORT,WideCharToMultiByte(codepage:UINT,dwFlags:UINT,lpWideStr:POINTER,cchWideStr:INT,lpMultiByteStr:POINTER,cchMultiByte:INT,lpDefaultChar:POINTER,lpUsedDefault:POINTER),INT
CONST CP_ACP = 0

' Parameter 1 - Extension
' Parameter 2 - Filename to be opened

DEF Args[50]:String
DEF NumArgs:INT

DEF pszArglist:pointer
DEF strTemp:WORD
DEF nArgs:WORD
DEF pszArglist1:pointer
DEF strTemp1:WORD
DEF nArgs1:WORD
DEF I:INT
DEF ExtParam:STRING
DEF FileParam:STRING 
DEF AppPath:STRING
DEF iStat as UINT
DEF strA:STRING
DEF strB:STRING
DEF strC:STRING
DEF strD:STRING
DEF strE:STRING
DEF strF:STRING
DEF AppExe:STRING
DEF StrG:STRING
DEF TmpInt:INT

$include "Registry.inc"

pszArglist = CommandLineToArgv(GetCommandLine(), &nArgs)
Buffer = ""
IF nArgs=3 THEN
   WideCharToMultiByte(CP_ACP,0,*<STRING>*<POINTER>(pszArglist+(4)),-1,ExtParam,254,NULL,NULL)
   WideCharToMultiByte(CP_ACP,0,*<STRING>*<POINTER>(pszArglist+(8)),-1,FileParam,254,NULL,NULL)
   WideCharToMultiByte(CP_ACP,0,*<STRING>*<POINTER>(pszArglist+(0)),-1,AppExe,254,NULL,NULL)
   strA =RegGetValue("HKEY_CLASSES_ROOT\\."+ExtParam)
   strB=RegGetValue("HKEY_CLASSES_ROOT\\" + strA + "\\shell\\Open\\command")
   if strA <>"" and strB<>"" THEN
      iStat = INSTR(strB,"%1")-1
      strC = LEFT$(strB,iStat) + FileParam + RIGHT$(strB,LEN(strB)-iStat-2)
      ParseString(strC)
      strD = Args[1]
      strE = RIGHT$(strC,LEN(strC)-LEN(strD))
      strF = LEFT$(strC,LEN(strD))
      strF = GetEvironmentString(strF)
      strE = GetEvironmentString(strE)
      AppPath = GetEvironmentString(AppPath)
      FileParam = GetEvironmentString(FileParam)
      iStat = ShellExecute(strF,strE, "", "open", 5)
      if iStat<33 THEN
' If it doesn't run properly try running using the extension directly rather than from the registry
         AppPath = fGetAppPath(ExtParam)
         iStat = ShellExecute(AppPath, FileParam, "", "open", 5)   
      ENDIF
   ELSE
      AppPath = fGetAppPath(ExtParam)
      iStat = ShellExecute(AppPath, FileParam, "", "open", 5)   
   ENDIF
END IF
END



Sub ParseString(CmdLine:STRING)
   DEF aChar: STRING 
   DEF aString:STRING
   DEF escBackslash:INT
   DIM inQuote:INT
   DIM I:INT

   NumArgs=0
   If LEN(CmdLine)>0 then
      escBackSlash=0
      inQuote=0
      aString =""
      For I=1 to LEN(CmdLine)
         aChar = MID$(CmdLine,I,1)
         Select aChar
            Case Chr$(34)
               IF inQuote=1 THEN
                  inQuote = 0
               ELSE
                  inQuote = 1
               ENDIF
               aString = aString + aChar               
            Case " "
               If inQuote=0 THEN
                  NumArgs = NumArgs + 1
                  Args[NumArgs]=aString
                  aString = ""
               ELSE
                  aString = aString + aChar                  
               ENDIF
               escBackSlash=0
            DEFAULT
               aString = aString + aChar
               escBackSlash=0
         ENDSELECT
      NEXT I
      if aString<>"" THEN
         NumArgs = NumArgs + 1
         Args[NumArgs]=aString
         aString = ""
      ENDIF
   ENDIF
EndSub


    SUB fGetAppPath(strExt:String),String

        '--- Returns the path to an executable or an empty string if an error occurs

        '--- Input
        ' strExt is the three character file extension associated with the executable

        DEF vntTmpData:String  'Data written to temp file
        DEF lngRtn:Int 'API function return
        DEF strPath:String 'Path to Windows Temp folder
        DEF strTmpFile1:String 'Temp file name
        DEF strTmpFile2:String 'Temp file with associated extension
        DEF strAppFile:String 'Buffer to return application filename
      DEF hfile as BFILE
      DEF RetStr as STRING
      DEF StrPos as INT

        'Check the passed in extension is not null
        If strExt = "" Then
            RETURN ""
        End If

        'Size the buffer for the temp folder path
        strPath = SPACE$(255)
        'Get the path to the temp folder
        lngRtn = GetTempPath(255, strPath)
        strPath = LTRIM$(RTRIM$(strPath))
      RetStr = ""

        'Size the buffer for the temp file name
        strTmpFile1 = SPACE$(255)
        'Create a temp file
        lngRtn = GetTempFileName(strPath, strExt, 0, strTmpFile1)
        'Check the result

        vntTmpData = "It is safe to delete this temporary file"
      IF OPENFILE(hfile, strTmpFile1, "W") = 0
         WRITE hfile, vntTmpData
         CLOSEFILE hfile
      ENDIF

        'Copy the temp file to our target extension
      StrPos = InStr(strTmpFile1, ".tmp")
        strTmpFile2 = Left$(strTmpFile1, StrPos) + strExt
        COPYFILE strTmpFile1, strTmpFile2,StrPos

        'Size the buffer for the path to the executable
        strAppFile = SPACE$(255)
        'Get the path to the associated executable
        lngRtn = FindExecutable(strTmpFile2, "", strAppFile)
        'Check the result
        If lngRtn > 32 Then
            'The function succeeded, remove the terminating null char and spaces
            RetStr =  LTRIM$(RTRIM$(strAppFile))
        End If

        'Delete the temp files
        DELETEFILE (strTmpFile1)
        DELETEFILE (strTmpFile2)

      RETURN RetStr
    End SUB




'===============================================================================
'
' Description:      Attempts to shell execute (launch via the shell) an operation on a file or command.
' Syntax:           UINT iResult = ShellExecute(sFileOrCommand, sParam="", sWorkDir="", sType="Open", iShowFlag=5)
' Parameter(s):     sFileOrCommand - string, filename or command name to execute
'               sParam - optional string, parameter for the file or command (default = "")
'               sWorkDir - optional string, working directory for file or command (default = "")
'               sType - optional string, the verb specifying the type of context operation to perform (default = "open")
'                     Some working examples are "open", "explore", "edit", "print", "properties", etc.
'               iShowFlag - optional integer indicating how Windows should display the executed process (default = SW_SHOW = 5)
'                     Some possible values:
'                        0 = SW_HIDE (the window/process is launched invisibly, and is activated)
'                        2 = SW_SHOWMINIMIZED (minimized at launch)
'                        3 = SW_MAXIMIZE (shown, maximized at launch, and activated)
'                        4 = SW_SHOWNOACTIVATE (shown, but not activated)
'                        5 = SW_SHOW (shown, activated, displayed in last used size & position)
' Requirement(s):   Emergence Basic (any version)
' Return Value(s):  On Success - Returns instance handle of launched process (a UINT > 32)
'                   On Failure - Returns a UINT value less than or equal to 32
'                  Some possible returned errors:
'                     2 = SE_ERR_FNF (file not found)
'                     3 = SE_ERR_PNF (path not found)
'                     5 = SE_ERR_ACCESSDENIED (access denied)
'                     8 = SE_ERR_OOM (out of memory)
'                     11 = ERROR_BAD_FORMAT (invalid EXE file or error in EXE image)
'                     26 = SE_ERR_SHARE (a sharing violation occured)
'                     27 = SE_ERR_ASSOCINCOMPLETE (incomplete or invalid file association)
'                     28 = SE_ERR_DDETIMEOUT (DDE timeout)
'                     29 = SE_ERR_DDEFAIL (DDE transaction failed)
'                     30 = SE_ERR_DDEBUSY (DDE busy)
'                     31 = SE_ERR_NOASSOC (no association for file extension)
'                     32 = SE_ERR_DLLNOTFOUND (DLL not found)
' Author(s):        SEO <locodarwin at yahoo dot com>
' Note(s):          This routine does not perform internal error checking and instead relies upon error checking provided
'               by the ShellExecuteA() WinAPI function.
'
'               Be careful when using a iShowFlag of 0, as the process you've launched will then be invisible and will
'               have to be terminated through task manager (or programmatically) if it does not terminate itself.
'
'               Also, the string value for sType represents verbs that are possible for that file, in context.  Using
'               a verb that doesn't apply to the file or command launched will result in an error.  Windows will do its
'               best to infer what you mean in all cases, based on file associations and file types.
'
'===============================================================================
Sub ShellExecute(sFileOrCommand as STRING, Opt sParam as STRING, Opt sWorkDir as STRING, Opt sType="Open" as STRING, Opt iShowFlag=5 as INT), UINT
   
   DECLARE IMPORT, ShellExecuteA(hwnd as UINT, pOp as POINTER, pFile as POINTER, pParam as POINTER, pDir as POINTER, nShow as INT), UINT


   UINT iRet
   iRet = ShellExecuteA(0, sType, sFileOrCommand, sParam, sWorkDir, iShowFlag)
   'iRet = ShellExecuteA(0, sType, ExpandEnv(sFileOrCommand), ExpandEnv(sParam), ExpandEnv(sWorkDir), iShowFlag)
   Return iRet
EndSub



SUB GetEvironmentString(VariableName:String),String
   Declare Import, ExpandEnvironmentStrings Alias "ExpandEnvironmentStringsA" (lpSrc:String, lpDst:String, nSize:INT), INT   
   STRING sBuffer

    sBuffer = Space$(256)
    If ExpandEnvironmentStrings(VariableName, sBuffer, Len(sBuffer)) > 0 Then
        GetEvironmentString = sBuffer
    Else
        GetEvironmentString = ""
    End If
ENDSUB