How to launch an external executable on windows in go - windows

I am trying to launch an external executable (msi driver installer) on windows with go. It is referred to with the relative path bin\launchme.msi
As of now, I am using the commander-cli/cmd library and it is working well with other external executable (though only command line ones).
My command is:
c := cmd.NewCommand(`bin\launchme.msi`)
c.Execute()
The executable is launched but displays the following:
An error occurred while writing installation information to disk.
Check to make sure enough disk space is available."
See here:
What is especially confusing to me is that, as you can see on the screenshot, the msi installer created a %SystemDrive% folder in the working directory.
This folder in turn contains a Program Files folder and some more subfolders.
Otherwise, if I simply launch the msi installer by double-clicking it, everything is fine, no error occurs.
Any help with this would be greatly appreciated.

It could be, that your .MSI file is using cmd.exe in the background.
If you type echo %my_env_var% in cmd.exe, there are two cases what can happen:
If the environment variable my_env_var is defined, the built-in echo command of cmd.exe prints it’s value.
If the environment variable my_env_var is not defined, the built-in echo command of cmd.exe prints %my_env_var% literally.
Every process inherits the environment variables of it’s parent process. If a process is started from the (Windows) File Explorer (explorer.exe) or from the (graphical) shell of Windows (also explorer.exe), then it inherits the system settings for environment variables.
It seems like your library is dropping some environment variables like SystemDrive when starting a new process from the executable bin\launchme.msi.
Try to use import("os/exec") from the Go standard library https://pkg.go.dev/os/exec .
For more information about environment variable in Microsoft Windows see for example: https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables
Tip:
You can use Process Explorer (procexp.exe) to see the environment variables of running processes, by doing this:
Open Process Explorer, to get a list of running processes
Right-click on the process you are intrested in, to open the context menu
In the context menu click on Preferences
In the new window click on the Tab Environment.

one workaround, for testing, would be to launch that Go program in C:\ as working directory:
// caputred is the captured output from all executed source code
// fnResult contains the result of the executed function
captured, fnResult := cmd.CaptureStandardOut(func() interface{} {
c := NewCommand("C:\path\to\bin\launchme.msi", cmd.WithWorkingDir("C:\\")
err := c.Execute()
return err
})
// prints "hello"
fmt.Println(captured)

Related

How do you run programs in Windows terminal?

What is the windows equivalent to "./filename"
So for example I would usually compile by doing something like:
gcc -c homework1.c
gcc -o homework1 homework1.o
This would give me the executable names homework1
And for me to run the program, I would type: ( ./homework1 ) <-- ignore the parenthesis.
Usually I was write all my code in my schools Unix Shell thingy and I also compile it and run it there, but recently I think I took up all the disc space (because it says "disc quota exceeded").
Run cmd.exe
Go to where the program is example : cd C:\foder1\
Then type the program name with extension, for example : test1.exe or "test1.exe"
In windows (as in Linux) you can either run a program though a GUI interface or from a shell environment.
The GUI option is a program called Explorer, you navigate through the file system and double click executable files to run then. Executable typically have the extension '.exe' or '.bat', but there are others.
The shell environment in windows is called the 'command prompt', you can run it by going to the start menu and selecting 'run' or simply press the windows key and 'r' simultaneously. A box will popup, type 'cmd' (without the quotes) and hit enter - the command prompt should open. From there you can navigate the file system using commands like 'cd'. To run your executable type the name of the file (it should work with or without the '.exe').
A nice shortcut to open the command prompt already at a particular path, is to browse to the folder in Explorer, hold shift and then right-click the folder - the resulting context menu that pops up should have an option like 'open in command prompt'.

Coding a Delphi GUI utility for use in a CMD window

I'm writing myself a GUI utility for use in a CMD window to navigate between folders,
rather in the style of the old Norton Change Directory utility for DOS.
When run, the app pops up a folder tree to allow the user to select a folder to which
to navigate and then closes and returns to the CMD prompt. At the moment, the way it
works is that it is run as the first command in a "main" batch file. It writes a secondary batch
file, in my app's folder under AppData, containing the commands to change drive and
directory to the folder the user selected, and the main batch file then invokes this
second batch file using CALL.
It works fine, but this way of actually changing the CMD window's current directory
strikes me as inelegant both from the point of view of needing to be run from a batch file
(so that the user's selection can be acted upon after my app has closed) and of
needing the secondary batch file to do the actual navigation.
So, my question is, how can my app send the instructions to the instance of CMD
that owns the window in which the app is run to the folder the user selected? I've tried doing a ShellExecute
of "CMD /K ..." but although that does indeed navigate to the
selected folder, it does so in a new CMD window, not the one my app is run in. The
conceptual gap I have is how to get the current CMD to act on my app's instructions
after my app has terminated.
Fwiw, I thought of trying to write the user's folder selection into an environment variable in the CMD window's environment for the CMD processor to
act upon from there, but this seems to require that the CMD window be opened via "Run as Administrator", which I definitely don't want.
Your program cannot influence the environment variables of the command interpreter because they're separate processes. Your program cannot change the directory of the command interpreter directly, either, because, again, they're separate processes.
You need to use a batch file because the command interpreter executes batch files internally. Since it's all the same process, the batch file has the power to change the current directory, and for that change to remain in effect after the batch file finishes running.
Therefore, you need some way for your interactive program to communicate the directory selection back to the batch file so that it can act on it.
Instead of writing the instructions to another batch file, you could write the result to standard output. Have the batch file capture that output into a variable, and then execute cd on that variable. The batch code would look something like this:
for /f "tokens=*" %%a in ('[select_dir.exe]') do (
set DIRSELECTION=%%a
)
cd /d %DIRSELECTION%
Your Delphi code would look like this:
writeln(selected_dir);
To allow that command to work, you'll need to make sure your program is marked as a console program, as with {$APPTYPE CONSOLE}. If it's not, then the batch file won't receive any output, and probably won't even wait for your program to finish running before proceeding. It's OK for a console program to display a TForm, just like a GUI program.

Run .exe anywhere in cmd without PATH variable

This works (Notepad++):
C:\Anywhere> start notepad++ hello.txt
And this works (SoX for removing silence in sounds):
C:\Anywhere> sox in.wav out1.wav silence 1 0.1 1%
Yet, my PATH variable includes neither (would send on request).
How can I do this with my program?
To run from everywhere.
Also, why doesn't Notepad++ work without the start command?
(I did this workaround by putting the .exe in C:\ and then simply calling C:\Anywhere> /myprogram but I'm still curious about the above.)
To get the indicated scenario where
you can start applications from anywhere using the start command (or the windows Run dialog) without including its parent folder in path variable,
but you can not start the application without the start command from any directory whithout including the full path to reach it (it is not in the path) or being located in the adecuated directory
the applications are included in the registry under the key
HKEY_CLASSES_ROOT\Applications
note: It is a "merged" view showing the combined contents of
HKEY_LOCAL_MACHINE\Software\Classes\Applications
HKEY_CURRENT_USER\Software\Classes\Applications
If you are not administrator to change the local machine configuration, you can always modify your user registry information to include the applications you need.
edited There is a second place in registry that will allow to include an application in the registry to be executed using start command, Run dialog or from anything that uses the ShellExecute or ShellExecuteEx API calls.
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\

batch file commands in powershell execute in a different command prompt

I'm using this new machine, so as usual I go and set the execution policy so that I can use my profile script, after doing that however powershell now opens all batch files in a new cmd.exe window.
I tried undoing this step but it's still the same so I think it has nothing to do with the script execution policy, also I still have the powershell window in which I originally set the execution policy and this one behaves normally, only new windows have this problem.
I may have installed some software, but nothing is related to windows, and I tried setting the PATH variable to its exact value in the working window but it does not work.
Batch files will open in a new window if the PATHEXT environment variable does not contain '.BAT' as one of the executable extensions.
To check the variable, enter the following at the PowerShell prompt: $env:PATHEXT

Execute Lua WINAPI code without displaying the shell

I created a simple Lua application using Alien for Lua. It works perfectly, except when you execute it, the Lua Shell shows as well. Is there a way to "hide" this shell, run it in background, turn it off, etc so that I simply see the message box?
Code:
require "luarocks.require"
require "alien"
local MessageBox = alien.User32.MessageBoxA
MessageBox:types{ret = "long", abi = "stdcall", "long", "string", "string", "long" }
MessageBox(0, "Hello World!", "My Window Title", 0x00000040)
Current Output:
Desired Output:
tl;dr
Rename your script to hello.wlua so that wlua.exe is used.
Details
While it is likely possible, if verbose, to locate and close the offending console window that Windows provided your process, it would be better if that console never appeared in the first place. If it does appear, then it is likely to flash on screen, and cause some users to be confused.
Subsystems
Windows has, since its earliest days, had the concept of a "subsystem" which each individual executable identifies with. Normal GUI applications are linked with /SUBSYSTEM:WINDOWS and get the full GUI treatment including the responsibility to create and display their own window(s) if and when needed.
Applications that expect to be run from a command line (or batch file) are linked with /SUBSYSTEM:CONSOLE, and as a result have standard file handles that are guaranteed to be open and are likely to be connected to some console window (or a pipe, or redirected to a file, but they do exist). That guarantee is strong enough that when a console program is started outside of a console (as when double-clicked from Exporer, or named in the Start|Run box) then the system automatically creates a console window for it, and binds the standard file handles to the new console.
There are other subsystems, but those two are the only important ones for normal users and developers.
lua.exe and wlua.exe
So why does this matter?
The stock lua.exe will be linked for the console, because that makes it possible to use interactively from a command prompt. However, it means that it will always be supplied with a console window even when you don't want one.
The Lua for Windows distribution (which from the pathname showing in your console's title bar it looks like you are using) includes a second copy named wlua.exe which only differs by being linked for the Windows subsystem. As a result, it only displays a window if the script explicitly creates one to display. Of course, it also means that it cannot be used interactively at the command prompt.
File types and associations
For convenience, you can associate the file type .wlua with wlua.exe, and name your GUI script with that file type. That will enable launching programs in the usual way without getting the extra consoles. Of course, when debugging them, you can always run them with lua.exe from a command prompt and take advantage of the existence of stdout and the utility of the print function.
On my PC (64-bit Win 7 Pro) I have the following associations, which look like they were created by the installation of Lua for Windows:
C:...>assoc .lua
.lua=Lua.Script
C:...>ftype lua.script
lua.script="C:\Program Files (x86)\Lua\5.1\lua.exe" "%1" %*
C:...>assoc .wlua
.wlua=wLua.Script
C:...>ftype Wlua.script
Wlua.script="C:\Program Files (x86)\Lua\5.1\wlua.exe" "%1" %*
Extra credit: PATHEXT
You could also add .lua to the PATHEXT environment variable to save typing the file type at the command prompt. I'm not configured that way presently, but have in the past done that. I found that the standard practice of naming both modules and scripts with the same file type made that less useful.
The PATHEXT environment variable lists the file types that will be searched for in the PATH when you name a program to run without specifying its file type. Documentation for this is rather hard to locate, as there does not appear to be a single MSDN page listing all the "official" environment variables and their usage. This chapter of a book about Windows NT has a nice description of the interaction of PATH and PATHEXT, and despite being subtly out of date in some respects, it is the clearest detailed explanation of how the command prompt operates that I've come across.
It clarifies that each folder in PATH is searched for each extension named in PATHEXT:
If the command name includes a file extension, the shell searches each directory for the exact file name specified by the command name. If the command name does not include a file extension, the shell adds the extensions listed in the PATHEXT environment variable, one by one, and searches the directory for that file name. Note that the shell tries all possible file extensions in a specific directory before moving on to search the next directory (if there is one).
It also documents how file types and associations interact with the command prompt. Despite its age, it is well worth the read.
Windows executables explicitly list the subsystem they run on. As the windows "lua.exe" is linked for the console subsystem, windows automagically creates a console window for it. Just relink "lua.exe" for gui subsystem, and you won't get to see the output any more unless you run it from a console window. BTW: Gui programs can programmatically create the console.
An alternative is closing the created console on start.
For that, you must first use SetStdHandle to redirect STDIN, STDOUT and STDERR (use a file open to device nul if you don't want it at all), and then call FreeConsole to finally dismiss your unloved console window. No sweat, you have "alien" set up already...
Programmatic solution (run the same script under wlua.exe if possible)
do
local i, j = 0, 0
repeat j = j + 1 until not arg[j]
repeat i = i - 1 until not arg[i-1]
local exe = arg[i]:lower()
-- check if the script is running under lua.exe
if exe:find('lua%.exe$') and not exe:find('wlua%.exe$') then
arg[i] = exe:gsub('lua%.exe$','w%0')
-- check if wlua.exe exists
if io.open(arg[i]) then
-- run the same script under wlua.exe
os.execute('"start "" "'..table.concat(arg,'" "',i,j-1)..'""')
-- exit right now to close console window
os.exit()
end
end
end
-- Your main program is here:
require "luarocks.require"
require "alien"
local MessageBox = alien.User32.MessageBoxA
MessageBox:types{ret = "long", abi = "stdcall", "long", "string", "string", "long" }
MessageBox(0, "Hello World!", "My Window Title", 0x00000040)
If you can use winapi module or have similar calls in Alien, you can find the handler of the console window and hide the window itself. The code would be similar to this:
require winapi
local pid = winapi.get_current_pid()
local wins = winapi.find_all_windows(function(w)
return w:get_process():get_pid() == pid
and w:get_class_name() == 'ConsoleWindowClass'
end)
for _,win in pairs(wins) do win:show_async(winapi.SW_HIDE) end
You'll need to check if this leave the MessageBox visible or not.

Resources