Convert small .ahk (COM) to PB?

Windows specific forum
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Convert small .ahk (COM) to PB?

Post by jacky »

This is the .ahk code:

Code: Select all

ComObjCreate("Shell.Application").Windows.FindWindowSW(0 , 0 , 8 , 0 , 1).Document.Application.ShellExecute("""c:\windows\notepad.exe""")
Can anybody convert this to PB code please?

So far it's the only reliable way I've found (and in this case by far the shortest) that is able to run a program with user rights if the calling program is running as admin...

All the solutions I've found here:
viewtopic.php?f=5&t=71575

produce only fully elevated ones...
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Convert small .ahk (COM) to PB?

Post by Mijikai »

Try:

Code: Select all

runas /trustlevel:0x20000 notepad.exe
Or:

Code: Select all

explorer notepad.exe
Or:

Code: Select all

schtasks /run /tn notepad.exe
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Convert small .ahk (COM) to PB?

Post by jacky »

Thanks for the suggestions, Mijikai.

01. Doesn't work, notepad will be elevated
03. That would require a task (which needs to be setup beforehand)

02. Works in a command prompt, but do you have any idea how to pass arguments to notepad in this case?

Code: Select all

explorer.exe ""c:\windows\notepad.exe" "D:\some file.txt""
explorer.exe '"c:\windows\notepad.exe" "D:\some file.txt"'
Both don't work as expected.

It's easy to do it with the COM code, though:

Code: Select all

ComObjCreate("Shell.Application").Windows.FindWindowSW(0 , 0 , 8 , 0 , 1).Document.Application.ShellExecute("""c:\windows\notepad.exe""", """D:\some text file.txt""")
fryquez
Enthusiast
Enthusiast
Posts: 369
Joined: Mon Dec 21, 2015 8:12 pm

Re: Convert small .ahk (COM) to PB?

Post by fryquez »

Takes a bit more Code in PureBasic :shock:

Code: Select all

EnableExplicit

Import "Uuid.Lib"
  IID_IShellFolderViewDual
  CLSID_ShellWindows
  IID_IShellWindows
  IID_IShellView
  SID_STopLevelBrowser
  IID_IShellBrowser
  IID_IDispatch
  IID_IShellDispatch2
  IID_IServiceProvider
EndImport

Macro SUCCEEDED_(HRESULT)
  (HRESULT & $80000000 = 0)
EndMacro


Procedure IUnknown_QueryService(*punk.IUnknown, guidService, riid, *ppvOut.Integer)
  
  *ppvOut\i = 0
  
  Protected.IServiceProvider *ISP
  Protected hr.l = *punk\QueryInterface(@IID_IServiceProvider, @*ISP)
  
  If Not SUCCEEDED_(hr)
    ProcedureReturn #E_NOTIMPL
  Else
    hr = *ISP\QueryService(guidService, riid, @*ppvOut\i)
    *ISP\Release()
  EndIf
  
  ProcedureReturn hr
  
EndProcedure



Procedure GetShellViewForDesktop(riid, *ppv.Integer)
 
  *ppv\i = 0
 
  Protected.IShellWindows *psw
  Protected hr.l = CoCreateInstance_(@CLSID_ShellWindows, #Null, #CLSCTX_LOCAL_SERVER, @IID_IShellWindows, @*psw)
 
  If SUCCEEDED_(hr)
    Protected hwnd
    Protected.IDispatch *pdisp
    Protected.VARIANT vEmpty
   
    #SWC_DESKTOP = 8
    #SWFO_NEEDDISPATCH = 1
   
    hr = *psw\FindWindowSW(@vEmpty, @vEmpty, #SWC_DESKTOP, @hwnd, #SWFO_NEEDDISPATCH, @*pdisp)
   
    If #S_OK = hr
     
      Protected.IShellBrowser *psb
      hr = IUnknown_QueryService(*pdisp, @SID_STopLevelBrowser, @IID_IShellBrowser, @*psb)
     
      If SUCCEEDED_(hr)
       
        Protected.IShellView *psv
        hr = *psb\QueryActiveShellView(@*psv)
               
        If SUCCEEDED_(hr)
          hr = *psv\QueryInterface(riid, @*ppv\i)
          *psv\Release()
        EndIf
       
        *psb\Release()
       
      EndIf
     
      *pdisp\Release()
     
    Else
     
      hr = #E_FAIL
     
    EndIf
   
    *psw\Release()
   
  EndIf
 
  ProcedureReturn hr
 
EndProcedure



Procedure GetShellDispatchFromView(*psv.IShellView, riid, *ppv.Integer)
 
  *ppv\i = 0
 
  Protected.IDispatch *pdispBackground
  #SVGIO_BACKGROUND = 0
  Protected hr.l = *psv\GetItemObject(#SVGIO_BACKGROUND, @IID_IDispatch, @*pdispBackground)
 
  If SUCCEEDED_(hr)
   
    Protected.IShellFolderViewDual *psfvd
    hr = *pdispBackground\QueryInterface(@IID_IShellFolderViewDual, @*psfvd)
   
    If SUCCEEDED_(hr)
      Protected.IDispatch *pdisp
      hr = *psfvd\get_Application(@*pdisp)
     
      If SUCCEEDED_(hr)
        hr = *pdisp\QueryInterface(riid, @*ppv\i)
        *pdisp\Release(); 
      EndIf
     
      *psfvd\Release()
    EndIf
   
    *pdispBackground\Release();
   
  EndIf
 
  ProcedureReturn hr
 
EndProcedure



Procedure ShellExecInExplorerProcess(sFile.s, sParameter.s = "")
 
  Protected.IShellView *psv
  Protected hr.l = GetShellViewForDesktop(@IID_IShellView, @*psv)
 
  If SUCCEEDED_(hr)   
    Protected.IShellDispatch2 *psd
    hr = GetShellDispatchFromView(*psv, @IID_IShellDispatch2, @*psd)
    If SUCCEEDED_(hr)
     
      Protected.VARIANT vArguments, vDirectory, vOperation, vShow
      
      If sParameter <> ""
        vArguments\vt = #VT_BSTR
        vArguments\bstrVal = SysAllocString_(@sParameter)
      EndIf
      
      vShow\vt = #VT_I2
      vShow\iVal = #SW_SHOWDEFAULT
      
      hr = *psd\ShellExecute(sFile, @vArguments, @vDirectory, @vOperation, @vShow)
      
      If vArguments\bstrVal
        SysFreeString_(vArguments\bstrVal) 
      EndIf
      
      *psd\Release()
     
    EndIf
   
    *psv\Release()
  EndIf
  ProcedureReturn hr
 
EndProcedure


Procedure WinMain()
 
  Protected hr.l = CoInitializeEx_(#Null, #COINIT_APARTMENTTHREADED | #COINIT_DISABLE_OLE1DDE)
  If SUCCEEDED_(hr)   
    ShellExecInExplorerProcess("notepad.exe", "C:\Windows\WindowsUpdate.log")
    CoUninitialize_();
  EndIf
  ProcedureReturn 0;
EndProcedure

WinMain()
Last edited by fryquez on Thu Dec 31, 2020 12:13 pm, edited 1 time in total.
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Convert small .ahk (COM) to PB?

Post by jacky »

Holy cow :mrgreen:

Quite a lot of code to do this with COM...

No clue how you did this, fryquez, but it's working perfectly fine.

Thanks so much!
BarryG
Addict
Addict
Posts: 3324
Joined: Thu Apr 18, 2019 8:17 am

Re: Convert small .ahk (COM) to PB?

Post by BarryG »

fryquez, what is your code meant to do? I assume it's to launch an admin exe as limited (because jacky said "Doesn't work, notepad will be elevated", so he wants Notepad to be limited?). If so, it doesn't work for me (I get a UAC prompt for any admin exe that I launch with it).
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Convert small .ahk (COM) to PB?

Post by jacky »

The application that contains this code (and is started with "Run as administrator") can run another application with current user permissions. This should work for every user that is in the administrator group and is currently logged in but not necessarily for the user account "Administrator" itself.
fryquez
Enthusiast
Enthusiast
Posts: 369
Joined: Mon Dec 21, 2015 8:12 pm

Re: Convert small .ahk (COM) to PB?

Post by fryquez »

I made small improvements to my previous post.

PS: The code is translated from Windows-classic-samples
BarryG
Addict
Addict
Posts: 3324
Joined: Thu Apr 18, 2019 8:17 am

Re: Convert small .ahk (COM) to PB?

Post by BarryG »

Hi jacky, I understand now. I can confirm it works as you describe (admin exe runs another exe as limited). Thanks to fryquez for the code!
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Convert small .ahk (COM) to PB?

Post by jacky »

@fryquez

Thanks again!

I wanted to ask why sFile can be used directly without storing it in a variable of type VARIANT but after reading
https://docs.microsoft.com/en-us/window ... ellexecute
I'll understand it now :P

I've slightly modified your translated code (thanks for posting the link to the C++ source for it, incredible valuable!) by readding sWorkingDir and a mode argument so that a program can also be executed with a specific working directory and e.g. #SW_HIDE.

Code: Select all

Procedure ShellExecInExplorerProcess(sFile.s, sParameter.s = "", sWorkingDir.s = "", iMode = #SW_SHOWDEFAULT)

  Protected.IShellView *psv
  Protected hr.l = GetShellViewForDesktop(@IID_IShellView, @*psv)

  If SUCCEEDED_(hr)
    Protected.IShellDispatch2 *psd
    hr = GetShellDispatchFromView(*psv, @IID_IShellDispatch2, @*psd)
    If SUCCEEDED_(hr)

      Protected.VARIANT vArguments, vDirectory, vOperation, vShow

      If sParameter <> ""
        vArguments\vt = #VT_BSTR
        vArguments\bstrVal = SysAllocString_(@sParameter)
      EndIf

      vDirectory\vt = #VT_BSTR
      If sWorkingDir = ""
        vDirectory\bstrVal = SysAllocString_(GetPathPart(sFile))
      Else
        vDirectory\bstrVal = SysAllocString_(@sWorkingDir)
      EndIf

      vShow\vt = #VT_I2
      vShow\iVal = iMode

      hr = *psd\ShellExecute(sFile, @vArguments, @vDirectory, @vOperation, @vShow)

      If vArguments\bstrVal
        SysFreeString_(vArguments\bstrVal)
      EndIf

      If vDirectory\bstrVal
        SysFreeString_(vDirectory\bstrVal)
      EndIf

      *psd\Release()

    EndIf

    *psv\Release()
  EndIf
  ProcedureReturn hr

EndProcedure
Last edited by jacky on Thu Dec 31, 2020 3:44 pm, edited 1 time in total.
BarryG
Addict
Addict
Posts: 3324
Joined: Thu Apr 18, 2019 8:17 am

Re: Convert small .ahk (COM) to PB?

Post by BarryG »

Jacky, I just modified your code to use the file's dir as the working dir if a working dir is NOT specified, because a working dir is sometimes needed for an app:

Code: Select all

vDirectory\vt = #VT_BSTR
If sWorkingDir = ""
  vDirectory\bstrVal = SysAllocString_(GetPathPart(sFile))
Else
  vDirectory\bstrVal = SysAllocString_(@sWorkingDir)
EndIf
jacky
User
User
Posts: 63
Joined: Mon Jan 21, 2019 1:41 pm

Re: Convert small .ahk (COM) to PB?

Post by jacky »

Yeah, that makes sense. I've added the change to my last post.
Post Reply