Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | //--------------------------------------------------------------------------- |
---|---|
2 | // Copyright 2002-2008 Andre Burgaud <andre@burgaud.com> |
3 | // Copyright 2009 Patrick Spendrin <ps_ml@gmx.de> |
4 | // See license.txt |
5 | //--------------------------------------------------------------------------- |
6 | |
7 | //--------------------------------------------------------------------------- |
8 | // kdecm.cpp |
9 | // Defines the entry point for the DLL application. |
10 | //--------------------------------------------------------------------------- |
11 | //krazy:excludeall=includes |
12 | |
13 | #include <kcomponentdata.h> |
14 | #include <klockfile.h> |
15 | #include <kmimetype.h> |
16 | #include <kmimetypetrader.h> |
17 | #include <kservice.h> |
18 | #include <kstandarddirs.h> |
19 | |
20 | #include <QtCore/QDebug> |
21 | #include <QtCore/QProcess> |
22 | #include <QtCore/QString> |
23 | #include <QtCore/QStringList> |
24 | #include <QtCore/QSettings> |
25 | |
26 | #include <QtDBus> |
27 | |
28 | #define INC_OLE2 |
29 | |
30 | #include <windows.h> |
31 | #include <windowsx.h> |
32 | #include <shlobj.h> |
33 | #include <stdio.h> |
34 | #include <stdlib.h> |
35 | #if defined(_MSC_VER) || defined(__MINGW64__) |
36 | #include <ShellApi.h> |
37 | #endif |
38 | |
39 | #include <math.h> |
40 | |
41 | #define GUID_SIZE 128 |
42 | #define ResultFromShort(i) ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i))) |
43 | |
44 | #pragma data_seg(".text") |
45 | #define INITGUID |
46 | #include <initguid.h> |
47 | #include <shlguid.h> |
48 | |
49 | #include "resource.h" |
50 | #include "kdecm.h" |
51 | #pragma data_seg() |
52 | |
53 | |
54 | //--------------------------------------------------------------------------- |
55 | // Global variables |
56 | //--------------------------------------------------------------------------- |
57 | UINT _cRef = 0; // COM Reference count. |
58 | HINSTANCE _hModule = NULL; // DLL Module. |
59 | |
60 | TCHAR szShellExtensionTitle[] = TEXT("Kate"); |
61 | |
62 | typedef struct{ |
63 | HKEY hRootKey; |
64 | LPTSTR szSubKey; |
65 | LPTSTR lpszValueName; |
66 | LPTSTR szData; |
67 | } DOREGSTRUCT; |
68 | |
69 | BOOL RegisterServer(CLSID, LPTSTR); |
70 | BOOL UnregisterServer(CLSID, LPTSTR); |
71 | |
72 | |
73 | inline QString clsid2QString(REFCLSID rclsid) |
74 | { |
75 | return QString("{%1-%2-%3-%4-%5%6%7}").arg((unsigned long)rclsid.Data1, 0, 16)\ |
76 | .arg((unsigned long)rclsid.Data2, 0, 16)\ |
77 | .arg((unsigned long)rclsid.Data3, 0, 16)\ |
78 | .arg((unsigned long)(rclsid.Data4[0]*256 + rclsid.Data4[1]), 0, 16)\ |
79 | .arg((unsigned long)(rclsid.Data4[2]*256 + rclsid.Data4[3]), 0, 16)\ |
80 | .arg((unsigned long)(rclsid.Data4[4]*256 + rclsid.Data4[5]), 0, 16)\ |
81 | .arg((unsigned long)(rclsid.Data4[6]*256 + rclsid.Data4[7]), 0, 16).toUpper(); |
82 | } |
83 | |
84 | inline QString lptstr2QString(LPTSTR str) |
85 | { |
86 | return QString::fromUtf16( reinterpret_cast<ushort*>( str ) ); |
87 | } |
88 | |
89 | void myMessageOutput(QtMsgType type, const char *msg) |
90 | { |
91 | QString output; |
92 | switch (type) { |
93 | case QtDebugMsg: |
94 | output = QString("Debug:"); |
95 | break; |
96 | case QtWarningMsg: |
97 | output = QString("Warning:"); |
98 | break; |
99 | case QtCriticalMsg: |
100 | output = QString("Critical:"); |
101 | break; |
102 | case QtFatalMsg: |
103 | output = QString("Fatal:"); |
104 | } |
105 | output += QString(msg) + QString("\n"); |
106 | LPCTSTR outputarray = (LPCTSTR)output.utf16(); |
107 | OutputDebugString(outputarray); |
108 | if(QtFatalMsg == type) |
109 | { |
110 | abort(); |
111 | } |
112 | } |
113 | |
114 | //--------------------------------------------------------------------------- |
115 | // DllMain |
116 | //--------------------------------------------------------------------------- |
117 | STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) |
118 | { |
119 | qInstallMsgHandler(myMessageOutput); |
120 | |
121 | if (dwReason == DLL_PROCESS_ATTACH) { |
122 | _hModule = hInstance; |
123 | } |
124 | |
125 | // the following code has been stolen from the private function KToolInvocation::startKdeinit() |
126 | KComponentData inst( "startkdeinitlock"); |
127 | KLockFile lock( KStandardDirs::locateLocal( "tmp", "startkdeinitlock", inst )); |
128 | if( lock.lock( KLockFile::NoBlockFlag ) != KLockFile::LockOK ) { |
129 | lock.lock(); |
130 | // QDBusConnection::sessionBus().interface(); |
131 | /* if( QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.klauncher" ))*/ |
132 | return TRUE; // whoever held the lock has already started it |
133 | } |
134 | // Try to launch kdeinit. |
135 | QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4")); |
136 | if (srv.isEmpty()) |
137 | return FALSE; |
138 | |
139 | QStringList args; |
140 | args += "--suicide"; |
141 | |
142 | QProcess::execute(srv, args); |
143 | |
144 | return TRUE; |
145 | } |
146 | |
147 | //--------------------------------------------------------------------------- |
148 | // DllCanUnloadNow |
149 | //--------------------------------------------------------------------------- |
150 | STDAPI DllCanUnloadNow(void) |
151 | { |
152 | return (_cRef == 0 ? S_OK : S_FALSE); |
153 | } |
154 | |
155 | //--------------------------------------------------------------------------- |
156 | // DllGetClassObject |
157 | //--------------------------------------------------------------------------- |
158 | STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut) |
159 | { |
160 | // qDebug() << "getclassobject" << clsid2QString(rclsid) |
161 | // << clsid2QString(CLSID_ShellExtension); |
162 | |
163 | *ppvOut = NULL; |
164 | if (IsEqualIID(rclsid, CLSID_ShellExtension)) { |
165 | CShellExtClassFactory *pcf = new CShellExtClassFactory; |
166 | return pcf->QueryInterface(riid, ppvOut); |
167 | } |
168 | return CLASS_E_CLASSNOTAVAILABLE; |
169 | } |
170 | |
171 | //--------------------------------------------------------------------------- |
172 | // DllRegisterServer |
173 | //--------------------------------------------------------------------------- |
174 | STDAPI DllRegisterServer(void) |
175 | { |
176 | return (RegisterServer(CLSID_ShellExtension, szShellExtensionTitle) ? S_OK : E_FAIL); |
177 | } |
178 | |
179 | //--------------------------------------------------------------------------- |
180 | // DllUnregisterServer |
181 | //--------------------------------------------------------------------------- |
182 | STDAPI DllUnregisterServer(void) |
183 | { |
184 | return (UnregisterServer(CLSID_ShellExtension, szShellExtensionTitle) ? S_OK : E_FAIL); |
185 | } |
186 | |
187 | //--------------------------------------------------------------------------- |
188 | // RegisterServer |
189 | //--------------------------------------------------------------------------- |
190 | BOOL RegisterServer(CLSID clsid, LPTSTR lpszTitle) |
191 | { |
192 | #if 0 |
193 | TCHAR dllPath[MAX_PATH]; |
194 | |
195 | QSettings settings("HKEY_CLASSES_ROOT", QSettings::NativeFormat); |
196 | |
197 | //get this app's path and file name |
198 | GetModuleFileNameW(_hModule, dllPath, MAX_PATH); |
199 | |
200 | qDebug() << "register dll for KDE ContextMenu:"<< lptstr2QString( dllPath ); |
201 | |
202 | settings.setValue(QString("CLSID/") + clsid2QString(clsid) + |
203 | QString("/Default"), lptstr2QString( lpszTitle )); |
204 | settings.setValue(QString("CLSID/") + clsid2QString(clsid) + |
205 | QString("/InprocServer32/Default"), lptstr2QString( dllPath ) ); |
206 | settings.setValue(QString("CLSID/") + clsid2QString(clsid) + |
207 | QString("/InprocServer32/ThreadingModel"), "Apartment"); |
208 | settings.setValue(QString("/*/shellex/ContextMenuHandlers/") + lptstr2QString(lpszTitle) + |
209 | QString("/Default"), clsid2QString(clsid) ); |
210 | return TRUE; |
211 | #else |
212 | int i; |
213 | HKEY hKey; |
214 | LRESULT lResult; |
215 | DWORD dwDisp; |
216 | TCHAR szSubKey[MAX_PATH]; |
217 | TCHAR szCLSID[MAX_PATH]; |
218 | TCHAR szModule[MAX_PATH]; |
219 | LPOLESTR pwsz; |
220 | |
221 | StringFromIID(clsid, &pwsz); |
222 | if(pwsz) { |
223 | lstrcpy(szCLSID, pwsz); |
224 | //free the string |
225 | LPMALLOC pMalloc; |
226 | CoGetMalloc(1, &pMalloc); |
227 | pMalloc->Free(pwsz); |
228 | pMalloc->Release(); |
229 | } |
230 | |
231 | //get this app's path and file name |
232 | GetModuleFileName(_hModule, szModule, MAX_PATH); |
233 | |
234 | DOREGSTRUCT ClsidEntries[] = { |
235 | HKEY_CLASSES_ROOT, TEXT("CLSID\\%s"), NULL, lpszTitle, |
236 | HKEY_CLASSES_ROOT, TEXT("CLSID\\%s\\InprocServer32"), NULL, szModule, |
237 | HKEY_CLASSES_ROOT, TEXT("CLSID\\%s\\InprocServer32"), TEXT( "ThreadingModel"), TEXT( "Apartment"), |
238 | HKEY_CLASSES_ROOT, TEXT("*\\shellex\\ContextMenuHandlers\\Kate"), NULL, szCLSID, |
239 | NULL, NULL, NULL, NULL |
240 | }; |
241 | |
242 | // Register the CLSID entries |
243 | for(i = 0; ClsidEntries[i].hRootKey; i++) { |
244 | // Create the sub key string - for this case, insert the file extension |
245 | wsprintf(szSubKey, ClsidEntries[i].szSubKey, szCLSID); |
246 | lResult = RegCreateKeyEx(ClsidEntries[i].hRootKey, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); |
247 | if(NOERROR == lResult) { |
248 | TCHAR szData[MAX_PATH]; |
249 | // If necessary, create the value string |
250 | wsprintf(szData, ClsidEntries[i].szData, szModule); |
251 | lResult = RegSetValueEx(hKey, ClsidEntries[i].lpszValueName, 0, REG_SZ, (LPBYTE)szData, (lstrlen(szData) + 1) * sizeof(TCHAR)); |
252 | RegCloseKey(hKey); |
253 | } |
254 | else |
255 | return FALSE; |
256 | } |
257 | return TRUE; |
258 | #endif |
259 | } |
260 | |
261 | //--------------------------------------------------------------------------- |
262 | // UnregisterServer |
263 | //--------------------------------------------------------------------------- |
264 | BOOL UnregisterServer(CLSID clsid, LPTSTR lpszTitle) |
265 | { |
266 | /*! |
267 | * This function removes the keys from registry |
268 | * NOTE: we can do this better with Qt |
269 | */ |
270 | |
271 | TCHAR szCLSID[GUID_SIZE + 1]; |
272 | TCHAR szCLSIDKey[GUID_SIZE + 32]; |
273 | TCHAR szKeyTemp[MAX_PATH + GUID_SIZE]; |
274 | LPTSTR pwsz; |
275 | |
276 | StringFromIID(clsid, &pwsz); |
277 | if(pwsz) { |
278 | lstrcpy(szCLSID, pwsz); |
279 | //free the string |
280 | LPMALLOC pMalloc; |
281 | CoGetMalloc(1, &pMalloc); |
282 | pMalloc->Free(pwsz); |
283 | pMalloc->Release(); |
284 | } |
285 | |
286 | lstrcpy(szCLSIDKey, TEXT("CLSID\\")); |
287 | lstrcat(szCLSIDKey, szCLSID); |
288 | |
289 | wsprintf(szKeyTemp, TEXT("*\\shellex\\ContextMenuHandlers\\%s"), lpszTitle); |
290 | RegDeleteKey(HKEY_CLASSES_ROOT, szKeyTemp); |
291 | |
292 | wsprintf(szKeyTemp, TEXT("%s\\%s"), szCLSIDKey, TEXT( "InprocServer32")); |
293 | RegDeleteKey(HKEY_CLASSES_ROOT, szKeyTemp); |
294 | RegDeleteKey(HKEY_CLASSES_ROOT, szCLSIDKey); |
295 | |
296 | return TRUE; |
297 | } |
298 | |
299 | //--------------------------------------------------------------------------- |
300 | // CShellExtClassFactory |
301 | //--------------------------------------------------------------------------- |
302 | /*! |
303 | * seems to be a normal factory for CShellExt |
304 | */ |
305 | CShellExtClassFactory::CShellExtClassFactory() |
306 | { |
307 | m_cRef = 0L; |
308 | _cRef++; |
309 | } |
310 | |
311 | CShellExtClassFactory::~CShellExtClassFactory() |
312 | { |
313 | _cRef--; |
314 | } |
315 | |
316 | STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID riid, LPVOID FAR *ppv) |
317 | { |
318 | *ppv = NULL; |
319 | if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) { |
320 | *ppv = (LPCLASSFACTORY)this; |
321 | AddRef(); |
322 | return NOERROR; |
323 | } |
324 | return E_NOINTERFACE; |
325 | } |
326 | |
327 | STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef() |
328 | { |
329 | return ++m_cRef; |
330 | } |
331 | |
332 | STDMETHODIMP_(ULONG) CShellExtClassFactory::Release() |
333 | { |
334 | if (--m_cRef) |
335 | return m_cRef; |
336 | delete this; |
337 | return 0L; |
338 | } |
339 | |
340 | STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj) |
341 | { |
342 | *ppvObj = NULL; |
343 | if (pUnkOuter) |
344 | return CLASS_E_NOAGGREGATION; |
345 | CShellExt* pShellExt = new CShellExt(); |
346 | if (0 == pShellExt) |
347 | return E_OUTOFMEMORY; |
348 | return pShellExt->QueryInterface(riid, ppvObj); |
349 | } |
350 | |
351 | STDMETHODIMP CShellExtClassFactory::LockServer(BOOL fLock) |
352 | { |
353 | return NOERROR; |
354 | } |
355 | |
356 | //--------------------------------------------------------------------------- |
357 | // CShellExt |
358 | //--------------------------------------------------------------------------- |
359 | CShellExt::CShellExt() |
360 | { |
361 | m_cRef = 0L; |
362 | _cRef++; |
363 | m_pDataObj = NULL; |
364 | |
365 | m_hKdeLogoBmp = LoadBitmap(_hModule, MAKEINTRESOURCE(IDB_KDE)); |
366 | if(0 != GetLastError()) { |
367 | LPCTSTR msgBuf; |
368 | |
369 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0,(LPWSTR)&msgBuf, 0, NULL); |
370 | qDebug() << "Error:"<< msgBuf; |
371 | } |
372 | } |
373 | |
374 | CShellExt::~CShellExt() |
375 | { |
376 | if (m_pDataObj) |
377 | m_pDataObj->Release(); |
378 | _cRef--; |
379 | } |
380 | |
381 | STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv) |
382 | { |
383 | *ppv = NULL; |
384 | if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) { |
385 | *ppv = (LPSHELLEXTINIT)this; |
386 | } |
387 | else if (IsEqualIID(riid, IID_IContextMenu)) { |
388 | *ppv = (LPCONTEXTMENU)this; |
389 | } |
390 | if (*ppv) { |
391 | AddRef(); |
392 | return NOERROR; |
393 | } |
394 | return E_NOINTERFACE; |
395 | } |
396 | |
397 | STDMETHODIMP_(ULONG) CShellExt::AddRef() |
398 | { |
399 | return ++m_cRef; |
400 | } |
401 | |
402 | STDMETHODIMP_(ULONG) CShellExt::Release() |
403 | { |
404 | if (--m_cRef) |
405 | return m_cRef; |
406 | delete this; |
407 | return 0L; |
408 | } |
409 | |
410 | STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hRegKey) |
411 | { |
412 | if (m_pDataObj) |
413 | m_pDataObj->Release(); |
414 | if (pDataObj) { |
415 | m_pDataObj = pDataObj; |
416 | pDataObj->AddRef(); |
417 | } |
418 | return NOERROR; |
419 | } |
420 | |
421 | STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) |
422 | { |
423 | UINT idCmd = idCmdFirst; |
424 | BOOL bAppendItems=TRUE; |
425 | TCHAR szFileUserClickedOn[MAX_PATH]; |
426 | |
427 | FORMATETC fmte = { |
428 | CF_HDROP, |
429 | (DVTARGETDEVICE FAR *)NULL, |
430 | DVASPECT_CONTENT, |
431 | -1, |
432 | TYMED_HGLOBAL |
433 | }; |
434 | |
435 | HRESULT hres = m_pDataObj->GetData(&fmte, &m_stgMedium); |
436 | |
437 | if (SUCCEEDED(hres)) { |
438 | if (m_stgMedium.hGlobal) |
439 | m_cbFiles = DragQueryFile((HDROP)m_stgMedium.hGlobal, (UINT)-1, 0, 0); |
440 | qDebug() << "number of files:"<< m_cbFiles; |
441 | for (unsigned i = 0; i < m_cbFiles; i++) { |
442 | DragQueryFile((HDROP)m_stgMedium.hGlobal, i, szFileUserClickedOn, MAX_PATH); |
443 | qDebug() << "file to open:"<< lptstr2QString(szFileUserClickedOn); |
444 | } |
445 | } |
446 | QString path = lptstr2QString(szFileUserClickedOn); |
447 | |
448 | UINT nIndex = indexMenu++; |
449 | |
450 | KMimeType::Ptr ptr = KMimeType::findByPath(path); |
451 | |
452 | KService::List lst = KMimeTypeTrader::self()->query(ptr->name(), "Application"); |
453 | |
454 | if(lst.size() > 0) |
455 | { |
456 | TCHAR str[256]; |
457 | wsprintf(str, TEXT("Open with %s"), (LPTSTR)lst.at(0)->name().utf16()); |
458 | InsertMenu(hMenu, nIndex, MF_STRING|MF_BYPOSITION, idCmd++, str ); |
459 | |
460 | if (m_hKdeLogoBmp) { |
461 | SetMenuItemBitmaps(hMenu, nIndex, MF_BYPOSITION, m_hKdeLogoBmp, m_hKdeLogoBmp); |
462 | } |
463 | } |
464 | |
465 | return ResultFromShort(idCmd-idCmdFirst); |
466 | } |
467 | |
468 | STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) |
469 | { |
470 | TCHAR szFileUserClickedOn[MAX_PATH]; |
471 | TCHAR dllPath[MAX_PATH]; |
472 | QString command; |
473 | |
474 | FORMATETC fmte = { |
475 | CF_HDROP, |
476 | (DVTARGETDEVICE FAR *)NULL, |
477 | DVASPECT_CONTENT, |
478 | -1, |
479 | TYMED_HGLOBAL |
480 | }; |
481 | |
482 | GetModuleFileName(_hModule, dllPath, MAX_PATH); |
483 | QString module = lptstr2QString(dllPath); |
484 | command += module.left(module.lastIndexOf( |
485 | command += |
486 | |
487 | for (unsigned i = 0; i < m_cbFiles; i++) { |
488 | DragQueryFile((HDROP)m_stgMedium.hGlobal, i, szFileUserClickedOn, MAX_PATH); |
489 | QString path = lptstr2QString(szFileUserClickedOn); |
490 | |
491 | if(0 == i) |
492 | { |
493 | KMimeType::Ptr ptr = KMimeType::findByPath(path); |
494 | |
495 | KService::List lst = KMimeTypeTrader::self()->query(ptr->name(), "Application"); |
496 | |
497 | if(lst.size() > 0) |
498 | { |
499 | QString exec = lst.at(0)->exec(); |
500 | if( -1 != exec.indexOf("%u", 0, Qt::CaseInsensitive) ) |
501 | { |
502 | exec = exec.left(exec.indexOf("%u", 0, Qt::CaseInsensitive)); |
503 | } |
504 | command += exec; |
505 | } |
506 | }; |
507 | |
508 | command += "\""+ path + "\""; |
509 | } |
510 | |
511 | STARTUPINFO si; |
512 | PROCESS_INFORMATION pi; |
513 | ZeroMemory(&si, sizeof(si)); |
514 | si.cb = sizeof(si); |
515 | si.dwFlags = STARTF_USESHOWWINDOW; |
516 | si.wShowWindow = SW_RESTORE; |
517 | if (!CreateProcess(NULL, (LPTSTR)command.utf16(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { |
518 | MessageBox(lpcmi->hwnd, |
519 | TEXT("Error creating process: kdecm.dll needs to be in the same directory as the executable"), |
520 | TEXT("KDE Extension"), |
521 | MB_OK); |
522 | } |
523 | |
524 | return NOERROR; |
525 | } |
526 | |
527 | STDMETHODIMP CShellExt::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax) |
528 | { |
529 | /*! |
530 | * This function is inherited from IContextMenu and should return some strings |
531 | * lookup http://msdn.microsoft.com/en-us/library/bb776094(VS.85).aspx |
532 | */ |
533 | TCHAR szFileUserClickedOn[MAX_PATH]; |
534 | DragQueryFile((HDROP)m_stgMedium.hGlobal, m_cbFiles - 1, szFileUserClickedOn, MAX_PATH); |
535 | |
536 | if (uFlags == GCS_HELPTEXT && cchMax > 35) |
537 | lstrcpy((LPTSTR)pszName, TEXT("Edits the selected file(s) with the connected KDE Application")); |
538 | return NOERROR; |
539 | } |
540 |
Warning: That file was not part of the compilation database. It may have many parsing errors.