From bc92eceb86413cf6169bdf2b69d33bd5f52a8cd6 Mon Sep 17 00:00:00 2001 From: Rafal Harabien Date: Wed, 11 Jan 2012 20:20:01 +0000 Subject: [PATCH] [SHELL32] - Add CLSID_ShellFileDefExt, CLSID_ShellDrvDefExt, CLSID_ShellNetDefExt GUIDs - Move File Properties default pages to CFileDefExt svn path=/trunk/; revision=54908 --- reactos/dll/win32/shell32/CMakeLists.txt | 2 + reactos/dll/win32/shell32/drvdefext.cpp | 1 + reactos/dll/win32/shell32/drvdefext.h | 1 + reactos/dll/win32/shell32/filedefext.cpp | 812 ++++++++++++++++++ reactos/dll/win32/shell32/filedefext.h | 110 +++ reactos/dll/win32/shell32/fprop.cpp | 757 +--------------- reactos/dll/win32/shell32/precomp.h | 3 +- .../win32/shell32/res/rgs/shellfiledefext.rgs | 13 + reactos/dll/win32/shell32/rgs_res.rc | 1 + reactos/dll/win32/shell32/shell32.rbuild | 2 + reactos/dll/win32/shell32/shresdef.h | 2 + reactos/include/psdk/shlguid_undoc.h | 7 +- 12 files changed, 972 insertions(+), 739 deletions(-) create mode 100644 reactos/dll/win32/shell32/drvdefext.cpp create mode 100644 reactos/dll/win32/shell32/drvdefext.h create mode 100644 reactos/dll/win32/shell32/filedefext.cpp create mode 100644 reactos/dll/win32/shell32/filedefext.h create mode 100644 reactos/dll/win32/shell32/res/rgs/shellfiledefext.rgs diff --git a/reactos/dll/win32/shell32/CMakeLists.txt b/reactos/dll/win32/shell32/CMakeLists.txt index 031755e3cc9..17cf9e68717 100644 --- a/reactos/dll/win32/shell32/CMakeLists.txt +++ b/reactos/dll/win32/shell32/CMakeLists.txt @@ -69,6 +69,8 @@ list(APPEND SOURCE newmenu.cpp startmenu.cpp folder_options.cpp + filedefext.cpp + drvdefext.cpp shell32.rc ${CMAKE_CURRENT_BINARY_DIR}/shell32_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/shell32.def) diff --git a/reactos/dll/win32/shell32/drvdefext.cpp b/reactos/dll/win32/shell32/drvdefext.cpp new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/reactos/dll/win32/shell32/drvdefext.cpp @@ -0,0 +1 @@ + diff --git a/reactos/dll/win32/shell32/drvdefext.h b/reactos/dll/win32/shell32/drvdefext.h new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/reactos/dll/win32/shell32/drvdefext.h @@ -0,0 +1 @@ + diff --git a/reactos/dll/win32/shell32/filedefext.cpp b/reactos/dll/win32/shell32/filedefext.cpp new file mode 100644 index 00000000000..4776d2d3d9c --- /dev/null +++ b/reactos/dll/win32/shell32/filedefext.cpp @@ -0,0 +1,812 @@ +/* + * provides new shell item service + * + * Copyright 2007 Johannes Anderwald (janderwald@reactos.org) + * Copyright 2009 Andrew Hill + * Copyright 2012 Rafal Harabien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +BOOL PathIsExeW(LPCWSTR lpszPath); + +BOOL CFileVersionInfo::Load(LPCWSTR pwszPath) +{ + ULONG cbInfo = GetFileVersionInfoSizeW(pwszPath, NULL); + if (!cbInfo) + { + WARN("GetFileVersionInfoSize %ls failed\n", pwszPath); + return FALSE; + } + + m_pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbInfo); + if (!m_pInfo) + { + ERR("HeapAlloc failed bytes %x\n", cbInfo); + return FALSE; + } + + if (!GetFileVersionInfoW(pwszPath, 0, cbInfo, m_pInfo)) + { + ERR("GetFileVersionInfoW failed\n"); + return FALSE; + } + + LPLANGANDCODEPAGE lpLangCode; + UINT cBytes; + if (!VerQueryValueW(m_pInfo, L"VarFileInfo\\Translation", (LPVOID *)&lpLangCode, &cBytes)) + { + ERR("VerQueryValueW failed\n"); + return FALSE; + } + + /* FIXME: find language from current locale / if not available, + * default to english + * for now default to first available language + */ + m_wLang = lpLangCode->lang; + m_wCode = lpLangCode->code; + return TRUE; +} + +LPCWSTR CFileVersionInfo::GetString(LPCWSTR pwszName) +{ + if (!m_pInfo) + return NULL; + + WCHAR wszBuf[256]; + swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\%s", m_wLang, m_wCode, pwszName); + + LPCWSTR pwszResult = NULL; + UINT cBytes = 0; + if (!VerQueryValueW(m_pInfo, wszBuf, (LPVOID *)&pwszResult, &cBytes)) + return NULL; + + return pwszResult; +} + +VS_FIXEDFILEINFO *CFileVersionInfo::GetFixedInfo() +{ + if (!m_pInfo) + return NULL; + + VS_FIXEDFILEINFO *pInfo; + UINT cBytes; + if (!VerQueryValueW(m_pInfo, L"\\", (PVOID*)&pInfo, &cBytes)) + return NULL; + return pInfo; +} + +/************************************************************************* + * + * SH_FormatFileSizeWithBytes + * + * Format a size in bytes to string. + * + * lpQwSize = Pointer to 64bit large integer to format + * pszBuf = Buffer to fill with output string + * cchBuf = size of pszBuf in characters + * + */ + +LPWSTR +SH_FormatFileSizeWithBytes(PULARGE_INTEGER lpQwSize, LPWSTR pszBuf, UINT cchBuf) +{ + NUMBERFMTW nf; + WCHAR szNumber[24]; + WCHAR szDecimalSep[8]; + WCHAR szThousandSep[8]; + WCHAR szGrouping[12]; + int Len, cchFormatted, i; + size_t cchRemaining; + LPWSTR Ptr; + + // Try to build first Format byte string + if (StrFormatByteSizeW(lpQwSize->QuadPart, pszBuf, cchBuf) == NULL) + return NULL; + + // If there is less bytes than 1KB, we have nothing to do + if (lpQwSize->QuadPart < 1024) + return pszBuf; + + // Print the number in uniform mode + swprintf(szNumber, L"%I64u", lpQwSize->QuadPart); + + // Get system strings for decimal and thousand separators. + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSep, sizeof(szDecimalSep) / sizeof(*szDecimalSep)); + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szThousandSep, sizeof(szThousandSep) / sizeof(*szThousandSep)); + + // Initialize format for printing the number in bytes + ZeroMemory(&nf, sizeof(nf)); + nf.NumDigits = 0; + nf.LeadingZero = 0; + nf.Grouping = 0; + nf.lpDecimalSep = szDecimalSep; + nf.lpThousandSep = szThousandSep; + nf.NegativeOrder = 0; + + // Get system string for groups separator + Len = GetLocaleInfoW(LOCALE_USER_DEFAULT, + LOCALE_SGROUPING, + szGrouping, + sizeof(szGrouping) / sizeof(*szGrouping)); + + // Convert grouping specs from string to integer + for (i = 0; i < Len; i++) + { + WCHAR wch = szGrouping[i]; + + if (wch >= L'0' && wch <= L'9') + nf.Grouping = nf.Grouping * 10 + (wch - L'0'); + else if (wch != L';') + break; + } + + if ((nf.Grouping % 10) == 0) + nf.Grouping /= 10; + else + nf.Grouping *= 10; + + // Concate " (" at the end of buffer + Len = wcslen(pszBuf); + Ptr = pszBuf + Len; + cchRemaining = cchBuf - Len; + StringCchCopyExW(Ptr, cchRemaining, L" (", &Ptr, &cchRemaining, 0); + + // Save formatted number of bytes in buffer + cchFormatted = GetNumberFormatW(LOCALE_USER_DEFAULT, + 0, + szNumber, + &nf, + Ptr, + cchRemaining); + + if (cchFormatted == 0) + return NULL; + + // cchFormatted is number of characters including NULL - make it a real length + --cchFormatted; + + // Copy ' ' to buffer + Ptr += cchFormatted; + cchRemaining -= cchFormatted; + StringCchCopyExW(Ptr, cchRemaining, L" ", &Ptr, &cchRemaining, 0); + + // Copy 'bytes' string and remaining ')' + Len = LoadStringW(shell32_hInstance, IDS_BYTES_FORMAT, Ptr, cchRemaining); + Ptr += Len; + cchRemaining -= Len; + StringCchCopy(Ptr, cchRemaining, L")"); + + return pszBuf; +} + +/************************************************************************* + * + * SH_CreatePropertySheetPage [Internal] + * + * creates a property sheet page from an resource name + * + */ + +HPROPSHEETPAGE +SH_CreatePropertySheetPage(LPCSTR pszResName, DLGPROC pfnDlgProc, LPARAM lParam, LPWSTR pwszTitle) +{ + if (pszResName == NULL) + return NULL; + + HRSRC hRes = FindResourceA(shell32_hInstance, pszResName, (LPSTR)RT_DIALOG); + if (hRes == NULL) + { + ERR("failed to find resource name\n"); + return NULL; + } + + LPVOID pTemplate = LoadResource(shell32_hInstance, hRes); + if (pTemplate == NULL) + { + ERR("failed to load resource\n"); + return NULL; + } + + PROPSHEETPAGEW Page; + memset(&Page, 0x0, sizeof(PROPSHEETPAGEW)); + Page.dwSize = sizeof(PROPSHEETPAGEW); + Page.dwFlags = PSP_DLGINDIRECT; + Page.pResource = (DLGTEMPLATE*)pTemplate; + Page.pfnDlgProc = pfnDlgProc; + Page.lParam = lParam; + Page.pszTitle = pwszTitle; + + if (pwszTitle) + Page.dwFlags |= PSP_USETITLE; + + return CreatePropertySheetPageW(&Page); +} + +VOID +CFileDefExt::InitOpensWithField(HWND hwndDlg) +{ + WCHAR wszBuf[MAX_PATH] = L""; + WCHAR wszPath[MAX_PATH] = L""; + DWORD dwSize = sizeof(wszBuf); + BOOL bUnknownApp = TRUE; + LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); + + if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS) + { + bUnknownApp = FALSE; + StringCbCatW(wszBuf, sizeof(wszBuf), L"\\shell\\open\\command"); + dwSize = sizeof(wszPath); + if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"", RRF_RT_REG_SZ, NULL, wszPath, &dwSize) == ERROR_SUCCESS) + { + /* Get path from command line */ + ExpandEnvironmentStringsW(wszPath, wszBuf, _countof(wszBuf)); + PathRemoveArgs(wszBuf); + PathUnquoteSpacesW(wszBuf); + PathSearchAndQualify(wszBuf, wszPath, _countof(wszPath)); + + if (PathFileExistsW(wszPath)) + { + /* Get file description */ + CFileVersionInfo VerInfo; + VerInfo.Load(wszPath); + LPCWSTR pwszDescr = VerInfo.GetString(L"FileDescription"); + if (pwszDescr) + SetDlgItemTextW(hwndDlg, 14007, pwszDescr); + else + { + /* File has no description - display filename */ + LPWSTR pwszFilename = PathFindFileNameW(wszPath); + PathRemoveExtension(pwszFilename); + pwszFilename[0] = towupper(pwszFilename[0]); + SetDlgItemTextW(hwndDlg, 14007, pwszFilename); + } + } + else + bUnknownApp = TRUE; + } else + WARN("RegGetValueW %ls failed\n", wszBuf); + } else + WARN("RegGetValueW %ls failed\n", pwszExt); + + if (bUnknownApp) + { + /* Unknown application */ + LoadStringW(shell32_hInstance, IDS_UNKNOWN_APP, wszBuf, _countof(wszBuf)); + SetDlgItemTextW(hwndDlg, 14007, wszBuf); + } +} + +/************************************************************************* + * + * SH_FileGeneralFileType [Internal] + * + * retrieves file extension description from registry and sets it in dialog + * + * TODO: retrieve file extension default icon and load it + * find executable name from registry, retrieve description from executable + */ + +BOOL +CFileDefExt::InitFileType(HWND hwndDlg) +{ + TRACE("path %s\n", debugstr_w(m_wszPath)); + + HWND hDlgCtrl = GetDlgItem(hwndDlg, 14005); + if (hDlgCtrl == NULL) + return FALSE; + + /* Get file information */ + SHFILEINFO fi; + if (!SHGetFileInfoW(m_wszPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME|SHGFI_ICON)) + { + ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_wszPath, GetLastError()); + fi.szTypeName[0] = L'\0'; + fi.hIcon = NULL; + } + + LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); + if (pwszExt[0]) + { + WCHAR wszBuf[256]; + + if (!fi.szTypeName[0]) + { + /* The file type is unknown, so default to string "FileExtension File" */ + size_t cchRemaining = 0; + LPWSTR pwszEnd = NULL; + + StringCchPrintfExW(wszBuf, _countof(wszBuf), &pwszEnd, &cchRemaining, 0, L"%s ", pwszExt + 1); + SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)cchRemaining, (LPARAM)pwszEnd); + + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf); + } + else + { + /* Update file type */ + StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s (%s)", fi.szTypeName, pwszExt); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf); + } + } + + /* Update file icon */ + if (fi.hIcon) + SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)fi.hIcon, 0); + else + ERR("No icon %ls\n", m_wszPath); + + return TRUE; +} + +/************************************************************************* + * + * SHFileGeneralGetFileTimeString [Internal] + * + * formats a given LPFILETIME struct into readable user format + */ + +BOOL +CFileDefExt::GetFileTimeString(LPFILETIME lpFileTime, WCHAR *lpResult) +{ + FILETIME ft; + SYSTEMTIME st; + + if (lpFileTime == NULL || lpResult == NULL) + return FALSE; + + if (!FileTimeToLocalFileTime(lpFileTime, &ft)) + return FALSE; + + FileTimeToSystemTime(&ft, &st); + + /* ddmmyy */ + swprintf(lpResult, L"%02hu/%02hu/%04hu %02hu:%02hu", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute); + + TRACE("result %s\n", debugstr_w(lpResult)); + return TRUE; +} + +/************************************************************************* + * + * SH_FileGeneralSetText [Internal] + * + * sets file path string and filename string + * + */ + +BOOL +CFileDefExt::InitFilePath(HWND hwndDlg) +{ + /* Find the filename */ + WCHAR *pwszFilename = PathFindFileNameW(m_wszPath); + + if (pwszFilename > m_wszPath) + { + /* Location field */ + WCHAR wszLocation[MAX_PATH]; + StringCchCopyNW(wszLocation, _countof(wszLocation), m_wszPath, pwszFilename - m_wszPath); + PathRemoveBackslashW(wszLocation); + + SetDlgItemTextW(hwndDlg, 14009, wszLocation); + } + + /* Filename field */ + SetDlgItemTextW(hwndDlg, 14001, pwszFilename); + + return TRUE; +} + +/************************************************************************* + * + * SH_FileGeneralSetFileSizeTime [Internal] + * + * retrieves file information from file and sets in dialog + * + */ + +BOOL +CFileDefExt::InitFileSizeTime(HWND hwndDlg) +{ + WCHAR wszBuf[MAX_PATH]; + + TRACE("SH_FileGeneralSetFileSizeTime %ls\n", m_wszPath); + + HANDLE hFile = CreateFileW(m_wszPath, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + WARN("failed to open file %s\n", debugstr_w(m_wszPath)); + return FALSE; + } + + FILETIME CreateTime, AccessedTime, WriteTime; + if (!GetFileTime(hFile, &CreateTime, &AccessedTime, &WriteTime)) + { + WARN("GetFileTime failed\n"); + CloseHandle(hFile); + return FALSE; + } + + LARGE_INTEGER FileSize; + if (!GetFileSizeEx(hFile, &FileSize)) + { + WARN("GetFileSize failed\n"); + CloseHandle(hFile); + return FALSE; + } + + CloseHandle(hFile); + + if (GetFileTimeString(&CreateTime, wszBuf)) + SetDlgItemTextW(hwndDlg, 14015, wszBuf); + + if (GetFileTimeString(&AccessedTime, wszBuf)) + SetDlgItemTextW(hwndDlg, 14019, wszBuf); + + if (GetFileTimeString(&WriteTime, wszBuf)) + SetDlgItemTextW(hwndDlg, 14017, wszBuf); + + if (SH_FormatFileSizeWithBytes((PULARGE_INTEGER)&FileSize, + wszBuf, + sizeof(wszBuf) / sizeof(WCHAR))) + { + SetDlgItemTextW(hwndDlg, 14011, wszBuf); + } + + return TRUE; +} + +/************************************************************************* + * + * CFileDefExt::InitGeneralPage [Internal] + * + * sets all file general properties in dialog + */ + +BOOL +CFileDefExt::InitGeneralPage(HWND hwndDlg) +{ + /* Set general text properties filename filelocation and icon */ + InitFilePath(hwndDlg); + + /* Set file type and icon */ + InitFileType(hwndDlg); + + /* Set open with application */ + if (!PathIsExeW(m_wszPath)) + InitOpensWithField(hwndDlg); + else + { + LPCWSTR pwszDescr = m_VerInfo.GetString(L"FileDescription"); + if (pwszDescr) + SetDlgItemTextW(hwndDlg, 14007, pwszDescr); + } + + /* Set file created/modfied/accessed time */ + InitFileSizeTime(hwndDlg); + + return TRUE; +} + +/************************************************************************* + * + * CFileDefExt::GeneralPageProc + * + * wnd proc of 'General' property sheet page + * + */ + +INT_PTR CALLBACK +CFileDefExt::GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam; + + if (ppsp == NULL || !ppsp->lParam) + break; + + TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n", hwndDlg, lParam, ppsp->lParam); + + CFileDefExt *pFileDefExt = (CFileDefExt*)ppsp->lParam; + pFileDefExt->InitGeneralPage(hwndDlg); + } + default: + break; + } + + return FALSE; +} + +/************************************************************************* + * + * CFileDefExt::InitVersionPage [Internal] + * + * sets all file version properties in dialog + */ + +BOOL +CFileDefExt::InitVersionPage(HWND hwndDlg) +{ + /* Get fixed info */ + VS_FIXEDFILEINFO *pInfo = m_VerInfo.GetFixedInfo(); + if (pInfo) + { + WCHAR wszVersion[256]; + swprintf(wszVersion, L"%u.%u.%u.%u", HIWORD(pInfo->dwFileVersionMS), + LOWORD(pInfo->dwFileVersionMS), + HIWORD(pInfo->dwFileVersionLS), + LOWORD(pInfo->dwFileVersionLS)); + TRACE("MS %x LS %x ver %s \n", pInfo->dwFileVersionMS, pInfo->dwFileVersionLS, debugstr_w(wszVersion)); + SetDlgItemTextW(hwndDlg, 14001, wszVersion); + } + + /* Update labels */ + SetVersionLabel(hwndDlg, 14003, L"FileDescription"); + SetVersionLabel(hwndDlg, 14005, L"LegalCopyright"); + + /* Add items to listbox */ + AddVersionString(hwndDlg, L"CompanyName"); + /* FIXME insert language identifier */ + AddVersionString(hwndDlg, L"ProductName"); + AddVersionString(hwndDlg, L"InternalName"); + AddVersionString(hwndDlg, L"OriginalFilename"); + AddVersionString(hwndDlg, L"FileVersion"); + AddVersionString(hwndDlg, L"ProductVersion"); + + /* Attach file version to dialog window */ + SetWindowLongPtr(hwndDlg, DWL_USER, (LONG_PTR)this); + + /* Select first item */ + HWND hDlgCtrl = GetDlgItem(hwndDlg, 14009); + SendMessageW(hDlgCtrl, LB_SETCURSEL, 0, 0); + LPCWSTR pwszText = (WCHAR *)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)0, (LPARAM)NULL); + SetDlgItemTextW(hwndDlg, 14010, pwszText); + + return TRUE; +} + +/************************************************************************* + * + * CFileDefExt::SetVersionLabel [Internal] + * + * + */ + +BOOL +CFileDefExt::SetVersionLabel(HWND hwndDlg, DWORD idCtrl, LPCWSTR pwszName) +{ + if (hwndDlg == NULL || pwszName == NULL) + return FALSE; + + LPCWSTR pwszValue = m_VerInfo.GetString(pwszName); + if (pwszValue) + { + /* file description property */ + TRACE("%s :: %s\n", debugstr_w(pwszName), debugstr_w(pwszValue)); + SetDlgItemTextW(hwndDlg, idCtrl, pwszValue); + return TRUE; + } + + return FALSE; +} + +/************************************************************************* + * + * CFileDefExt::AddVersionString [Internal] + * + * retrieves a version string and adds it to listbox + * + */ + +BOOL +CFileDefExt::AddVersionString(HWND hwndDlg, LPCWSTR pwszName) +{ + TRACE("pwszName %s, hwndDlg %p\n", debugstr_w(pwszName), hwndDlg); + + if (hwndDlg == NULL || pwszName == NULL) + return FALSE; + + LPCWSTR pwszValue = m_VerInfo.GetString(pwszName); + if (pwszValue) + { + /* listbox name property */ + HWND hDlgCtrl = GetDlgItem(hwndDlg, 14009); + TRACE("%s :: %s\n", debugstr_w(pwszName), debugstr_w(pwszValue)); + UINT Index = SendMessageW(hDlgCtrl, LB_ADDSTRING, (WPARAM) -1, (LPARAM)pwszName); + SendMessageW(hDlgCtrl, LB_SETITEMDATA, (WPARAM)Index, (LPARAM)(WCHAR *)pwszValue); + return TRUE; + } + + return FALSE; +} + +/************************************************************************* + * + * CFileDefExt::VersionPageProc + * + * wnd proc of 'Version' property sheet page + */ + +INT_PTR CALLBACK +CFileDefExt::VersionPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam; + + if (ppsp == NULL || !ppsp->lParam) + break; + + TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam); + + CFileDefExt *pFileDefExt = (CFileDefExt*)ppsp->lParam; + return pFileDefExt->InitVersionPage(hwndDlg); + } + case WM_COMMAND: + if (LOWORD(wParam) == 14009 && HIWORD(wParam) == LBN_SELCHANGE) + { + HWND hDlgCtrl = (HWND)lParam; + + LRESULT Index = SendMessageW(hDlgCtrl, LB_GETCURSEL, (WPARAM)NULL, (LPARAM)NULL); + if (Index == LB_ERR) + break; + + LPCWSTR pwszData = (LPCWSTR)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)Index, (LPARAM)NULL); + if (pwszData == NULL) + break; + + TRACE("hDlgCtrl %x string %s\n", hDlgCtrl, debugstr_w(pwszData)); + SetDlgItemTextW(hwndDlg, 14010, pwszData); + + return TRUE; + } + break; + case WM_DESTROY: + break; + default: + break; + } + + return FALSE; +} + +CFileDefExt::CFileDefExt() +{ + m_wszPath[0] = L'\0'; +} + +CFileDefExt::~CFileDefExt() +{ + +} + +HRESULT WINAPI +CFileDefExt::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pDataObj, HKEY hkeyProgID) +{ + FORMATETC format; + STGMEDIUM stgm; + HRESULT hr; + + TRACE("%p %p %p %p\n", this, pidlFolder, pDataObj, hkeyProgID); + + if (!pDataObj) + return E_FAIL; + + format.cfFormat = CF_HDROP; + format.ptd = NULL; + format.dwAspect = DVASPECT_CONTENT; + format.lindex = -1; + format.tymed = TYMED_HGLOBAL; + + hr = pDataObj->GetData(&format, &stgm); + if (FAILED(hr)) + return hr; + + if (!DragQueryFileW((HDROP)stgm.hGlobal, 0, m_wszPath, _countof(m_wszPath))) + { + ERR("DragQueryFileW failed\n"); + ReleaseStgMedium(&stgm); + return E_FAIL; + } + + ReleaseStgMedium(&stgm); + TRACE("File properties %ls\n", m_wszPath); + m_VerInfo.Load(m_wszPath); + + return S_OK; +} + +HRESULT WINAPI +CFileDefExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT WINAPI +CFileDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT WINAPI +CFileDefExt::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT WINAPI +CFileDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) +{ + HPROPSHEETPAGE hPage; + + hPage = SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", + GeneralPageProc, + (LPARAM)this, + NULL); + if (hPage) + pfnAddPage(hPage, lParam); + + if (GetFileVersionInfoSizeW(m_wszPath, NULL)) + { + hPage = SH_CreatePropertySheetPage("SHELL_FILE_VERSION_DLG", + VersionPageProc, + (LPARAM)this, + NULL); + if (hPage) + pfnAddPage(hPage, lParam); + } + + return S_OK; +} + +HRESULT WINAPI +CFileDefExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT WINAPI +CFileDefExt::SetSite(IUnknown *punk) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT WINAPI +CFileDefExt::GetSite(REFIID iid, void **ppvSite) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/shell32/filedefext.h b/reactos/dll/win32/shell32/filedefext.h new file mode 100644 index 00000000000..8e5b4c075b8 --- /dev/null +++ b/reactos/dll/win32/shell32/filedefext.h @@ -0,0 +1,110 @@ +/* + * Provides default file shell extension + * + * Copyright 2012 Rafal Harabien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _FILE_DEF_EXT_H_ +#define _FILE_DEF_EXT_H_ + +class CFileVersionInfo +{ + private: + PVOID m_pInfo; + WORD m_wLang, m_wCode; + + typedef struct _LANGANDCODEPAGE_ + { + WORD lang; + WORD code; + } LANGANDCODEPAGE, *LPLANGANDCODEPAGE; + + public: + inline CFileVersionInfo(): + m_pInfo(NULL), m_wLang(0), m_wCode(0) {} + + inline ~CFileVersionInfo() + { + if (m_pInfo) + HeapFree(GetProcessHeap(), 0, m_pInfo); + } + + BOOL Load(LPCWSTR pwszPath); + + LPCWSTR GetString(LPCWSTR pwszName); + + VS_FIXEDFILEINFO *GetFixedInfo(); +}; + +class CFileDefExt : + public CComCoClass, + public CComObjectRootEx, + public IShellExtInit, + public IContextMenu, + public IShellPropSheetExt, + public IObjectWithSite +{ +private: + VOID InitOpensWithField(HWND hwndDlg); + BOOL InitFileType(HWND hwndDlg); + static BOOL GetFileTimeString(LPFILETIME lpFileTime, WCHAR *lpResult); + BOOL InitFilePath(HWND hwndDlg); + BOOL InitFileSizeTime(HWND hwndDlg); + BOOL InitGeneralPage(HWND hwndDlg); + BOOL SetVersionLabel(HWND hwndDlg, DWORD idCtrl, LPCWSTR pwszName); + BOOL AddVersionString(HWND hwndDlg, LPCWSTR pwszName); + BOOL InitVersionPage(HWND hwndDlg); + static INT_PTR CALLBACK GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK VersionPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + + WCHAR m_wszPath[MAX_PATH]; + CFileVersionInfo m_VerInfo; + +public: + CFileDefExt(); + ~CFileDefExt(); + + // IShellExtInit + virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpici); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax); + + // IShellPropSheetExt + virtual HRESULT WINAPI AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam); + virtual HRESULT WINAPI ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam); + + // IObjectWithSite + virtual HRESULT WINAPI SetSite(IUnknown *punk); + virtual HRESULT WINAPI GetSite(REFIID iid, void **ppvSite); + +DECLARE_REGISTRY_RESOURCEID(IDR_FILEDEFEXT) +DECLARE_NOT_AGGREGATABLE(CFileDefExt) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CFileDefExt) + COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IShellPropSheetExt, IShellPropSheetExt) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) +END_COM_MAP() +}; + +#endif // _FILE_DEF_EXT_H_ diff --git a/reactos/dll/win32/shell32/fprop.cpp b/reactos/dll/win32/shell32/fprop.cpp index 6ce7a9cc52d..6c395ea6f5a 100644 --- a/reactos/dll/win32/shell32/fprop.cpp +++ b/reactos/dll/win32/shell32/fprop.cpp @@ -2,6 +2,7 @@ * Shell Library Functions * * Copyright 2005 Johannes Anderwald + * Copyright 2012 Rafal Harabien * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,727 +21,11 @@ #include -WINE_DEFAULT_DEBUG_CHANNEL(shell); - #define MAX_PROPERTY_SHEET_PAGE 32 -typedef struct _LANGANDCODEPAGE_ -{ - WORD lang; - WORD code; -} LANGANDCODEPAGE, *LPLANGANDCODEPAGE; +WINE_DEFAULT_DEBUG_CHANNEL(shell); EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj); -BOOL PathIsExeW(LPCWSTR lpszPath); - -class CFileVersionInfo -{ - public: - inline CFileVersionInfo(): - m_pInfo(NULL), m_wLang(0), m_wCode(0) {} - - inline ~CFileVersionInfo() - { - if (m_pInfo) - HeapFree(GetProcessHeap(), 0, m_pInfo); - } - - BOOL Load(LPCWSTR pwszPath) - { - ULONG cbBuf = GetFileVersionInfoSizeW(pwszPath, NULL); - if (!cbBuf) - { - WARN("GetFileVersionInfoSize %ls failed\n", pwszPath); - return FALSE; - } - - m_pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBuf); - if (!m_pInfo) - { - ERR("HeapAlloc failed bytes %x\n", cbBuf); - return FALSE; - } - - if (!GetFileVersionInfoW(pwszPath, 0, cbBuf, m_pInfo)) - { - ERR("GetFileVersionInfoW failed\n"); - return FALSE; - } - - LPLANGANDCODEPAGE lpLangCode; - UINT cBytes; - if (!VerQueryValueW(m_pInfo, L"VarFileInfo\\Translation", (LPVOID *)&lpLangCode, &cBytes)) - { - ERR("VerQueryValueW failed\n"); - return FALSE; - } - - /* FIXME: find language from current locale / if not available, - * default to english - * for now default to first available language - */ - m_wLang = lpLangCode->lang; - m_wCode = lpLangCode->code; - return TRUE; - } - - LPCWSTR GetString(LPCWSTR pwszName) - { - if (!m_pInfo) - return NULL; - - WCHAR wszBuf[256]; - swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\%s", m_wLang, m_wCode, pwszName); - - LPCWSTR pwszResult = NULL; - UINT cBytes = 0; - if (!VerQueryValueW(m_pInfo, wszBuf, (LPVOID *)&pwszResult, &cBytes)) - return NULL; - - return pwszResult; - } - - VS_FIXEDFILEINFO *GetFixedInfo() - { - if (!m_pInfo) - return NULL; - - VS_FIXEDFILEINFO *pInfo; - UINT cBytes; - if (!VerQueryValueW(m_pInfo, L"\\", (PVOID*)&pInfo, &cBytes)) - return NULL; - return pInfo; - } - - - private: - PVOID m_pInfo; - WORD m_wLang, m_wCode; -}; - -static VOID -SH_FileGeneralOpensWith(HWND hwndDlg, LPCWSTR pwszExt) -{ - WCHAR wszBuf[MAX_PATH] = L""; - WCHAR wszPath[MAX_PATH] = L""; - DWORD dwSize = sizeof(wszBuf); - - if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS) - { - StringCbCatW(wszBuf, sizeof(wszBuf), L"\\shell\\open\\command"); - dwSize = sizeof(wszPath); - if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"", RRF_RT_REG_SZ, NULL, wszPath, &dwSize) == ERROR_SUCCESS) - { - /* Get path from command line */ - ExpandEnvironmentStringsW(wszPath, wszBuf, _countof(wszBuf)); - PathRemoveArgs(wszBuf); - PathUnquoteSpacesW(wszBuf); - PathSearchAndQualify(wszBuf, wszPath, _countof(wszPath)); - - if (PathFileExistsW(wszPath)) - { - /* Get file description */ - CFileVersionInfo VerInfo; - VerInfo.Load(wszPath); - LPCWSTR pwszDescr = VerInfo.GetString(L"FileDescription"); - if (pwszDescr) - SetDlgItemTextW(hwndDlg, 14007, pwszDescr); - else - { - /* File has no description - display filename */ - LPWSTR pwszFilename = PathFindFileNameW(wszPath); - PathRemoveExtension(pwszFilename); - pwszFilename[0] = towupper(pwszFilename[0]); - SetDlgItemTextW(hwndDlg, 14007, pwszFilename); - } - } - else - { - /* Unknown application */ - LoadStringW(shell32_hInstance, IDS_UNKNOWN_APP, wszBuf, _countof(wszBuf)); - SetDlgItemTextW(hwndDlg, 14007, wszBuf); - } - } else - WARN("RegGetValueW %ls failed\n", wszBuf); - } else - WARN("RegGetValueW %ls failed\n", pwszExt); - - -} - -/************************************************************************* - * - * SH_FormatFileSizeWithBytes - * - * Format a size in bytes to string. - * - * lpQwSize = Pointer to 64bit large integer to format - * pszBuf = Buffer to fill with output string - * cchBuf = size of pszBuf in characters - * - */ - -LPWSTR -SH_FormatFileSizeWithBytes(PULARGE_INTEGER lpQwSize, LPWSTR pszBuf, UINT cchBuf) -{ - NUMBERFMTW nf; - WCHAR szNumber[24]; - WCHAR szDecimalSep[8]; - WCHAR szThousandSep[8]; - WCHAR szGrouping[12]; - int Len, cchFormatted, i; - size_t cchRemaining; - LPWSTR Ptr; - - // Try to build first Format byte string - if (StrFormatByteSizeW(lpQwSize->QuadPart, pszBuf, cchBuf) == NULL) - return NULL; - - // If there is less bytes than 1KB, we have nothing to do - if (lpQwSize->QuadPart < 1024) - return pszBuf; - - // Print the number in uniform mode - swprintf(szNumber, L"%I64u", lpQwSize->QuadPart); - - // Get system strings for decimal and thousand separators. - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimalSep, sizeof(szDecimalSep) / sizeof(*szDecimalSep)); - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szThousandSep, sizeof(szThousandSep) / sizeof(*szThousandSep)); - - // Initialize format for printing the number in bytes - ZeroMemory(&nf, sizeof(nf)); - nf.NumDigits = 0; - nf.LeadingZero = 0; - nf.Grouping = 0; - nf.lpDecimalSep = szDecimalSep; - nf.lpThousandSep = szThousandSep; - nf.NegativeOrder = 0; - - // Get system string for groups separator - Len = GetLocaleInfoW(LOCALE_USER_DEFAULT, - LOCALE_SGROUPING, - szGrouping, - sizeof(szGrouping) / sizeof(*szGrouping)); - - // Convert grouping specs from string to integer - for (i = 0; i < Len; i++) - { - WCHAR wch = szGrouping[i]; - - if (wch >= L'0' && wch <= L'9') - nf.Grouping = nf.Grouping * 10 + (wch - L'0'); - else if (wch != L';') - break; - } - - if ((nf.Grouping % 10) == 0) - nf.Grouping /= 10; - else - nf.Grouping *= 10; - - // Concate " (" at the end of buffer - Len = wcslen(pszBuf); - Ptr = pszBuf + Len; - cchRemaining = cchBuf - Len; - StringCchCopyExW(Ptr, cchRemaining, L" (", &Ptr, &cchRemaining, 0); - - // Save formatted number of bytes in buffer - cchFormatted = GetNumberFormatW(LOCALE_USER_DEFAULT, - 0, - szNumber, - &nf, - Ptr, - cchRemaining); - - if (cchFormatted == 0) - return NULL; - - // cchFormatted is number of characters including NULL - make it a real length - --cchFormatted; - - // Copy ' ' to buffer - Ptr += cchFormatted; - cchRemaining -= cchFormatted; - StringCchCopyExW(Ptr, cchRemaining, L" ", &Ptr, &cchRemaining, 0); - - // Copy 'bytes' string and remaining ')' - Len = LoadStringW(shell32_hInstance, IDS_BYTES_FORMAT, Ptr, cchRemaining); - Ptr += Len; - cchRemaining -= Len; - StringCchCopy(Ptr, cchRemaining, L")"); - - return pszBuf; -} - -/************************************************************************* - * - * SH_CreatePropertySheetPage [Internal] - * - * creates a property sheet page from an resource name - * - */ - -HPROPSHEETPAGE -SH_CreatePropertySheetPage(LPCSTR pwszResName, DLGPROC pfnDlgProc, LPARAM lParam, LPWSTR pwszTitle) -{ - if (pwszResName == NULL) - return NULL; - - HRSRC hRes = FindResourceA(shell32_hInstance, pwszResName, (LPSTR)RT_DIALOG); - if (hRes == NULL) - { - ERR("failed to find resource name\n"); - return NULL; - } - - LPVOID pTemplate = LoadResource(shell32_hInstance, hRes); - if (pTemplate == NULL) - { - ERR("failed to load resource\n"); - return NULL; - } - - PROPSHEETPAGEW Page; - memset(&Page, 0x0, sizeof(PROPSHEETPAGEW)); - Page.dwSize = sizeof(PROPSHEETPAGEW); - Page.dwFlags = PSP_DLGINDIRECT; - Page.pResource = (DLGTEMPLATE*)pTemplate; - Page.pfnDlgProc = pfnDlgProc; - Page.lParam = lParam; - Page.pszTitle = pwszTitle; - - if (pwszTitle) - Page.dwFlags |= PSP_USETITLE; - - return CreatePropertySheetPageW(&Page); -} - -/************************************************************************* - * - * SH_FileGeneralFileType [Internal] - * - * retrieves file extension description from registry and sets it in dialog - * - * TODO: retrieve file extension default icon and load it - * find executable name from registry, retrieve description from executable - */ - -static BOOL -SH_FileGeneralSetFileType(HWND hwndDlg, LPCWSTR pwszPath) -{ - TRACE("path %s\n", debugstr_w(pwszPath)); - - if (pwszPath == NULL || !pwszPath[0]) - return FALSE; - - HWND hDlgCtrl = GetDlgItem(hwndDlg, 14005); - if (hDlgCtrl == NULL) - return FALSE; - - /* Get file information */ - SHFILEINFO fi; - if (!SHGetFileInfoW(pwszPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME|SHGFI_ICON)) - { - ERR("SHGetFileInfoW failed for %ls (%lu)\n", pwszPath, GetLastError()); - fi.szTypeName[0] = L'\0'; - fi.hIcon = NULL; - } - - LPCWSTR pwszExt = PathFindExtensionW(pwszPath); - if (pwszExt[0]) - { - WCHAR wszBuf[256]; - - if (!fi.szTypeName[0]) - { - /* The file type is unknown, so default to string "FileExtension File" */ - size_t cchRemaining = 0; - LPWSTR pwszEnd = NULL; - - StringCchPrintfExW(wszBuf, _countof(wszBuf), &pwszEnd, &cchRemaining, 0, L"%s ", pwszExt + 1); - SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)cchRemaining, (LPARAM)pwszEnd); - - SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf); - } - else - { - /* Update file type */ - StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s (%s)", fi.szTypeName, pwszExt); - SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf); - } - } - - /* Update file icon */ - if (fi.hIcon) - SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)fi.hIcon, 0); - else - ERR("No icon %ls\n", pwszPath); - - return TRUE; -} - -/************************************************************************* - * - * SHFileGeneralGetFileTimeString [Internal] - * - * formats a given LPFILETIME struct into readable user format - */ - -static BOOL -SHFileGeneralGetFileTimeString(LPFILETIME lpFileTime, WCHAR *lpResult) -{ - FILETIME ft; - SYSTEMTIME st; - - if (lpFileTime == NULL || lpResult == NULL) - return FALSE; - - if (!FileTimeToLocalFileTime(lpFileTime, &ft)) - return FALSE; - - FileTimeToSystemTime(&ft, &st); - - /* ddmmyy */ - swprintf(lpResult, L"%02hu/%02hu/%04hu %02hu:%02hu", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute); - - TRACE("result %s\n", debugstr_w(lpResult)); - return TRUE; -} - -/************************************************************************* - * - * SH_FileGeneralSetText [Internal] - * - * sets file path string and filename string - * - */ - -static BOOL -SH_FileGeneralSetText(HWND hwndDlg, LPCWSTR pwszPath) -{ - if (pwszPath == NULL) - return FALSE; - - /* Find the filename */ - WCHAR *pwszFilename = PathFindFileNameW(pwszPath); - - if (pwszFilename > pwszPath) - { - /* Location field */ - WCHAR wszLocation[MAX_PATH]; - StringCchCopyNW(wszLocation, _countof(wszLocation), pwszPath, pwszFilename - pwszPath); - PathRemoveBackslashW(wszLocation); - - SetDlgItemTextW(hwndDlg, 14009, wszLocation); - } - - /* Filename field */ - SetDlgItemTextW(hwndDlg, 14001, pwszFilename); - - return TRUE; -} - -/************************************************************************* - * - * SH_FileGeneralSetFileSizeTime [Internal] - * - * retrieves file information from file and sets in dialog - * - */ - -static BOOL -SH_FileGeneralSetFileSizeTime(HWND hwndDlg, LPCWSTR pwszPath) -{ - HANDLE hFile; - FILETIME CreateTime; - FILETIME AccessedTime; - FILETIME WriteTime; - WCHAR wszBuf[MAX_PATH]; - LARGE_INTEGER FileSize; - - if (pwszPath == NULL) - return FALSE; - - TRACE("SH_FileGeneralSetFileSizeTime %ls\n", pwszPath); - - hFile = CreateFileW(pwszPath, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (hFile == INVALID_HANDLE_VALUE) - { - WARN("failed to open file %s\n", debugstr_w(pwszPath)); - return FALSE; - } - - if (!GetFileTime(hFile, &CreateTime, &AccessedTime, &WriteTime)) - { - WARN("GetFileTime failed\n"); - CloseHandle(hFile); - return FALSE; - } - - if (!GetFileSizeEx(hFile, &FileSize)) - { - WARN("GetFileSize failed\n"); - CloseHandle(hFile); - return FALSE; - } - - CloseHandle(hFile); - - if (SHFileGeneralGetFileTimeString(&CreateTime, wszBuf)) - SetDlgItemTextW(hwndDlg, 14015, wszBuf); - - if (SHFileGeneralGetFileTimeString(&AccessedTime, wszBuf)) - SetDlgItemTextW(hwndDlg, 14019, wszBuf); - - if (SHFileGeneralGetFileTimeString(&WriteTime, wszBuf)) - SetDlgItemTextW(hwndDlg, 14017, wszBuf); - - if (SH_FormatFileSizeWithBytes((PULARGE_INTEGER)&FileSize, - wszBuf, - sizeof(wszBuf) / sizeof(WCHAR))) - { - SetDlgItemTextW(hwndDlg, 14011, wszBuf); - } - - return TRUE; -} - -/************************************************************************* - * - * SH_SetFileVersionText [Internal] - * - * - */ - -static BOOL -SH_FileVersionQuerySetText(HWND hwndDlg, DWORD idCtrl, CFileVersionInfo *pVerInfo, LPCWSTR pwszName) -{ - if (hwndDlg == NULL || pwszName == NULL) - return FALSE; - - LPCWSTR pwszValue = pVerInfo->GetString(pwszName); - if (pwszValue) - { - /* file description property */ - TRACE("%s :: %s\n", debugstr_w(pwszName), debugstr_w(pwszValue)); - SetDlgItemTextW(hwndDlg, idCtrl, pwszValue); - return TRUE; - } - - return FALSE; -} - -/************************************************************************* - * - * SH_FileVersionQuerySetListText [Internal] - * - * retrieves a version string and adds it to listbox - * - */ - -static BOOL -SH_FileVersionQuerySetListText(HWND hwndDlg, CFileVersionInfo *pVerInfo, LPCWSTR pwszName) -{ - TRACE("pwszName %s, hwndDlg %p\n", debugstr_w(pwszName), hwndDlg); - - if (hwndDlg == NULL || pwszName == NULL) - return FALSE; - - LPCWSTR pwszValue = pVerInfo->GetString(pwszName); - if (pwszValue) - { - /* listbox name property */ - HWND hDlgCtrl = GetDlgItem(hwndDlg, 14009); - TRACE("%s :: %s\n", debugstr_w(pwszName), debugstr_w(pwszValue)); - UINT Index = SendMessageW(hDlgCtrl, LB_ADDSTRING, (WPARAM) -1, (LPARAM)pwszName); - SendMessageW(hDlgCtrl, LB_SETITEMDATA, (WPARAM)Index, (LPARAM)(WCHAR *)pwszValue); - return TRUE; - } - - return FALSE; -} - -/************************************************************************* - * - * SH_FileVersionInitialize [Internal] - * - * sets all file version properties in dialog - */ - -static BOOL -SH_FileVersionInitialize(HWND hwndDlg, LPCWSTR pwszPath) -{ - if (pwszPath == NULL) - return FALSE; - - /* Get file version info */ - CFileVersionInfo *pVerInfo; - pVerInfo = new CFileVersionInfo; - if (!pVerInfo || !pVerInfo->Load(pwszPath)) - return FALSE; - - /* Get fixed info */ - VS_FIXEDFILEINFO *pInfo = pVerInfo->GetFixedInfo(); - if (pInfo) - { - WCHAR wszVersion[256]; - swprintf(wszVersion, L"%u.%u.%u.%u", HIWORD(pInfo->dwFileVersionMS), - LOWORD(pInfo->dwFileVersionMS), - HIWORD(pInfo->dwFileVersionLS), - LOWORD(pInfo->dwFileVersionLS)); - TRACE("MS %x LS %x ver %s \n", pInfo->dwFileVersionMS, pInfo->dwFileVersionLS, debugstr_w(wszVersion)); - SetDlgItemTextW(hwndDlg, 14001, wszVersion); - } - - /* Update labels */ - SH_FileVersionQuerySetText(hwndDlg, 14003, pVerInfo, L"FileDescription"); - SH_FileVersionQuerySetText(hwndDlg, 14005, pVerInfo, L"LegalCopyright"); - - /* Add items to listbox */ - SH_FileVersionQuerySetListText(hwndDlg, pVerInfo, L"CompanyName"); - /* FIXME insert language identifier */ - SH_FileVersionQuerySetListText(hwndDlg, pVerInfo, L"ProductName"); - SH_FileVersionQuerySetListText(hwndDlg, pVerInfo, L"InternalName"); - SH_FileVersionQuerySetListText(hwndDlg, pVerInfo, L"OriginalFilename"); - SH_FileVersionQuerySetListText(hwndDlg, pVerInfo, L"FileVersion"); - SH_FileVersionQuerySetListText(hwndDlg, pVerInfo, L"ProductVersion"); - - /* Attach file version to dialog window */ - SetWindowLongPtr(hwndDlg, DWL_USER, (LONG_PTR)pVerInfo); - - /* Select first item */ - HWND hDlgCtrl = GetDlgItem(hwndDlg, 14009); - SendMessageW(hDlgCtrl, LB_SETCURSEL, 0, 0); - LPCWSTR pwszText = (WCHAR *)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)0, (LPARAM)NULL); - SetDlgItemTextW(hwndDlg, 14010, pwszText); - - return TRUE; -} - -/************************************************************************* - * - * SH_FileVersionDlgProc - * - * wnd proc of 'Version' property sheet page - */ - -INT_PTR CALLBACK -SH_FileVersionDlgProc(HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam; - - if (ppsp == NULL) - break; - - TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam); - - LPCWSTR pwszFilename = (LPCWSTR)ppsp->lParam; - - if (pwszFilename == NULL) - break; - - return SH_FileVersionInitialize(hwndDlg, pwszFilename); - } - case WM_COMMAND: - if (LOWORD(wParam) == 14009 && HIWORD(wParam) == LBN_SELCHANGE) - { - HWND hDlgCtrl = (HWND)lParam; - - LRESULT Index = SendMessageW(hDlgCtrl, LB_GETCURSEL, (WPARAM)NULL, (LPARAM)NULL); - if (Index == LB_ERR) - break; - - LPCWSTR pwszData = (LPCWSTR)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)Index, (LPARAM)NULL); - if (pwszData == NULL) - break; - - TRACE("hDlgCtrl %x string %s\n", hDlgCtrl, debugstr_w(pwszData)); - SetDlgItemTextW(hwndDlg, 14010, pwszData); - - return TRUE; - } - break; - case WM_DESTROY: - { - CFileVersionInfo *pVerInfo = (CFileVersionInfo*)GetWindowLongPtr(hwndDlg, DWL_USER); - if (pVerInfo) - delete pVerInfo; - break; - } - default: - break; - } - - return FALSE; -} - -/************************************************************************* - * - * SH_FileGeneralDlgProc - * - * wnd proc of 'General' property sheet page - * - */ - -INT_PTR CALLBACK -SH_FileGeneralDlgProc(HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch (uMsg) - { - case WM_INITDIALOG: - { - LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam; - - if (ppsp == NULL) - break; - - TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n", hwndDlg, lParam, ppsp->lParam); - - LPCWSTR pwszPath = (WCHAR *)ppsp->lParam; - if (pwszPath == NULL) - { - ERR("no path\n"); - break; - } - - /* Set general text properties filename filelocation and icon */ - SH_FileGeneralSetText(hwndDlg, pwszPath); - - /* Set file type and icon */ - SH_FileGeneralSetFileType(hwndDlg, pwszPath); - - /* Set open with application */ - if (!PathIsExeW(pwszPath)) - SH_FileGeneralOpensWith(hwndDlg, PathFindExtensionW(pwszPath)); - - /* Set file created/modfied/accessed time */ - SH_FileGeneralSetFileSizeTime(hwndDlg, pwszPath); - - return TRUE; - } - default: - break; - } - - return FALSE; -} static BOOL CALLBACK AddPropSheetPageCallback(HPROPSHEETPAGE hPage, LPARAM lParam) @@ -844,31 +129,29 @@ SH_ShowPropertiesDialog(LPCWSTR pwszPath, LPCITEMIDLIST pidlFolder, LPCITEMIDLIS Header.phpage = hppages; Header.pszCaption = PathFindFileNameW(wszPath); - hppages[Header.nPages] = - SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", - SH_FileGeneralDlgProc, - (LPARAM)wszPath, - NULL); - - if (hppages[Header.nPages]) - Header.nPages++; - - if (GetFileVersionInfoSizeW(wszPath, NULL) && Header.nPages < _countof(hppages)) - { - hppages[Header.nPages] = - SH_CreatePropertySheetPage("SHELL_FILE_VERSION_DLG", - SH_FileVersionDlgProc, - (LPARAM)wszPath, - NULL); - if (hppages[Header.nPages]) - Header.nPages++; - } - CComPtr pDataObj; hr = SHCreateDataObject(pidlFolder, 1, apidl, NULL, IID_IDataObject, (LPVOID *)&pDataObj); if (SUCCEEDED(hr)) + { + CComObject *pFileDefExt; + ATLTRY(pFileDefExt = new CComObject); + if (pFileDefExt) + { + hr = pFileDefExt->Initialize(pidlFolder, pDataObj, NULL); + if (SUCCEEDED(hr)) + { + hr = pFileDefExt->AddPages(AddPropSheetPageCallback, (LPARAM)&Header); + if (FAILED(hr)) + ERR("AddPages failed\n"); + } else + ERR("Initialize failed\n"); + + pFileDefExt->Release(); + } + LoadPropSheetHandlers(wszPath, &Header, MAX_PROPERTY_SHEET_PAGE - 1, hpsxa, pDataObj); + } INT_PTR Result = PropertySheetW(&Header); diff --git a/reactos/dll/win32/shell32/precomp.h b/reactos/dll/win32/shell32/precomp.h index 21cfb46a25c..01569e7e20c 100644 --- a/reactos/dll/win32/shell32/precomp.h +++ b/reactos/dll/win32/shell32/precomp.h @@ -82,6 +82,8 @@ #include "openwithmenu.h" #include "newmenu.h" #include "startmenu.h" +#include "filedefext.h" +#include "drvdefext.h" #include "wine/debug.h" #include "wine/unicode.h" @@ -96,5 +98,4 @@ extern const GUID CLSID_UnixDosFolder; extern const GUID SHELL32_AdvtShortcutProduct; extern const GUID SHELL32_AdvtShortcutComponent; - #endif diff --git a/reactos/dll/win32/shell32/res/rgs/shellfiledefext.rgs b/reactos/dll/win32/shell32/res/rgs/shellfiledefext.rgs new file mode 100644 index 00000000000..65384be38f8 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/shellfiledefext.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {21B22460-3AEA-1069-A2DC-08002B30309D} = s 'File Default Extension' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/rgs_res.rc b/reactos/dll/win32/shell32/rgs_res.rc index 7cd29792e88..be0d2928e0f 100644 --- a/reactos/dll/win32/shell32/rgs_res.rc +++ b/reactos/dll/win32/shell32/rgs_res.rc @@ -21,3 +21,4 @@ IDR_SHELLFSFOLDER REGISTRY "res\\rgs\\shellfsfolder.rgs" IDR_SHELLLINK REGISTRY "res\\rgs\\shelllink.rgs" IDR_STARTMENU REGISTRY "res\\rgs\\startmenu.rgs" IDR_OPENWITHMENU REGISTRY "res\\rgs\\openwithmenu.rgs" +IDR_FILEDEFEXT REGISTRY "res\\rgs\\shellfiledefext.rgs" diff --git a/reactos/dll/win32/shell32/shell32.rbuild b/reactos/dll/win32/shell32/shell32.rbuild index dbffa235286..5813012d3ed 100644 --- a/reactos/dll/win32/shell32/shell32.rbuild +++ b/reactos/dll/win32/shell32/shell32.rbuild @@ -84,6 +84,8 @@ openwithmenu.cpp newmenu.cpp folder_options.cpp + filedefext.cpp + drvdefext.cpp shell32.rc diff --git a/reactos/dll/win32/shell32/shresdef.h b/reactos/dll/win32/shell32/shresdef.h index b9036c58987..70698062e8c 100644 --- a/reactos/dll/win32/shell32/shresdef.h +++ b/reactos/dll/win32/shell32/shresdef.h @@ -476,5 +476,7 @@ FIXME: Need to add them, but for now just let them use the same: searching.avi #define IDR_SHELLLINK 144 #define IDR_STARTMENU 145 #define IDR_OPENWITHMENU 146 +#define IDR_FILEDEFEXT 147 +#define IDR_DRVDEFEXT 148 #endif diff --git a/reactos/include/psdk/shlguid_undoc.h b/reactos/include/psdk/shlguid_undoc.h index d2c85227053..63edd52ef18 100644 --- a/reactos/include/psdk/shlguid_undoc.h +++ b/reactos/include/psdk/shlguid_undoc.h @@ -19,6 +19,7 @@ #ifndef __SHLGUID_UNDOC_H #define __SHLGUID_UNDOC_H + DEFINE_GUID(CLSID_RebarBandSite, 0xECD4FC4D, 0x521C, 0x11D0, 0xB7, 0x92, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1); DEFINE_GUID(CLSID_BandSiteMenu, 0xECD4FC4E, 0x521C, 0x11D0, 0xB7, 0x92, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1); DEFINE_GUID(IID_IBandSiteHelper, 0xD1E7AFEA, 0x6A2E, 0x11D0, 0x8C, 0x78, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xB4); @@ -97,8 +98,12 @@ DEFINE_GUID(CLSID_AdminFolderShortcut, 0xD20EA4E1, 0x3957, 0x11D2, 0xA4, 0x0 DEFINE_GUID(CLSID_FolderOptions, 0x6DFD7C5C, 0x2451, 0x11D3, 0xA2, 0x99, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xAF); +DEFINE_GUID(CLSID_ShellFileDefExt, 0x21B22460, 0x3AEA, 0x1069, 0xA2, 0xDC, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); +DEFINE_GUID(CLSID_ShellDrvDefExt, 0x5F5295E0, 0x429F, 0x1069, 0xA2, 0xE2, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); +DEFINE_GUID(CLSID_ShellNetDefExt, 0x86422020, 0x42A0, 0x1069, 0xA2, 0xE5, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); + // In theory, this is documented. But until I see an SDK header that defines it, it will be treated as undocumented... -DEFINE_GUID(CLSID_ShellItem, 0x2fe352ea, 0xfd1f, 0x11d2, 0xb1, 0xf4, 0x00, 0xc0, 0x4f, 0x8e, 0xeb, 0x3e); +DEFINE_GUID(CLSID_ShellItem, 0x2FE352EA, 0xFD1F, 0x11D2, 0xB1, 0xF4, 0x00, 0xC0, 0x4F, 0x8E, 0xEB, 0x3E); #define CGID_IExplorerToolbar IID_IExplorerToolbar #define SID_IExplorerToolbar IID_IExplorerToolbar