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//---------------------------------------------------------------------------
57UINT _cRef = 0; // COM Reference count.
58HINSTANCE _hModule = NULL; // DLL Module.
59
60TCHAR szShellExtensionTitle[] = TEXT("Kate");
61
62typedef struct{
63 HKEY hRootKey;
64 LPTSTR szSubKey;
65 LPTSTR lpszValueName;
66 LPTSTR szData;
67} DOREGSTRUCT;
68
69BOOL RegisterServer(CLSID, LPTSTR);
70BOOL UnregisterServer(CLSID, LPTSTR);
71
72
73inline 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
84inline QString lptstr2QString(LPTSTR str)
85{
86 return QString::fromUtf16( reinterpret_cast<ushort*>( str ) );
87}
88
89void 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//---------------------------------------------------------------------------
117STDAPI_(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//---------------------------------------------------------------------------
150STDAPI DllCanUnloadNow(void)
151{
152 return (_cRef == 0 ? S_OK : S_FALSE);
153}
154
155//---------------------------------------------------------------------------
156// DllGetClassObject
157//---------------------------------------------------------------------------
158STDAPI 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//---------------------------------------------------------------------------
174STDAPI DllRegisterServer(void)
175{
176 return (RegisterServer(CLSID_ShellExtension, szShellExtensionTitle) ? S_OK : E_FAIL);
177}
178
179//---------------------------------------------------------------------------
180// DllUnregisterServer
181//---------------------------------------------------------------------------
182STDAPI DllUnregisterServer(void)
183{
184 return (UnregisterServer(CLSID_ShellExtension, szShellExtensionTitle) ? S_OK : E_FAIL);
185}
186
187//---------------------------------------------------------------------------
188// RegisterServer
189//---------------------------------------------------------------------------
190BOOL 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//---------------------------------------------------------------------------
264BOOL 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 */
305CShellExtClassFactory::CShellExtClassFactory()
306{
307 m_cRef = 0L;
308 _cRef++;
309}
310
311CShellExtClassFactory::~CShellExtClassFactory()
312{
313 _cRef--;
314}
315
316STDMETHODIMP 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
327STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef()
328{
329 return ++m_cRef;
330}
331
332STDMETHODIMP_(ULONG) CShellExtClassFactory::Release()
333{
334 if (--m_cRef)
335 return m_cRef;
336 delete this;
337 return 0L;
338}
339
340STDMETHODIMP 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
351STDMETHODIMP CShellExtClassFactory::LockServer(BOOL fLock)
352{
353 return NOERROR;
354}
355
356//---------------------------------------------------------------------------
357// CShellExt
358//---------------------------------------------------------------------------
359CShellExt::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
374CShellExt::~CShellExt()
375{
376 if (m_pDataObj)
377 m_pDataObj->Release();
378 _cRef--;
379}
380
381STDMETHODIMP 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
397STDMETHODIMP_(ULONG) CShellExt::AddRef()
398{
399 return ++m_cRef;
400}
401
402STDMETHODIMP_(ULONG) CShellExt::Release()
403{
404 if (--m_cRef)
405 return m_cRef;
406 delete this;
407 return 0L;
408}
409
410STDMETHODIMP 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
421STDMETHODIMP 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
468STDMETHODIMP 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
527STDMETHODIMP 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.