Skip to content

Instantly share code, notes, and snippets.

@xWTF
Last active February 17, 2024 07:13
Show Gist options
  • Save xWTF/3c07aec941bbe13a9b78a37cebd9ae9b to your computer and use it in GitHub Desktop.
Save xWTF/3c07aec941bbe13a9b78a37cebd9ae9b to your computer and use it in GitHub Desktop.
Yet Another Windows Shim Wrapper Solution. Chocolatey's shimgen https://github.com/chocolatey/shimgen is not FOSS, so I made one.
"""
Get updates from [this gist](https://gist.github.com/xWTF/3c07aec941bbe13a9b78a37cebd9ae9b)
Copyright © 2023 xWTF
This work is free. You can redistribute it and/or modify it under the
terms of the Do What The Fuck You Want To Public License, Version 2,
as published by Sam Hocevar. See the COPYING file or http://www.wtfpl.net/
for more details.
"""
import os
import sys
import shutil
SHIM_CFG_FILE = "../.shim.cfg"
if len(sys.argv) < 2:
print("Usage: python generate_shim.py <target dir>")
exit(1)
os.chdir(os.path.dirname(os.path.realpath(__file__)))
known_shims = set()
shim_cfg = open(SHIM_CFG_FILE, "r").read()
for line in shim_cfg.split("\n"):
known_shims.add(line.split("=")[0])
target_dir = sys.argv[1].replace("/", "\\")
if target_dir.endswith("\\"):
target_dir = target_dir[:-1]
for file in os.listdir(target_dir):
if not file.endswith(".exe"):
continue
if file in known_shims:
print("Skipping " + file)
continue
print("Generating shim for " + file)
shutil.copyfile("shim.exe", "../" + file)
shim_cfg += "\n" + file + "=" + target_dir
shim_cfg += "\n"
open(SHIM_CFG_FILE, "w").write(shim_cfg)
/**
* Get updates from [this gist](https://gist.github.com/xWTF/3c07aec941bbe13a9b78a37cebd9ae9b)
*
* Copyright © 2023 xWTF
* This work is free. You can redistribute it and/or modify it under the
* terms of the Do What The Fuck You Want To Public License, Version 2,
* as published by Sam Hocevar. See the COPYING file or http://www.wtfpl.net/
* for more details.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#define SHIM_CFG_FILE L".shim.cfg"
#define MAX_ENV 32767
int wmain(int argc, wchar_t* argv[])
{
wchar_t module_file[MAX_PATH];
if (GetModuleFileNameW(NULL, module_file, MAX_PATH) == 0) {
std::cerr << "GetModuleFileName failed (" << GetLastError() << ").\n";
return -1;
}
std::wstring cfg_path(module_file), exe_name;
size_t pos = cfg_path.find_last_of('\\');
if (pos == std::string::npos) {
std::cerr << "Failed to locate config file (" << GetLastError() << ").\n";
return -1;
}
exe_name = cfg_path.substr(pos + 1);
cfg_path = cfg_path.substr(0, pos + 1);
cfg_path += SHIM_CFG_FILE;
//// Read Config /////////////////////////////////////////////
bool found = false;
std::wstring line, expected_path;
std::wifstream cfg(cfg_path.data());
while (std::getline(cfg, line)) {
if (line.empty() || line[0] == '#') {
continue;
}
auto pos = line.find('=');
if (pos == std::string::npos) {
continue;
}
auto key = line.substr(0, pos);
if (key == exe_name) {
expected_path = line.substr(pos + 1);
found = true;
break;
}
}
cfg.close();
if (!found) {
std::wcerr << "No entry for " << exe_name << " in " << cfg_path << "\n";
return -1;
}
//// Prepend PATH /////////////////////////////////////////////////
wchar_t PATH[MAX_ENV];
DWORD lPATH = GetEnvironmentVariableW(L"PATH", PATH, MAX_ENV);
if (lPATH == 0) {
std::cerr << "GetEnvironmentVariable failed (" << GetLastError() << ").\n";
return -1;
}
wchar_t* PATH_new = new wchar_t[lPATH + expected_path.size() + 2];
wcscpy(PATH_new, expected_path.c_str());
PATH_new[expected_path.size()] = L';';
wcsncpy(PATH_new + expected_path.size() + 1, PATH, lPATH);
PATH_new[lPATH + expected_path.size() + 1] = L'\0';
if (!SetEnvironmentVariableW(L"PATH", PATH_new)) {
std::cerr << "SetEnvironmentVariable failed (" << GetLastError() << ").\n";
return -1;
}
delete[] PATH_new;
//// Prepare Command Line /////////////////////////////////////////////////
auto lpCmdLineW = GetCommandLineW();
if (*lpCmdLineW == '"') {
++lpCmdLineW;
while (*lpCmdLineW++ != '"');
} else {
while (*lpCmdLineW && *lpCmdLineW != ' ' && *lpCmdLineW != '\t') {
++lpCmdLineW;
}
}
while (*lpCmdLineW == ' ' || *lpCmdLineW == '\t') {
lpCmdLineW++;
}
// Append executable name
expected_path += L'\\';
expected_path += exe_name;
//// Create process //////////////////////////////////////////////
STARTUPINFOW si {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi {};
if (!CreateProcessW(expected_path.data(), const_cast<wchar_t*>((exe_name + L' ' + lpCmdLineW).c_str()),
NULL, NULL, // Process, thread attributes
TRUE, // Handle inheritance
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, &pi) // Pointers
) {
std::cerr << "CreateProcess failed (" << GetLastError() << ").\n";
return -1;
}
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exitCode;
if (!GetExitCodeProcess(pi.hProcess, &exitCode)) {
std::cerr << "GetExitCodeProcess failed (" << GetLastError() << ").\n";
return -1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return exitCode;
}
"""
Get updates from [this gist](https://gist.github.com/xWTF/3c07aec941bbe13a9b78a37cebd9ae9b)
Copyright © 2023 xWTF
This work is free. You can redistribute it and/or modify it under the
terms of the Do What The Fuck You Want To Public License, Version 2,
as published by Sam Hocevar. See the COPYING file or http://www.wtfpl.net/
for more details.
"""
import os
import shutil
for file in os.listdir("../"):
if not file.endswith(".exe"):
continue
print("Updating shim for " + file)
shutil.copyfile("shim.exe", "../" + file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment