diff --git a/README.md b/README.md index babca27..79aa1db 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,86 @@ # winrun + Simple Windows Executable to run commands from a file. ## About -The current [Base Camp™](https://mountain.gg/base-camp/) release does not support running commands or launching programs with custom launch options, -while at the same time only allowing you to select .exe files to be launched. -This program is a quick and dirty workaround for this usecase. -I can't think of any other usecase, because usually you could just write a .bat file or something similar. +The current [Base Camp™](https://mountain.gg/base-camp/) release does not support running commands or launching programs with custom launch options, while at the same time only allowing you to select .exe files to be launched. + +This program is a quick and dirty workaround for this usecase. + +Sometimes it may be desired to launch applications in the background, without giving focus to them. ***winrun*** allows for this. ## Installation and Usage + - Download the [latest version](https://github.com/schnotzler/winrun/releases) (winrun.exe) - Move the downloaded executable to any directory you like. I prefer to use same location as the program i want to run is in. -- Create a simple file named `winrun.cfg` in the ***same directory as winrun.exe*** -- Add you command(s) to `winrun.cfg`. See [this example](https://github.com/schnotzler/winrun/blob/main/winrun.cfg) which would run the windows calculator app +- Create a simple file named `winrun.cfg` in the ***same directory as winrun.exe*** +- Add the process(es) you wish to run `winrun.cfg`. See [this example](https://github.com/schnotzler/winrun/blob/main/winrun.cfg) which would run the windows editor (notepad.exe). Have a look at section [Advanced Usage](#detailed-usage-of-cfg) for more information - Now select `winrun.exe` from your directory in `Base Camp™`»`Device`»`Key Binding`»`Key`»`Function`»`Run Program`»`Link` -Note: Of course you can have multiple configuration of `winrun` in use, just make sure to use a different directory with a different `winrun.cfg` +Note: Of course you can have multiple configurations of `winrun` in use, just make sure to use a different directory with a different `winrun.cfg` + +## Detailed usage of `.cfg` + +### General + +The winrun.cfg file is parsed line by line. +Each line is executed one after another. +Empty lines are skipped. +It is therefore possible to open multiple programs in one go. + +### Leading whitespaces +Leading spaces or tabs are ignored. +So each one of the lines below is valid in a `winrun.cfg` and is going to give the same result. + +```cfg +notepad.exe winrun.cfg + notepad.exe winrun.cfg + notepad.exe winrun.cfg + notepad.exe winrun.cfg +``` + +### Running in background + +The default behaviour if not specified is, that the newly launched Program will receive focus. + +But it is possible to start programs in the background, without giving focus to them, as well. +However some applications give focus to themselves on launch, so your mileage may vary here. + +To mark program, to be run without focus, just add `#NOFOCUS` before the command. + +Whitespace handling is quite lenient here as well. + +So each one of the lines below is valid in a `winrun.cfg` and is going to give the same result, that is opening notepad without giving focus to the new window. + + +```cfg +#NOFOCUSnotepad.exe winrun.cfg +#NOFOCUS notepad.exe winrun.cfg + #NOFOCUS notepad.exe winrun.cfg + #NOFOCUSnotepad.exe winrun.cfg +#NOFOCUS notepad.exe winrun.cfg + #NOFOCUS notepad.exe winrun.cfg + #NOFOCUSnotepad.exe winrun.cfg +``` + +Analog to `#NOFOCUS` there is also support for `#FOCUS`, which as you may have guessed gives focus to the new window. +`#FOCUS` may be omitted, since it is the default behaviour anyway. + +You can mix and match `#NOFOCUS`, `#FOCUS`, and no explicit specification in the same `winrun.cfg` to your liking on a per-line-basis. + +Example for a mixed `winrun.cfg`, that would start 2 instances of notepad in the background and 2 in the foreground (only the last one will retain focus obviously). 2 of the editors will be empty, while 2 opened winrun.cfg. With the empty notepad launched by line 3 having focus. + +```cfg +#NOFOCUSnotepad.exe winrun.cfg +#FOCUS notepad.exe winrun.cfg +notepad.exe +#NOFOCUS notepad.exe +``` + +## Troubleshooting + +- If you have problems running your program, try using the absolute file path of your program `C:\WINDOWS\system32\notepad.exe` for example +- Open an Issue only **after** you have read this `Readme.md` entirely This is provided as-is. Use this program at you own risk, i am not responsible for any problems or damages you might have due to using this program diff --git a/main.c b/main.c index 0bda2cd..a3af1d9 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,13 @@ #include #include +void ShowErrorBox( char* msg, char* windowtitle ) { + HWND hwnd = NULL; // Use NULL to display the message box as a standalone window + LPCSTR text = msg; // The text to display in the message box + LPCSTR title = windowtitle; // The title of the message box + MessageBox( hwnd, text, title, MB_OK | MB_ICONERROR ); +} + int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int nCmdShow ) { FILE* fp; char linebuf[256 + 1] = { 0 }; @@ -25,8 +32,10 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdPara return -2; } + int retVal = 0; + // read and execute from file line by line - while ( 0 < fscanf( fp, "%256[A-Za-z0-9 -\\:]\n", linebuf ) ) { + while ( EOF != fscanf( fp, "%256[A-Za-z0-9 -\\:]\n", linebuf ) ) { STARTUPINFOA startupInfo = { 0 }; PROCESS_INFORMATION processInfo = { 0 }; @@ -37,25 +46,56 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdPara startupInfo.cb = sizeof( STARTUPINFO ); startupInfo.dwFlags = STARTF_USESHOWWINDOW; - // Focus new Window - // startupInfo.wShowWindow = SW_SHOWNORMAL; + // Trim leading whitespace(s) + while ( *commandLineArgs == ' ' || *commandLineArgs == '\t' ) { + commandLineArgs++; + } - // Don't Focus new Window - startupInfo.wShowWindow = SW_SHOWNOACTIVATE; + // Check for specified focus state and handle accordingly + if ( strncmp( "#NOFOCUS", commandLineArgs, 8 ) == 0 ) { + // Don't Focus new Window + startupInfo.wShowWindow = SW_SHOWNOACTIVATE; + commandLineArgs += 8; + } else { // Focus new Window + if ( strncmp( "#FOCUS", commandLineArgs, 6 ) == 0 ) { + commandLineArgs += 6; + } + startupInfo.wShowWindow = SW_SHOWNORMAL; + } + + // Trim leading whitespace(s) + while ( *commandLineArgs == ' ' || *commandLineArgs == '\t' ) { + commandLineArgs++; + } + + // Skip empty lines + if ( strlen( commandLineArgs ) == 0 ) { + // move fp by 1 + fgetc( fp ); + continue; + } // Launch the process if ( CreateProcessA( NULL, commandLineArgs, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo ) ) { - printf( "Process started with process ID %lu\n", processInfo.dwProcessId ); + // printf( "Process started with process ID %lu\n", processInfo.dwProcessId ); CloseHandle( processInfo.hProcess ); CloseHandle( processInfo.hThread ); } else { - printf( "Error launching process: %lu\n", GetLastError() ); - fclose( fp ); - return ( -3 ); + char* errortext = calloc( sizeof( char ), 512 + 1 /* \0 */ ); + // char errortext[512]; + snprintf( errortext, + 512, + "Error launching process: %lu\nFailed command: >%s<\nLine in file: %s", + GetLastError(), + commandLineArgs, + linebuf ); + ShowErrorBox( errortext, "CreateProcess Error" ); + free( errortext ); + retVal = -3; } } // cleanup and close fclose( fp ); - return ( 0 ); + return ( retVal ); } diff --git a/winrun.cbp b/winrun.cbp index ac40024..67b6e8a 100644 --- a/winrun.cbp +++ b/winrun.cbp @@ -3,6 +3,7 @@ diff --git a/winrun.cfg b/winrun.cfg index f8e3807..3d25181 100644 --- a/winrun.cfg +++ b/winrun.cfg @@ -1 +1 @@ -start calc +notepad.exe winrun.cfg \ No newline at end of file