17db96d56Sopenharmony_ci// Support back to Vista
27db96d56Sopenharmony_ci#define _WIN32_WINNT _WIN32_WINNT_VISTA
37db96d56Sopenharmony_ci#include <sdkddkver.h>
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci// Use WRL to define a classic COM class
67db96d56Sopenharmony_ci#define __WRL_CLASSIC_COM__
77db96d56Sopenharmony_ci#include <wrl.h>
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci#include <windows.h>
107db96d56Sopenharmony_ci#include <shlobj.h>
117db96d56Sopenharmony_ci#include <shlwapi.h>
127db96d56Sopenharmony_ci#include <olectl.h>
137db96d56Sopenharmony_ci#include <strsafe.h>
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci#define DDWM_UPDATEWINDOW (WM_USER+3)
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_cistatic HINSTANCE hModule;
187db96d56Sopenharmony_cistatic CLIPFORMAT cfDropDescription;
197db96d56Sopenharmony_cistatic CLIPFORMAT cfDragWindow;
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci#define CLASS_GUID "{BEA218D2-6950-497B-9434-61683EC065FE}"
227db96d56Sopenharmony_cistatic const LPCWSTR CLASS_SUBKEY = L"Software\\Classes\\CLSID\\" CLASS_GUID;
237db96d56Sopenharmony_cistatic const LPCWSTR DRAG_MESSAGE = L"Open with %1";
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ciusing namespace Microsoft::WRL;
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ciHRESULT FilenameListCchLengthA(LPCSTR pszSource, size_t cchMax, size_t *pcchLength, size_t *pcchCount) {
287db96d56Sopenharmony_ci    HRESULT hr = S_OK;
297db96d56Sopenharmony_ci    size_t count = 0;
307db96d56Sopenharmony_ci    size_t length = 0;
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci    while (pszSource && pszSource[0]) {
337db96d56Sopenharmony_ci        size_t oneLength;
347db96d56Sopenharmony_ci        hr = StringCchLengthA(pszSource, cchMax - length, &oneLength);
357db96d56Sopenharmony_ci        if (FAILED(hr)) {
367db96d56Sopenharmony_ci            return hr;
377db96d56Sopenharmony_ci        }
387db96d56Sopenharmony_ci        count += 1;
397db96d56Sopenharmony_ci        length += oneLength + (strchr(pszSource, ' ') ? 3 : 1);
407db96d56Sopenharmony_ci        pszSource = &pszSource[oneLength + 1];
417db96d56Sopenharmony_ci    }
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci    *pcchCount = count;
447db96d56Sopenharmony_ci    *pcchLength = length;
457db96d56Sopenharmony_ci    return hr;
467db96d56Sopenharmony_ci}
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_ciHRESULT FilenameListCchLengthW(LPCWSTR pszSource, size_t cchMax, size_t *pcchLength, size_t *pcchCount) {
497db96d56Sopenharmony_ci    HRESULT hr = S_OK;
507db96d56Sopenharmony_ci    size_t count = 0;
517db96d56Sopenharmony_ci    size_t length = 0;
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci    while (pszSource && pszSource[0]) {
547db96d56Sopenharmony_ci        size_t oneLength;
557db96d56Sopenharmony_ci        hr = StringCchLengthW(pszSource, cchMax - length, &oneLength);
567db96d56Sopenharmony_ci        if (FAILED(hr)) {
577db96d56Sopenharmony_ci            return hr;
587db96d56Sopenharmony_ci        }
597db96d56Sopenharmony_ci        count += 1;
607db96d56Sopenharmony_ci        length += oneLength + (wcschr(pszSource, ' ') ? 3 : 1);
617db96d56Sopenharmony_ci        pszSource = &pszSource[oneLength + 1];
627db96d56Sopenharmony_ci    }
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci    *pcchCount = count;
657db96d56Sopenharmony_ci    *pcchLength = length;
667db96d56Sopenharmony_ci    return hr;
677db96d56Sopenharmony_ci}
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ciHRESULT FilenameListCchCopyA(STRSAFE_LPSTR pszDest, size_t cchDest, LPCSTR pszSource, LPCSTR pszSeparator) {
707db96d56Sopenharmony_ci    HRESULT hr = S_OK;
717db96d56Sopenharmony_ci    size_t count = 0;
727db96d56Sopenharmony_ci    size_t length = 0;
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci    while (pszSource[0]) {
757db96d56Sopenharmony_ci        STRSAFE_LPSTR newDest;
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci        hr = StringCchCopyExA(pszDest, cchDest, pszSource, &newDest, &cchDest, 0);
787db96d56Sopenharmony_ci        if (FAILED(hr)) {
797db96d56Sopenharmony_ci            return hr;
807db96d56Sopenharmony_ci        }
817db96d56Sopenharmony_ci        pszSource += (newDest - pszDest) + 1;
827db96d56Sopenharmony_ci        pszDest = PathQuoteSpacesA(pszDest) ? newDest + 2 : newDest;
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci        if (pszSource[0]) {
857db96d56Sopenharmony_ci            hr = StringCchCopyExA(pszDest, cchDest, pszSeparator, &newDest, &cchDest, 0);
867db96d56Sopenharmony_ci            if (FAILED(hr)) {
877db96d56Sopenharmony_ci                return hr;
887db96d56Sopenharmony_ci            }
897db96d56Sopenharmony_ci            pszDest = newDest;
907db96d56Sopenharmony_ci        }
917db96d56Sopenharmony_ci    }
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ci    return hr;
947db96d56Sopenharmony_ci}
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ciHRESULT FilenameListCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, LPCWSTR pszSource, LPCWSTR pszSeparator) {
977db96d56Sopenharmony_ci    HRESULT hr = S_OK;
987db96d56Sopenharmony_ci    size_t count = 0;
997db96d56Sopenharmony_ci    size_t length = 0;
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci    while (pszSource[0]) {
1027db96d56Sopenharmony_ci        STRSAFE_LPWSTR newDest;
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ci        hr = StringCchCopyExW(pszDest, cchDest, pszSource, &newDest, &cchDest, 0);
1057db96d56Sopenharmony_ci        if (FAILED(hr)) {
1067db96d56Sopenharmony_ci            return hr;
1077db96d56Sopenharmony_ci        }
1087db96d56Sopenharmony_ci        pszSource += (newDest - pszDest) + 1;
1097db96d56Sopenharmony_ci        pszDest = PathQuoteSpacesW(pszDest) ? newDest + 2 : newDest;
1107db96d56Sopenharmony_ci
1117db96d56Sopenharmony_ci        if (pszSource[0]) {
1127db96d56Sopenharmony_ci            hr = StringCchCopyExW(pszDest, cchDest, pszSeparator, &newDest, &cchDest, 0);
1137db96d56Sopenharmony_ci            if (FAILED(hr)) {
1147db96d56Sopenharmony_ci                return hr;
1157db96d56Sopenharmony_ci            }
1167db96d56Sopenharmony_ci            pszDest = newDest;
1177db96d56Sopenharmony_ci        }
1187db96d56Sopenharmony_ci    }
1197db96d56Sopenharmony_ci
1207db96d56Sopenharmony_ci    return hr;
1217db96d56Sopenharmony_ci}
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ciclass DECLSPEC_UUID(CLASS_GUID) PyShellExt : public RuntimeClass<
1247db96d56Sopenharmony_ci    RuntimeClassFlags<ClassicCom>,
1257db96d56Sopenharmony_ci    IDropTarget,
1267db96d56Sopenharmony_ci    IPersistFile
1277db96d56Sopenharmony_ci>
1287db96d56Sopenharmony_ci{
1297db96d56Sopenharmony_ci    LPOLESTR target, target_dir;
1307db96d56Sopenharmony_ci    DWORD target_mode;
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_ci    IDataObject *data_obj;
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_cipublic:
1357db96d56Sopenharmony_ci    PyShellExt() : target(NULL), target_dir(NULL), target_mode(0), data_obj(NULL) {
1367db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::PyShellExt");
1377db96d56Sopenharmony_ci    }
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_ci    ~PyShellExt() {
1407db96d56Sopenharmony_ci        if (target) {
1417db96d56Sopenharmony_ci            CoTaskMemFree(target);
1427db96d56Sopenharmony_ci        }
1437db96d56Sopenharmony_ci        if (target_dir) {
1447db96d56Sopenharmony_ci            CoTaskMemFree(target_dir);
1457db96d56Sopenharmony_ci        }
1467db96d56Sopenharmony_ci        if (data_obj) {
1477db96d56Sopenharmony_ci            data_obj->Release();
1487db96d56Sopenharmony_ci        }
1497db96d56Sopenharmony_ci    }
1507db96d56Sopenharmony_ci
1517db96d56Sopenharmony_ciprivate:
1527db96d56Sopenharmony_ci    HRESULT UpdateDropDescription(IDataObject *pDataObj) {
1537db96d56Sopenharmony_ci        STGMEDIUM medium;
1547db96d56Sopenharmony_ci        FORMATETC fmt = {
1557db96d56Sopenharmony_ci            cfDropDescription,
1567db96d56Sopenharmony_ci            NULL,
1577db96d56Sopenharmony_ci            DVASPECT_CONTENT,
1587db96d56Sopenharmony_ci            -1,
1597db96d56Sopenharmony_ci            TYMED_HGLOBAL
1607db96d56Sopenharmony_ci        };
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_ci        auto hr = pDataObj->GetData(&fmt, &medium);
1637db96d56Sopenharmony_ci        if (FAILED(hr)) {
1647db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::UpdateDropDescription - failed to get DROPDESCRIPTION format");
1657db96d56Sopenharmony_ci            return hr;
1667db96d56Sopenharmony_ci        }
1677db96d56Sopenharmony_ci        if (!medium.hGlobal) {
1687db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::UpdateDropDescription - DROPDESCRIPTION format had NULL hGlobal");
1697db96d56Sopenharmony_ci            ReleaseStgMedium(&medium);
1707db96d56Sopenharmony_ci            return E_FAIL;
1717db96d56Sopenharmony_ci        }
1727db96d56Sopenharmony_ci        auto dd = (DROPDESCRIPTION*)GlobalLock(medium.hGlobal);
1737db96d56Sopenharmony_ci        if (!dd) {
1747db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::UpdateDropDescription - failed to lock DROPDESCRIPTION hGlobal");
1757db96d56Sopenharmony_ci            ReleaseStgMedium(&medium);
1767db96d56Sopenharmony_ci            return E_FAIL;
1777db96d56Sopenharmony_ci        }
1787db96d56Sopenharmony_ci        StringCchCopy(dd->szMessage, sizeof(dd->szMessage) / sizeof(dd->szMessage[0]), DRAG_MESSAGE);
1797db96d56Sopenharmony_ci        StringCchCopy(dd->szInsert, sizeof(dd->szInsert) / sizeof(dd->szInsert[0]), PathFindFileNameW(target));
1807db96d56Sopenharmony_ci        dd->type = DROPIMAGE_MOVE;
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ci        GlobalUnlock(medium.hGlobal);
1837db96d56Sopenharmony_ci        ReleaseStgMedium(&medium);
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci        return S_OK;
1867db96d56Sopenharmony_ci    }
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci    HRESULT GetDragWindow(IDataObject *pDataObj, HWND *phWnd) {
1897db96d56Sopenharmony_ci        HRESULT hr;
1907db96d56Sopenharmony_ci        HWND *pMem;
1917db96d56Sopenharmony_ci        STGMEDIUM medium;
1927db96d56Sopenharmony_ci        FORMATETC fmt = {
1937db96d56Sopenharmony_ci            cfDragWindow,
1947db96d56Sopenharmony_ci            NULL,
1957db96d56Sopenharmony_ci            DVASPECT_CONTENT,
1967db96d56Sopenharmony_ci            -1,
1977db96d56Sopenharmony_ci            TYMED_HGLOBAL
1987db96d56Sopenharmony_ci        };
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci        hr = pDataObj->GetData(&fmt, &medium);
2017db96d56Sopenharmony_ci        if (FAILED(hr)) {
2027db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::GetDragWindow - failed to get DragWindow format");
2037db96d56Sopenharmony_ci            return hr;
2047db96d56Sopenharmony_ci        }
2057db96d56Sopenharmony_ci        if (!medium.hGlobal) {
2067db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::GetDragWindow - DragWindow format had NULL hGlobal");
2077db96d56Sopenharmony_ci            ReleaseStgMedium(&medium);
2087db96d56Sopenharmony_ci            return E_FAIL;
2097db96d56Sopenharmony_ci        }
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci        pMem = (HWND*)GlobalLock(medium.hGlobal);
2127db96d56Sopenharmony_ci        if (!pMem) {
2137db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::GetDragWindow - failed to lock DragWindow hGlobal");
2147db96d56Sopenharmony_ci            ReleaseStgMedium(&medium);
2157db96d56Sopenharmony_ci            return E_FAIL;
2167db96d56Sopenharmony_ci        }
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci        *phWnd = *pMem;
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci        GlobalUnlock(medium.hGlobal);
2217db96d56Sopenharmony_ci        ReleaseStgMedium(&medium);
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ci        return S_OK;
2247db96d56Sopenharmony_ci    }
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci    HRESULT GetArguments(IDataObject *pDataObj, LPCWSTR *pArguments) {
2277db96d56Sopenharmony_ci        HRESULT hr;
2287db96d56Sopenharmony_ci        DROPFILES *pdropfiles;
2297db96d56Sopenharmony_ci
2307db96d56Sopenharmony_ci        STGMEDIUM medium;
2317db96d56Sopenharmony_ci        FORMATETC fmt = {
2327db96d56Sopenharmony_ci            CF_HDROP,
2337db96d56Sopenharmony_ci            NULL,
2347db96d56Sopenharmony_ci            DVASPECT_CONTENT,
2357db96d56Sopenharmony_ci            -1,
2367db96d56Sopenharmony_ci            TYMED_HGLOBAL
2377db96d56Sopenharmony_ci        };
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci        hr = pDataObj->GetData(&fmt, &medium);
2407db96d56Sopenharmony_ci        if (FAILED(hr)) {
2417db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::GetArguments - failed to get CF_HDROP format");
2427db96d56Sopenharmony_ci            return hr;
2437db96d56Sopenharmony_ci        }
2447db96d56Sopenharmony_ci        if (!medium.hGlobal) {
2457db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::GetArguments - CF_HDROP format had NULL hGlobal");
2467db96d56Sopenharmony_ci            ReleaseStgMedium(&medium);
2477db96d56Sopenharmony_ci            return E_FAIL;
2487db96d56Sopenharmony_ci        }
2497db96d56Sopenharmony_ci
2507db96d56Sopenharmony_ci        pdropfiles = (DROPFILES*)GlobalLock(medium.hGlobal);
2517db96d56Sopenharmony_ci        if (!pdropfiles) {
2527db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::GetArguments - failed to lock CF_HDROP hGlobal");
2537db96d56Sopenharmony_ci            ReleaseStgMedium(&medium);
2547db96d56Sopenharmony_ci            return E_FAIL;
2557db96d56Sopenharmony_ci        }
2567db96d56Sopenharmony_ci
2577db96d56Sopenharmony_ci        if (pdropfiles->fWide) {
2587db96d56Sopenharmony_ci            LPCWSTR files = (LPCWSTR)((char*)pdropfiles + pdropfiles->pFiles);
2597db96d56Sopenharmony_ci            size_t len, count;
2607db96d56Sopenharmony_ci            hr = FilenameListCchLengthW(files, 32767, &len, &count);
2617db96d56Sopenharmony_ci            if (SUCCEEDED(hr)) {
2627db96d56Sopenharmony_ci                LPWSTR args = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1));
2637db96d56Sopenharmony_ci                if (args) {
2647db96d56Sopenharmony_ci                    hr = FilenameListCchCopyW(args, 32767, files, L" ");
2657db96d56Sopenharmony_ci                    if (SUCCEEDED(hr)) {
2667db96d56Sopenharmony_ci                        *pArguments = args;
2677db96d56Sopenharmony_ci                    } else {
2687db96d56Sopenharmony_ci                        CoTaskMemFree(args);
2697db96d56Sopenharmony_ci                    }
2707db96d56Sopenharmony_ci                } else {
2717db96d56Sopenharmony_ci                    hr = E_OUTOFMEMORY;
2727db96d56Sopenharmony_ci                }
2737db96d56Sopenharmony_ci            }
2747db96d56Sopenharmony_ci        } else {
2757db96d56Sopenharmony_ci            LPCSTR files = (LPCSTR)((char*)pdropfiles + pdropfiles->pFiles);
2767db96d56Sopenharmony_ci            size_t len, count;
2777db96d56Sopenharmony_ci            hr = FilenameListCchLengthA(files, 32767, &len, &count);
2787db96d56Sopenharmony_ci            if (SUCCEEDED(hr)) {
2797db96d56Sopenharmony_ci                LPSTR temp = (LPSTR)CoTaskMemAlloc(sizeof(CHAR) * (len + 1));
2807db96d56Sopenharmony_ci                if (temp) {
2817db96d56Sopenharmony_ci                    hr = FilenameListCchCopyA(temp, 32767, files, " ");
2827db96d56Sopenharmony_ci                    if (SUCCEEDED(hr)) {
2837db96d56Sopenharmony_ci                        int wlen = MultiByteToWideChar(CP_ACP, 0, temp, (int)len, NULL, 0);
2847db96d56Sopenharmony_ci                        if (wlen) {
2857db96d56Sopenharmony_ci                            LPWSTR args = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (wlen + 1));
2867db96d56Sopenharmony_ci                            if (MultiByteToWideChar(CP_ACP, 0, temp, (int)len, args, wlen + 1)) {
2877db96d56Sopenharmony_ci                                *pArguments = args;
2887db96d56Sopenharmony_ci                            } else {
2897db96d56Sopenharmony_ci                                OutputDebugString(L"PyShellExt::GetArguments - failed to convert multi-byte to wide-char path");
2907db96d56Sopenharmony_ci                                CoTaskMemFree(args);
2917db96d56Sopenharmony_ci                                hr = E_FAIL;
2927db96d56Sopenharmony_ci                            }
2937db96d56Sopenharmony_ci                        } else {
2947db96d56Sopenharmony_ci                            OutputDebugString(L"PyShellExt::GetArguments - failed to get length of wide-char path");
2957db96d56Sopenharmony_ci                            hr = E_FAIL;
2967db96d56Sopenharmony_ci                        }
2977db96d56Sopenharmony_ci                    }
2987db96d56Sopenharmony_ci                    CoTaskMemFree(temp);
2997db96d56Sopenharmony_ci                } else {
3007db96d56Sopenharmony_ci                    hr = E_OUTOFMEMORY;
3017db96d56Sopenharmony_ci                }
3027db96d56Sopenharmony_ci            }
3037db96d56Sopenharmony_ci        }
3047db96d56Sopenharmony_ci
3057db96d56Sopenharmony_ci        GlobalUnlock(medium.hGlobal);
3067db96d56Sopenharmony_ci        ReleaseStgMedium(&medium);
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_ci        return hr;
3097db96d56Sopenharmony_ci    }
3107db96d56Sopenharmony_ci
3117db96d56Sopenharmony_ci    HRESULT NotifyDragWindow(HWND hwnd) {
3127db96d56Sopenharmony_ci        LRESULT res;
3137db96d56Sopenharmony_ci
3147db96d56Sopenharmony_ci        if (!hwnd) {
3157db96d56Sopenharmony_ci            return S_FALSE;
3167db96d56Sopenharmony_ci        }
3177db96d56Sopenharmony_ci
3187db96d56Sopenharmony_ci        res = SendMessage(hwnd, DDWM_UPDATEWINDOW, 0, NULL);
3197db96d56Sopenharmony_ci
3207db96d56Sopenharmony_ci        if (res) {
3217db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::NotifyDragWindow - failed to post DDWM_UPDATEWINDOW");
3227db96d56Sopenharmony_ci            return E_FAIL;
3237db96d56Sopenharmony_ci        }
3247db96d56Sopenharmony_ci
3257db96d56Sopenharmony_ci        return S_OK;
3267db96d56Sopenharmony_ci    }
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_cipublic:
3297db96d56Sopenharmony_ci    // IDropTarget implementation
3307db96d56Sopenharmony_ci
3317db96d56Sopenharmony_ci    STDMETHODIMP DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
3327db96d56Sopenharmony_ci        HWND hwnd;
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DragEnter");
3357db96d56Sopenharmony_ci
3367db96d56Sopenharmony_ci        pDataObj->AddRef();
3377db96d56Sopenharmony_ci        data_obj = pDataObj;
3387db96d56Sopenharmony_ci
3397db96d56Sopenharmony_ci        *pdwEffect = DROPEFFECT_MOVE;
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci        if (FAILED(UpdateDropDescription(data_obj))) {
3427db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::DragEnter - failed to update drop description");
3437db96d56Sopenharmony_ci        }
3447db96d56Sopenharmony_ci        if (FAILED(GetDragWindow(data_obj, &hwnd))) {
3457db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::DragEnter - failed to get drag window");
3467db96d56Sopenharmony_ci        }
3477db96d56Sopenharmony_ci        if (FAILED(NotifyDragWindow(hwnd))) {
3487db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::DragEnter - failed to notify drag window");
3497db96d56Sopenharmony_ci        }
3507db96d56Sopenharmony_ci
3517db96d56Sopenharmony_ci        return S_OK;
3527db96d56Sopenharmony_ci    }
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci    STDMETHODIMP DragLeave() {
3557db96d56Sopenharmony_ci        return S_OK;
3567db96d56Sopenharmony_ci    }
3577db96d56Sopenharmony_ci
3587db96d56Sopenharmony_ci    STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
3597db96d56Sopenharmony_ci        return S_OK;
3607db96d56Sopenharmony_ci    }
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci    STDMETHODIMP Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
3637db96d56Sopenharmony_ci        LPCWSTR args;
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::Drop");
3667db96d56Sopenharmony_ci        *pdwEffect = DROPEFFECT_NONE;
3677db96d56Sopenharmony_ci
3687db96d56Sopenharmony_ci        if (pDataObj != data_obj) {
3697db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::Drop - unexpected data object");
3707db96d56Sopenharmony_ci            return E_FAIL;
3717db96d56Sopenharmony_ci        }
3727db96d56Sopenharmony_ci
3737db96d56Sopenharmony_ci        data_obj->Release();
3747db96d56Sopenharmony_ci        data_obj = NULL;
3757db96d56Sopenharmony_ci
3767db96d56Sopenharmony_ci        if (SUCCEEDED(GetArguments(pDataObj, &args))) {
3777db96d56Sopenharmony_ci            OutputDebugString(args);
3787db96d56Sopenharmony_ci            ShellExecute(NULL, NULL, target, args, target_dir, SW_NORMAL);
3797db96d56Sopenharmony_ci
3807db96d56Sopenharmony_ci            CoTaskMemFree((LPVOID)args);
3817db96d56Sopenharmony_ci        } else {
3827db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::Drop - failed to get launch arguments");
3837db96d56Sopenharmony_ci        }
3847db96d56Sopenharmony_ci
3857db96d56Sopenharmony_ci        return S_OK;
3867db96d56Sopenharmony_ci    }
3877db96d56Sopenharmony_ci
3887db96d56Sopenharmony_ci    // IPersistFile implementation
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci    STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName) {
3917db96d56Sopenharmony_ci        HRESULT hr;
3927db96d56Sopenharmony_ci        size_t len;
3937db96d56Sopenharmony_ci
3947db96d56Sopenharmony_ci        if (!ppszFileName) {
3957db96d56Sopenharmony_ci            return E_POINTER;
3967db96d56Sopenharmony_ci        }
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_ci        hr = StringCchLength(target, STRSAFE_MAX_CCH - 1, &len);
3997db96d56Sopenharmony_ci        if (FAILED(hr)) {
4007db96d56Sopenharmony_ci            return E_FAIL;
4017db96d56Sopenharmony_ci        }
4027db96d56Sopenharmony_ci
4037db96d56Sopenharmony_ci        *ppszFileName = (LPOLESTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1));
4047db96d56Sopenharmony_ci        if (!*ppszFileName) {
4057db96d56Sopenharmony_ci            return E_OUTOFMEMORY;
4067db96d56Sopenharmony_ci        }
4077db96d56Sopenharmony_ci
4087db96d56Sopenharmony_ci        hr = StringCchCopy(*ppszFileName, len + 1, target);
4097db96d56Sopenharmony_ci        if (FAILED(hr)) {
4107db96d56Sopenharmony_ci            CoTaskMemFree(*ppszFileName);
4117db96d56Sopenharmony_ci            *ppszFileName = NULL;
4127db96d56Sopenharmony_ci            return E_FAIL;
4137db96d56Sopenharmony_ci        }
4147db96d56Sopenharmony_ci
4157db96d56Sopenharmony_ci        return S_OK;
4167db96d56Sopenharmony_ci    }
4177db96d56Sopenharmony_ci
4187db96d56Sopenharmony_ci    STDMETHODIMP IsDirty() {
4197db96d56Sopenharmony_ci        return S_FALSE;
4207db96d56Sopenharmony_ci    }
4217db96d56Sopenharmony_ci
4227db96d56Sopenharmony_ci    STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode) {
4237db96d56Sopenharmony_ci        HRESULT hr;
4247db96d56Sopenharmony_ci        size_t len;
4257db96d56Sopenharmony_ci
4267db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::Load");
4277db96d56Sopenharmony_ci        OutputDebugString(pszFileName);
4287db96d56Sopenharmony_ci
4297db96d56Sopenharmony_ci        hr = StringCchLength(pszFileName, STRSAFE_MAX_CCH - 1, &len);
4307db96d56Sopenharmony_ci        if (FAILED(hr)) {
4317db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::Load - failed to get string length");
4327db96d56Sopenharmony_ci            return hr;
4337db96d56Sopenharmony_ci        }
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ci        if (target) {
4367db96d56Sopenharmony_ci            CoTaskMemFree(target);
4377db96d56Sopenharmony_ci        }
4387db96d56Sopenharmony_ci        if (target_dir) {
4397db96d56Sopenharmony_ci            CoTaskMemFree(target_dir);
4407db96d56Sopenharmony_ci        }
4417db96d56Sopenharmony_ci
4427db96d56Sopenharmony_ci        target = (LPOLESTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1));
4437db96d56Sopenharmony_ci        if (!target) {
4447db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::Load - E_OUTOFMEMORY");
4457db96d56Sopenharmony_ci            return E_OUTOFMEMORY;
4467db96d56Sopenharmony_ci        }
4477db96d56Sopenharmony_ci        target_dir = (LPOLESTR)CoTaskMemAlloc(sizeof(WCHAR) * (len + 1));
4487db96d56Sopenharmony_ci        if (!target_dir) {
4497db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::Load - E_OUTOFMEMORY");
4507db96d56Sopenharmony_ci            return E_OUTOFMEMORY;
4517db96d56Sopenharmony_ci        }
4527db96d56Sopenharmony_ci
4537db96d56Sopenharmony_ci        hr = StringCchCopy(target, len + 1, pszFileName);
4547db96d56Sopenharmony_ci        if (FAILED(hr)) {
4557db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::Load - failed to copy string");
4567db96d56Sopenharmony_ci            return hr;
4577db96d56Sopenharmony_ci        }
4587db96d56Sopenharmony_ci
4597db96d56Sopenharmony_ci        hr = StringCchCopy(target_dir, len + 1, pszFileName);
4607db96d56Sopenharmony_ci        if (FAILED(hr)) {
4617db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::Load - failed to copy string");
4627db96d56Sopenharmony_ci            return hr;
4637db96d56Sopenharmony_ci        }
4647db96d56Sopenharmony_ci        if (!PathRemoveFileSpecW(target_dir)) {
4657db96d56Sopenharmony_ci            OutputDebugStringW(L"PyShellExt::Load - failed to remove filespec from target");
4667db96d56Sopenharmony_ci            return E_FAIL;
4677db96d56Sopenharmony_ci        }
4687db96d56Sopenharmony_ci
4697db96d56Sopenharmony_ci        OutputDebugString(target);
4707db96d56Sopenharmony_ci        target_mode = dwMode;
4717db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::Load - S_OK");
4727db96d56Sopenharmony_ci        return S_OK;
4737db96d56Sopenharmony_ci    }
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci    STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember) {
4767db96d56Sopenharmony_ci        return E_NOTIMPL;
4777db96d56Sopenharmony_ci    }
4787db96d56Sopenharmony_ci
4797db96d56Sopenharmony_ci    STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName) {
4807db96d56Sopenharmony_ci        return E_NOTIMPL;
4817db96d56Sopenharmony_ci    }
4827db96d56Sopenharmony_ci
4837db96d56Sopenharmony_ci    STDMETHODIMP GetClassID(CLSID *pClassID) {
4847db96d56Sopenharmony_ci        *pClassID = __uuidof(PyShellExt);
4857db96d56Sopenharmony_ci        return S_OK;
4867db96d56Sopenharmony_ci    }
4877db96d56Sopenharmony_ci};
4887db96d56Sopenharmony_ci
4897db96d56Sopenharmony_ciCoCreatableClass(PyShellExt);
4907db96d56Sopenharmony_ci
4917db96d56Sopenharmony_ciSTDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv) {
4927db96d56Sopenharmony_ci    return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
4937db96d56Sopenharmony_ci}
4947db96d56Sopenharmony_ci
4957db96d56Sopenharmony_ciSTDAPI DllCanUnloadNow() {
4967db96d56Sopenharmony_ci    return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
4977db96d56Sopenharmony_ci}
4987db96d56Sopenharmony_ci
4997db96d56Sopenharmony_ciSTDAPI DllRegisterServer() {
5007db96d56Sopenharmony_ci    LONG res;
5017db96d56Sopenharmony_ci    SECURITY_ATTRIBUTES secattr = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
5027db96d56Sopenharmony_ci    LPSECURITY_ATTRIBUTES psecattr = NULL;
5037db96d56Sopenharmony_ci    HKEY key, ipsKey;
5047db96d56Sopenharmony_ci    WCHAR modname[MAX_PATH];
5057db96d56Sopenharmony_ci    DWORD modname_len;
5067db96d56Sopenharmony_ci
5077db96d56Sopenharmony_ci    OutputDebugString(L"PyShellExt::DllRegisterServer");
5087db96d56Sopenharmony_ci    if (!hModule) {
5097db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllRegisterServer - module handle was not set");
5107db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5117db96d56Sopenharmony_ci    }
5127db96d56Sopenharmony_ci    modname_len = GetModuleFileName(hModule, modname, MAX_PATH);
5137db96d56Sopenharmony_ci    if (modname_len == 0 ||
5147db96d56Sopenharmony_ci        (modname_len == MAX_PATH && GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5157db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllRegisterServer - failed to get module file name");
5167db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5177db96d56Sopenharmony_ci    }
5187db96d56Sopenharmony_ci
5197db96d56Sopenharmony_ci    DWORD disp;
5207db96d56Sopenharmony_ci    res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, CLASS_SUBKEY, 0, NULL, 0,
5217db96d56Sopenharmony_ci        KEY_ALL_ACCESS, psecattr, &key, &disp);
5227db96d56Sopenharmony_ci    if (res == ERROR_ACCESS_DENIED) {
5237db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllRegisterServer - failed to write per-machine registration. Attempting per-user instead.");
5247db96d56Sopenharmony_ci        res = RegCreateKeyEx(HKEY_CURRENT_USER, CLASS_SUBKEY, 0, NULL, 0,
5257db96d56Sopenharmony_ci            KEY_ALL_ACCESS, psecattr, &key, &disp);
5267db96d56Sopenharmony_ci    }
5277db96d56Sopenharmony_ci    if (res != ERROR_SUCCESS) {
5287db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllRegisterServer - failed to create class key");
5297db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5307db96d56Sopenharmony_ci    }
5317db96d56Sopenharmony_ci
5327db96d56Sopenharmony_ci    res = RegCreateKeyEx(key, L"InProcServer32", 0, NULL, 0,
5337db96d56Sopenharmony_ci        KEY_ALL_ACCESS, psecattr, &ipsKey, NULL);
5347db96d56Sopenharmony_ci    if (res != ERROR_SUCCESS) {
5357db96d56Sopenharmony_ci        RegCloseKey(key);
5367db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllRegisterServer - failed to create InProcServer32 key");
5377db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5387db96d56Sopenharmony_ci    }
5397db96d56Sopenharmony_ci
5407db96d56Sopenharmony_ci    res = RegSetValueEx(ipsKey, NULL, 0,
5417db96d56Sopenharmony_ci        REG_SZ, (LPBYTE)modname, modname_len * sizeof(modname[0]));
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_ci    if (res != ERROR_SUCCESS) {
5447db96d56Sopenharmony_ci        RegCloseKey(ipsKey);
5457db96d56Sopenharmony_ci        RegCloseKey(key);
5467db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllRegisterServer - failed to set server path");
5477db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5487db96d56Sopenharmony_ci    }
5497db96d56Sopenharmony_ci
5507db96d56Sopenharmony_ci    res = RegSetValueEx(ipsKey, L"ThreadingModel", 0,
5517db96d56Sopenharmony_ci        REG_SZ, (LPBYTE)(L"Apartment"), sizeof(L"Apartment"));
5527db96d56Sopenharmony_ci
5537db96d56Sopenharmony_ci    RegCloseKey(ipsKey);
5547db96d56Sopenharmony_ci    RegCloseKey(key);
5557db96d56Sopenharmony_ci    if (res != ERROR_SUCCESS) {
5567db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllRegisterServer - failed to set threading model");
5577db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5587db96d56Sopenharmony_ci    }
5597db96d56Sopenharmony_ci
5607db96d56Sopenharmony_ci    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
5617db96d56Sopenharmony_ci
5627db96d56Sopenharmony_ci    OutputDebugString(L"PyShellExt::DllRegisterServer - S_OK");
5637db96d56Sopenharmony_ci    return S_OK;
5647db96d56Sopenharmony_ci}
5657db96d56Sopenharmony_ci
5667db96d56Sopenharmony_ciSTDAPI DllUnregisterServer() {
5677db96d56Sopenharmony_ci    LONG res_lm, res_cu;
5687db96d56Sopenharmony_ci
5697db96d56Sopenharmony_ci    res_lm = RegDeleteTree(HKEY_LOCAL_MACHINE, CLASS_SUBKEY);
5707db96d56Sopenharmony_ci    if (res_lm != ERROR_SUCCESS && res_lm != ERROR_FILE_NOT_FOUND) {
5717db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllUnregisterServer - failed to delete per-machine registration");
5727db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5737db96d56Sopenharmony_ci    }
5747db96d56Sopenharmony_ci
5757db96d56Sopenharmony_ci    res_cu = RegDeleteTree(HKEY_CURRENT_USER, CLASS_SUBKEY);
5767db96d56Sopenharmony_ci    if (res_cu != ERROR_SUCCESS && res_cu != ERROR_FILE_NOT_FOUND) {
5777db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllUnregisterServer - failed to delete per-user registration");
5787db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5797db96d56Sopenharmony_ci    }
5807db96d56Sopenharmony_ci
5817db96d56Sopenharmony_ci    if (res_lm == ERROR_FILE_NOT_FOUND && res_cu == ERROR_FILE_NOT_FOUND) {
5827db96d56Sopenharmony_ci        OutputDebugString(L"PyShellExt::DllUnregisterServer - extension was not registered");
5837db96d56Sopenharmony_ci        return SELFREG_E_CLASS;
5847db96d56Sopenharmony_ci    }
5857db96d56Sopenharmony_ci
5867db96d56Sopenharmony_ci    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_ci    OutputDebugString(L"PyShellExt::DllUnregisterServer - S_OK");
5897db96d56Sopenharmony_ci    return S_OK;
5907db96d56Sopenharmony_ci}
5917db96d56Sopenharmony_ci
5927db96d56Sopenharmony_ciSTDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*) {
5937db96d56Sopenharmony_ci    if (reason == DLL_PROCESS_ATTACH) {
5947db96d56Sopenharmony_ci        hModule = hinst;
5957db96d56Sopenharmony_ci
5967db96d56Sopenharmony_ci        cfDropDescription = RegisterClipboardFormat(CFSTR_DROPDESCRIPTION);
5977db96d56Sopenharmony_ci        if (!cfDropDescription) {
5987db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::DllMain - failed to get CFSTR_DROPDESCRIPTION format");
5997db96d56Sopenharmony_ci        }
6007db96d56Sopenharmony_ci        cfDragWindow = RegisterClipboardFormat(L"DragWindow");
6017db96d56Sopenharmony_ci        if (!cfDragWindow) {
6027db96d56Sopenharmony_ci            OutputDebugString(L"PyShellExt::DllMain - failed to get DragWindow format");
6037db96d56Sopenharmony_ci        }
6047db96d56Sopenharmony_ci
6057db96d56Sopenharmony_ci        DisableThreadLibraryCalls(hinst);
6067db96d56Sopenharmony_ci    }
6077db96d56Sopenharmony_ci    return TRUE;
6087db96d56Sopenharmony_ci}