#include "FrameworkContextMenuExt.h" #include "Reg.h" #include #include #pragma comment(lib, "shlwapi.lib") extern HINSTANCE g_hInst; extern long g_cDllRef; static const int IDM_SENDTOPSCAN = 0; static const LPWSTR PScanCommandDisplayName = L"Send To PScan"; static const LPWSTR PScanPipeName = L"\\\\.\\pipe\\PScanPipe"; static const LPWSTR PScanMessageAddFiles = L"AddFiles"; FrameWorkContextMenuExt::FrameWorkContextMenuExt() : m_cRef(1) { InterlockedIncrement(&g_cDllRef); } FrameWorkContextMenuExt::~FrameWorkContextMenuExt() { InterlockedDecrement(&g_cDllRef); } void WriteUTF7Integer(HANDLE _hPipe, unsigned _value) { unsigned long written = 0; if(_value < 128) { unsigned char bValue = static_cast(_value); WriteFile(_hPipe, &bValue, sizeof(bValue), &written, nullptr); } else { unsigned short sValue = static_cast(((_value << 1) & ~0xFF) | 0x80 | (_value & 0x7F)); WriteFile(_hPipe, &sValue, sizeof(sValue), &written, nullptr); } } void WriteString(HANDLE _hPipe, LPWSTR _string) { char filename[1024]; WideCharToMultiByte(CP_UTF8, 0, _string, -1, filename, ARRAYSIZE(filename), nullptr, nullptr); unsigned length = static_cast(strlen(filename)); WriteUTF7Integer(_hPipe, length); unsigned long written = 0; WriteFile(_hPipe, filename, length, &written, nullptr); } void FrameWorkContextMenuExt::SendFilesToPScan() { HANDLE hPipe = CreateFile(PScanPipeName, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if(hPipe == INVALID_HANDLE_VALUE) { LaunchPScan(); // Retry until the pipe is created for(unsigned i = 0; i < 10; ++i) { hPipe = CreateFile(PScanPipeName, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if(hPipe != INVALID_HANDLE_VALUE) break; Sleep(500); } if(hPipe == INVALID_HANDLE_VALUE) return; } WriteString(hPipe, PScanMessageAddFiles); unsigned numFiles = static_cast(m_selectedFiles.size()); unsigned long written = 0; WriteFile(hPipe, &numFiles, sizeof(numFiles), &written, nullptr); for(unsigned i = 0; i < numFiles; ++i) { WriteString(hPipe, m_selectedFiles[i].Name); } CloseHandle(hPipe); } unsigned FrameWorkContextMenuExt::GetDataRoot(wchar_t *_dest, unsigned _dstSize) const { wchar_t rootDir[MAX_PATH]; if(FAILED(GetRegistryKeyAndValue(HKEY_CURRENT_USER, L"Software\\Ubisoft\\UbiArt\\UAF", L"rootDir", rootDir, sizeof(rootDir)))) return 0; StringCchCatW(rootDir, ARRAYSIZE(rootDir), L"\\lastvalidroot.txt"); HANDLE hFile = CreateFile(rootDir, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if(hFile == INVALID_HANDLE_VALUE) return 0; char dataroot[MAX_PATH] = {0}; unsigned long read = 0; ReadFile(hFile, dataroot, MAX_PATH - 1, &read, nullptr); CloseHandle(hFile); MultiByteToWideChar(CP_UTF8, 0, dataroot, -1, _dest, _dstSize); return read; } void FrameWorkContextMenuExt::LaunchPScan() const { wchar_t rootDir[MAX_PATH]; if(FAILED(GetRegistryKeyAndValue(HKEY_CURRENT_USER, L"Software\\Ubisoft\\UbiArt\\UAF", L"rootDir", rootDir, sizeof(rootDir)))) return; wchar_t appPath[MAX_PATH]; StringCchCopy(appPath, ARRAYSIZE(appPath), rootDir); StringCchCatW(appPath, ARRAYSIZE(appPath), L"\\pscansharpui.exe"); STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); PROCESS_INFORMATION pi; if(SUCCEEDED(CreateProcess(appPath, L"", nullptr, nullptr, FALSE, 0, nullptr, rootDir, &si, &pi))) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } } #pragma region IUnknown IFACEMETHODIMP FrameWorkContextMenuExt::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(FrameWorkContextMenuExt, IContextMenu), QITABENT(FrameWorkContextMenuExt, IShellExtInit), { 0 }, }; return QISearch(this, qit, riid, ppv); } IFACEMETHODIMP_(ULONG) FrameWorkContextMenuExt::AddRef() { return InterlockedIncrement(&m_cRef); } IFACEMETHODIMP_(ULONG) FrameWorkContextMenuExt::Release() { ULONG cRef = InterlockedDecrement(&m_cRef); if (!cRef) delete this; return cRef; } #pragma endregion #pragma region IShellExtInit IFACEMETHODIMP FrameWorkContextMenuExt::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID) { if (NULL == pDataObj) { return E_INVALIDARG; } HRESULT hr = E_FAIL; FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stm; wchar_t dataRoot[MAX_PATH]; unsigned dataRootLen = GetDataRoot(dataRoot, ARRAYSIZE(dataRoot)); for(unsigned i = 0; i < dataRootLen; ++i) { if(dataRoot[i] == L'/') dataRoot[i] = L'\\'; } if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) { HDROP hDrop = static_cast(GlobalLock(stm.hGlobal)); if (hDrop != NULL) { UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); for(unsigned i = 0; i < nFiles; ++i) { File selectedFile; if (0 != DragQueryFile(hDrop, i, selectedFile.Name, ARRAYSIZE(selectedFile.Name))) { if(dataRootLen > 0 && _wcsnicmp(dataRoot, selectedFile.Name, dataRootLen)) continue; m_selectedFiles.push_back(selectedFile); hr = S_OK; } } GlobalUnlock(stm.hGlobal); } ReleaseStgMedium(&stm); } return hr; } #pragma endregion #pragma region IContextMenu IFACEMETHODIMP FrameWorkContextMenuExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { if (CMF_DEFAULTONLY & uFlags) return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0)); MENUITEMINFO mii = { sizeof(mii) }; mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE; mii.wID = idCmdFirst + IDM_SENDTOPSCAN; mii.fType = MFT_STRING; mii.dwTypeData = PScanCommandDisplayName; mii.fState = MFS_ENABLED; mii.hbmpItem = nullptr; if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii)) return HRESULT_FROM_WIN32(GetLastError()); // Add a separator. MENUITEMINFO sep = { sizeof(sep) }; sep.fMask = MIIM_TYPE; sep.fType = MFT_SEPARATOR; if (!InsertMenuItem(hMenu, indexMenu + 1, TRUE, &sep)) return HRESULT_FROM_WIN32(GetLastError()); return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SENDTOPSCAN + 1)); } IFACEMETHODIMP FrameWorkContextMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO pici) { BOOL fUnicode = FALSE; if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX)) { if (pici->fMask & CMIC_MASK_UNICODE) { fUnicode = TRUE; } } if (!fUnicode && HIWORD(pici->lpVerb)) { if (StrCmpIA(pici->lpVerb, "sendtopscan") == 0) { SendFilesToPScan(); } else { return E_FAIL; } } else if (fUnicode && HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW)) { if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, L"sendtopscan") == 0) { SendFilesToPScan(); } else { return E_FAIL; } } else { if (LOWORD(pici->lpVerb) == IDM_SENDTOPSCAN) { SendFilesToPScan(); } else { return E_FAIL; } } return S_OK; } IFACEMETHODIMP FrameWorkContextMenuExt::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax) { HRESULT hr = E_INVALIDARG; if (idCommand == IDM_SENDTOPSCAN) { switch (uFlags) { case GCS_HELPTEXTW: hr = StringCchCopy(reinterpret_cast(pszName), cchMax, PScanCommandDisplayName); break; case GCS_VERBW: hr = StringCchCopy(reinterpret_cast(pszName), cchMax, PScanCommandDisplayName); break; default: hr = S_OK; } } return hr; } #pragma endregion