File indexing completed on 2023-09-24 04:04:49
0001 /* 0002 This file is part of the KDE libraries 0003 Copyright (C) 2004 Jarosław Staniek <staniek@kde.org> 0004 Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de> 0005 Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de> 0006 Copyright (C) 2008-2009 Ralf Habacker <ralf.habacker@freenet.de> 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License version 2 as published by the Free Software Foundation. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "kkernel_win.h" 0024 0025 #include <QTextCodec> 0026 0027 #ifdef Q_OS_WIN 0028 0029 #include <klocalizedstring.h> 0030 0031 #include <QDir> 0032 #include <QLibrary> 0033 0034 #include <shellapi.h> 0035 #include <process.h> 0036 0037 // console related includes 0038 #include <stdio.h> 0039 #include <fcntl.h> 0040 #include <io.h> 0041 #include <iostream> 0042 #include <fstream> 0043 #ifndef _USE_OLD_IOSTREAMS 0044 using namespace std; 0045 #endif 0046 0047 #if defined(__MINGW32__) 0048 # define WIN32_CAST_CHAR (const WCHAR*) 0049 #else 0050 # define WIN32_CAST_CHAR (LPCWSTR) 0051 #endif 0052 0053 #ifndef _WIN32_WCE 0054 static HINSTANCE kdecoreDllInstance = NULL; 0055 #else 0056 static HANDLE kdecoreDllInstance = NULL; 0057 #endif 0058 #ifdef KDELIBS_STATIC_LIBS 0059 static bool kde4prefixInitialized = false; 0060 #endif 0061 static wchar_t kde4prefixUtf16[MAX_PATH + 2] = L""; 0062 0063 static QString *kde4Prefix = NULL; 0064 0065 void initKde4prefixUtf16() 0066 { 0067 //the path is C:\some\path\kde4\bin\kdecore.dll 0068 #ifndef _WIN32_WCE 0069 GetModuleFileNameW(kdecoreDllInstance, kde4prefixUtf16, MAX_PATH + 1); 0070 #else 0071 GetModuleFileNameW((HMODULE)kdecoreDllInstance, kde4prefixUtf16, MAX_PATH + 1); 0072 #endif 0073 int bs1 = 0, bs2 = 0; 0074 0075 //we convert \ to / and remove \bin\kdecore.dll from the string 0076 int pos; 0077 for (pos = 0; pos < MAX_PATH + 1 && kde4prefixUtf16[pos] != 0; ++pos) { 0078 if (kde4prefixUtf16[pos] == '\\') { 0079 bs1 = bs2; 0080 bs2 = pos; 0081 kde4prefixUtf16[pos] = '/'; 0082 } 0083 } 0084 Q_ASSERT(bs1); 0085 Q_ASSERT(pos < MAX_PATH + 1); 0086 kde4prefixUtf16[bs1] = '/'; 0087 kde4prefixUtf16[bs1 + 1] = 0; 0088 } 0089 0090 // can't use QCoreApplication::applicationDirPath() because sometimes we 0091 // don't have an instantiated QCoreApplication 0092 QString getKde4Prefix() 0093 { 0094 #ifdef _WIN32_WCE 0095 if (kde4prefixInitialized) { 0096 return QString::fromUtf16((ushort *) kde4prefixUtf16); 0097 } 0098 0099 QDir kde4prefixDir(QString::fromUtf16((ushort *) STATIC_INSTALL_PATH)); 0100 if (kde4prefixDir.exists()) { 0101 wcscpy(kde4prefixUtf16, STATIC_INSTALL_PATH); 0102 kde4prefixUtf16[wcslen(kde4prefixUtf16)] = 0; 0103 kde4prefixInitialized = true; 0104 return QString::fromUtf16((ushort *) kde4prefixUtf16); 0105 } else { 0106 bool ok; 0107 QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok); 0108 if (!ok) { 0109 return QString(); 0110 } else { 0111 retval = QDir::fromNativeSeparators(retval); 0112 wcscpy(kde4prefixUtf16, retval.utf16()); 0113 kde4prefixUtf16[wcslen(kde4prefixUtf16)] = 0; 0114 kde4prefixInitialized = true; 0115 return retval; 0116 } 0117 } 0118 #else 0119 // we can get called after DLL_PROCESS_DETACH! 0120 return kde4Prefix ? *kde4Prefix : QString::fromUtf16((ushort *) kde4prefixUtf16); 0121 #endif 0122 } 0123 0124 #ifndef KDELIBS_STATIC_LIBS 0125 /** 0126 * The dll entry point - get the instance handle for GetModuleFleNameW 0127 * Maybe also some special initialization / cleanup can be done here 0128 **/ 0129 extern "C" 0130 #ifndef _WIN32_WCE 0131 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 0132 #else 0133 BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 0134 #endif 0135 { 0136 switch (fdwReason) { 0137 case DLL_PROCESS_ATTACH: 0138 kdecoreDllInstance = hinstDLL; 0139 initKde4prefixUtf16(); 0140 kde4Prefix = new QString(QString::fromUtf16((ushort *) kde4prefixUtf16)); 0141 break; 0142 case DLL_PROCESS_DETACH: 0143 /* msdn: 0144 When handling DLL_PROCESS_DETACH, a DLL should free resources such 0145 as heap memory only if the DLL is being unloaded dynamically (the 0146 lpReserved parameter is NULL). If the process is terminating (the 0147 lpvReserved parameter is non-NULL), all threads in the process except 0148 the current thread either have exited already or have been explicitly 0149 terminated by a call to the ExitProcess function, which might leave 0150 some process resources such as heaps in an inconsistent state. In this 0151 case, it is not safe for the DLL to clean up the resources. Instead, 0152 the DLL should allow the operating system to reclaim the memory. 0153 */ 0154 if (lpReserved == NULL) { 0155 delete kde4Prefix; 0156 } 0157 kde4Prefix = 0; 0158 break; 0159 default: 0160 break; 0161 } 0162 return true; 0163 } 0164 0165 #endif 0166 0167 /** 0168 \return a value from MS Windows native registry. 0169 @param key is usually one of HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE 0170 constants defined in WinReg.h. 0171 @param subKey is a registry subkey defined as a path to a registry folder, eg. 0172 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" 0173 ('\' delimiter must be used) 0174 @param item is an item inside subKey or "" if default folder's value should be returned 0175 @param ok if not null, will be set to true on success and false on failure 0176 */ 0177 QString getWin32RegistryValue(HKEY key, const QString &subKey, const QString &item, bool *ok) 0178 { 0179 #define FAILURE \ 0180 { if (ok) \ 0181 *ok = false; \ 0182 return QString(); } 0183 0184 if (subKey.isEmpty()) { 0185 FAILURE; 0186 } 0187 HKEY hKey; 0188 TCHAR *lszValue; 0189 DWORD dwType = REG_SZ; 0190 DWORD dwSize; 0191 0192 if (ERROR_SUCCESS != RegOpenKeyExW(key, WIN32_CAST_CHAR subKey.utf16(), 0, KEY_READ, &hKey)) { 0193 FAILURE; 0194 } 0195 0196 if (ERROR_SUCCESS != RegQueryValueExW(hKey, WIN32_CAST_CHAR item.utf16(), NULL, NULL, NULL, &dwSize)) { 0197 FAILURE; 0198 } 0199 0200 lszValue = new TCHAR[dwSize]; 0201 0202 if (ERROR_SUCCESS != RegQueryValueExW(hKey, WIN32_CAST_CHAR item.utf16(), NULL, &dwType, (LPBYTE) lszValue, &dwSize)) { 0203 delete [] lszValue; 0204 FAILURE; 0205 } 0206 RegCloseKey(hKey); 0207 0208 QString res = QString::fromUtf16((const ushort *) lszValue); 0209 delete [] lszValue; 0210 0211 if (ok) { 0212 *ok = true; 0213 } 0214 0215 return res; 0216 } 0217 0218 bool showWin32FilePropertyDialog(const QString &fileName) 0219 { 0220 QString path_ = QDir::toNativeSeparators(QFileInfo(fileName).absoluteFilePath()); 0221 0222 #ifndef _WIN32_WCE 0223 SHELLEXECUTEINFOW execInfo; 0224 #else 0225 SHELLEXECUTEINFO execInfo; 0226 #endif 0227 memset(&execInfo, 0, sizeof(execInfo)); 0228 execInfo.cbSize = sizeof(execInfo); 0229 #ifndef _WIN32_WCE 0230 execInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; 0231 #else 0232 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; 0233 #endif 0234 const QString verb(QLatin1String("properties")); 0235 execInfo.lpVerb = WIN32_CAST_CHAR verb.utf16(); 0236 execInfo.lpFile = WIN32_CAST_CHAR path_.utf16(); 0237 #ifndef _WIN32_WCE 0238 return ShellExecuteExW(&execInfo); 0239 #else 0240 return ShellExecuteEx(&execInfo); 0241 //There is no native file property dialog in wince 0242 // return false; 0243 #endif 0244 } 0245 0246 // note: QLocale().name().left(2).toLatin1() returns the same 0247 0248 QByteArray getWin32LocaleName() 0249 { 0250 bool ok; 0251 QString localeNumber = getWin32RegistryValue(HKEY_CURRENT_USER, 0252 QLatin1String("Control Panel\\International"), 0253 QLatin1String("Locale"), &ok); 0254 if (!ok) { 0255 return QByteArray(); 0256 } 0257 QString localeName = getWin32RegistryValue(HKEY_LOCAL_MACHINE, 0258 QLatin1String("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout\\DosKeybCodes"), 0259 localeNumber, &ok); 0260 if (!ok) { 0261 return QByteArray(); 0262 } 0263 return localeName.toLatin1(); 0264 } 0265 0266 /** 0267 \return a value from MS Windows native registry for shell folder \a folder. 0268 */ 0269 QString getWin32ShellFoldersPath(const QString &folder) 0270 { 0271 return getWin32RegistryValue(HKEY_CURRENT_USER, 0272 QLatin1String("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), 0273 folder); 0274 } 0275 0276 /** 0277 kde and qt debug message printer using windows debug message port 0278 */ 0279 static void kMessageOutputDebugString(QtMsgType type, const char *msg) 0280 { 0281 int BUFSIZE = 4096; 0282 char *buf = new char[BUFSIZE]; 0283 switch (type) { 0284 case QtDebugMsg: 0285 strlcpy(buf, "Debug:", BUFSIZE); 0286 strlcat(buf, msg, BUFSIZE); 0287 break; 0288 case QtWarningMsg: 0289 strlcpy(buf, "Warning:", BUFSIZE); 0290 strlcat(buf, msg, BUFSIZE); 0291 break; 0292 case QtCriticalMsg: 0293 strlcpy(buf, "Critical:", BUFSIZE); 0294 strlcat(buf, msg, BUFSIZE); 0295 break; 0296 case QtFatalMsg: 0297 strlcpy(buf, "Fatal:", BUFSIZE); 0298 strlcat(buf, msg, BUFSIZE); 0299 //abort(); 0300 break; 0301 } 0302 strlcat(buf, "\n", BUFSIZE); 0303 OutputDebugStringW((WCHAR *)QString::fromLatin1(buf).utf16()); 0304 delete[] buf; 0305 } 0306 0307 /** 0308 kde and qt debug message printer using FILE pointer based output 0309 */ 0310 static void kMessageOutputFileIO(QtMsgType type, const char *msg) 0311 { 0312 switch (type) { 0313 case QtDebugMsg: 0314 fprintf(stderr, "Debug: %s\n", msg); 0315 break; 0316 case QtWarningMsg: 0317 fprintf(stderr, "Warning: %s\n", msg); 0318 break; 0319 case QtCriticalMsg: 0320 fprintf(stderr, "Critical: %s\n", msg); 0321 break; 0322 case QtFatalMsg: 0323 fprintf(stderr, "Fatal: %s\n", msg); 0324 //abort(); 0325 } 0326 } 0327 0328 /** 0329 try to attach to the parents console 0330 \return true if console has been attached, false otherwise 0331 */ 0332 typedef BOOL (WINAPI *attachConsolePtr)(DWORD dwProcessId); 0333 static attachConsolePtr attachConsole = 0; 0334 static bool attachConsoleResolved = false; 0335 static bool attachToConsole() 0336 { 0337 bool out = true; 0338 if (!attachConsoleResolved) { 0339 attachConsoleResolved = true; 0340 attachConsole = (attachConsolePtr)QLibrary::resolve(QLatin1String("kernel32"), "AttachConsole"); 0341 } 0342 out = attachConsole ? attachConsole(~0U) != 0 : false; 0343 if (GetLastError() == ERROR_ACCESS_DENIED) { 0344 //we are already atatched to a console 0345 out = true; 0346 } 0347 return out; 0348 } 0349 0350 /** 0351 redirect stdout, stderr and 0352 cout, wcout, cin, wcin, wcerr, cerr, wclog and clog to console 0353 */ 0354 static void redirectToConsole() 0355 { 0356 //FIXME: for wince we cannot set stdio buffers 0357 #ifndef _WIN32_WCE 0358 int hCrt; 0359 FILE *hf; 0360 int i; 0361 0362 hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_INPUT_HANDLE), _O_TEXT); 0363 if (hCrt != -1) { 0364 hf = _fdopen(hCrt, "r"); 0365 *stdin = *hf; 0366 i = setvbuf(stdin, NULL, _IONBF, 0); 0367 } 0368 0369 hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); 0370 if (hCrt != -1) { 0371 hf = _fdopen(hCrt, "w"); 0372 *stdout = *hf; 0373 i = setvbuf(stdout, NULL, _IONBF, 0); 0374 } 0375 0376 hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), _O_TEXT); 0377 if (hCrt != -1) { 0378 hf = _fdopen(hCrt, "w"); 0379 *stderr = *hf; 0380 i = setvbuf(stderr, NULL, _IONBF, 0); 0381 } 0382 // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog 0383 // point to console as well 0384 ios::sync_with_stdio(); 0385 #endif 0386 } 0387 0388 #include <streambuf> 0389 0390 /** 0391 ios related debug message printer for win32 0392 */ 0393 class debug_streambuf: public std::streambuf 0394 { 0395 public: 0396 debug_streambuf(const char *prefix) 0397 { 0398 strcpy(buf, prefix); 0399 index = rindex = strlen(buf); 0400 } 0401 0402 protected: 0403 virtual int overflow(int c = EOF) 0404 { 0405 if (c != EOF) { 0406 char cc = traits_type::to_char_type(c); 0407 // @TODO: buffer size checking 0408 buf[index++] = cc; 0409 if (cc == '\n') { 0410 buf[index] = '\0'; 0411 OutputDebugStringW((WCHAR *)QString::fromLatin1(buf).utf16()); 0412 index = rindex; 0413 } 0414 } 0415 return traits_type::not_eof(c); 0416 } 0417 private: 0418 char buf[4096]; 0419 int index, rindex; 0420 }; 0421 0422 /** 0423 retrieve type of win32 subsystem from the executable header 0424 \return type of win32 subsystem - the subsystem types are defined at http://msdn.microsoft.com/en-us/library/ms680339(VS.85).aspx 0425 */ 0426 static int subSystem() 0427 { 0428 #ifdef _WIN32_WCE 0429 // there is only one subsystem on Windows CE 0430 return IMAGE_SUBSYSTEM_WINDOWS_CE_GUI; 0431 #else 0432 static int subSystem = -1; 0433 if (subSystem > -1) { 0434 return subSystem; 0435 } 0436 0437 // get base address of memory mapped executable 0438 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL); 0439 PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((char *)dosHeader + dosHeader->e_lfanew); 0440 if (ntHeader->Signature != 0x00004550) { 0441 subSystem = IMAGE_SUBSYSTEM_UNKNOWN; 0442 return subSystem; 0443 } 0444 subSystem = ntHeader->OptionalHeader.Subsystem; 0445 return subSystem; 0446 #endif 0447 } 0448 0449 /** 0450 win32 debug and console output handling 0451 0452 source type of output 0453 1. kde/qt debug system - kDebug(), kWarning(), kFatal(), kError(), qDebug(), qWarning(), qFatal() 0454 2. ios - cout, wcout, wcerr, cerr, wclog and clog 0455 3. FILE * - stdout,stderr 0456 0457 application console ------------------ output ----------------- 0458 type available qt/kde-debug ios FILE * 0459 0460 cui yes console console console 0461 cui no win32debug win32debug no output[1] 0462 0463 gui yes win32debug console console 0464 gui no win32debug win32debug win32debug 0465 0466 win-ce no win32debug win32debug win32debug 0467 0468 [1]no redirect solution for FILE * based output yet 0469 0470 TODO: report events to the windows event log system 0471 http://msdn.microsoft.com/en-us/library/aa363680(VS.85).aspx 0472 */ 0473 0474 /** 0475 setup up debug output 0476 */ 0477 static class kMessageOutputInstaller 0478 { 0479 public: 0480 kMessageOutputInstaller() : stdoutBuffer("stdout:"), stderrBuffer("stderr:"), oldStdoutBuffer(0), oldStderrBuffer(0) 0481 { 0482 if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_CUI) { 0483 if (attachToConsole()) { 0484 // setup kde and qt level 0485 qInstallMsgHandler(kMessageOutputFileIO); 0486 // redirect ios and file io to console 0487 redirectToConsole(); 0488 } else { 0489 // setup kde and qt level 0490 qInstallMsgHandler(kMessageOutputDebugString); 0491 // redirect ios to debug message port 0492 oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer); 0493 oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer); 0494 } 0495 } else if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_GUI) { 0496 // setup kde and qt level 0497 qInstallMsgHandler(kMessageOutputDebugString); 0498 // try to get a console 0499 if (attachToConsole()) { 0500 redirectToConsole(); 0501 } else { 0502 // redirect ios to debug message port 0503 oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer); 0504 oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer); 0505 // TODO: redirect FILE * level to console, no idea how to do yet 0506 } 0507 } else if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_CE_GUI) { 0508 // do not try to get a console on WinCE systems 0509 qInstallMsgHandler(kMessageOutputDebugString); 0510 oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer); 0511 oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer); 0512 } else { 0513 qWarning("unknown subsystem %d detected, could not setup qt message handler", subSystem()); 0514 } 0515 } 0516 ~kMessageOutputInstaller() 0517 { 0518 if (oldStdoutBuffer) { 0519 std::cout.rdbuf(oldStdoutBuffer); 0520 } 0521 if (oldStderrBuffer) { 0522 std::cerr.rdbuf(oldStderrBuffer); 0523 } 0524 } 0525 0526 private: 0527 debug_streambuf stdoutBuffer; 0528 debug_streambuf stderrBuffer; 0529 std::streambuf *oldStdoutBuffer; 0530 std::streambuf *oldStderrBuffer; 0531 0532 } kMessageOutputInstallerInstance; 0533 0534 bool isExecutable(const QString &file) 0535 { 0536 return (file.endsWith(QLatin1String(".exe")) || 0537 file.endsWith(QLatin1String(".com")) || 0538 file.endsWith(QLatin1String(".bat")) || 0539 file.endsWith(QLatin1String(".sln")) || 0540 file.endsWith(QLatin1String(".lnk"))); 0541 0542 } 0543 0544 #endif // Q_OS_WIN