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
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
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