Skip to content

Instantly share code, notes, and snippets.

@msarson
Last active April 5, 2023 10:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msarson/2f6d3cdd777316f9d8b1ca24f5f02ae9 to your computer and use it in GitHub Desktop.
Save msarson/2f6d3cdd777316f9d8b1ca24f5f02ae9 to your computer and use it in GitHub Desktop.
PROGRAM
MAP
ExtendedRun PROCEDURE(STRING inFilename,<STRING inParams>,<STRING inStartPath>,<BYTE inWait>,<BYTE inHide>,<BYTE inRunAs>),LONG,PROC
!Module Definition below must be inside Global MAP
MODULE('win32api')
!***NOTE THE NAMING HERE***
!Because other clarion definitions might clash with ShellExectueExa etc
!Changing the name here should alliviate that.
ER:ShellExecuteExA PROCEDURE(LONG lpShellExecuteInfoA),LONG,PASCAL,NAME('ShellExecuteExA'),DLL(1)
ER:WaitForSingleObject PROCEDURE(LONG hHandle,ULONG dwMilliseconds),LONG,PASCAL,NAME('WaitForSingleObject'),DLL(1)
ER:CloseHandle PROCEDURE( Long hObject ),Long,Pascal,Proc,Name('CloseHandle'),DLL(1)
END
END
!Masks ********************************
SEE_MASK_DEFAULT EQUATE(00000000h) !Use default values.
SEE_MASK_CLASSNAME EQUATE(00000001h) !Use the class name given by the lpClass member. If both SEE_MASK_CLASSKEY and SEE_MASK_CLASSNAME are set, the class key is used.
SEE_MASK_CLASSKEY EQUATE(00000003h) !Use the class key given by the hkeyClass member. If both SEE_MASK_CLASSKEY and SEE_MASK_CLASSNAME are set, the class key is used.
SEE_MASK_IDLIST EQUATE(00000004h) !Use the item identifier list given by the lpIDList member. The lpIDList member must point to an ITEMIDLIST structure.
SEE_MASK_INVOKEIDLIST EQUATE(0000000Ch) !Use the IContextMenu interface of the selected item's shortcut menu handler. Use either lpFile to identify the item by its file system path or lpIDList to identify the item by its PIDL. This flag allows applications to use ShellExecuteEx to invoke verbs from shortcut menu extensions instead of the static verbs listed in the registry.
!Note: SEE_MASK_INVOKEIDLIST overrides and implies SEE_MASK_IDLIST.
SEE_MASK_ICON EQUATE(00000010h) !Use the icon given by the hIcon member. This flag cannot be combined with SEE_MASK_HMONITOR.
!Note: This flag is used only in Windows XP and earlier. It is ignored as of Windows Vista.
SEE_MASK_HOTKEY EQUATE(00000020h) !Use the keyboard shortcut given by the dwHotKey member.
SEE_MASK_NOCLOSEPROCESS EQUATE(00000040h) !Use to indicate that the hProcess member receives the process handle. This handle is typically used to allow an application to find out when a process created with ShellExecuteEx terminates. In some cases, such as when execution is satisfied through a DDE conversation, no handle will be returned. The calling application is responsible for closing the handle when it is no longer needed.
SEE_MASK_CONNECTNETDRV EQUATE(00000080h) !Validate the share and connect to a drive letter. This enables reconnection of disconnected network drives. The lpFile member is a UNC path of a file on a network.
SEE_MASK_NOASYNC EQUATE(00000100h) !Wait for the execute operation to complete before returning. This flag should be used by callers that are using ShellExecute forms that might result in an async activation, for example DDE, and create a process that might be run on a background thread. (Note: ShellExecuteEx runs on a background thread by default if the caller's threading model is not Apartment.h) Calls to ShellExecuteEx from processes already running on background threads should always pass this flag. Also, applications that exit immediately after calling ShellExecuteEx should specify this flag.
!If the execute operation is performed on a background thread and the caller did not specify the SEE_MASK_ASYNCOK flag, then the calling thread waits until the new process has started before returning. This typically means that either CreateProcess has been called, the DDE communication has completed, or that the custom execution delegate has notified ShellExecuteEx that it is done. If the SEE_MASK_WAITFORINPUTIDLE flag is specified, then ShellExecuteEx calls WaitForInputIdle and waits for the new process to idle before returning, with a maximum timeout of 1 minute.
!For further discussion on when this flag is necessary, see the Remarks section.
SEE_MASK_FLAG_DDEWAIT EQUATE(00000100h) !The same as SEE_MASK_NOASYNC, use of that option is preferred.
SEE_MASK_DOENVSUBST EQUATE(00000200h) !Expand any environment variables specified in the string given by the lpDirectory or lpFile member.
SEE_MASK_FLAG_NO_UI EQUATE(00000400h) !Do not display an error message box if an error occurs.
SEE_MASK_UNICODE EQUATE(00004000h) !Use this flag to indicate a Unicode application.
SEE_MASK_NO_CONSOLE EQUATE(00008000h) !Use to inherit the parent's console for the new process instead of having it create a new console. It is the opposite of using a CREATE_NEW_CONSOLE flag with CreateProcess.
SEE_MASK_ASYNCOK EQUATE(00100000h) !The execution can be performed on a background thread and the call should return immediately without waiting for the background thread to finish. Note that in certain cases ShellExecuteEx ignores this flag and waits for the process to finish before returning.
SEE_MASK_NOQUERYCLASSSTORE EQUATE(01000000h) !Not used.
SEE_MASK_HMONITOR EQUATE(00200000h) !Use this flag when specifying a monitor on multi-monitor systems. The monitor is specified in the hMonitor member. This flag cannot be combined with SEE_MASK_ICON.
SEE_MASK_NOZONECHECKS EQUATE(00800000h) !Do not perform a zone check. This flag allows ShellExecuteEx to bypass zone checking put into place by IAttachmentExecute.
SEE_MASK_WAITFORINPUTIDLE EQUATE(02000000h) !After the new process is created, wait for the process to become idle before returning, with a one minute timeout. See WaitForInputIdle for more details.
SEE_MASK_FLAG_LOG_USAGE EQUATE(04000000h) !Indicates a user initiated launch that enables tracking of frequently used programs and other behaviors.
SEE_MASK_FLAG_HINST_IS_SITE EQUATE(08000000h) !The hInstApp member is used to specify the IUnknown of an object that implements IServiceProvider. This object will be used as a site pointer. The site pointer is used to provide services to the ShellExecute function, the handler binding process, and invoked verb handlers.
!To use SEE_MASK_FLAG_HINST_IS_SITE in operating systems prior to Windows 8, define it manually in your program: #define SEE_MASK_FLAG_HINST_IS_SITE 0x08000000.
!When this option is specified the call runs synchronously on the calling thread.
!Masks ********************************
!Type defined so can be used elsewhere
ShellExecInfoGroup GROUP,TYPE
cbSize ULONG
fMask ULONG
hwnd ULONG
lpVerb LONG
lpFile LONG
lpParameters LONG
lpDirectory LONG
nShow LONG
hInstApp ULONG
lpIDList ULONG
lpClass LONG
hkeyClass ULONG
dwHotKey ULONG
lpUnion LONG
hProcess ULONG
END
CODE
ExtendedRun('Some.exe','-a -b -c',,true) !the true here tells the call to ShellEx to wait until completed
ExtendedRun PROCEDURE(STRING inFilename,<STRING inParams>,<STRING inStartPath>,<BYTE inWait>,<BYTE inHide>,<BYTE inRunAs>)
ShellExecInfo GROUP(ShellExecInfoGroup).
szOperation CSTRING(12)
szFilename CSTRING(Size(inFilename)+1)
szParams &CSTRING
szPath &CSTRING
dwResult LONG
hWND LONG
dwProcessID LONG
CODE
!-- Check the Filename
IF ~inFilename THEN RETURN(FALSE).
szFilename = CLIP(inFilename)
!-- Wrap a file name containing a space with double quotes if necessary ..
!--
IF INSTRING(' ',szFilename,1,1) AND szFilename[1] ~= '"'
szFilename = '"' & szFilename & '"'
END
szOperation = 'open'
IF NOT OMITTED(inRunAs) and inRunAs THEN
szOperation = 'runas'
END
!-- StartIn Path ..
IF NOT OMITTED(inStartPath) and InStartPath THEN
szPath &= NEW CSTRING( SIZE(inStartPath) + 1)
szPath = CLIP(inStartPath)
ELSE
szPath &= NEW CSTRING(1)
END
IF NOT OMITTED(inParams) THEN
szParams &= new CSTRING( SIZE(inParams) + 1)
szParams = CLIP(inParams)
ELSE
szParams &= NEW CSTRING(1)
END
CLEAR(ShellExecInfo)
ShellExecInfo.cbSize = SIZE(ShellExecInfo)
ShellExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS ! SEE_MASK_NOCLOSEPROCESS (0x00000040)
ShellExecInfo.hwnd = 0
ShellExecInfo.lpVerb = ADDRESS(szOperation)
ShellExecInfo.lpFile = ADDRESS(szFilename)
ShellExecInfo.lpParameters = ADDRESS(szParams)
ShellExecInfo.lpDirectory = ADDRESS(szPath)
IF NOT OMITTED(inHide) and inHide
ShellExecInfo.nShow = 0
ELSE
ShellExecInfo.nShow = 10
END
!-- ShellExecuteExA ..
!-- Returns TRUE if successful; otherwise, FALSE. Call GetLastError for extended error information.
!-- If the function fails, it returns an error value that indicates the cause of the failure.
!-- The return value is cast as an HINSTANCE for backward compatibility with 16-bit Windows applications.
!-- It is not a true HINSTANCE, however. It can be cast only to an int and compared to either 32 or it's error codes.
IF ER:ShellExecuteExA(ADDRESS(ShellExecInfo)) = True
!MESSAGE('ShellExecute SEInfo.hProcess = ' & SEInfo.hProcess & |
! '|inWait = ' & inWait,procName)
IF ShellExecInfo.hProcess
!-- Do we need to wait for this process to finish ?
IF NOT OMITTED(inWait) and inWait = TRUE THEN
dwResult = ER:WaitForSingleObject(ShellExecInfo.hProcess, -1)
END
!-- Close the Process Handle once finished
ER:CloseHandle(ShellExecInfo.hProcess)
RETURN(TRUE)
END
END
DISPOSE(szParams)
DISPOSE(szPath)
RETURN(False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment