Shell32 File Property Dialog

Johannes Anderwald j_anderw at sbox.tugraz.at
Sat Oct 29 13:59:51 CDT 2005


This patch adds file property dialog to shell32
affected files: shell32_En.rc
                     shlexec.c
                     shv_item_cmenu.c
                     fprop.c (implementation file dialog)

Name: Johannes Anderwald

kind regards,

-- 
Johannes Anderwald
-------------- next part --------------
Index: wine/dlls/shell32/shell32_En.rc
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shell32_En.rc,v
retrieving revision 1.21
diff -u -p -r1.21 shell32_En.rc
--- wine/dlls/shell32/shell32_En.rc	6 May 2005 15:44:32 -0000	1.21
+++ wine/dlls/shell32/shell32_En.rc	29 Oct 2005 18:29:36 -0000
@@ -131,6 +131,33 @@ FONT 8, "MS Shell Dlg"
  PUSHBUTTON "&Browse...", 12288, 170, 63, 50, 14, WS_TABSTOP
 }
 
+SHELL_FILE_GENERAL_DLG DIALOGEX 0, 0, 240, 130
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "General"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+{
+ ICON "", 14000, 10, 5, 30, 30, WS_VISIBLE
+ EDITTEXT 14001, 70, 5, 100, 10, ES_LEFT | ES_READONLY
+ LTEXT "Type of file:", 14004, 10, 30, 50, 10
+ LTEXT "%s File", 14005, 70, 30, 150, 10
+ LTEXT "Opens with: ", 14006, 10, 40, 50, 10
+ LTEXT "Unknown Application", 14007, 70, 40, 150, 10
+ LTEXT "Location: ", 14008, 10, 55, 45, 10
+ LTEXT "", 14009, 70, 55, 150, 10
+ LTEXT "Size: ",14010, 10, 65, 45, 10
+ LTEXT "", 14011, 70, 65, 150, 10
+ LTEXT "Created: ", 14014, 10, 80, 45, 10
+ LTEXT "", 14015, 70, 80, 150, 10
+ LTEXT "Modied: ", 14016, 10, 90, 45, 10
+ LTEXT "", 14017, 70, 90, 150, 10
+ LTEXT "Accessed: ", 14018, 10, 100, 45, 10
+ LTEXT "", 14019, 70, 100, 150, 10
+ LTEXT "Attributes: ", 14020, 10, 115, 45, 10
+ CHECKBOX "&Read-only", 14021, 70, 115, 45, 10
+ CHECKBOX "&Hidden", 14022, 130, 115, 50, 10
+ CHECKBOX "&Archive", 14023, 180, 115, 45, 10
+}
+
 STRINGTABLE DISCARDABLE
 {
         /* columns in the shellview */
Index: wine/dlls/shell32/shlexec.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlexec.c,v
retrieving revision 1.74
diff -u -p -r1.74 shlexec.c
--- wine/dlls/shell32/shlexec.c	18 Oct 2005 14:11:17 -0000	1.74
+++ wine/dlls/shell32/shlexec.c	29 Oct 2005 18:17:30 -0000
@@ -995,6 +995,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW 
     static const WCHAR wHttp[] = {'h','t','t','p',':','/','/',0};
     static const WCHAR wExtLnk[] = {'.','l','n','k',0};
     static const WCHAR wExplorer[] = {'e','x','p','l','o','r','e','r','.','e','x','e',0};
+    static const WCHAR wProperties[] = {'p','r','o','p','e','r','t','i','e','s',0};
     static const DWORD unsupportedFlags =
         SEE_MASK_INVOKEIDLIST  | SEE_MASK_ICON         | SEE_MASK_HOTKEY |
         SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI |
@@ -1082,7 +1083,11 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW 
         strcatW(wszApplicationName, wQuote);
         TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
     }
-
+    if (sei_tmp.lpVerb)
+    {
+        if (!strcmpW(sei_tmp.lpVerb,wProperties))
+            return SH_ShowPropertiesDialog(sei_tmp.lpFile);
+    }
     if (sei_tmp.fMask & SEE_MASK_CLASSALL)
     {
 	/* launch a document by fileclass like 'WordPad.Document.1' */
Index: wine/dlls/shell32/shv_item_cmenu.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shv_item_cmenu.c,v
retrieving revision 1.35
diff -u -p -r1.35 shv_item_cmenu.c
--- wine/dlls/shell32/shv_item_cmenu.c	2 Sep 2005 11:32:17 -0000	1.35
+++ wine/dlls/shell32/shv_item_cmenu.c	29 Oct 2005 18:26:31 -0000
@@ -384,6 +384,34 @@ static BOOL DoCopyOrCut(
 	}
 	return TRUE;
 }
+
+/**************************************************************************
+ * DoProperties
+ *
+ * shows the file property dialog
+ */
+static void DoProperties(
+    IContextMenu2 *iface,
+    HWND hwnd)
+{
+    ItemCmImpl *This = (ItemCmImpl *)iface;
+
+    LPITEMIDLIST	pidlFQ;
+    SHELLEXECUTEINFOA	sei;
+
+    pidlFQ = ILCombine(This->pidl, This->apidl[0]);
+
+    ZeroMemory(&sei, sizeof(sei));
+    sei.cbSize = sizeof(sei);
+    sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
+    sei.lpIDList = pidlFQ;
+    sei.hwnd = hwnd;
+    sei.nShow = SW_SHOWNORMAL;
+    sei.lpVerb = "properties";
+    ShellExecuteExA(&sei);
+    SHFree(pidlFQ);
+}
+
 /**************************************************************************
 * ISvItemCm_fnInvokeCommand()
 */
@@ -432,6 +460,10 @@ static HRESULT WINAPI ISvItemCm_fnInvoke
             TRACE("Verb FCIDM_SHVIEW_CUT\n");
             DoCopyOrCut(iface, lpcmi->hwnd, TRUE);
             break;
+           case FCIDM_SHVIEW_PROPERTIES:
+            TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
+            DoProperties(iface,lpcmi->hwnd);
+            break;
         default:
             FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
         }
-------------- next part --------------
/*
 *                 Shell Library Functions
 *
 * Copyright 2005 Johannes Anderwald
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"
#include "wine/port.h"

#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "wingdi.h"
#include "winuser.h"
#include "commdlg.h"
#include "wine/debug.h"

#include "shellapi.h"
#include <shlwapi.h>
#include "shlobj.h"
#include "shell32_main.h"
#include "shresdef.h"
#include "undocshell.h"
#include <prsht.h>


#define MAX_PROPERTY_SHEET_PAGE    32
#define TIMER_INTERVAL            100

/*************************************************************************
 *
 * SH_CreatePropertySheetPage [Internal]
 *
 * creates a property sheet page from an resource name
 *
 */

HPROPSHEETPAGE
SH_CreatePropertySheetPage(LPSTR resname, DLGPROC dlgproc, LPFNPSPCALLBACKW pfnCallback, LPARAM lParam)
{
    HRSRC hRes;
    LPVOID lpsztemplate;
    PROPSHEETPAGEW ppage;

    if (resname == NULL)
        return (HPROPSHEETPAGE)0;

    hRes = FindResourceA(shell32_hInstance, resname, (LPSTR)RT_DIALOG);

    if (hRes == NULL)
        return (HPROPSHEETPAGE)0;

    lpsztemplate = LoadResource(shell32_hInstance, hRes);
    if (lpsztemplate == NULL)
        return (HPROPSHEETPAGE)0;

    memset(&ppage, 0x0, sizeof(PROPSHEETPAGE));
    ppage.dwSize = sizeof(PROPSHEETPAGE);
    ppage.dwFlags = PSP_DLGINDIRECT | PSP_USECALLBACK;
    ppage.pResource = lpsztemplate;
    ppage.pfnDlgProc = dlgproc;
    ppage.lParam = lParam;
    ppage.pfnCallback = pfnCallback;

    return CreatePropertySheetPageW(&ppage);
}

/*************************************************************************
 *
 * SH_FileTimerProc [Internal]
 *
 * is invoked every 100ms to check if the property sheet should be closed
 *  A timer is required because the property sheet pages are per default
 *  modeless and the property sheetpage does not have a window procedure
 *
 */

VOID
CALLBACK 
SH_FileTimerProc(HWND hwnd, 
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime)
{
    if (!SendMessage(hwnd, PSM_GETCURRENTPAGEHWND, (WPARAM)0, (LPARAM)0))
    {
        TRACE("\n");
        KillTimer(hwnd, (UINT_PTR)hwnd);
        DestroyWindow(hwnd);
    }
}

/*************************************************************************
 *
 * SH_FileGeneralFileType [Internal]
 *
 * retrieves file extension description from registry and sets it in dialog
 *
 * FIXME: retrieve file extension default icon and load it
 *        find executable name from registry, retrieve description from executable
 */

BOOL
SH_FileGeneralSetFileType(HWND hwndDlg, WCHAR * filext)
{
     WCHAR name[MAX_PATH];
     WCHAR value[MAX_PATH];
     DWORD lname = MAX_PATH;
     DWORD lvalue = MAX_PATH;
 
     HKEY hKey;
     LONG result;
     HWND hDlgCtrl = GetDlgItem(hwndDlg, 14005);

     if (filext == NULL || hDlgCtrl == NULL)
         return FALSE;

     memset(name, 0x0, sizeof(TCHAR) * MAX_PATH);
     memset(value, 0x0, sizeof(TCHAR) * MAX_PATH);
     if (RegOpenKeyW(HKEY_CLASSES_ROOT, filext, &hKey) != ERROR_SUCCESS)
     {
         /* the fileextension is unknown, so default to string "FileExtension File" */
         SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)value);
         sprintfW(name, value, &filext[1]);
         SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)name);
         return TRUE;
     }
 
     result = RegEnumValueW(hKey,0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue);
     RegCloseKey(hKey);

    if (result != ERROR_SUCCESS)
        return FALSE;
 
    if (RegOpenKeyW(HKEY_CLASSES_ROOT, value, &hKey) == ERROR_SUCCESS)
    {
        lvalue = lname = MAX_PATH;
        memset(name, 0x0, sizeof(TCHAR) * MAX_PATH);
        memset(value, 0x0, sizeof(TCHAR) * MAX_PATH);
        result = RegEnumValueW(hKey,0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue);
        RegCloseKey(hKey);
    }

    /* file extension type */
    SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)value);
 
    return TRUE;
}
/*************************************************************************
 *
 * SHFileGeneralGetFileTimeString [Internal]
 *
 * formats a given LPFILETIME struct into readable user format 
 */

BOOL 
SHFileGeneralGetFileTimeString(LPFILETIME lpFileTime, WCHAR * lpResult)
{
    FILETIME ft;
    SYSTEMTIME dt;
    WORD wYear;
    WCHAR wFormat[] = {'%','0','2','d','/','%','0','2','d','/','%','0','4','d',' ',' ','%','0','2','d',':','%','0','2','u',0};
  
    if (lpFileTime == NULL || lpResult == NULL)
        return FALSE;

    if (!FileTimeToLocalFileTime(lpFileTime, &ft))
        return FALSE;

    FileTimeToSystemTime(&ft, &dt);

    wYear = dt.wYear;
    /* ddmmyy */
    sprintfW (lpResult, wFormat, dt.wDay, dt.wMonth, wYear, dt.wHour, dt.wMinute);
    
    TRACE("result %s \n",debug_strw(lpResult));
    return TRUE;
}

/*************************************************************************
 *
 * SH_FileGeneralSetText [Internal]
 *
 * sets file path string and filename string
 *
 */

BOOL 
SH_FileGeneralSetText(HWND hwndDlg, WCHAR * lpstr)
{
    int flength;
    int plength;
    WCHAR * lpdir;
    WCHAR buff[256];
    HWND hDlgCtrl;
  
    if (lpstr == NULL)
        return FALSE;

    lpdir = strrchrW(lpstr, '\\'); /* find the last occurence of '\\' */

    plength = strlenW(lpstr);
    flength = strlenW(lpdir);
  
    if (lpdir)
    {
        /* location text field */
        strncpyW(buff, lpstr, plength - flength);
        buff[plength - flength] = UNICODE_NULL;
        hDlgCtrl = GetDlgItem(hwndDlg, 14009);
        SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
    }

    if(flength > 1)
    {
         /* text filename field */
         strncpyW(buff, &lpdir[1], flength);
         hDlgCtrl = GetDlgItem(hwndDlg, 14001);
         SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
    }

    return TRUE;
}

/*************************************************************************
 *
 * SH_FileGeneralSetFileTime [Internal]
 *
 * retrieves file information from file and sets in dialog
 *
 */

BOOL
SH_FileGeneralSetFileTime(HWND hwndDlg, WCHAR * lpfilename)
{
    BOOL result;
    HANDLE hFile; 
    FILETIME create_time;
    FILETIME accessed_time;
    FILETIME write_time;
    WCHAR resultstr[60];
    HWND hDlgCtrl;

    if (lpfilename == NULL)
        return FALSE;
  
    hFile = CreateFileW(lpfilename,
                        GENERIC_READ,
                        FILE_SHARE_READ,NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);

    if (hFile == INVALID_HANDLE_VALUE)
    {
        WARN("failed to open file \n");
        return FALSE;
    }
    
    result = GetFileTime(hFile, &create_time, &accessed_time, &write_time);
    CloseHandle(hFile);
  
    if (!result)
    {
        WARN("GetFileTime failed \n");
        return FALSE;
    }
    if (SHFileGeneralGetFileTimeString(&create_time,resultstr))
    {
        hDlgCtrl = GetDlgItem(hwndDlg, 14015);
        TRACE("hDlgCtrl %x text %s \n",hDlgCtrl, debug_strw(resultstr));
        SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
    }

    if (SHFileGeneralGetFileTimeString(&accessed_time, resultstr))
    {
        hDlgCtrl = GetDlgItem(hwndDlg, 14017);
        SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
    }

    if (SHFileGeneralGetFileTimeString(&write_time, resultstr))
    {
        hDlgCtrl = GetDlgItem(hwndDlg, 14019);
        SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
    }
  
    return TRUE;
}

/*************************************************************************
 *
 * SH_FileGeneralSetFileSize [Internal]
 *
 * retrieves file size and sets in dialog
 *
 */


BOOL
SH_FileGeneralSetFileSize(HWND hwndDlg, WCHAR * filename, PULARGE_INTEGER lpfilesize)
{
    HANDLE hFile;
    ULARGE_INTEGER result;
    DWORD dwFileHi;
    DWORD dwFileLo;
    WCHAR fileres[60];
    HWND hDlgCtrl;

    if (filename == NULL)
        return FALSE;

    hFile = CreateFileW(filename,
                        GENERIC_READ,
                        FILE_SHARE_READ,NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);

    if (hFile == INVALID_HANDLE_VALUE)
    {
        WARN("failed to open file \n");
        return FALSE;
    }
    if (GetFileSize(hFile, NULL) == 0xFFFFFFFF)
    {
        WARN("GetFileSize failed \n");
        CloseHandle(hFile);
        return FALSE;
    }
 
    dwFileLo = GetFileSize(hFile, &dwFileHi);
    CloseHandle(hFile);
 
    if (dwFileLo == 0xFFFFFFFF && GetLastError() != NO_ERROR) 
        return FALSE;
 
    result.LowPart = dwFileLo;
    result.HighPart = dwFileHi;

   if (!StrFormatByteSizeW((LONGLONG)result.QuadPart, fileres, sizeof(fileres)))
       return FALSE;

   hDlgCtrl = GetDlgItem(hwndDlg, 14011);
   TRACE("result %s \n", debug_strw(fileres));
   SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)fileres);
 
   if (lpfilesize)
   {
       lpfilesize->LowPart = dwFileLo;
       lpfilesize->HighPart = dwFileHi;
   }
   return TRUE;
}

/*************************************************************************
 *
 * SH_FileGeneralDlgProc
 *
 * wnd proc of 'General' property sheet page
 *
 */

INT_PTR 
CALLBACK 
SH_FileGeneralDlgProc(   
    HWND hwndDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    LPPROPSHEETPAGEW ppsp;
    WCHAR * lpstr;

    switch(uMsg)
    {
    case WM_INITDIALOG:
        ppsp = (LPPROPSHEETPAGE)lParam;
        if (ppsp == NULL)
            break;

        TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n",hwndDlg, lParam, ppsp->lParam);

        lpstr = (WCHAR *)ppsp->lParam;

        if (lpstr == NULL)
            break;

        /* set general text properties filename filelocation and icon */
        SH_FileGeneralSetText(hwndDlg, lpstr);
        /* enumerate file extension from registry and application which opens it*/
        SH_FileGeneralSetFileType(hwndDlg, strrchrW(lpstr, '.'));
        /* set file time create/modfied/accessed */
        SH_FileGeneralSetFileTime(hwndDlg, lpstr);
        /* set file size */
        SH_FileGeneralSetFileSize(hwndDlg, lpstr, NULL);

        return TRUE;
  default:
      break;
  }
  return FALSE;
}

/*************************************************************************
 *
 * SH_ShowPropertiesDialog
 *
 * called from ShellExecuteExW32
 * 
 * lpf contains (quoted) path of folder/file
 *
 * FIXME: provide button change application type if file has registered type
 *        make filename field editable and apply changes to filename on close
 */
	
BOOL
SH_ShowPropertiesDialog(WCHAR * lpf)
{
    PROPSHEETHEADERW pinfo;
    HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE];
    HPROPSHEETPAGE hpage;
    HWND hwnd;
    WCHAR wFileName[MAX_PATH];
  
    TRACE("SH_ShowPropertiesDialog entered\n");

    if (lpf== NULL)
        return FALSE;
  
    memset(hppages, 0x0, sizeof(HPROPSHEETPAGE) * MAX_PROPERTY_SHEET_PAGE);

    if (lpf[0] == '"')
    {
        /* remove quotes from lpf */
        LPWSTR src = lpf + 1;
        LPWSTR dst = wFileName;
      
        while(*src && *src!='"')
            *dst++ = *src++;

        *dst = '\0';
    }
    else
        strcpyW(wFileName, lpf);


    if (PathIsDirectoryW(wFileName) || strlenW(wFileName) == 3)
    {
        FIXME("directory / drive resources dont exist yet \n");
        return FALSE;
    }

    hpage = SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", SH_FileGeneralDlgProc, NULL, (LPARAM)wFileName);

    if (hpage == NULL)
        return FALSE;
  
    hppages[0] = hpage;

    memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
    pinfo.dwSize = sizeof(PROPSHEETHEADER);
    pinfo.dwFlags = PSH_MODELESS | PSH_NOCONTEXTHELP | PSH_PROPTITLE;
    pinfo.nPages = 1;
    pinfo.phpage = hppages;
    pinfo.pszCaption = wFileName;
    hwnd = (HWND)PropertySheetW(&pinfo);
  
    if (hwnd != INVALID_HANDLE_VALUE)
    {
        if (!SetTimer(hwnd, (UINT_PTR)hwnd, TIMER_INTERVAL, SH_FileTimerProc))
        {
            DestroyWindow(hwnd);
            return FALSE;
        }
    }
    return TRUE;
}
/*EOF */


More information about the wine-patches mailing list