KDECore
kkernel_win.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE libraries 00003 Copyright (C) 2004 Jarosław Staniek <staniek@kde.org> 00004 Copyright (C) 2007 Christian Ehrlicher <ch.ehrlicher@gmx.de> 00005 Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de> 00006 Copyright (C) 2008-2009 Ralf Habacker <ralf.habacker@freenet.de> 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License version 2 as published by the Free Software Foundation. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kkernel_win.h" 00024 00025 #include <config.h> 00026 #include <QtCore/QBool> 00027 #include <QtCore/QTextCodec> 00028 00029 #ifdef Q_OS_WIN 00030 00031 #include "kglobal.h" 00032 #include <klocale.h> 00033 00034 #include <QtCore/QDir> 00035 #include <QtCore/QString> 00036 #include <QtCore/QLibrary> 00037 00038 #include <windows.h> 00039 #include <shellapi.h> 00040 #include <process.h> 00041 00042 // console related includes 00043 #include <stdio.h> 00044 #include <fcntl.h> 00045 #include <io.h> 00046 #include <iostream> 00047 #include <fstream> 00048 #ifndef _USE_OLD_IOSTREAMS 00049 using namespace std; 00050 #endif 00051 00052 #if defined(__MINGW32__) 00053 # define WIN32_CAST_CHAR (const WCHAR*) 00054 #else 00055 # define WIN32_CAST_CHAR (LPCWSTR) 00056 #endif 00057 00058 #ifndef _WIN32_WCE 00059 static HINSTANCE kdecoreDllInstance = NULL; 00060 #else 00061 static HANDLE kdecoreDllInstance = NULL; 00062 #endif 00063 #ifdef KDELIBS_STATIC_LIBS 00064 static bool kde4prefixInitialized = false; 00065 #endif 00066 static wchar_t kde4prefixUtf16[MAX_PATH + 2] = L""; 00067 00068 static QString *kde4Prefix = NULL; 00069 00070 void initKde4prefixUtf16() 00071 { 00072 //the path is C:\some\path\kde4\bin\kdecore.dll 00073 #ifndef _WIN32_WCE 00074 GetModuleFileNameW(kdecoreDllInstance, kde4prefixUtf16, MAX_PATH + 1); 00075 #else 00076 GetModuleFileNameW((HMODULE)kdecoreDllInstance, kde4prefixUtf16, MAX_PATH + 1); 00077 #endif 00078 int bs1 = 0, bs2 = 0; 00079 00080 //we convert \ to / and remove \bin\kdecore.dll from the string 00081 int pos; 00082 for (pos = 0; pos < MAX_PATH + 1 && kde4prefixUtf16[pos] != 0; ++pos) { 00083 if (kde4prefixUtf16[pos] == '\\') { 00084 bs1 = bs2; 00085 bs2 = pos; 00086 kde4prefixUtf16[pos] = '/'; 00087 } 00088 } 00089 Q_ASSERT(bs1); 00090 Q_ASSERT(pos < MAX_PATH + 1); 00091 kde4prefixUtf16[bs1] = '/'; 00092 kde4prefixUtf16[bs1+1] = 0; 00093 } 00094 00095 // can't use QCoreApplication::applicationDirPath() because sometimes we 00096 // don't have an instantiated QCoreApplication 00097 QString getKde4Prefix() 00098 { 00099 #ifdef _WIN32_WCE 00100 if (kde4prefixInitialized) 00101 return QString::fromUtf16((ushort*) kde4prefixUtf16); 00102 00103 QDir kde4prefixDir(QString::fromUtf16((ushort*) STATIC_INSTALL_PATH)); 00104 if (kde4prefixDir.exists()){ 00105 wcscpy(kde4prefixUtf16, STATIC_INSTALL_PATH); 00106 kde4prefixUtf16[wcslen(kde4prefixUtf16)] = 0; 00107 kde4prefixInitialized = true; 00108 return QString::fromUtf16((ushort*) kde4prefixUtf16); 00109 } else { 00110 bool ok; 00111 QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok); 00112 if (!ok){ 00113 return QString(); 00114 } else { 00115 retval = QDir::fromNativeSeparators(retval); 00116 wcscpy(kde4prefixUtf16, retval.utf16()); 00117 kde4prefixUtf16[wcslen(kde4prefixUtf16)] = 0; 00118 kde4prefixInitialized = true; 00119 return retval; 00120 } 00121 } 00122 #else 00123 // we can get called after DLL_PROCESS_DETACH! 00124 return kde4Prefix ? *kde4Prefix : QString::fromUtf16((ushort*) kde4prefixUtf16); 00125 #endif 00126 } 00127 00128 #ifndef KDELIBS_STATIC_LIBS 00129 00133 extern "C" 00134 #ifndef _WIN32_WCE 00135 BOOL WINAPI DllMain ( HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved) 00136 #else 00137 BOOL WINAPI DllMain ( HANDLE hinstDLL,DWORD fdwReason,LPVOID lpReserved) 00138 #endif 00139 { 00140 switch ( fdwReason ) { 00141 case DLL_PROCESS_ATTACH: 00142 kdecoreDllInstance = hinstDLL; 00143 initKde4prefixUtf16(); 00144 kde4Prefix = new QString( QString::fromUtf16((ushort*) kde4prefixUtf16) ); 00145 break; 00146 case DLL_PROCESS_DETACH: 00147 /* msdn: 00148 When handling DLL_PROCESS_DETACH, a DLL should free resources such 00149 as heap memory only if the DLL is being unloaded dynamically (the 00150 lpReserved parameter is NULL). If the process is terminating (the 00151 lpvReserved parameter is non-NULL), all threads in the process except 00152 the current thread either have exited already or have been explicitly 00153 terminated by a call to the ExitProcess function, which might leave 00154 some process resources such as heaps in an inconsistent state. In this 00155 case, it is not safe for the DLL to clean up the resources. Instead, 00156 the DLL should allow the operating system to reclaim the memory. 00157 */ 00158 if( lpReserved == NULL ) 00159 delete kde4Prefix; 00160 kde4Prefix = 0; 00161 break; 00162 default: 00163 break; 00164 } 00165 return true; 00166 } 00167 00168 #endif 00169 00180 QString getWin32RegistryValue ( HKEY key, const QString& subKey, const QString& item, bool *ok ) 00181 { 00182 #define FAILURE \ 00183 { if (ok) \ 00184 *ok = false; \ 00185 return QString(); } 00186 00187 if ( subKey.isEmpty() ) 00188 FAILURE; 00189 HKEY hKey; 00190 TCHAR *lszValue; 00191 DWORD dwType=REG_SZ; 00192 DWORD dwSize; 00193 00194 if ( ERROR_SUCCESS!=RegOpenKeyExW ( key, WIN32_CAST_CHAR subKey.utf16(), 0, KEY_READ, &hKey ) ) 00195 FAILURE; 00196 00197 if ( ERROR_SUCCESS!=RegQueryValueExW ( hKey, WIN32_CAST_CHAR item.utf16(), NULL, NULL, NULL, &dwSize ) ) 00198 FAILURE; 00199 00200 lszValue = new TCHAR[dwSize]; 00201 00202 if ( ERROR_SUCCESS!=RegQueryValueExW ( hKey, WIN32_CAST_CHAR item.utf16(), NULL, &dwType, ( LPBYTE ) lszValue, &dwSize ) ) { 00203 delete [] lszValue; 00204 FAILURE; 00205 } 00206 RegCloseKey ( hKey ); 00207 00208 QString res = QString::fromUtf16 ( ( const ushort* ) lszValue ); 00209 delete [] lszValue; 00210 00211 if (ok) 00212 *ok = true; 00213 00214 return res; 00215 } 00216 00217 00218 bool showWin32FilePropertyDialog ( const QString& fileName ) 00219 { 00220 QString path_ = QDir::convertSeparators ( QFileInfo ( fileName ).absoluteFilePath() ); 00221 00222 #ifndef _WIN32_WCE 00223 SHELLEXECUTEINFOW execInfo; 00224 #else 00225 SHELLEXECUTEINFO execInfo; 00226 #endif 00227 memset ( &execInfo,0,sizeof ( execInfo ) ); 00228 execInfo.cbSize = sizeof ( execInfo ); 00229 #ifndef _WIN32_WCE 00230 execInfo.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; 00231 #else 00232 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; 00233 #endif 00234 const QString verb ( QLatin1String ( "properties" ) ); 00235 execInfo.lpVerb = WIN32_CAST_CHAR verb.utf16(); 00236 execInfo.lpFile = WIN32_CAST_CHAR path_.utf16(); 00237 #ifndef _WIN32_WCE 00238 return ShellExecuteExW ( &execInfo ); 00239 #else 00240 return ShellExecuteEx ( &execInfo ); 00241 //There is no native file property dialog in wince 00242 // return false; 00243 #endif 00244 } 00245 00246 // note: QLocale().name().left(2).toLatin1() returns the same 00247 00248 QByteArray getWin32LocaleName() 00249 { 00250 bool ok; 00251 QString localeNumber = getWin32RegistryValue ( HKEY_CURRENT_USER, 00252 QLatin1String("Control Panel\\International"), 00253 QLatin1String("Locale"), &ok ); 00254 if ( !ok ) 00255 return QByteArray(); 00256 QString localeName = getWin32RegistryValue ( HKEY_LOCAL_MACHINE, 00257 QLatin1String("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout\\DosKeybCodes"), 00258 localeNumber, &ok ); 00259 if ( !ok ) 00260 return QByteArray(); 00261 return localeName.toLatin1(); 00262 } 00263 00267 QString getWin32ShellFoldersPath ( const QString& folder ) 00268 { 00269 return getWin32RegistryValue ( HKEY_CURRENT_USER, 00270 QLatin1String("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), 00271 folder ); 00272 } 00273 00277 static void kMessageOutputDebugString(QtMsgType type, const char *msg) 00278 { 00279 int BUFSIZE=4096; 00280 char *buf = new char[BUFSIZE]; 00281 switch (type) { 00282 case QtDebugMsg: 00283 strlcpy(buf,"Debug:",BUFSIZE); 00284 strlcat(buf,msg,BUFSIZE); 00285 break; 00286 case QtWarningMsg: 00287 strlcpy(buf,"Warning:",BUFSIZE); 00288 strlcat(buf,msg,BUFSIZE); 00289 break; 00290 case QtCriticalMsg: 00291 strlcpy(buf,"Critical:",BUFSIZE); 00292 strlcat(buf,msg,BUFSIZE); 00293 break; 00294 case QtFatalMsg: 00295 strlcpy(buf,"Fatal:",BUFSIZE); 00296 strlcat(buf,msg,BUFSIZE); 00297 //abort(); 00298 break; 00299 } 00300 strlcat(buf,"\n",BUFSIZE); 00301 OutputDebugStringW( (WCHAR*)QString::fromAscii(buf).utf16()); 00302 delete[] buf; 00303 } 00304 00308 static void kMessageOutputFileIO(QtMsgType type, const char *msg) 00309 { 00310 switch (type) { 00311 case QtDebugMsg: 00312 fprintf(stderr, "Debug: %s\n", msg); 00313 break; 00314 case QtWarningMsg: 00315 fprintf(stderr, "Warning: %s\n", msg); 00316 break; 00317 case QtCriticalMsg: 00318 fprintf(stderr, "Critical: %s\n", msg); 00319 break; 00320 case QtFatalMsg: 00321 fprintf(stderr, "Fatal: %s\n", msg); 00322 //abort(); 00323 } 00324 } 00325 00330 typedef BOOL (WINAPI*attachConsolePtr)(DWORD dwProcessId); 00331 static attachConsolePtr attachConsole = 0; 00332 static bool attachConsoleResolved = false; 00333 static bool attachToConsole() 00334 { 00335 if(!attachConsoleResolved) { 00336 attachConsoleResolved = true; 00337 attachConsole = (attachConsolePtr)QLibrary::resolve(QLatin1String("kernel32"), "AttachConsole"); 00338 } 00339 return attachConsole ? attachConsole(~0U) != 0 : false; 00340 } 00341 00346 static void redirectToConsole() 00347 { 00348 //FIXME: for wince we cannot set stdio buffers 00349 #ifndef _WIN32_WCE 00350 int hCrt; 00351 FILE *hf; 00352 int i; 00353 00354 hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_INPUT_HANDLE),_O_TEXT); 00355 if(hCrt != -1) { 00356 hf = _fdopen( hCrt, "r" ); 00357 *stdin = *hf; 00358 i = setvbuf( stdin, NULL, _IONBF, 0 ); 00359 } 00360 00361 hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT); 00362 if(hCrt != -1) { 00363 hf = _fdopen( hCrt, "w" ); 00364 *stdout = *hf; 00365 i = setvbuf( stdout, NULL, _IONBF, 0 ); 00366 } 00367 00368 hCrt = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE),_O_TEXT); 00369 if(hCrt != -1) { 00370 hf = _fdopen( hCrt, "w" ); 00371 *stderr = *hf; 00372 i = setvbuf( stderr, NULL, _IONBF, 0 ); 00373 } 00374 // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog 00375 // point to console as well 00376 ios::sync_with_stdio(); 00377 #endif 00378 } 00379 00380 #include <streambuf> 00381 00385 class debug_streambuf: public std::streambuf 00386 { 00387 public: 00388 debug_streambuf(const char *prefix) 00389 { 00390 strcpy(buf,prefix); 00391 index = rindex = strlen(buf); 00392 } 00393 00394 protected: 00395 virtual int overflow(int c = EOF) 00396 { 00397 if (c != EOF) 00398 { 00399 char cc = traits_type::to_char_type(c); 00400 // @TODO: buffer size checking 00401 buf[index++] = cc; 00402 if (cc == '\n') 00403 { 00404 buf[index] = '\0'; 00405 OutputDebugStringW((WCHAR*)QString::fromAscii(buf).utf16()); 00406 index = rindex; 00407 } 00408 } 00409 return traits_type::not_eof(c); 00410 } 00411 private: 00412 char buf[4096]; 00413 int index, rindex; 00414 }; 00415 00420 static int subSystem() 00421 { 00422 #ifdef _WIN32_WCE 00423 // there is only one subsystem on Windows CE 00424 return IMAGE_SUBSYSTEM_WINDOWS_CE_GUI; 00425 #else 00426 static int subSystem = -1; 00427 if (subSystem > -1) 00428 return subSystem; 00429 00430 // get base address of memory mapped executable 00431 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL); 00432 PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS) ((char *)dosHeader + dosHeader->e_lfanew); 00433 if (ntHeader->Signature != 0x00004550) 00434 { 00435 subSystem = IMAGE_SUBSYSTEM_UNKNOWN; 00436 return subSystem; 00437 } 00438 subSystem = ntHeader->OptionalHeader.Subsystem; 00439 return subSystem; 00440 #endif 00441 } 00442 00471 static class kMessageOutputInstaller { 00472 public: 00473 kMessageOutputInstaller() : stdoutBuffer("stdout:"), stderrBuffer("stderr:"), oldStdoutBuffer(0), oldStderrBuffer(0) 00474 { 00475 if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_CUI) { 00476 if (attachToConsole()) { 00477 // setup kde and qt level 00478 qInstallMsgHandler(kMessageOutputFileIO); 00479 // redirect ios and file io to console 00480 redirectToConsole(); 00481 } 00482 else { 00483 // setup kde and qt level 00484 qInstallMsgHandler(kMessageOutputDebugString); 00485 // redirect ios to debug message port 00486 oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer); 00487 oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer); 00488 } 00489 } 00490 else if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_GUI) { 00491 // setup kde and qt level 00492 qInstallMsgHandler(kMessageOutputDebugString); 00493 // try to get a console 00494 if (attachToConsole()) { 00495 redirectToConsole(); 00496 } 00497 else { 00498 // redirect ios to debug message port 00499 oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer); 00500 oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer); 00501 // TODO: redirect FILE * level to console, no idea how to do yet 00502 } 00503 } else if (subSystem() == IMAGE_SUBSYSTEM_WINDOWS_CE_GUI) { 00504 // do not try to get a console on WinCE systems 00505 qInstallMsgHandler(kMessageOutputDebugString); 00506 oldStdoutBuffer = std::cout.rdbuf(&stdoutBuffer); 00507 oldStderrBuffer = std::cerr.rdbuf(&stderrBuffer); 00508 } 00509 else 00510 qWarning("unknown subsystem %d detected, could not setup qt message handler",subSystem()); 00511 } 00512 ~kMessageOutputInstaller() 00513 { 00514 if (oldStdoutBuffer) 00515 std::cout.rdbuf(oldStdoutBuffer); 00516 if (oldStderrBuffer) 00517 std::cerr.rdbuf(oldStderrBuffer); 00518 } 00519 00520 private: 00521 debug_streambuf stdoutBuffer; 00522 debug_streambuf stderrBuffer; 00523 std::streambuf* oldStdoutBuffer; 00524 std::streambuf* oldStderrBuffer; 00525 00526 } kMessageOutputInstallerInstance; 00527 00528 00529 bool isExecutable(const QString &file) 00530 { 00531 return ( file.endsWith( QLatin1String( ".exe" ) ) || 00532 file.endsWith( QLatin1String( ".com" ) ) || 00533 file.endsWith( QLatin1String( ".bat" ) ) || 00534 file.endsWith( QLatin1String( ".sln" ) ) || 00535 file.endsWith( QLatin1String( ".lnk" ) ) ); 00536 00537 } 00538 00539 #endif // Q_OS_WIN
KDE 4.6 API Reference