| 
									
										
										
										
											2016-07-16 16:17:33 -07:00
										 |  |  | // Support back to Vista
 | 
					
						
							|  |  |  | #define _WIN32_WINNT _WIN32_WINNT_VISTA
 | 
					
						
							|  |  |  | #include <sdkddkver.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Use WRL to define a classic COM class
 | 
					
						
							|  |  |  | #define __WRL_CLASSIC_COM__
 | 
					
						
							|  |  |  | #include <wrl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | #include <shlobj.h>
 | 
					
						
							|  |  |  | #include <shlwapi.h>
 | 
					
						
							|  |  |  | #include <olectl.h>
 | 
					
						
							|  |  |  | #include <strsafe.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define DDWM_UPDATEWINDOW (WM_USER+3)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static HINSTANCE hModule; | 
					
						
							|  |  |  | static CLIPFORMAT cfDropDescription; | 
					
						
							|  |  |  | static CLIPFORMAT cfDragWindow; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 04:32:23 +05:00
										 |  |  | #define CLASS_GUID "{BEA218D2-6950-497B-9434-61683EC065FE}"
 | 
					
						
							|  |  |  | static const LPCWSTR CLASS_SUBKEY = L"Software\\Classes\\CLSID\\" CLASS_GUID; | 
					
						
							| 
									
										
										
										
											2016-07-16 16:17:33 -07:00
										 |  |  | static const LPCWSTR DRAG_MESSAGE = L"Open with %1"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace Microsoft::WRL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HRESULT FilenameListCchLengthA(LPCSTR pszSource, size_t cchMax, size_t *pcchLength, size_t *pcchCount) { | 
					
						
							|  |  |  |     HRESULT hr = S_OK; | 
					
						
							|  |  |  |     size_t count = 0; | 
					
						
							|  |  |  |     size_t length = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (pszSource && pszSource[0]) { | 
					
						
							|  |  |  |         size_t oneLength; | 
					
						
							|  |  |  |         hr = StringCchLengthA(pszSource, cchMax - length, &oneLength); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         count += 1; | 
					
						
							|  |  |  |         length += oneLength + (strchr(pszSource, ' ') ? 3 : 1); | 
					
						
							|  |  |  |         pszSource = &pszSource[oneLength + 1]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *pcchCount = count; | 
					
						
							|  |  |  |     *pcchLength = length; | 
					
						
							|  |  |  |     return hr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HRESULT FilenameListCchLengthW(LPCWSTR pszSource, size_t cchMax, size_t *pcchLength, size_t *pcchCount) { | 
					
						
							|  |  |  |     HRESULT hr = S_OK; | 
					
						
							|  |  |  |     size_t count = 0; | 
					
						
							|  |  |  |     size_t length = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (pszSource && pszSource[0]) { | 
					
						
							|  |  |  |         size_t oneLength; | 
					
						
							|  |  |  |         hr = StringCchLengthW(pszSource, cchMax - length, &oneLength); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         count += 1; | 
					
						
							|  |  |  |         length += oneLength + (wcschr(pszSource, ' ') ? 3 : 1); | 
					
						
							|  |  |  |         pszSource = &pszSource[oneLength + 1]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *pcchCount = count; | 
					
						
							|  |  |  |     *pcchLength = length; | 
					
						
							|  |  |  |     return hr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HRESULT FilenameListCchCopyA(STRSAFE_LPSTR pszDest, size_t cchDest, LPCSTR pszSource, LPCSTR pszSeparator) { | 
					
						
							|  |  |  |     HRESULT hr = S_OK; | 
					
						
							|  |  |  |     size_t count = 0; | 
					
						
							|  |  |  |     size_t length = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (pszSource[0]) { | 
					
						
							|  |  |  |         STRSAFE_LPSTR newDest; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = StringCchCopyExA(pszDest, cchDest, pszSource, &newDest, &cchDest, 0); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         pszSource += (newDest - pszDest) + 1; | 
					
						
							|  |  |  |         pszDest = PathQuoteSpacesA(pszDest) ? newDest + 2 : newDest; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (pszSource[0]) { | 
					
						
							|  |  |  |             hr = StringCchCopyExA(pszDest, cchDest, pszSeparator, &newDest, &cchDest, 0); | 
					
						
							|  |  |  |             if (FAILED(hr)) { | 
					
						
							|  |  |  |                 return hr; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             pszDest = newDest; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return hr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HRESULT FilenameListCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, LPCWSTR pszSource, LPCWSTR pszSeparator) { | 
					
						
							|  |  |  |     HRESULT hr = S_OK; | 
					
						
							|  |  |  |     size_t count = 0; | 
					
						
							|  |  |  |     size_t length = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (pszSource[0]) { | 
					
						
							|  |  |  |         STRSAFE_LPWSTR newDest; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = StringCchCopyExW(pszDest, cchDest, pszSource, &newDest, &cchDest, 0); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         pszSource += (newDest - pszDest) + 1; | 
					
						
							|  |  |  |         pszDest = PathQuoteSpacesW(pszDest) ? newDest + 2 : newDest; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (pszSource[0]) { | 
					
						
							|  |  |  |             hr = StringCchCopyExW(pszDest, cchDest, pszSeparator, &newDest, &cchDest, 0); | 
					
						
							|  |  |  |             if (FAILED(hr)) { | 
					
						
							|  |  |  |                 return hr; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             pszDest = newDest; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return hr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 04:32:23 +05:00
										 |  |  | class DECLSPEC_UUID(CLASS_GUID) PyShellExt : public RuntimeClass< | 
					
						
							| 
									
										
										
										
											2016-07-16 16:17:33 -07:00
										 |  |  |     RuntimeClassFlags<ClassicCom>, | 
					
						
							|  |  |  |     IDropTarget, | 
					
						
							|  |  |  |     IPersistFile | 
					
						
							|  |  |  | > | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     LPOLESTR target, target_dir; | 
					
						
							|  |  |  |     DWORD target_mode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     IDataObject *data_obj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     PyShellExt() : target(NULL), target_dir(NULL), target_mode(0), data_obj(NULL) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::PyShellExt"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ~PyShellExt() { | 
					
						
							|  |  |  |         if (target) { | 
					
						
							|  |  |  |             CoTaskMemFree(target); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (target_dir) { | 
					
						
							|  |  |  |             CoTaskMemFree(target_dir); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (data_obj) { | 
					
						
							|  |  |  |             data_obj->Release(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     HRESULT UpdateDropDescription(IDataObject *pDataObj) { | 
					
						
							|  |  |  |         STGMEDIUM medium; | 
					
						
							|  |  |  |         FORMATETC fmt = { | 
					
						
							|  |  |  |             cfDropDescription, | 
					
						
							|  |  |  |             NULL, | 
					
						
							|  |  |  |             DVASPECT_CONTENT, | 
					
						
							|  |  |  |             -1, | 
					
						
							|  |  |  |             TYMED_HGLOBAL | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto hr = pDataObj->GetData(&fmt, &medium); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::UpdateDropDescription - failed to get DROPDESCRIPTION format"); | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!medium.hGlobal) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::UpdateDropDescription - DROPDESCRIPTION format had NULL hGlobal"); | 
					
						
							|  |  |  |             ReleaseStgMedium(&medium); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         auto dd = (DROPDESCRIPTION*)GlobalLock(medium.hGlobal); | 
					
						
							| 
									
										
										
										
											2018-09-24 22:25:23 -06:00
										 |  |  |         if (!dd) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::UpdateDropDescription - failed to lock DROPDESCRIPTION hGlobal"); | 
					
						
							|  |  |  |             ReleaseStgMedium(&medium); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-07-16 16:17:33 -07:00
										 |  |  |         StringCchCopy(dd->szMessage, sizeof(dd->szMessage) / sizeof(dd->szMessage[0]), DRAG_MESSAGE); | 
					
						
							|  |  |  |         StringCchCopy(dd->szInsert, sizeof(dd->szInsert) / sizeof(dd->szInsert[0]), PathFindFileNameW(target)); | 
					
						
							|  |  |  |         dd->type = DROPIMAGE_MOVE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         GlobalUnlock(medium.hGlobal); | 
					
						
							|  |  |  |         ReleaseStgMedium(&medium); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     HRESULT GetDragWindow(IDataObject *pDataObj, HWND *phWnd) { | 
					
						
							|  |  |  |         HRESULT hr; | 
					
						
							|  |  |  |         HWND *pMem; | 
					
						
							|  |  |  |         STGMEDIUM medium; | 
					
						
							|  |  |  |         FORMATETC fmt = { | 
					
						
							|  |  |  |             cfDragWindow, | 
					
						
							|  |  |  |             NULL, | 
					
						
							|  |  |  |             DVASPECT_CONTENT, | 
					
						
							|  |  |  |             -1, | 
					
						
							|  |  |  |             TYMED_HGLOBAL | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = pDataObj->GetData(&fmt, &medium); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::GetDragWindow - failed to get DragWindow format"); | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!medium.hGlobal) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::GetDragWindow - DragWindow format had NULL hGlobal"); | 
					
						
							|  |  |  |             ReleaseStgMedium(&medium); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pMem = (HWND*)GlobalLock(medium.hGlobal); | 
					
						
							|  |  |  |         if (!pMem) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::GetDragWindow - failed to lock DragWindow hGlobal"); | 
					
						
							|  |  |  |             ReleaseStgMedium(&medium); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         *phWnd = *pMem; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         GlobalUnlock(medium.hGlobal); | 
					
						
							|  |  |  |         ReleaseStgMedium(&medium); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     HRESULT GetArguments(IDataObject *pDataObj, LPCWSTR *pArguments) { | 
					
						
							|  |  |  |         HRESULT hr; | 
					
						
							|  |  |  |         DROPFILES *pdropfiles; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         STGMEDIUM medium; | 
					
						
							|  |  |  |         FORMATETC fmt = { | 
					
						
							|  |  |  |             CF_HDROP, | 
					
						
							|  |  |  |             NULL, | 
					
						
							|  |  |  |             DVASPECT_CONTENT, | 
					
						
							|  |  |  |             -1, | 
					
						
							|  |  |  |             TYMED_HGLOBAL | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = pDataObj->GetData(&fmt, &medium); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::GetArguments - failed to get CF_HDROP format"); | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!medium.hGlobal) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::GetArguments - CF_HDROP format had NULL hGlobal"); | 
					
						
							|  |  |  |             ReleaseStgMedium(&medium); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pdropfiles = (DROPFILES*)GlobalLock(medium.hGlobal); | 
					
						
							|  |  |  |         if (!pdropfiles) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::GetArguments - failed to lock CF_HDROP hGlobal"); | 
					
						
							|  |  |  |             ReleaseStgMedium(&medium); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (pdropfiles->fWide) { | 
					
						
							|  |  |  |             LPCWSTR files = (LPCWSTR)((char*)pdropfiles + pdropfiles->pFiles); | 
					
						
							|  |  |  |             size_t len, count; | 
					
						
							|  |  |  |             hr = FilenameListCchLengthW(files, 32767, &len, &count); | 
					
						
							|  |  |  |             if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |                 LPWSTR args = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1)); | 
					
						
							|  |  |  |                 if (args) { | 
					
						
							|  |  |  |                     hr = FilenameListCchCopyW(args, 32767, files, L" "); | 
					
						
							|  |  |  |                     if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |                         *pArguments = args; | 
					
						
							|  |  |  |                     } else { | 
					
						
							|  |  |  |                         CoTaskMemFree(args); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     hr = E_OUTOFMEMORY; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             LPCSTR files = (LPCSTR)((char*)pdropfiles + pdropfiles->pFiles); | 
					
						
							|  |  |  |             size_t len, count; | 
					
						
							|  |  |  |             hr = FilenameListCchLengthA(files, 32767, &len, &count); | 
					
						
							|  |  |  |             if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |                 LPSTR temp = (LPSTR)CoTaskMemAlloc(sizeof(CHAR) * (len + 1)); | 
					
						
							|  |  |  |                 if (temp) { | 
					
						
							|  |  |  |                     hr = FilenameListCchCopyA(temp, 32767, files, " "); | 
					
						
							|  |  |  |                     if (SUCCEEDED(hr)) { | 
					
						
							|  |  |  |                         int wlen = MultiByteToWideChar(CP_ACP, 0, temp, (int)len, NULL, 0); | 
					
						
							|  |  |  |                         if (wlen) { | 
					
						
							|  |  |  |                             LPWSTR args = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (wlen + 1)); | 
					
						
							|  |  |  |                             if (MultiByteToWideChar(CP_ACP, 0, temp, (int)len, args, wlen + 1)) { | 
					
						
							|  |  |  |                                 *pArguments = args; | 
					
						
							|  |  |  |                             } else { | 
					
						
							|  |  |  |                                 OutputDebugString(L"PyShellExt::GetArguments - failed to convert multi-byte to wide-char path"); | 
					
						
							|  |  |  |                                 CoTaskMemFree(args); | 
					
						
							|  |  |  |                                 hr = E_FAIL; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } else { | 
					
						
							|  |  |  |                             OutputDebugString(L"PyShellExt::GetArguments - failed to get length of wide-char path"); | 
					
						
							|  |  |  |                             hr = E_FAIL; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     CoTaskMemFree(temp); | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     hr = E_OUTOFMEMORY; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         GlobalUnlock(medium.hGlobal); | 
					
						
							|  |  |  |         ReleaseStgMedium(&medium); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return hr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     HRESULT NotifyDragWindow(HWND hwnd) { | 
					
						
							|  |  |  |         LRESULT res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!hwnd) { | 
					
						
							|  |  |  |             return S_FALSE; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res = SendMessage(hwnd, DDWM_UPDATEWINDOW, 0, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (res) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::NotifyDragWindow - failed to post DDWM_UPDATEWINDOW"); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     // IDropTarget implementation
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { | 
					
						
							|  |  |  |         HWND hwnd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DragEnter"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pDataObj->AddRef(); | 
					
						
							|  |  |  |         data_obj = pDataObj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         *pdwEffect = DROPEFFECT_MOVE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (FAILED(UpdateDropDescription(data_obj))) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::DragEnter - failed to update drop description"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (FAILED(GetDragWindow(data_obj, &hwnd))) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::DragEnter - failed to get drag window"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (FAILED(NotifyDragWindow(hwnd))) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::DragEnter - failed to notify drag window"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP DragLeave() { | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { | 
					
						
							|  |  |  |         LPCWSTR args; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::Drop"); | 
					
						
							|  |  |  |         *pdwEffect = DROPEFFECT_NONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (pDataObj != data_obj) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::Drop - unexpected data object"); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         data_obj->Release(); | 
					
						
							|  |  |  |         data_obj = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (SUCCEEDED(GetArguments(pDataObj, &args))) { | 
					
						
							|  |  |  |             OutputDebugString(args); | 
					
						
							|  |  |  |             ShellExecute(NULL, NULL, target, args, target_dir, SW_NORMAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             CoTaskMemFree((LPVOID)args); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::Drop - failed to get launch arguments"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // IPersistFile implementation
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName) { | 
					
						
							|  |  |  |         HRESULT hr; | 
					
						
							|  |  |  |         size_t len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!ppszFileName) { | 
					
						
							|  |  |  |             return E_POINTER; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = StringCchLength(target, STRSAFE_MAX_CCH - 1, &len); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         *ppszFileName = (LPOLESTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1)); | 
					
						
							|  |  |  |         if (!*ppszFileName) { | 
					
						
							|  |  |  |             return E_OUTOFMEMORY; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = StringCchCopy(*ppszFileName, len + 1, target); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             CoTaskMemFree(*ppszFileName); | 
					
						
							|  |  |  |             *ppszFileName = NULL; | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP IsDirty() { | 
					
						
							|  |  |  |         return S_FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode) { | 
					
						
							|  |  |  |         HRESULT hr; | 
					
						
							|  |  |  |         size_t len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::Load"); | 
					
						
							|  |  |  |         OutputDebugString(pszFileName); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = StringCchLength(pszFileName, STRSAFE_MAX_CCH - 1, &len); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::Load - failed to get string length"); | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (target) { | 
					
						
							|  |  |  |             CoTaskMemFree(target); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (target_dir) { | 
					
						
							|  |  |  |             CoTaskMemFree(target_dir); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         target = (LPOLESTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1)); | 
					
						
							|  |  |  |         if (!target) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::Load - E_OUTOFMEMORY"); | 
					
						
							|  |  |  |             return E_OUTOFMEMORY; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         target_dir = (LPOLESTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1)); | 
					
						
							|  |  |  |         if (!target_dir) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::Load - E_OUTOFMEMORY"); | 
					
						
							|  |  |  |             return E_OUTOFMEMORY; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = StringCchCopy(target, len + 1, pszFileName); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::Load - failed to copy string"); | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hr = StringCchCopy(target_dir, len + 1, pszFileName); | 
					
						
							|  |  |  |         if (FAILED(hr)) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::Load - failed to copy string"); | 
					
						
							|  |  |  |             return hr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!PathRemoveFileSpecW(target_dir)) { | 
					
						
							|  |  |  |             OutputDebugStringW(L"PyShellExt::Load - failed to remove filespec from target"); | 
					
						
							|  |  |  |             return E_FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         OutputDebugString(target); | 
					
						
							|  |  |  |         target_mode = dwMode; | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::Load - S_OK"); | 
					
						
							|  |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember) { | 
					
						
							|  |  |  |         return E_NOTIMPL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName) { | 
					
						
							|  |  |  |         return E_NOTIMPL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     STDMETHODIMP GetClassID(CLSID *pClassID) { | 
					
						
							| 
									
										
										
										
											2020-06-24 04:32:23 +05:00
										 |  |  |         *pClassID = __uuidof(PyShellExt); | 
					
						
							| 
									
										
										
										
											2016-07-16 16:17:33 -07:00
										 |  |  |         return S_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CoCreatableClass(PyShellExt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv) { | 
					
						
							|  |  |  |     return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STDAPI DllCanUnloadNow() { | 
					
						
							|  |  |  |     return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STDAPI DllRegisterServer() { | 
					
						
							|  |  |  |     LONG res; | 
					
						
							|  |  |  |     SECURITY_ATTRIBUTES secattr = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE }; | 
					
						
							|  |  |  |     LPSECURITY_ATTRIBUTES psecattr = NULL; | 
					
						
							|  |  |  |     HKEY key, ipsKey; | 
					
						
							|  |  |  |     WCHAR modname[MAX_PATH]; | 
					
						
							|  |  |  |     DWORD modname_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OutputDebugString(L"PyShellExt::DllRegisterServer"); | 
					
						
							|  |  |  |     if (!hModule) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllRegisterServer - module handle was not set"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     modname_len = GetModuleFileName(hModule, modname, MAX_PATH); | 
					
						
							|  |  |  |     if (modname_len == 0 || | 
					
						
							|  |  |  |         (modname_len == MAX_PATH && GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllRegisterServer - failed to get module file name"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DWORD disp; | 
					
						
							|  |  |  |     res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, CLASS_SUBKEY, 0, NULL, 0, | 
					
						
							|  |  |  |         KEY_ALL_ACCESS, psecattr, &key, &disp); | 
					
						
							|  |  |  |     if (res == ERROR_ACCESS_DENIED) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllRegisterServer - failed to write per-machine registration. Attempting per-user instead."); | 
					
						
							|  |  |  |         res = RegCreateKeyEx(HKEY_CURRENT_USER, CLASS_SUBKEY, 0, NULL, 0, | 
					
						
							|  |  |  |             KEY_ALL_ACCESS, psecattr, &key, &disp); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (res != ERROR_SUCCESS) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllRegisterServer - failed to create class key"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res = RegCreateKeyEx(key, L"InProcServer32", 0, NULL, 0, | 
					
						
							|  |  |  |         KEY_ALL_ACCESS, psecattr, &ipsKey, NULL); | 
					
						
							|  |  |  |     if (res != ERROR_SUCCESS) { | 
					
						
							|  |  |  |         RegCloseKey(key); | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllRegisterServer - failed to create InProcServer32 key"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res = RegSetValueEx(ipsKey, NULL, 0, | 
					
						
							|  |  |  |         REG_SZ, (LPBYTE)modname, modname_len * sizeof(modname[0])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (res != ERROR_SUCCESS) { | 
					
						
							|  |  |  |         RegCloseKey(ipsKey); | 
					
						
							|  |  |  |         RegCloseKey(key); | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllRegisterServer - failed to set server path"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res = RegSetValueEx(ipsKey, L"ThreadingModel", 0, | 
					
						
							|  |  |  |         REG_SZ, (LPBYTE)(L"Apartment"), sizeof(L"Apartment")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RegCloseKey(ipsKey); | 
					
						
							|  |  |  |     RegCloseKey(key); | 
					
						
							|  |  |  |     if (res != ERROR_SUCCESS) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllRegisterServer - failed to set threading model"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OutputDebugString(L"PyShellExt::DllRegisterServer - S_OK"); | 
					
						
							|  |  |  |     return S_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STDAPI DllUnregisterServer() { | 
					
						
							|  |  |  |     LONG res_lm, res_cu; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res_lm = RegDeleteTree(HKEY_LOCAL_MACHINE, CLASS_SUBKEY); | 
					
						
							|  |  |  |     if (res_lm != ERROR_SUCCESS && res_lm != ERROR_FILE_NOT_FOUND) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllUnregisterServer - failed to delete per-machine registration"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res_cu = RegDeleteTree(HKEY_CURRENT_USER, CLASS_SUBKEY); | 
					
						
							|  |  |  |     if (res_cu != ERROR_SUCCESS && res_cu != ERROR_FILE_NOT_FOUND) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllUnregisterServer - failed to delete per-user registration"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (res_lm == ERROR_FILE_NOT_FOUND && res_cu == ERROR_FILE_NOT_FOUND) { | 
					
						
							|  |  |  |         OutputDebugString(L"PyShellExt::DllUnregisterServer - extension was not registered"); | 
					
						
							|  |  |  |         return SELFREG_E_CLASS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OutputDebugString(L"PyShellExt::DllUnregisterServer - S_OK"); | 
					
						
							|  |  |  |     return S_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*) { | 
					
						
							|  |  |  |     if (reason == DLL_PROCESS_ATTACH) { | 
					
						
							|  |  |  |         hModule = hinst; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         cfDropDescription = RegisterClipboardFormat(CFSTR_DROPDESCRIPTION); | 
					
						
							|  |  |  |         if (!cfDropDescription) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::DllMain - failed to get CFSTR_DROPDESCRIPTION format"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         cfDragWindow = RegisterClipboardFormat(L"DragWindow"); | 
					
						
							|  |  |  |         if (!cfDragWindow) { | 
					
						
							|  |  |  |             OutputDebugString(L"PyShellExt::DllMain - failed to get DragWindow format"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         DisableThreadLibraryCalls(hinst); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  | } |