Page 1 of 1
					
				Alternative for RunProgram
				Posted: Thu Jul 25, 2024 8:27 pm
				by blueznl
				Hi peeps. I've been gone for quite a while (doing lots of other stuff) but I need to build a little tool right now, and I'll (obviously) do so in PureBasic. I'm looking for something (and I know I've seen it somewhere on the forum, but I can't find it back).
What's the best way to launch / open certain apps / programs?
I want to simulate:
-  start notepad -> should start (you guessed it) notepad.exe 

 without specifying the path, ie. let windows figure out the right app, potentially simply by launching something in such a way that the windows path is searched, but I don't thing RunProgram offers options for that
-  launch the right application for a given file+extension, ie. word for .docx, excel for .xlsx etc., in other words, open the right application by only specifiying the file
Is there a way to do that easily?
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Thu Jul 25, 2024 8:43 pm
				by RASHAD
				I think RunProgram can run any shell and no need to the path
Anyhow
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Thu Jul 25, 2024 10:55 pm
				by boddhi
				Hello,
blueznl wrote:
-  launch the right application for a given file+extension, ie. word for .docx, excel for .xlsx etc., in other words, open the right application by only specifiying the file
If you use RunProgram() with filename and without appname, it will lauch the default system app:
Code: Select all
RunProgram(#PB_Compiler_Home+"Examples\Sources\Data\WebView\webview.html")
RunProgram(#PB_Compiler_Home+"Examples\Sources\Data\ToolBar\Readme.txt")
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Thu Jul 25, 2024 11:55 pm
				by blueznl
				Wait... I thought I tested that... Trying again. Moment...
			 
			
					
				Re: Alternative for RunProgram
				Posted: Fri Jul 26, 2024 10:57 am
				by Axolotl
				If you want to know the associated application and you are working under Windows, try this. (Reading a registry value) 
Code: Select all
Procedure.s GetAssociatedProgram(Extension$)  ; returns executable or Empty$ 
  Protected hKey.l, dataSize.l, pos.l
  Protected result$, keyValue$, keyNext$, associatedProgram$ 
  hKey = 0 : dataSize = 255 : keyValue$ = Space(dataSize) : associatedProgram$ = ""  
  If Left(Extension$, 1) <> "." 
    Extension$ = "." + Extension$   ; extension == <.ext> 
  EndIf 
  If RegOpenKeyEx_(#HKEY_CLASSES_ROOT, Extension$, 0, #KEY_READ, @hKey)  = #ERROR_SUCCESS  
    If RegQueryValueEx_(hKey, "", 0, 0, @keyValue$, @datasize) = #ERROR_SUCCESS  
      keyNext$ = Left(keyValue$, dataSize - 1) 
      hKey = 0 : dataSize = 255 : keyValue$ = Space(dataSize) 
      If RegOpenKeyEx_(#HKEY_CLASSES_ROOT, keyNext$ + "\Shell\Open\Command", 0, #KEY_READ, @hKey) = #ERROR_SUCCESS  
        If RegQueryValueEx_(hKey, "", 0, 0, @keyValue$, @dataSize) = #ERROR_SUCCESS  
          associatedProgram$ = Left(keyValue$, dataSize - 1)   
        EndIf  
      EndIf  
    EndIf  
  EndIf                                             ; : Debug " -->" + associatedProgram$ + "<--" 
  ; remove the stored parameter (i.e. %1 or /Shell "%1" or etc. 
  ; 
  pos = FindString(LCase(associatedProgram$), ".exe", 1)  
  If pos <> 0  
    associatedProgram$ = Left(associatedProgram$, pos + 4)  ; keep the .exe
    associatedProgram$ = RemoveString(associatedProgram$, #DQUOTE$)  ; remove any "  
  EndIf  
  ProcedureReturn associatedProgram$  
EndProcedure  
;  test on some very well known extensions..... 
; Debug "doc => " + GetAssociatedProgram("doc")  
; Debug "xls => " + GetAssociatedProgram("xls")  
; Debug "mdb => " + GetAssociatedProgram("mdb")  
; Debug "jpg => " + GetAssociatedProgram("jpg")  
; Debug "gif => " + GetAssociatedProgram("gif")  
; Debug "htm => " + GetAssociatedProgram("htm")  
; Debug "done" 
That app is used if you call something like 
 
On the other hand if you call apps like robocopy.exe or cmd.exe you don't need a path because of the environment variable %PATH%.
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Fri Jul 26, 2024 12:05 pm
				by chi
				Hi blueznl, on Windows you could also use AssocQueryString as shown 
here 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Fri Jul 26, 2024 1:06 pm
				by AZJIO
				https://azjio.narod.ru/PureBasic/pb_use ... String.htm
Axolotl wrote: Fri Jul 26, 2024 10:57 am
 
This method does not take into account the HKEY_CLASSES_ROOT\Applications key.
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Fri Jul 26, 2024 2:16 pm
				by blueznl
				Thanks all! I remembered playing around with this in the past, and suddenly recalled I wrote a procedure for this ages ago 

 (Probably stole it from someone... credits to the unknown creator then 

 )
Memory, and too busy with other things than programming 
Code: Select all
Procedure x_shellexecute(executable.s, parameters.s="", working.s="")                            ; alternative for runprogram()
  Protected x_retval.i, coinit.i, shellexecuteinfo.shellexecuteinfo\cbSize = SizeOf(shellexecuteinfo)
  ;
  ;shellexecuteinfo\fMask = #SEE_MASK_FLAG_NO_UI
  ;
  shellexecuteinfo\lpFile = @executable
  If parameters > ""
    shellexecuteinfo\lpParameters = @parameters
  EndIf
  If working
    shellexecuteinfo\lpDirectory = @working
  EndIf
  shellexecuteinfo\nShow = #SW_SHOWNORMAL
  coinit = CoInitializeEx_(0, #COINIT_APARTMENTTHREADED | #COINIT_DISABLE_OLE1DDE)
  If coinit = #S_OK Or coinit = #S_FALSE Or coinit & $FFFFFFFF = #RPC_E_CHANGED_MODE & $FFFFFFFF
    If ShellExecuteEx_(@shellexecuteinfo)
      x_retval = #True
    EndIf
    If coinit & $FFFFFFFF <> #RPC_E_CHANGED_MODE & $FFFFFFFF
      CoUninitialize_()
    EndIf
  EndIf
  ;
  ProcedureReturn x_retval
EndProcedure
Thanks for helping me jog my memory!
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Fri Jul 26, 2024 4:15 pm
				by Fred
				Is it different than RunProgram() ?
			 
			
					
				Re: Alternative for RunProgram
				Posted: Sat Jul 27, 2024 3:02 am
				by BarryG
				@blueznl: What advantage does that extra code have over a single "RunProgram" command?
@Axolotl: Here's how I get the exe for any given document (no Registry access needed):
Code: Select all
Procedure.s ExeForDoc(doc$)
  doc$=LCase(doc$)
  If FileSize(doc$)=-1
    doc$=GetTemporaryDirectory()+Chr(160)+"."+GetExtensionPart(doc$)
    f=CreateFile(#PB_Any,doc$) : If f : CloseFile(f) : tmp=1 : EndIf
  EndIf
  exe$=Space(999) : FindExecutable_(GetFilePart(doc$),GetPathPart(doc$),@exe$)
  long$=Space(999) : GetLongPathName_(exe$,@long$,990)
  If LCase(exe$)=doc$ Or LCase(long$)=doc$ : exe$="" : EndIf ; Not a document.
  If tmp=1 : DeleteFile_(doc$) : EndIf
  ProcedureReturn exe$
EndProcedure
Debug ExeForDoc("C:\PROGRA~1\INTERN~1\iexplore.exe") ; Null because path is invalid.
Debug ExeForDoc("C:\Windows\System32\Bubbles.scr") ; Null because is not a document.
Debug ExeForDoc("C:\WINDOWS\regedit.exe") ; Null because is not a document.
Debug ExeForDoc("C:\Non-Existent-File.jpg") ; Shows exe for your image viewer.
Debug ExeForDoc("C:\test.txt") ; Shows exe for your text editor.
Debug ExeForDoc("index.html") ; Shows exe for your web browser.
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Sat Jul 27, 2024 2:33 pm
				by Quin
				Think you meant 999 here 

. Super useful tip though, thanks for sharing! Feels like I learn some new Windows API functions every couple of days now.
Code: Select all
long$=Space(999) : GetLongPathName_(exe$,@long$,999)[/code]
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Wed Jul 31, 2024 10:54 am
				by Axolotl
				Thanks for the different solutions. 
Funny thing, they all show a different result (at least on my computer). Just an observation.
			 
			
					
				Re: Alternative for RunProgram
				Posted: Wed Jul 31, 2024 12:18 pm
				by BarryG
				Code: Select all
long$=Space(999) : GetLongPathName_(exe$,@long$,990)
I once read that the allocated string should always be larger than the buffer given to the API command, which is why I allocate 999 and request a max of 990 to that buffer. My apps used to crash in the old days if I didn't do that, due to Unicode lengths. So it's a habit I've stuck with.
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Wed Jul 31, 2024 12:46 pm
				by Axolotl
				Well, in the ANSI version there is the limit of #MAX_PATH (260) and on UNICODE you need "\\?\" to extend to 32767 TCHARs. 
Fun Fakt: Most of the windows functions offer a help on that by using size ZERO for a first call to receive the needed buffer size. 
Learned from MSDN: 
Return value
If the function succeeds, the return value is the length, in TCHARs, of the string copied to lpszLongPath, not including the terminating null character. 
If the lpBuffer buffer is too small to contain the path, the return value is the size, in TCHARs, of the buffer that is required to hold the path and the terminating null character. 
If the function fails for any other reason, such as if the file does not exist, the return value is zero. To get extended error information, call GetLastError. 
 
			 
			
					
				Re: Alternative for RunProgram
				Posted: Wed Jul 31, 2024 5:42 pm
				by AZJIO
				BarryG
If you use Space(), then you don't need to add anything, since the internal variables are in #PB_Unicode format and create a variable with +2 bytes, meaning you have a variable that doesn't need to be appended with 2 bytes for the terminating 00.
If you use AllocateMemory() for a string, then you need to add 2 bytes. You don't need to add 9 bytes, everything should be accurate.