diff --git a/Misc/NEWS b/Misc/NEWS index b54592069d6..8f1aa349c10 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -244,6 +244,12 @@ Build - Don't use largefile support for GNU/Hurd. +Windows +------- + +- Issue #27469: Adds a shell extension to the launcher so that drag and drop + works correctly. + Tools/Demos ----------- diff --git a/PC/pyshellext.cpp b/PC/pyshellext.cpp new file mode 100644 index 00000000000..04fe61e8961 --- /dev/null +++ b/PC/pyshellext.cpp @@ -0,0 +1,605 @@ +// Support back to Vista +#define _WIN32_WINNT _WIN32_WINNT_VISTA +#include + +// Use WRL to define a classic COM class +#define __WRL_CLASSIC_COM__ +#include + +#include +#include +#include +#include +#include + +#include "pyshellext_h.h" + +#define DDWM_UPDATEWINDOW (WM_USER+3) + +static HINSTANCE hModule; +static CLIPFORMAT cfDropDescription; +static CLIPFORMAT cfDragWindow; + +static const LPCWSTR CLASS_SUBKEY = L"Software\\Classes\\CLSID\\{BEA218D2-6950-497B-9434-61683EC065FE}"; +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; +} + + +class PyShellExt : public RuntimeClass< + RuntimeClassFlags, + 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); + 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) { + *pClassID = CLSID_PyShellExt; + return S_OK; + } +}; + +CoCreatableClass(PyShellExt); + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv) { + return Module::GetModule().GetClassObject(rclsid, riid, ppv); +} + +STDAPI DllCanUnloadNow() { + return Module::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; +} \ No newline at end of file diff --git a/PC/pyshellext.def b/PC/pyshellext.def new file mode 100644 index 00000000000..5424bd1180d --- /dev/null +++ b/PC/pyshellext.def @@ -0,0 +1,6 @@ +LIBRARY "pyshellext" +EXPORTS + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE diff --git a/PC/pyshellext.idl b/PC/pyshellext.idl new file mode 100644 index 00000000000..c0a183876ad --- /dev/null +++ b/PC/pyshellext.idl @@ -0,0 +1,12 @@ +import "ocidl.idl"; + +[uuid(44039A76-3BDD-41C1-A31B-71C00202CE81), version(1.0)] +library PyShellExtLib +{ + [uuid(BEA218D2-6950-497B-9434-61683EC065FE), version(1.0)] + coclass PyShellExt + { + [default] interface IDropTarget; + interface IPersistFile; + } +}; \ No newline at end of file diff --git a/PC/pyshellext.rc b/PC/pyshellext.rc new file mode 100644 index 00000000000..e5924a42dab --- /dev/null +++ b/PC/pyshellext.rc @@ -0,0 +1,46 @@ +#include + +#include "python_ver_rc.h" + +// Include the manifest file that indicates we support all +// current versions of Windows. +#include +1 RT_MANIFEST "python.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PYVERSION64 + PRODUCTVERSION PYVERSION64 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", PYTHON_COMPANY "\0" + VALUE "FileDescription", "Python\0" + VALUE "FileVersion", PYTHON_VERSION + VALUE "InternalName", "Python Launcher Shell Extension\0" + VALUE "LegalCopyright", PYTHON_COPYRIGHT "\0" + VALUE "OriginalFilename", "pyshellext" PYTHON_DEBUG_EXT ".dll\0" + VALUE "ProductName", "Python\0" + VALUE "ProductVersion", PYTHON_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END \ No newline at end of file diff --git a/PC/pyshellext_d.def b/PC/pyshellext_d.def new file mode 100644 index 00000000000..7d2148bb861 --- /dev/null +++ b/PC/pyshellext_d.def @@ -0,0 +1,6 @@ +LIBRARY "pyshellext_d" +EXPORTS + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj index 9b865e88b25..c320434de82 100644 --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -46,6 +46,8 @@ + + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln index 766a870684e..42a4d2b9ee2 100644 --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22823.1 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{553EC33E-9816-4996-A660-5D6186A0B0B3}" ProjectSection(SolutionItems) = preProject @@ -63,8 +63,14 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testbuffer", "_testbuffer.vcxproj", "{A2697BD3-28C1-4AEC-9106-8B748639FD16}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pylauncher", "pylauncher.vcxproj", "{7B2727B5-5A3F-40EE-A866-43A13CD31446}" + ProjectSection(ProjectDependencies) = postProject + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782} = {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pywlauncher", "pywlauncher.vcxproj", "{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}" + ProjectSection(ProjectDependencies) = postProject + {7B2727B5-5A3F-40EE-A866-43A13CD31446} = {7B2727B5-5A3F-40EE-A866-43A13CD31446} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_freeze_importlib", "_freeze_importlib.vcxproj", "{19C0C13F-47CA-4432-AFF3-799A296A4DDC}" EndProject @@ -84,6 +90,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libeay", "libeay.vcxproj", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssleay", "ssleay.vcxproj", "{10615B24-73BF-4EFA-93AA-236916321317}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyshellext", "pyshellext.vcxproj", "{0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -684,6 +692,22 @@ Global {10615B24-73BF-4EFA-93AA-236916321317}.Release|Win32.Build.0 = Release|Win32 {10615B24-73BF-4EFA-93AA-236916321317}.Release|x64.ActiveCfg = Release|x64 {10615B24-73BF-4EFA-93AA-236916321317}.Release|x64.Build.0 = Release|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|Win32.Build.0 = Debug|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|x64.ActiveCfg = Debug|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Debug|x64.Build.0 = Debug|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGInstrument|x64.Build.0 = PGInstrument|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|x64.Build.0 = PGUpdate|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.ActiveCfg = Release|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.Build.0 = Release|Win32 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.ActiveCfg = Release|x64 + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index a3a9c2be64b..05473fd054c 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -83,8 +83,9 @@ true Win32 X64 - $(OutDir)%(Filename).tlb - $(IntDir)%(Filename)_h.h + $(IntDir) + $(MSBuildProjectName)_i.c + $(MSBuildProjectName)_p.c diff --git a/PCbuild/pyshellext.vcxproj b/PCbuild/pyshellext.vcxproj new file mode 100644 index 00000000000..029393504c0 --- /dev/null +++ b/PCbuild/pyshellext.vcxproj @@ -0,0 +1,87 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + Win32 + + + Release + x64 + + + + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782} + pyshellext + pyshellext + false + + + + + DynamicLibrary + Unicode + + + + + + ClCompile + + + + + + + + + _CONSOLE;%(PreprocessorDefinitions) + + + version.lib;shlwapi.lib;%(AdditionalDependencies) + Console + ..\PC\pyshellext$(PyDebugExt).def + + + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PCbuild/pyshellext.vcxproj.filters b/PCbuild/pyshellext.vcxproj.filters new file mode 100644 index 00000000000..648e499f6f4 --- /dev/null +++ b/PCbuild/pyshellext.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Source Files + + + + + Resource Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Tools/msi/launcher/launcher.wixproj b/Tools/msi/launcher/launcher.wixproj index 67fb0255dee..01a9dcb29ed 100644 --- a/Tools/msi/launcher/launcher.wixproj +++ b/Tools/msi/launcher/launcher.wixproj @@ -7,6 +7,7 @@ Package UpgradeCode=1B68A0EC-4DD3-5134-840E-73854B0863F1;$(DefineConstants) true + ICE80 @@ -18,5 +19,18 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/launcher/launcher.wxs b/Tools/msi/launcher/launcher.wxs index 80e838afad4..ebd875cd9a5 100644 --- a/Tools/msi/launcher/launcher.wxs +++ b/Tools/msi/launcher/launcher.wxs @@ -28,7 +28,7 @@ UPGRADE or REMOVE_350_LAUNCHER - + diff --git a/Tools/msi/launcher/launcher_files.wxs b/Tools/msi/launcher/launcher_files.wxs index 589dee56547..5b79d76bdfe 100644 --- a/Tools/msi/launcher/launcher_files.wxs +++ b/Tools/msi/launcher/launcher_files.wxs @@ -20,6 +20,19 @@ ALLUSERS=1 + + + VersionNT64 + + + + + + NOT VersionNT64 + + + + diff --git a/Tools/msi/launcher/launcher_reg.wxs b/Tools/msi/launcher/launcher_reg.wxs index bb42255b0ae..981961ab0d8 100644 --- a/Tools/msi/launcher/launcher_reg.wxs +++ b/Tools/msi/launcher/launcher_reg.wxs @@ -10,14 +10,14 @@ - + - + @@ -25,21 +25,21 @@ - + - + - +