summaryrefslogtreecommitdiffstats
path: root/core/modules/run-virt/winres
diff options
context:
space:
mode:
authorJonathan Bauer2016-12-23 13:12:09 +0100
committerJonathan Bauer2016-12-23 13:12:09 +0100
commit6806ae4a850fc7785a8c05304237cf53b5b8f951 (patch)
treeb1dd8413d6c7b9a250251da7f0d49bb52b4ddc57 /core/modules/run-virt/winres
parentwrong kernel version variable used (diff)
downloadmltk-6806ae4a850fc7785a8c05304237cf53b5b8f951.tar.gz
mltk-6806ae4a850fc7785a8c05304237cf53b5b8f951.tar.xz
mltk-6806ae4a850fc7785a8c05304237cf53b5b8f951.zip
merge with latest dev version (tm-scripts commit f5a59daf8d70a9027118292cd40b18c221897408)
Diffstat (limited to 'core/modules/run-virt/winres')
-rwxr-xr-xcore/modules/run-virt/winres/compile13
-rw-r--r--core/modules/run-virt/winres/winres.c1166
-rw-r--r--core/modules/run-virt/winres/winres.manifest34
-rw-r--r--core/modules/run-virt/winres/winres.rc4
4 files changed, 1217 insertions, 0 deletions
diff --git a/core/modules/run-virt/winres/compile b/core/modules/run-virt/winres/compile
new file mode 100755
index 00000000..da2f59eb
--- /dev/null
+++ b/core/modules/run-virt/winres/compile
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+rm -- winres.exe
+i686-w64-mingw32-windres -i winres.rc -o resource.res -O coff
+i686-w64-mingw32-gcc -Wall -Wextra -pedantic -Wno-unused-parameter -flto -std=c99 -Os -Wl,--subsystem,windows -o winres.exe winres.c resource.res -lole32 -luuid -lgdi32 -lws2_32 -lshell32 -lmpr -lshlwapi
+rm -- resource.res
+if strip winres.exe; then
+ echo "Successfully created winres.exe"
+ echo "It has NOT been moved to data/.../openslx.exe"
+else
+ echo "FAIL FAIL FAIL no EXE generated!"
+fi
+
diff --git a/core/modules/run-virt/winres/winres.c b/core/modules/run-virt/winres/winres.c
new file mode 100644
index 00000000..44654161
--- /dev/null
+++ b/core/modules/run-virt/winres/winres.c
@@ -0,0 +1,1166 @@
+#define NTDDI_VERSION NTDDI_VISTA
+#define WINVER 0x0602
+#define _WIN32_WINNT 0x0602
+#define WIN32_LEAN_AND_MEAN
+#define _UNICODE
+#define UNICODE
+#define NO_SHLWAPI_STRFCNS
+#include <windows.h>
+#include <winsock2.h>
+#include <winnetwk.h>
+#include <mmdeviceapi.h>
+#include <endpointvolume.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <initguid.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <time.h>
+#include <shlobj.h>
+#include <shlguid.h>
+#include <strsafe.h>
+#include <tlhelp32.h>
+#include <shlwapi.h>
+#include <shellapi.h>
+
+DEFINE_GUID(ID_IAudioEndpointVolume, 0x5CDF2C82, 0x841E, 0x4546, 0x97, 0x22, 0x0C, 0xF7, 0x40, 0x78, 0x22, 0x9A);
+DEFINE_GUID(ID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6);
+DEFINE_GUID(ID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
+
+#define WM_SOCKDATA (WM_APP+1)
+
+typedef struct {
+ const char* path;
+ const char* pathIp;
+ const char* letter;
+ const char* shortcut;
+ const char* user;
+ const char* pass;
+ BOOL success;
+} netdrive_t;
+
+static const ssize_t KEYLEN = 16;
+#define DRIVEMAX (100)
+#define LOGFILELEN (300)
+#define SETTINGS_FILE "B:\\OPENSLX.INI"
+#define SETTINGS_FILE_W L"B:\\OPENSLX.INI"
+
+static BOOL _debug = FALSE;
+
+static HINSTANCE hKernel32, hShell32;
+static OSVERSIONINFO winVer;
+static BOOL bGetShares = FALSE;
+static netdrive_t drives[DRIVEMAX];
+static wchar_t desktopPath[MAX_PATH+1], tempPath[MAX_PATH+1], programsPath[MAX_PATH+1], windowsPath[MAX_PATH+1];
+static wchar_t logFile[LOGFILELEN];
+static DWORD _startTime;
+#define FS_UNKNOWN (-1)
+#define FS_ERROR (0)
+#define FS_OK (1)
+static int _folderStatus = FS_UNKNOWN; // -1 = Not handled yet, 0 = patching failed, 1 = remapped ok
+#define RM_NONE (0)
+#define RM_NATIVE (1)
+#define RM_NATIVE_FALLBACK (2)
+#define RM_VMWARE (3)
+static int _remapMode = RM_NONE;
+static const char* _remapHomeDrive = NULL;
+
+#define SCRIPTFILELEN (50)
+char _scriptFile[SCRIPTFILELEN];
+
+struct {
+ BOOL documents;
+ BOOL downloads;
+ BOOL desktop;
+ BOOL media;
+ BOOL other;
+} remap;
+static BOOL _createMissingRemap = FALSE;
+
+static void setPowerState();
+static int setResolution();
+static int muteSound();
+static int setShutdownText();
+static void readShareFile();
+static BOOL mountNetworkShares();
+static int queryPasswordDaemon();
+static BOOL fileExists(wchar_t* szPath);
+static BOOL folderExists(wchar_t* szPath);
+static void patchUserPaths(wchar_t *letter);
+static void remapViaSharedFolder();
+
+static HRESULT createFolderShortcut(wchar_t* sTargetfile, wchar_t* sLinkfile, wchar_t* comment);
+
+static void alog(const char *fmt, ...)
+{
+ FILE *f = _wfopen(logFile, L"a+");
+ if (f == NULL) return;
+ time_t raw = time(NULL);
+ struct tm *tinf;
+ char buffer[80];
+ tinf = localtime(&raw);
+ strftime(buffer, 80, "%I:%M:%S ", tinf);
+ fputs(buffer, f);
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(f, fmt, args);
+ va_end(args);
+ fputc('\n', f);
+ fclose(f);
+}
+
+static void wlog(const wchar_t *fmt, ...)
+{
+ wchar_t wbuffer[1000];
+ char abuffer[1000];
+ va_list args;
+
+ FILE *f = _wfopen(logFile, L"a+");
+ if (f == NULL) return;
+ time_t raw = time(NULL);
+ struct tm *tinf;
+ tinf = localtime(&raw);
+ strftime(abuffer, 1000, "%I:%M:%S ", tinf);
+ fputs(abuffer, f);
+
+ va_start(args, fmt);
+ StringCchVPrintfW(wbuffer, 1000, fmt, args);
+ va_end(args);
+ if (WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, abuffer, 1000, NULL, NULL) == 0) {
+ snprintf(abuffer, 1000, "Cannot wlog: widechar to utf8 failed.");
+ }
+ fputs(abuffer, f);
+ fputc('\n', f);
+ fclose(f);
+}
+
+static void CALLBACK resetShutdown(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ static BOOL bInProc = FALSE;
+ if (!bInProc) {
+ bInProc = TRUE;
+ setShutdownText();
+ bInProc = FALSE;
+ }
+}
+
+static void CALLBACK tmrResolution(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ static BOOL bInProc = FALSE;
+ if (!bInProc) {
+ bInProc = TRUE;
+ if (setResolution() == 0) {
+ KillTimer(hWnd, idEvent);
+ }
+ bInProc = FALSE;
+ }
+}
+
+static void CALLBACK setupNetworkDrives(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ static BOOL bInProc = FALSE;
+ static int fails = 0;
+ if (bInProc)
+ return;
+ bInProc = TRUE;
+ if (!bGetShares && (_remapMode == RM_NATIVE_FALLBACK || _remapMode == RM_VMWARE)) {
+ remapViaSharedFolder();
+ } else {
+ int ret = queryPasswordDaemon();
+ if (ret != 0) {
+ if (++fails < 10)
+ goto exit_func;
+ alog("queryPasswordDaemon returned %d", ret);
+ } else {
+ if (!mountNetworkShares()) {
+ if (GetTickCount() - _startTime < 30000 && ++fails < 15)
+ goto exit_func;
+ }
+ }
+ // Finished successfully or failed completely
+ if (_folderStatus != FS_OK && (_remapMode == RM_NATIVE_FALLBACK || _remapMode == RM_VMWARE)) {
+ remapViaSharedFolder();
+ }
+ }
+ KillTimer(hWnd, idEvent);
+ if (_remapMode != RM_NONE) {
+ if (_folderStatus == FS_ERROR) {
+ MessageBoxA(NULL, "Fehler beim Einbinden des Home-Verzeichnisses. Bitte nichts Wichtiges in der VM speichern, sondern z.B. einen USB-Stick verwenden.", "Warnung", MB_ICONERROR);
+ } else if (_folderStatus == FS_UNKNOWN) {
+ MessageBoxA(NULL, "Kein Home-Verzeichnis gefunden. Bitte nichts Wichtiges in der VM speichern, sondern z.B. einen USB-Stick verwenden.", "Warnung", MB_ICONERROR);
+ }
+ }
+ return;
+exit_func:
+ bInProc = FALSE;
+}
+
+typedef HRESULT (*GFPTYPE)(HWND, int, HANDLE, DWORD, wchar_t*);
+typedef HRESULT (*GSFTYPE)(HWND, int, ITEMIDLIST**);
+typedef BOOL (*ID2PTYPE)(const ITEMIDLIST*, wchar_t*);
+
+/**
+ * Load given path (CSIDL). Store in default (must be allocated to hold at least MAX_PATH+1 chars).
+ * If it could not be retrieved by CSIDL and envName is not NULL, it will be read from the
+ * environment if possible.
+ * fallback will be used if everything else fails.
+ * fallback can be NULL, in which case the fallback is empty.
+ */
+static void loadPath(wchar_t *dest, int csidl, wchar_t *envName, wchar_t *fallback)
+{
+ if (hShell32 != NULL) {
+ GFPTYPE aGetFolderPath = (GFPTYPE)GetProcAddress(hShell32, "SHGetFolderPathW");
+ if (aGetFolderPath != NULL) {
+ if ((aGetFolderPath)(HWND_DESKTOP, csidl, NULL, SHGFP_TYPE_CURRENT, dest) == S_OK)
+ return;
+ }
+ // Fallback
+ GSFTYPE aGetSpecialFolder = (GSFTYPE)GetProcAddress(hShell32, "SHGetSpecialFolderLocation");
+ ID2PTYPE aPathToId = (ID2PTYPE)GetProcAddress(hShell32, "SHGetPathFromIDListW");
+ if (aGetSpecialFolder != NULL && aPathToId != NULL) {
+ ITEMIDLIST *list = NULL;
+ HRESULT ret1 = (aGetSpecialFolder)(HWND_DESKTOP, csidl, &list);
+ BOOL ret2 = FALSE;
+ if (ret1 == 0) {
+ ret2 = (aPathToId)(list, dest);
+ }
+ if (list != NULL) {
+ CoTaskMemFree(list);
+ }
+ if (ret2)
+ return;
+ }
+ }
+ if (envName != NULL) {
+ // Fallback
+ DWORD ret = GetEnvironmentVariableW(envName, dest, MAX_PATH+1);
+ if (ret > 0 && ret <= MAX_PATH)
+ return;
+ }
+ if (fallback != NULL) {
+ StringCchPrintfW(programsPath, MAX_PATH+1, fallback);
+ return;
+ }
+ *dest = '\0';
+}
+
+static void loadPaths()
+{
+ // Determine a couple of default directories
+ // dest, id, env, fallback
+ loadPath(programsPath, CSIDL_PROGRAM_FILES, L"ProgramFiles", L"C:\\Program Files");
+ loadPath(windowsPath, CSIDL_WINDOWS, L"windir", L"C:\\WINDOWS");
+ loadPath(desktopPath, CSIDL_DESKTOPDIRECTORY, NULL, NULL);
+ if (GetTempPathW(MAX_PATH+1, tempPath) == 0) {
+ DWORD ret = GetEnvironmentVariableW(L"TEMP", tempPath, MAX_PATH+1);
+ if (ret == 0 || ret > MAX_PATH) {
+ tempPath[0] = 0;
+ }
+ }
+ //wlog(L"Programs: %s, Windows: %s, Desktop: %s, Temp: %s", programsPath, windowsPath, desktopPath, tempPath);
+ StringCchPrintfW(logFile, LOGFILELEN, L"%s\\%s", desktopPath, L"openslx.log");
+ FILE *tfh = _wfopen(logFile, L"a+");
+ if (tfh == NULL) {
+ StringCchPrintfW(logFile, LOGFILELEN, L"%s\\%s", tempPath, L"openslx.log");
+ tfh = _wfopen(logFile, L"a+");
+ }
+ if (tfh != NULL) {
+ fseek(tfh, 0, SEEK_END);
+ long pos = ftell(tfh);
+ fclose(tfh);
+ if (pos < 3) {
+ _wremove(logFile);
+ }
+ }
+ // Read settings from ini file
+ remap.documents = GetPrivateProfileIntA("remap", "documents", 1, SETTINGS_FILE) != 0;
+ remap.downloads = GetPrivateProfileIntA("remap", "downloads", 1, SETTINGS_FILE) != 0;
+ remap.desktop = GetPrivateProfileIntA("remap", "desktop", 0, SETTINGS_FILE) != 0;
+ remap.media = GetPrivateProfileIntA("remap", "media", 1, SETTINGS_FILE) != 0;
+ remap.other = GetPrivateProfileIntA("remap", "other", 0, SETTINGS_FILE) != 0;
+ _createMissingRemap = GetPrivateProfileIntA("openslx", "createMissingRemap", 1, SETTINGS_FILE) != 0;
+ _remapMode = GetPrivateProfileIntA("openslx", "remapMode", RM_NATIVE_FALLBACK, SETTINGS_FILE);
+ if (_remapMode == RM_NONE) {
+ _folderStatus = FS_OK;
+ }
+ char buffer[10];
+ GetPrivateProfileStringA("openslx", "homeDrive", "H:", buffer, sizeof(buffer), SETTINGS_FILE);
+ buffer[0] = toupper(buffer[0]);
+ buffer[1] = ':';
+ buffer[2] = '\0';
+ _remapHomeDrive = strdup(buffer);
+ // Get extension for autorun script
+ GetPrivateProfileStringA("openslx", "scriptExt", "", buffer, sizeof(buffer), SETTINGS_FILE);
+ StringCchPrintfA(_scriptFile, SCRIPTFILELEN, "B:\\runscript%s", buffer);
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ hKernel32 = LoadLibraryW(L"kernel32.dll");
+ if (hKernel32 == NULL) {
+ alog("Cannot load kernel32.dll");
+ }
+ hShell32 = LoadLibraryW(L"shell32.dll");
+ if (hShell32 == NULL) {
+ alog("Cannot load shell32.dll");
+ }
+ winVer.dwOSVersionInfoSize = sizeof(winVer);
+ BOOL retVer = GetVersionEx(&winVer);
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+ _startTime = GetTickCount();
+ loadPaths();
+ if (lpCmdLine != NULL && strstr(lpCmdLine, "debug") != NULL) {
+ _debug = TRUE;
+ alog("Windows Version %d.%d", (int)winVer.dwMajorVersion, (int)winVer.dwMinorVersion);
+ }
+ // Mute sound by default
+ if (retVer && winVer.dwMajorVersion >= 6)
+ muteSound();
+ // Disable screen saver as it might give the false impression that the session is securely locked
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
+ // Same with standby
+ setPowerState();
+ // Any network shares to mount?
+ readShareFile();
+ if (bGetShares || _remapMode != RM_NONE) {
+ UINT_PTR tRet = SetTimer(NULL, 0, 1550, (TIMERPROC)&setupNetworkDrives);
+ if (tRet == 0) {
+ alog("Could not create timer for mounting network shares: %d", (int)GetLastError());
+ }
+ }
+ // Shutdown button label
+ if (retVer && winVer.dwMajorVersion == 6 && winVer.dwMinorVersion == 1) {
+ // Only on Windows 7
+ // Repeatedly set caption
+ UINT_PTR tRet = SetTimer(NULL, 0, 5230, (TIMERPROC)&resetShutdown);
+ if (tRet == 0) {
+ alog("Could not create timer for shutdown button: %d", (int)GetLastError());
+ }
+ }
+ // Resolution
+ if (fileExists(SETTINGS_FILE_W) && setResolution() != 0) {
+ UINT_PTR tRet = SetTimer(NULL, 0, 3111, (TIMERPROC)&tmrResolution);
+ if (tRet == 0) {
+ alog("Could not create timer for resolution setting: %d", (int)GetLastError());
+ }
+ }
+ // Runscript (if any)
+ if (PathFileExistsA(_scriptFile)) {
+ ShellExecuteA(NULL, "open", _scriptFile, NULL, "B:\\", SW_SHOWNORMAL);
+ }
+ // Message pump
+ MSG Msg;
+ while(GetMessage(&Msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&Msg);
+ DispatchMessage(&Msg);
+ }
+ FreeLibrary(hKernel32);
+ FreeLibrary(hShell32);
+ return 0;
+}
+
+static BOOL fileExists(wchar_t* szPath)
+{
+ DWORD dwAttrib = GetFileAttributesW(szPath);
+ return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0);
+}
+
+static BOOL folderExists(wchar_t* szPath)
+{
+ DWORD dwAttrib = GetFileAttributesW(szPath);
+ return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
+}
+
+static int execute(wchar_t *path, wchar_t *arguments)
+{
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&si, sizeof(si));
+ ZeroMemory(&pi, sizeof(pi));
+ si.cb = sizeof(si);
+ if (!CreateProcessW(path, arguments, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
+ return -1;
+ }
+ while (MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_SENDMESSAGE) == WAIT_OBJECT_0+1) {
+ MSG Msg;
+ while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE)) {
+ TranslateMessage(&Msg);
+ DispatchMessage(&Msg);
+ }
+ }
+ DWORD exitCode;
+ BOOL ret = GetExitCodeProcess(pi.hProcess, &exitCode);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ if (!ret) {
+ return -2;
+ }
+ return (int)exitCode;
+}
+
+typedef EXECUTION_STATE (WINAPI *TETYPE)(EXECUTION_STATE);
+
+static void setPowerState()
+{
+ // Disable standby and idle-mode (this is a VM!)
+ if (hKernel32 == NULL || winVer.dwMajorVersion < 5 || (winVer.dwMajorVersion == 5 && winVer.dwMinorVersion < 1))
+ return;
+ TETYPE aExecState = (TETYPE)GetProcAddress(hKernel32, "SetThreadExecutionState");
+ if (aExecState == NULL) {
+ alog("Cannot get SetThreadExecutionState from kernel32.dll");
+ return;
+ }
+ if (winVer.dwMajorVersion >= 6) { // Vista+
+ (aExecState)(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_AWAYMODE_REQUIRED);
+ } else { // XP/2003
+ (aExecState)(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
+ }
+}
+
+static int setResolution()
+{
+ int ret;
+ static int width = 0, height = 0;
+ if (width == 0 && height == 0) {
+ // use config file in floppy
+ char data[200] = "";
+ GetPrivateProfileStringA("openslx", "resolution", "", data, sizeof(data), SETTINGS_FILE);
+ char *x = strchr(data, 'x');
+ if (x == NULL) {
+ alog("Malformed resolution in " SETTINGS_FILE ": '%s'", data);
+ return 0;
+ }
+ *x++ = '\0';
+ width = atoi(data);
+ height = atoi(x);
+ if (width < 320 || height < 240) {
+ alog("Invalid resolution in " SETTINGS_FILE ": '%s' (parsed width=%d, height=%d)", data, width, height);
+ return 0;
+ }
+ }
+ // Try vmware tools
+ static wchar_t path[MAX_PATH] = L"";
+ if (path[0] == 0) {
+ StringCchPrintfW(path, MAX_PATH, L"%s\\VMware\\VMware Tools\\VMwareResolutionSet.exe", programsPath);
+ if (!fileExists(path)) {
+ // Strip (x86) if found and try again
+ wchar_t *x86 = wcsstr(path, L" (x86)");
+ if (x86 != NULL) {
+ while ((*x86 = *(x86 + 6)) != 0) ++x86;
+ }
+ }
+ if (!fileExists(path)) {
+ char buffer[300];
+ WideCharToMultiByte(CP_UTF8, 0, path, -1, buffer, 300, NULL, NULL);
+ alog("vmware tools not found, using winapi to set resolution (path: %s)", buffer);
+ }
+ }
+ if (path[0] != 0 && fileExists(path)) {
+ wchar_t cmdline[MAX_PATH];
+ StringCchPrintfW(cmdline, MAX_PATH, L"VMwareResolutionSet.exe 0 1 , 0 0 %d %d", width, height);
+ int ret = execute(path, cmdline);
+ if (ret == -1) {
+ alog("VmwareRes: CreateProcess failed (%d)", (int)GetLastError());
+ } else if (ret == -2) {
+ alog("VmwareRes: GetExitCode failed (%d)", (int)GetLastError());
+ }
+ }
+ // Use WinAPI as fallback
+ DEVMODE mode;
+ int query = 1337;
+ memset(&mode, 0, sizeof(mode));
+ mode.dmSize = sizeof(mode);
+ // MSDN recommends to fill the struct first by querying....
+ query = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode);
+ // Then set our own desired mode
+ mode.dmPelsWidth = width;
+ mode.dmPelsHeight = height;
+ mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+ ret = ChangeDisplaySettings(&mode, CDS_GLOBAL | CDS_UPDATEREGISTRY);
+ if (ret != DISP_CHANGE_SUCCESSFUL) {
+ ret = ChangeDisplaySettings(&mode, CDS_GLOBAL);
+ }
+ if (ret != DISP_CHANGE_SUCCESSFUL) {
+ ret = ChangeDisplaySettings(&mode, CDS_UPDATEREGISTRY);
+ }
+ if (ret != DISP_CHANGE_SUCCESSFUL) {
+ ret = ChangeDisplaySettings(&mode, 0);
+ }
+ if (ret != DISP_CHANGE_SUCCESSFUL) {
+ static int fails = 0;
+ if (++fails == 5) {
+ alog("Fehler beim Setzen der Auflösung: %d (soll: 0) / %d ( soll: !0) - Zielaufloesung: %d * %d",
+ ret, query, width, height);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int muteSound()
+{
+ IMMDeviceEnumerator *deviceEnumerator = NULL;
+ HRESULT hr = CoCreateInstance(&ID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &ID_IMMDeviceEnumerator, (LPVOID *)&deviceEnumerator);
+ if (hr != S_OK) {
+ alog("CoCreateInstance failed. Cannot mute.");
+ return 1;
+ }
+ //deviceEnumerator->lpVtbl->AddRef(deviceEnumerator);
+ IMMDevice *defaultDevice = NULL;
+ hr = deviceEnumerator->lpVtbl->GetDefaultAudioEndpoint(deviceEnumerator, eRender, eConsole, &defaultDevice);
+ if (hr != S_OK) {
+ alog("GetDefaultAudioEndpoint failed. Cannot mute.");
+ return 2;
+ }
+ //defaultDevice->lpVtbl->AddRef(defaultDevice);
+ //deviceEnumerator->lpVtbl->Release(deviceEnumerator);
+ IAudioEndpointVolume *endpointVolume = NULL;
+ hr = defaultDevice->lpVtbl->Activate(defaultDevice, &ID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
+ if (hr != S_OK) {
+ alog("IMMDevice::Activate() failed. Cannot mute.");
+ return 3;
+ }
+ //endpointVolume->lpVtbl->AddRef(endpointVolume);
+ //defaultDevice->lpVtbl->Release(defaultDevice);
+ float targetVolume = 1;
+ endpointVolume->lpVtbl->SetMasterVolumeLevelScalar(endpointVolume, targetVolume, NULL);
+ endpointVolume->lpVtbl->SetMute(endpointVolume, TRUE, NULL);
+ //endpointVolume->lpVtbl->Release(endpointVolume);
+ //CoUninitialize();
+ return 0;
+}
+
+static int setShutdownText()
+{
+ HWND hMenu = FindWindowA("DV2ControlHost", NULL);
+ if (hMenu == NULL) return 1; // TODO: Enum all of them
+ HWND hPane = FindWindowExA(hMenu, NULL, "DesktopLogoffPane", NULL);
+ if (hMenu == NULL) return 2;
+ HWND hButton = FindWindowExA(hPane, NULL, "Button", NULL);
+ if (hButton == NULL) return 3;
+ if (SendMessageA(hButton, WM_SETTEXT, 0, (LPARAM)"Abmelden") != TRUE) return 4;
+ return 0;
+}
+
+static char *shost = NULL, *sport = NULL, *suser = NULL, *spass = NULL;
+static uint8_t *bkey1 = NULL, *bkey2 = NULL;
+
+static char* xorString(const uint8_t* text, int len, const uint8_t* key);
+static int getbin(int x);
+static uint8_t* hex2bin(char *szHexString);
+
+static char* getToken(char **ptr, BOOL doDup)
+{
+ if (*ptr == NULL || **ptr == '\0') return NULL;
+ char *dest = *ptr;
+ while (**ptr != '\0') {
+ if (**ptr == '\n' || **ptr == '\r' || **ptr == '\t') {
+ *(*ptr)++ = '\0';
+ break;
+ }
+ (*ptr)++;
+ }
+ if (doDup) {
+ dest = strdup(dest);
+ }
+ return dest;
+}
+
+const char* uncReplaceFqdnByIp(const char* path)
+{
+ if (path == NULL || path[0] != '\\' || path[1] != '\\')
+ return NULL;
+ const char *host = path + 2;
+ const char *rest = strchr(host, '\\');
+ if (rest == NULL || rest - host >= 200)
+ return NULL;
+ char name[201];
+ strncpy(name, host, rest - host);
+ name[rest-host] = '\0';
+ if (_debug) {
+ alog("Trying to resolve '%s'...", name);
+ }
+ struct hostent *remote = gethostbyname(name);
+ if (remote == NULL || remote->h_addrtype != AF_INET || remote->h_addr_list[0] == 0)
+ return NULL;
+ struct in_addr addr;
+ addr.s_addr = *(u_long*)remote->h_addr_list[0];
+ char *ip = inet_ntoa(addr);
+ if (ip == NULL)
+ return NULL;
+ size_t len = 2 /* \\ */ + strlen(ip) /* 1.2.3.4 */ + strlen(rest) /* \path\to\share */ + 1 /* nullchar */;
+ char *retval = malloc(len);
+ snprintf(retval, len, "\\\\%s%s", ip, rest);
+ if (_debug) {
+ alog("Turned '%s' into '%s'", path, retval);
+ }
+ return retval;
+}
+
+#define FREENULL(x) do { free((void*)(x)); (x) = NULL; } while (0)
+
+static void readShareFile()
+{
+ if (bGetShares)
+ return;
+ memset(drives, 0, sizeof(drives));
+ FILE *h = fopen("B:\\shares.dat", "r");
+ if (h == NULL) return;
+ char creds[300] = "", buffer[500] = "";
+ char *skey1 = NULL, *skey2 = NULL;
+ if (fgets(creds, sizeof(creds), h) != NULL) {
+ char *ptr = creds;
+ shost = getToken(&ptr, TRUE);
+ sport = getToken(&ptr, TRUE);
+ skey1 = getToken(&ptr, FALSE);
+ skey2 = getToken(&ptr, FALSE);
+ suser = getToken(&ptr, TRUE);
+ }
+ int idx = 0;
+ while (fgets(buffer, sizeof(buffer), h) != NULL && idx < DRIVEMAX) {
+ char *ptr = buffer;
+ netdrive_t *d = &drives[idx];
+ d->path = getToken(&ptr, TRUE);
+ d->letter = getToken(&ptr, TRUE);
+ d->shortcut = getToken(&ptr, TRUE);
+ d->user = getToken(&ptr, TRUE);
+ d->pass = getToken(&ptr, TRUE);
+ if (d->path == NULL || d->path[0] == '\0')
+ goto drive_fail;
+ d->success = FALSE;
+ // Hack: For unknown reasons, with some servers mounting fails using a fqdn, but using the ip address instead succeeds.
+ d->pathIp = uncReplaceFqdnByIp(d->path);
+ //
+ idx++;
+ continue;
+drive_fail:
+ FREENULL(d->path);
+ FREENULL(d->letter);
+ FREENULL(d->shortcut);
+ FREENULL(d->user);
+ FREENULL(d->pass);
+ }
+ fclose(h);
+ if (idx == 0) // No drives to map
+ return;
+ if (shost == NULL || sport == NULL || skey1 == NULL || skey2 == NULL || suser == NULL) // Credential stuff missing
+ return;
+ if (strlen(skey1) != KEYLEN*2 || strlen(skey2) != KEYLEN*2) // Messed up keys
+ return;
+ if (atoi(sport) < 1000 || atoi(sport) > 65535) // Invalid port
+ return;
+ bkey1 = hex2bin(skey1);
+ bkey2 = hex2bin(skey2);
+ if (bkey1 == NULL || bkey2 == NULL)
+ return;
+ bGetShares = TRUE;
+}
+
+static void udpReceived(SOCKET sock);
+
+LRESULT CALLBACK slxWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg != WM_SOCKDATA) {
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+ // Socket event
+ int event = LOWORD(lParam);
+ int errorCode = HIWORD(lParam);
+ if (errorCode == 0 && event == FD_READ) {
+ udpReceived((SOCKET)wParam);
+ }
+ return 0;
+}
+
+static int queryPasswordDaemon()
+{
+ // See if preconditions are met
+ if (!bGetShares || spass != NULL)
+ return 0;
+ static int wsaInit = 1337;
+ static SOCKET sock = INVALID_SOCKET;
+ static HWND sockWnd = NULL;
+ // Init socket stuff
+ if (wsaInit == 1337) {
+ WSADATA wsa;
+ wsaInit = WSAStartup(MAKEWORD(2, 2), &wsa);
+ }
+ if (wsaInit != 0)
+ return 2;
+ // Create window for socket events
+ if (sockWnd == NULL) {
+ sockWnd = CreateWindowA("STATIC", "OpenSLX mystery window", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ if (sockWnd == NULL)
+ return GetLastError();
+ SetWindowLong(sockWnd, GWL_WNDPROC, (LONG)&slxWindowProc);
+ }
+ // Create socket
+ if (sock == INVALID_SOCKET) {
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET)
+ return 3;
+ if (WSAAsyncSelect(sock, sockWnd, WM_SOCKDATA, FD_READ) != 0) {
+ alog("WSAAsyncSelect returned %d", (int)WSAGetLastError());
+ }
+ }
+ SOCKADDR_IN remote;
+ remote.sin_family = AF_INET;
+ remote.sin_port = htons((u_short)atoi(sport));
+ remote.sin_addr.s_addr = inet_addr(shost);
+ // Send out request for password
+ if (sendto(sock, (const char*)bkey1, KEYLEN, 0, (struct sockaddr*)&remote, sizeof(remote)) != KEYLEN)
+ return 4;
+ if (spass == NULL)
+ return -1;
+ return 0;
+}
+
+static void udpReceived(SOCKET sock)
+{
+ int ret;
+ uint8_t buffer[200];
+ ret = recv(sock, (char*)buffer, sizeof(buffer), 0);
+ // See if reply is valid
+ if (ret < 2) return;
+ uint16_t len = (uint16_t)(((uint16_t)buffer[0] << 8) | buffer[1]);
+ if (ret - 2 != len) return;
+ // Success
+ spass = xorString(buffer + 2, len, bkey2);
+ closesocket(sock);
+ mountNetworkShares();
+}
+
+#define BUFLEN (200)
+
+static DWORD mount(LPNETRESOURCEW share, LPWSTR pass, LPWSTR user)
+{
+ DWORD retval;
+ // Now try to mount
+ if ((pass && *pass) || (user && *user)) {
+ retval = WNetAddConnection2W(share, pass, user, CONNECT_TEMPORARY | CONNECT_CURRENT_MEDIA);
+ if (retval == NO_ERROR) {
+ return retval;
+ }
+ if (retval != ERROR_INVALID_PASSWORD && retval != ERROR_LOGON_FAILURE
+ && retval != ERROR_BAD_USERNAME && retval != ERROR_ACCESS_DENIED
+ && retval != ERROR_SESSION_CREDENTIAL_CONFLICT && retval != ERROR_BAD_NET_NAME) {
+ return retval;
+ }
+ }
+ static wchar_t nuser[BUFLEN] = L"\0", npass[BUFLEN] = L"\0";
+ if (nuser[0] == 0 && npass[0] == 0) {
+ BOOL ok = TRUE;
+ if (suser != NULL) {
+ ok = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)suser, -1, (LPWSTR)nuser, BUFLEN) > 0 && ok;
+ }
+ if (spass != NULL) {
+ ok = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)spass, -1, (LPWSTR)npass, BUFLEN) > 0 && ok;
+ }
+ if (!ok)
+ return ERROR_INVALID_PARAMETER;
+ }
+ retval = WNetAddConnection2W(share, npass, nuser, CONNECT_TEMPORARY | CONNECT_CURRENT_MEDIA);
+ return retval;
+}
+
+static void postSuccessfulMount(const netdrive_t *d, wchar_t *letter)
+{
+ if (d->shortcut != NULL && strlen(d->shortcut) != 0) {
+ wchar_t tmp[MAX_PATH], wShortcut[MAX_PATH], wTarget[MAX_PATH];
+ MultiByteToWideChar(CP_UTF8, 0, d->shortcut, -1, tmp, MAX_PATH);
+ StringCchPrintfW(wShortcut, MAX_PATH, L"%s\\%s.lnk", desktopPath, tmp);
+ MultiByteToWideChar(CP_UTF8, 0, d->path, -1, tmp, MAX_PATH);
+ StringCchPrintfW(wTarget, MAX_PATH, L"\"%s\"", tmp);
+ DeleteFileW(wShortcut);
+ createFolderShortcut(wTarget, wShortcut, letter);
+ // Fix paths and kill explorer if it's the home directory
+ if (_folderStatus != FS_OK && strncmp(d->shortcut, "Home-", 5) == 0) {
+ BOOL isVmware = strcmp(d->path, "\\\\vmware-host\\Shared Folders\\home") == 0;
+ if (_remapMode == RM_NATIVE_FALLBACK
+ || (isVmware && _remapMode == RM_VMWARE)
+ || (!isVmware && _remapMode == RM_NATIVE)) {
+ patchUserPaths(letter);
+ }
+ }
+ }
+}
+
+static BOOL mountNetworkShare(const netdrive_t *d, BOOL useIp)
+{
+ wchar_t path[BUFLEN] = L"", user[BUFLEN] = L"", pass[BUFLEN] = L"", letter[10] = L"", shortcut[BUFLEN] = L"";
+ int ok = -1;
+ if (useIp && d->pathIp[0] == '\0')
+ return FALSE;
+ const char *uncPath = useIp ? d->pathIp : d->path;
+ ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)uncPath, -1, (LPWSTR)path, BUFLEN) > 0;
+ if (d->letter != NULL) {
+ ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->letter, -1, (LPWSTR)letter, 10) > 0;
+ }
+ if (d->user != NULL) {
+ ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->user, -1, (LPWSTR)user, BUFLEN) > 0;
+ }
+ if (d->pass != NULL) {
+ ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->pass, -1, (LPWSTR)pass, BUFLEN) > 0;
+ }
+ if (d->shortcut != NULL) {
+ ok &= MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)d->shortcut, -1, (LPWSTR)shortcut, BUFLEN) > 0;
+ }
+ if (!ok || path[0] == 0) { // Convert failed/no path - return true anyways since retrying wouldn't change anything
+ alog("mountNetworkShare: utf8 to utf16 failed, or path empty (src: '%s')", uncPath);
+ return TRUE;
+ }
+ DWORD retval;
+ NETRESOURCEW share = { 0 };
+ share.dwType = RESOURCETYPE_DISK;
+ share.lpLocalName = letter;
+ share.lpRemoteName = path;
+ share.lpProvider = NULL;
+ letter[1] = ':';
+ letter[2] = 0;
+ letter[3] = 0;
+ if (letter[0] != 0) {
+ // Try with specific letter
+ // Connect defined share
+ retval = mount(&share, pass, user);
+ if (retval == NO_ERROR) {
+ postSuccessfulMount(d, letter);
+ return TRUE;
+ }
+ if (retval != ERROR_ALREADY_ASSIGNED && retval != ERROR_DEVICE_ALREADY_REMEMBERED
+ && retval != ERROR_CONNECTION_UNAVAIL) {
+ alog("mountNetworkShare: with letter failed: %d", (int)retval);
+ return FALSE;
+ }
+ }
+ // Try to find free drive letter
+ for (letter[0] = 'Z'; letter[0] > 'C'; --letter[0]) {
+ retval = mount(&share, pass, user);
+ if (retval == ERROR_ALREADY_ASSIGNED || retval == ERROR_DEVICE_ALREADY_REMEMBERED
+ || retval == ERROR_CONNECTION_UNAVAIL)
+ continue;
+ if (retval == NO_ERROR) {
+ postSuccessfulMount(d, letter);
+ return TRUE;
+ }
+ alog("mountNetworkShare: without letter failed: %d", (int)retval);
+ if (retval == ERROR_INVALID_PASSWORD || retval == ERROR_LOGON_FAILURE
+ || retval == ERROR_BAD_USERNAME || retval == ERROR_ACCESS_DENIED
+ || retval == ERROR_SESSION_CREDENTIAL_CONFLICT) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+static BOOL mountNetworkShares()
+{
+ if (!bGetShares)
+ return TRUE;
+ if (spass == NULL)
+ return FALSE;
+ int failCount = 0;
+ for (int i = 0; i < DRIVEMAX; ++i) {
+ if (drives[i].path == NULL)
+ break;
+ if (drives[i].success)
+ continue;
+ if (mountNetworkShare(&drives[i], FALSE)) {
+ drives[i].success = TRUE;
+ } else if (mountNetworkShare(&drives[i], TRUE)) {
+ drives[i].success = TRUE;
+ } else {
+ failCount++;
+ }
+ }
+ if (failCount > 0)
+ return FALSE;
+ SecureZeroMemory(spass, strlen(spass));
+ return TRUE;
+}
+
+static void remapViaSharedFolder()
+{
+ static const char* homeDirA = "\\\\vmware-host\\Shared Folders\\home"; // thiscase!
+ static const wchar_t* homeDirW = L"\\\\vmware-host\\shared folders\\home"; // lowercase!
+ static BOOL once = FALSE;
+ if (once) return;
+ once = TRUE;
+ netdrive_t d;
+ d.path = homeDirA;
+ d.letter = _remapHomeDrive;
+ d.shortcut = "Home-Verzeichnis";
+ d.user = "";
+ d.pass = "";
+ d.success = FALSE;
+ // See if it's already mapped
+ wchar_t letter[5] = L"C:\\";
+ char buffer[600];
+ UNIVERSAL_NAME_INFOW *uni = (UNIVERSAL_NAME_INFOW*)buffer;
+ for (letter[0] = 'D'; letter[0] <= 'Z'; ++letter[0]) {
+ //wlog(L"Checking %s", letter);
+ DWORD len = (DWORD)sizeof(buffer);
+ if (NO_ERROR == WNetGetUniversalNameW(letter, UNIVERSAL_NAME_INFO_LEVEL, uni, &len)) {
+ _wcslwr(uni->lpUniversalName);
+ //wlog(L"Is %s", uni->lpUniversalName);
+ if (wcscmp(uni->lpUniversalName, homeDirW) == 0) {
+ letter[2] = '\0';
+ postSuccessfulMount(&d, letter);
+ return;
+ }
+ }
+ }
+ // Map vmware shared folder
+ mountNetworkShare(&d, FALSE);
+}
+
+static char* xorString(const uint8_t* text, int len, const uint8_t* key)
+{
+ int i;
+ uint8_t *retval = malloc(len + 1);
+ uint8_t *ptr = retval;
+ for (i = 0; i < len; ++i) {
+ ptr[i] = text[i] ^ key[i % KEYLEN];
+ }
+ ptr[len] = '\0';
+ return (char*)retval;
+}
+
+static int getbin(int x)
+{
+ if (x >= '0' && x <= '9')
+ return x - '0';
+ if (x >= 'A' && x <= 'F')
+ return x - 'A' + 10;
+ return x - 'a' + 10;
+}
+
+static uint8_t* hex2bin(char *szHexString)
+{
+ int size = strlen(szHexString) / 2, i;
+ char *p = szHexString;
+ uint8_t *pBinary = malloc(size);
+
+ for(i = 0; i < size; i++, p += 2) {
+ pBinary[i] = (uint8_t)((getbin(p[0]) << 4) | getbin(p[1]));
+ }
+ return pBinary;
+}
+
+// Stuff for creating a simple shortcut (.lnk)
+
+static HRESULT createFolderShortcut(wchar_t* targetDir, wchar_t* linkFile, wchar_t* comment)
+{
+ HRESULT hRes; /* Returned COM result code */
+ IShellLink* pShellLink; /* IShellLink object pointer */
+ IPersistFile* pPersistFile; /* IPersistFile object pointer */
+
+ hRes = E_INVALIDARG;
+ if (
+ (targetDir != NULL) && (wcslen(targetDir) > 0) &&
+ (linkFile != NULL) && (wcslen(linkFile) > 0)
+ ) {
+ hRes = CoCreateInstance(
+ &CLSID_ShellLink, /* pre-defined CLSID of the IShellLink object */
+ NULL, /* pointer to parent interface if part of aggregate */
+ CLSCTX_INPROC_SERVER, /* caller and called code are in same process */
+ &IID_IShellLink, /* pre-defined interface of the IShellLink object */
+ (void**)&pShellLink); /* Returns a pointer to the IShellLink object */
+ if (SUCCEEDED(hRes)) {
+ wchar_t explorer[MAX_PATH];
+ StringCchPrintfW(explorer, MAX_PATH, L"\"%s\\explorer.exe\"", windowsPath);
+ // Set the fields in the IShellLink object
+ hRes = pShellLink->lpVtbl->SetPath(pShellLink, explorer);
+ hRes = pShellLink->lpVtbl->SetArguments(pShellLink, targetDir);
+ if (comment != NULL) {
+ hRes = pShellLink->lpVtbl->SetDescription(pShellLink, comment);
+ }
+ StringCchPrintfW(explorer, MAX_PATH, L"%s\\system32\\imageres.dll", windowsPath);
+ hRes = pShellLink->lpVtbl->SetIconLocation(pShellLink, explorer, 137);
+
+ /* Use the IPersistFile object to save the shell link */
+ hRes = pShellLink->lpVtbl->QueryInterface(
+ pShellLink, /* existing IShellLink object */
+ &IID_IPersistFile, /* pre-defined interface of the IPersistFile object */
+ (void**)&pPersistFile); /* returns a pointer to the IPersistFile object */
+ if (SUCCEEDED(hRes)) {
+ hRes = pPersistFile->lpVtbl->Save(pPersistFile, linkFile, TRUE);
+ pPersistFile->lpVtbl->Release(pPersistFile);
+ }
+ pShellLink->lpVtbl->Release(pShellLink);
+ }
+
+ }
+ return (hRes);
+}
+
+// Patch user directories
+
+static BOOL patchRegPath(BOOL *patchOk, BOOL *anyMapped, HKEY hKey, wchar_t *letter, wchar_t *value, ...)
+{
+ wchar_t *folder = NULL;
+ wchar_t first[MAX_PATH] = {0};
+ wchar_t path[MAX_PATH];
+ wchar_t oldvalue[MAX_PATH];
+ va_list args;
+ LONG ret;
+ DWORD type;
+ DWORD len;
+ // Let's check the path in the registry first
+ len = (DWORD)(sizeof(oldvalue) - sizeof(wchar_t));
+ ret = RegQueryValueExW(hKey, value, NULL, &type, (BYTE*)oldvalue, &len);
+ if (ret == ERROR_SUCCESS && (type == REG_EXPAND_SZ || type == REG_SZ)) {
+ len /= 2;
+ oldvalue[len] = '\0';
+ if (towlower(oldvalue[0]) == towlower(letter[0]) && folderExists(oldvalue)) // Same drive, folder exists, yay
+ return TRUE;
+ }
+ // Old registry value doesn't fit - figure out new value
+ va_start(args, value);
+ while ((folder = va_arg(args, wchar_t*)) != NULL) {
+ StringCchPrintfW(path, MAX_PATH, L"%s\\%s", letter, folder);
+ if (folderExists(path))
+ break;
+ if (*first == 0) {
+ wcsncpy(first, path, MAX_PATH);
+ }
+ }
+ va_end(args);
+ if (folder != NULL) {
+ // Found something existing
+ folder = path;
+ } else if (!_createMissingRemap) {
+ // Nothing found, must not create
+ wlog(L"Cannot remap %s to %s: target not found!", value, first);
+ return FALSE;
+ } else {
+ // Nothing found, use first element of list and create it
+ folder = first;
+ CreateDirectoryW(folder, NULL);
+ }
+ _wcslwr(folder);
+ _wcslwr(oldvalue);
+ if (wcscmp(folder, oldvalue) == 0) {
+ // Path already in registry, don't update
+ return TRUE;
+ }
+ ret = RegSetValueExW(hKey, value, 0, REG_SZ, (BYTE*)folder, (wcslen(folder) + 1) * sizeof(wchar_t));
+ if (ret == ERROR_SUCCESS) {
+ *anyMapped = TRUE;
+ return TRUE;
+ }
+ wlog(L"Setting reg key %s to %s failed (return value %ld)", value, folder, (long)ret);
+ *patchOk = FALSE;
+ return FALSE;
+}
+
+typedef HANDLE (WINAPI *SNTYPE)(DWORD, DWORD);
+typedef BOOL (WINAPI *P32TYPE)(HANDLE, PROCESSENTRY32W*);
+
+static void patchUserPaths(wchar_t *letter)
+{
+ LONG ret;
+ HKEY hKey;
+ BOOL patchOk = TRUE;
+ BOOL killOk = FALSE;
+ BOOL anyMapped = FALSE;
+ _folderStatus = FS_ERROR;
+ ret = RegOpenKeyExW(HKEY_CURRENT_USER,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders",
+ 0, KEY_WOW64_64KEY | KEY_READ | KEY_WRITE, &hKey);
+ if (ret != ERROR_SUCCESS) {
+ alog("Opening registry for patching of pathes failed with return code %ld", (long)ret);
+ return;
+ }
+ // Ha!
+ const BOOL win10 = winVer.dwMajorVersion >= 10;
+ if (remap.other) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{56784854-C6CB-462B-8169-88E350ACB882}", L"Contacts", L"Profile\\Contacts", L"Kontakte", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"Favorites", L"Favorites", L"Profile\\Favorites", L"Favoriten", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{7D1D3A04-DEBB-4115-95CF-2F29DA2920DA}", L"Searches", L"Profile\\Searches", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968}", L"Links", L"Profile\\Links", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}", L"Saved Games", L"SavedGames", L"Profile\\SavedGames", NULL);
+ }
+ if (remap.media) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"My Video", L"Videos", L"My Videos", L"Eigene Videos", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"My Pictures", L"Pictures", L"My Pictures", L"Eigene Bilder", L"Bilder", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"My Music", L"Music", L"My Music", L"Eigene Musik", L"Musik", NULL);
+ if (win10) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{35286a68-3c57-41a1-bbb1-0eae73d76c95}", L"Videos", L"My Videos", L"Eigene Videos", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{0ddd015d-b06c-45d5-8c4c-f59713854639}", L"Pictures", L"My Pictures", L"Eigene Bilder", L"Bilder", NULL);
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{a0c69a99-21c8-4671-8703-7934162fcf1d}", L"Music", L"My Music", L"Eigene Musik", L"Musik", NULL);
+ }
+ }
+ if (remap.downloads) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{374DE290-123F-4565-9164-39C4925E467B}", L"Downloads", L"Profile\\Downloads", NULL);
+ if (win10) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{7d83ee9b-2244-4e70-b1f5-5393042af1e4}", L"Downloads", L"Profile\\Downloads", NULL);
+ }
+ }
+ if (remap.documents) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"Personal", L"Documents", L"Dokumente", L"My Documents", L"Eigene Dateien", NULL);
+ if (win10) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{f42ee2d3-909f-4907-8871-4c22fc0bf756}", L"Documents", L"Dokumente", L"My Documents", L"Eigene Dateien", NULL);
+ }
+ }
+ if (remap.desktop) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"Desktop", L"Windows Desktop", L"Desktop", L"Arbeitsfl\u00E4che", NULL);
+ if (win10) {
+ patchRegPath(&patchOk, &anyMapped, hKey, letter, L"{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}", L"Windows Desktop", L"Desktop", L"Arbeitsfl\u00E4che", NULL);
+ }
+ }
+ RegCloseKey(hKey);
+ if (!anyMapped) {
+ _folderStatus = FS_OK;
+ return;
+ }
+ // Kill explorer
+ // Late binding
+ if (hKernel32 == NULL || winVer.dwMajorVersion < 5 || (winVer.dwMajorVersion == 5 && winVer.dwMinorVersion < 1)) {
+ return;
+ }
+ SNTYPE aCreateSnapshot;
+ P32TYPE aProcessFirst, aProcessNext;
+ aCreateSnapshot = (SNTYPE)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");
+ if (aCreateSnapshot == NULL) {
+ alog("No CreateToolhelp32Snapshot in kernel.dll");
+ return;
+ }
+ aProcessFirst = (P32TYPE)GetProcAddress(hKernel32, "Process32FirstW");
+ if (aProcessFirst == NULL) {
+ alog("No Process32FirstW in kernel.dll");
+ return;
+ }
+ aProcessNext = (P32TYPE)GetProcAddress(hKernel32, "Process32NextW");
+ if (aProcessNext == NULL) {
+ alog("No Process32NextW in kernel.dll");
+ return;
+ }
+ PROCESSENTRY32W entry;
+ entry.dwSize = sizeof(PROCESSENTRY32W);
+ HANDLE snapshot = (aCreateSnapshot)(TH32CS_SNAPPROCESS, 0);
+ if (snapshot != INVALID_HANDLE_VALUE && (aProcessFirst)(snapshot, &entry)) {
+ do {
+ if (_wcsicmp(entry.szExeFile, L"explorer.exe") == 0) {
+ HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
+ if (hProcess == NULL) {
+ alog("Cannot OpenProcess explorer.exe: Remapped paths will not work properly (GetLastError=%d)", (int)GetLastError());
+ } else {
+ if (TerminateProcess(hProcess, 23)) {
+ killOk = TRUE;
+ }
+ CloseHandle(hProcess);
+ }
+ }
+ } while ((aProcessNext)(snapshot, &entry));
+ } else {
+ alog("Could not get process list");
+ }
+ CloseHandle(snapshot);
+ if (patchOk && killOk) {
+ _folderStatus = FS_OK;
+ }
+}
+
diff --git a/core/modules/run-virt/winres/winres.manifest b/core/modules/run-virt/winres/winres.manifest
new file mode 100644
index 00000000..a4ffc98e
--- /dev/null
+++ b/core/modules/run-virt/winres/winres.manifest
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+ <assemblyIdentity type="win32"
+ name="org.openslx.windows.winres"
+ version="4.0.0.0"
+ processorArchitecture="x86"
+ publicKeyToken="0000000000000000"
+ />
+ <description>Sausageface</description>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ uiAccess="false"
+ />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/core/modules/run-virt/winres/winres.rc b/core/modules/run-virt/winres/winres.rc
new file mode 100644
index 00000000..a9faf9a0
--- /dev/null
+++ b/core/modules/run-virt/winres/winres.rc
@@ -0,0 +1,4 @@
+#include <windows.h>
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "winres.manifest"
+