windows-nt/Source/XPSP1/NT/shell/shell32/prop.cpp
2020-09-26 16:20:57 +08:00

2263 lines
97 KiB
C++

#include "shellprv.h"
#include "prop.h"
#include <ntquery.h> // defines some values used for fmtid and pid
#include "findfilter.h" // includes oledb (which defines some values used for fmtid and pid) properly
#include "ids.h"
#include "imgprop.h"
#include <gdiplus\gdiplus.h> // for PropertyTag* definitions
#define MAX_UTF8_CHAR_SIZE (sizeof(CHAR) * 3)
// FMTID_ExeDllInformation,
//// {0CEF7D53-FA64-11d1-A203-0000F81FEDEE}
#define PSFMTID_VERSION { 0xcef7d53, 0xfa64, 0x11d1, 0xa2, 0x3, 0x0, 0x0, 0xf8, 0x1f, 0xed, 0xee }
#define PIDVSI_FileDescription 0x003
#define PIDVSI_FileVersion 0x004
#define PIDVSI_InternalName 0x005
#define PIDVSI_OriginalFileName 0x006
#define PIDVSI_ProductName 0x007
#define PIDVSI_ProductVersion 0x008
#define TIFFTAG_FAX_END_TIME 40052
#define TIFFTAG_SENDER_NAME 40021
#define TIFFTAG_TSID 40002
#define TIFFTAG_CALLERID 40005
#define TIFFTAG_RECIP_NAME 40006
#define TIFFTAG_RECIP_NUMBER 40007
#define TIFFTAG_CSID 40001
#define TIFFTAG_ROUTING 40004
// Internal PSGUID/PIDs
//
// Note:
// This section was added to allow SCIDs to be defined without exposing them
// externally (via public header files). In this way, we can define SCIDs
// without having to worry about maintaining external support for them in
// future.
// {8D72ACA1-0716-419a-9AC1-ACB07B18DC32}
#define PSGUID_PRV_STORAGE {0x8d72aca1, 0x716, 0x419a, 0x9a, 0xc1, 0xac, 0xb0, 0x7b, 0x18, 0xdc, 0x32}
#define PID_PRV_STG_ATTRIBUTES_DESCRIPTION 2
DEFINE_SCID(SCID_Author , PSGUID_SUMMARYINFORMATION , PIDSI_AUTHOR);
DEFINE_SCID(SCID_LastAuthor , PSGUID_SUMMARYINFORMATION , PIDSI_LASTAUTHOR);
DEFINE_SCID(SCID_RevNumber , PSGUID_SUMMARYINFORMATION , PIDSI_REVNUMBER);
DEFINE_SCID(SCID_AppName , PSGUID_SUMMARYINFORMATION , PIDSI_APPNAME);
DEFINE_SCID(SCID_Title , PSGUID_SUMMARYINFORMATION , PIDSI_TITLE);
DEFINE_SCID(SCID_Subject , PSGUID_SUMMARYINFORMATION , PIDSI_SUBJECT);
DEFINE_SCID(SCID_Category , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_CATEGORY);
DEFINE_SCID(SCID_Keywords , PSGUID_SUMMARYINFORMATION , PIDSI_KEYWORDS );
DEFINE_SCID(SCID_Rating , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_RATING );
DEFINE_SCID(SCID_Template , PSGUID_SUMMARYINFORMATION , PIDSI_TEMPLATE );
DEFINE_SCID(SCID_Copyright , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_COPYRIGHT);
DEFINE_SCID(SCID_CompanyName , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_COMPANY);
DEFINE_SCID(SCID_Manager , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_MANAGER);
DEFINE_SCID(SCID_PresFormat , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_PRESFORMAT);
DEFINE_SCID(SCID_PageCount , PSGUID_SUMMARYINFORMATION , PIDSI_PAGECOUNT);
DEFINE_SCID(SCID_Comment , PSGUID_SUMMARYINFORMATION , PIDSI_COMMENTS);
DEFINE_SCID(SCID_DocCreated , PSGUID_SUMMARYINFORMATION , PIDSI_CREATE_DTM); // in the doc, not file system
DEFINE_SCID(SCID_WordCount , PSGUID_SUMMARYINFORMATION , PIDSI_WORDCOUNT);
DEFINE_SCID(SCID_CharCount , PSGUID_SUMMARYINFORMATION , PIDSI_CHARCOUNT);
DEFINE_SCID(SCID_LastSaveDTM , PSGUID_SUMMARYINFORMATION , PIDSI_LASTSAVE_DTM);
DEFINE_SCID(SCID_LastPrinted , PSGUID_SUMMARYINFORMATION , PIDSI_LASTPRINTED);
DEFINE_SCID(SCID_EditTime , PSGUID_SUMMARYINFORMATION , PIDSI_EDITTIME);
DEFINE_SCID(SCID_ByteCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_BYTECOUNT);
DEFINE_SCID(SCID_LineCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_LINECOUNT);
DEFINE_SCID(SCID_ParagraphCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_PARCOUNT);
DEFINE_SCID(SCID_SlideCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_SLIDECOUNT);
DEFINE_SCID(SCID_NoteCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_NOTECOUNT);
DEFINE_SCID(SCID_HiddenCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_HIDDENCOUNT);
DEFINE_SCID(SCID_MMClipCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_MMCLIPCOUNT);
DEFINE_SCID(SCID_Scale , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_SCALE);
DEFINE_SCID(SCID_LinksDirty , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_LINKSDIRTY);
DEFINE_SCID(SCID_TYPE , PSGUID_STORAGE , PID_STG_STORAGETYPE);
DEFINE_SCID(SCID_NAME , PSGUID_STORAGE , PID_STG_NAME);
DEFINE_SCID(SCID_SIZE , PSGUID_STORAGE , PID_STG_SIZE);
DEFINE_SCID(SCID_ATTRIBUTES , PSGUID_STORAGE , PID_STG_ATTRIBUTES);
DEFINE_SCID(SCID_WRITETIME , PSGUID_STORAGE , PID_STG_WRITETIME);
DEFINE_SCID(SCID_CREATETIME , PSGUID_STORAGE , PID_STG_CREATETIME);
DEFINE_SCID(SCID_ACCESSTIME , PSGUID_STORAGE , PID_STG_ACCESSTIME);
DEFINE_SCID(SCID_DIRECTORY , PSGUID_STORAGE , PID_STG_DIRECTORY);
DEFINE_SCID(SCID_FREESPACE , PSGUID_VOLUME , PID_VOLUME_FREE);
DEFINE_SCID(SCID_CAPACITY , PSGUID_VOLUME , PID_VOLUME_CAPACITY);
DEFINE_SCID(SCID_FILESYSTEM , PSGUID_VOLUME , PID_VOLUME_FILESYSTEM);
DEFINE_SCID(SCID_DELETEDFROM , PSGUID_DISPLACED , PID_DISPLACED_FROM);
DEFINE_SCID(SCID_DATEDELETED , PSGUID_DISPLACED , PID_DISPLACED_DATE);
DEFINE_SCID(SCID_SYNCCOPYIN , PSGUID_BRIEFCASE , PID_SYNC_COPY_IN);
DEFINE_SCID(SCID_RANK , PSGUID_QUERY_D , PID_QUERY_RANK);
DEFINE_SCID(SCID_LASTVISITED , PSGUID_INTERNETSITE , PID_INTSITE_LASTVISIT);
DEFINE_SCID(SCID_LASTMODIFIED , PSGUID_INTERNETSITE , PID_INTSITE_LASTMOD);
DEFINE_SCID(SCID_VISITCOUNT , PSGUID_INTERNETSITE , PID_INTSITE_VISITCOUNT);
DEFINE_SCID(SCID_STATUS , PSGUID_INTERNETSITE , PID_INTSITE_FLAGS);
DEFINE_SCID(SCID_FINDDATA , PSGUID_SHELLDETAILS , PID_FINDDATA);
DEFINE_SCID(SCID_NETRESOURCE , PSGUID_SHELLDETAILS , PID_NETRESOURCE);
DEFINE_SCID(SCID_DESCRIPTIONID , PSGUID_SHELLDETAILS , PID_DESCRIPTIONID);
DEFINE_SCID(SCID_WHICHFOLDER , PSGUID_SHELLDETAILS , PID_WHICHFOLDER);
DEFINE_SCID(SCID_NETWORKLOCATION , PSGUID_SHELLDETAILS , PID_NETWORKLOCATION);
DEFINE_SCID(SCID_COMPUTERNAME , PSGUID_SHELLDETAILS , PID_COMPUTERNAME);
DEFINE_SCID(SCID_OWNER , PSGUID_MISC , PID_MISC_OWNER);
// DEFINE_SCID(SCID_STATUS , PSGUID_MISC , PID_MISC_STATUS);
// DEFINE_SCID(SCID_ACCESSCOUNT , PSGUID_MISC , PID_MISC_ACCESSCOUNT);
DEFINE_SCID(SCID_DetailsProperties , PSGUID_WEBVIEW , PID_DISPLAY_PROPERTIES);
DEFINE_SCID(SCID_FolderIntroText , PSGUID_WEBVIEW , PID_INTROTEXT);
DEFINE_SCID(SCID_CONTROLPANELCATEGORY , PSGUID_CONTROLPANEL , PID_CONTROLPANEL_CATEGORY);
DEFINE_SCID(SCID_MUSIC_Artist , PSGUID_MUSIC , PIDSI_ARTIST);
DEFINE_SCID(SCID_MUSIC_Album , PSGUID_MUSIC , PIDSI_ALBUM);
DEFINE_SCID(SCID_MUSIC_Year , PSGUID_MUSIC , PIDSI_YEAR);
DEFINE_SCID(SCID_MUSIC_Track , PSGUID_MUSIC , PIDSI_TRACK);
DEFINE_SCID(SCID_MUSIC_Genre , PSGUID_MUSIC , PIDSI_GENRE);
DEFINE_SCID(SCID_MUSIC_Lyrics , PSGUID_MUSIC , PIDSI_LYRICS);
DEFINE_SCID(SCID_DRM_Protected , PSGUID_DRM , PIDDRSI_PROTECTED);
DEFINE_SCID(SCID_DRM_Description , PSGUID_DRM , PIDDRSI_DESCRIPTION);
DEFINE_SCID(SCID_DRM_PlayCount , PSGUID_DRM , PIDDRSI_PLAYCOUNT);
DEFINE_SCID(SCID_DRM_PlayStarts , PSGUID_DRM , PIDDRSI_PLAYSTARTS);
DEFINE_SCID(SCID_DRM_PlayExpires , PSGUID_DRM , PIDDRSI_PLAYEXPIRES);
DEFINE_SCID(SCID_AUDIO_Duration , PSGUID_AUDIO , PIDASI_TIMELENGTH); //100ns units, not milliseconds. VT_UI8, not VT_UI4
DEFINE_SCID(SCID_AUDIO_Bitrate , PSGUID_AUDIO , PIDASI_AVG_DATA_RATE); // bits per second
DEFINE_SCID(SCID_AUDIO_SampleRate , PSGUID_AUDIO , PIDASI_SAMPLE_RATE); // samples per second
DEFINE_SCID(SCID_AUDIO_SampleSize , PSGUID_AUDIO , PIDASI_SAMPLE_SIZE); // bits per sample
DEFINE_SCID(SCID_AUDIO_ChannelCount , PSGUID_AUDIO , PIDASI_CHANNEL_COUNT); // 1 (mono), 2(stero)
DEFINE_SCID(SCID_AUDIO_Format , PSGUID_AUDIO , PIDASI_FORMAT);
DEFINE_SCID(SCID_VIDEO_Bitrate , PSGUID_VIDEO , PIDVSI_DATA_RATE); // bits per second
DEFINE_SCID(SCID_VIDEO_FrameRate , PSGUID_VIDEO , PIDVSI_FRAME_RATE); // frames per 1000s
DEFINE_SCID(SCID_VIDEO_SampleSize , PSGUID_VIDEO , PIDVSI_SAMPLE_SIZE); // bits
DEFINE_SCID(SCID_VIDEO_Compression , PSGUID_VIDEO , PIDVSI_COMPRESSION);
DEFINE_SCID(SCID_VIDEO_StreamName , PSGUID_VIDEO , PIDVSI_STREAM_NAME);
DEFINE_SCID(SCID_FileType , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_FILETYPE);
DEFINE_SCID(SCID_ImageCX , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_CX);
DEFINE_SCID(SCID_ImageCY , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_CY);
DEFINE_SCID(SCID_ResolutionX , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_RESOLUTIONX);
DEFINE_SCID(SCID_ResolutionY , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_RESOLUTIONY);
DEFINE_SCID(SCID_BitDepth , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_BITDEPTH);
DEFINE_SCID(SCID_Colorspace , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_COLORSPACE);
DEFINE_SCID(SCID_Compression , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_COMPRESSION);
DEFINE_SCID(SCID_Transparency , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_TRANSPARENCY);
DEFINE_SCID(SCID_GammaValue , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_GAMMAVALUE);
DEFINE_SCID(SCID_FrameCount , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_FRAMECOUNT);
DEFINE_SCID(SCID_ImageDimensions , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_DIMENSIONS);
DEFINE_SCID(SCID_CameraModel , PSGUID_IMAGEPROPERTIES , PropertyTagEquipModel);
DEFINE_SCID(SCID_TagCopyright , PSGUID_IMAGEPROPERTIES , PropertyTagCopyright);
DEFINE_SCID(SCID_TagSoftwareUsed , PSGUID_IMAGEPROPERTIES , PropertyTagSoftwareUsed);
DEFINE_SCID(SCID_WhenTaken , PSGUID_IMAGEPROPERTIES , PropertyTagExifDTOrig);
DEFINE_SCID(SCID_Flash , PSGUID_IMAGEPROPERTIES , PropertyTagExifFlash);
DEFINE_SCID(SCID_ColorSpace , PSGUID_IMAGEPROPERTIES , PropertyTagExifColorSpace);
DEFINE_SCID(SCID_ShutterSpeed , PSGUID_IMAGEPROPERTIES , PropertyTagExifShutterSpeed);
DEFINE_SCID(SCID_Aperture , PSGUID_IMAGEPROPERTIES , PropertyTagExifAperture);
DEFINE_SCID(SCID_SubjectDist , PSGUID_IMAGEPROPERTIES , PropertyTagExifSubjectDist);
DEFINE_SCID(SCID_FocalLength , PSGUID_IMAGEPROPERTIES , PropertyTagExifFocalLength);
DEFINE_SCID(SCID_FNumber , PSGUID_IMAGEPROPERTIES , PropertyTagExifFNumber);
DEFINE_SCID(SCID_ExposureTime , PSGUID_IMAGEPROPERTIES , PropertyTagExifExposureTime);
DEFINE_SCID(SCID_FlashEnergy , PSGUID_IMAGEPROPERTIES , PropertyTagExifFlashEnergy);
DEFINE_SCID(SCID_ISOSpeed , PSGUID_IMAGEPROPERTIES , PropertyTagExifISOSpeed);
DEFINE_SCID(SCID_MeteringMode , PSGUID_IMAGEPROPERTIES , PropertyTagExifMeteringMode);
DEFINE_SCID(SCID_LightSource , PSGUID_IMAGEPROPERTIES , PropertyTagExifLightSource);
DEFINE_SCID(SCID_ExposureProg , PSGUID_IMAGEPROPERTIES , PropertyTagExifExposureProg);
DEFINE_SCID(SCID_ExposureBias , PSGUID_IMAGEPROPERTIES , PropertyTagExifExposureBias);
DEFINE_SCID(SCID_FaxEndTime , PSGUID_IMAGEPROPERTIES , TIFFTAG_FAX_END_TIME);
DEFINE_SCID(SCID_FaxSenderName , PSGUID_IMAGEPROPERTIES , TIFFTAG_SENDER_NAME);
DEFINE_SCID(SCID_FaxTSID , PSGUID_IMAGEPROPERTIES , TIFFTAG_TSID);
DEFINE_SCID(SCID_FaxCallerId , PSGUID_IMAGEPROPERTIES , TIFFTAG_CALLERID);
DEFINE_SCID(SCID_FaxRecipName , PSGUID_IMAGEPROPERTIES , TIFFTAG_RECIP_NAME);
DEFINE_SCID(SCID_FaxRecipNumber , PSGUID_IMAGEPROPERTIES , TIFFTAG_RECIP_NUMBER);
DEFINE_SCID(SCID_FaxCSID , PSGUID_IMAGEPROPERTIES , TIFFTAG_CSID);
DEFINE_SCID(SCID_FaxRouting , PSGUID_IMAGEPROPERTIES , TIFFTAG_ROUTING);
DEFINE_SCID(SCID_TagEquipMake , PSGUID_IMAGEPROPERTIES , PropertyTagEquipMake);
DEFINE_SCID(SCID_Media_SequenceNumber , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_SEQUENCE_NO);
DEFINE_SCID(SCID_Media_Owner , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_OWNER);
DEFINE_SCID(SCID_Media_Editor , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_EDITOR);
DEFINE_SCID(SCID_Media_Supplier , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_SUPPLIER);
DEFINE_SCID(SCID_Media_Source , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_SOURCE);
DEFINE_SCID(SCID_Media_Copyright , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_COPYRIGHT);
DEFINE_SCID(SCID_Media_Project , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_PROJECT);
DEFINE_SCID(SCID_Media_Status , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_STATUS);
DEFINE_SCID(SCID_Media_Production , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_PRODUCTION);
DEFINE_SCID(SCID_CSC_STATUS , PSGUID_SHARE , PID_SHARE_CSC_STATUS);
DEFINE_SCID(SCID_LINKTARGET , PSGUID_LINK , PID_LINK_TARGET);
DEFINE_SCID(SCID_ATTRIBUTES_DESCRIPTION , PSGUID_PRV_STORAGE , PID_PRV_STG_ATTRIBUTES_DESCRIPTION);
typedef struct
{
LPCWSTR pwszName;
const SHCOLUMNID *pscid;
UINT idDisplayName;
UINT idMnemonicName;
UINT idHelp; // IDH_ values
} PROPUI_INFO;
#define PROPUI_ENTRY_NORES(name, scid) {L ## name, &scid, 0, 0, 0},
#define PROPUI_ENTRY(name, scid, idDisplayName, idMnemonicName, idHelp) {L ## name, &scid, idDisplayName, idMnemonicName, idHelp},
const PROPUI_INFO c_rgPropUIInfo[] =
{
PROPUI_ENTRY("Name" , SCID_NAME , IDS_NAME_COL , IDS_MNEMONIC_NAME_COL , 10114)
PROPUI_ENTRY("Type" , SCID_TYPE , IDS_TYPE_COL , IDS_MNEMONIC_TYPE_COL , 10015)
PROPUI_ENTRY("Size" , SCID_SIZE , IDS_SIZE_COL , IDS_MNEMONIC_SIZE_COL , 10115)
PROPUI_ENTRY("Write" , SCID_WRITETIME , IDS_MODIFIED_COL , IDS_MNEMONIC_MODIFIED_COL , 10016)
PROPUI_ENTRY("Attributes" , SCID_ATTRIBUTES , IDS_ATTRIB_COL , IDS_MNEMONIC_ATTRIB_COL , 10019)
PROPUI_ENTRY("AttributesDescription", SCID_ATTRIBUTES_DESCRIPTION , IDS_ATTRIB_COL , IDS_MNEMONIC_ATTRIB_COL , 10019)
PROPUI_ENTRY("Owner" , SCID_OWNER , IDS_EXCOL_OWNER , IDS_MNEMONIC_EXCOL_OWNER , 10021)
PROPUI_ENTRY("Create" , SCID_CREATETIME , IDS_EXCOL_CREATE , IDS_MNEMONIC_EXCOL_CREATE , 10017)
PROPUI_ENTRY("Access" , SCID_ACCESSTIME , IDS_EXCOL_ACCESSTIME , IDS_MNEMONIC_EXCOL_ACCESSTIME , 10018)
PROPUI_ENTRY("DocCreatedTm" , SCID_DocCreated , IDS_EXCOL_CREATE , IDS_MNEMONIC_EXCOL_CREATE , 10068)
PROPUI_ENTRY("DocTitle" , SCID_Title , IDS_EXCOL_TITLE , IDS_MNEMONIC_EXCOL_TITLE , 10023)
PROPUI_ENTRY("DocSubject" , SCID_Subject , IDS_EXCOL_SUBJECT , IDS_MNEMONIC_EXCOL_SUBJECT , 10024)
PROPUI_ENTRY("DocAuthor" , SCID_Author , IDS_EXCOL_AUTHOR , IDS_MNEMONIC_EXCOL_AUTHOR , 10022)
PROPUI_ENTRY("DocLastAuthor" , SCID_LastAuthor , IDS_EXCOL_LASTAUTHOR , IDS_MNEMONIC_EXCOL_LASTAUTHOR , 20010)
PROPUI_ENTRY("DocRevNumber" , SCID_RevNumber , IDS_EXCOL_REVNUMBER , IDS_MNEMONIC_EXCOL_REVNUMBER , 20011)
PROPUI_ENTRY("DocAppName" , SCID_AppName , IDS_EXCOL_APPNAME , IDS_MNEMONIC_EXCOL_APPNAME , 20012)
PROPUI_ENTRY("DocPageCount" , SCID_PageCount , IDS_EXCOL_PAGECOUNT , IDS_MNEMONIC_EXCOL_PAGECOUNT , 10026)
PROPUI_ENTRY("DocComments" , SCID_Comment , IDS_EXCOL_COMMENT , IDS_MNEMONIC_EXCOL_COMMENT , 10020)
PROPUI_ENTRY("Copyright" , SCID_Copyright , IDS_EXCOL_COPYRIGHT , IDS_MNEMONIC_EXCOL_COPYRIGHT , 10027)
PROPUI_ENTRY("DocCategory" , SCID_Category , IDS_EXCOL_CATEGORY , IDS_MNEMONIC_EXCOL_CATEGORY , 10025)
PROPUI_ENTRY("DocKeywords" , SCID_Keywords , IDS_EXCOL_KEYWORDS , IDS_MNEMONIC_EXCOL_KEYWORDS , 20013)
PROPUI_ENTRY("Rating" , SCID_Rating , IDS_EXCOL_RATING , IDS_MNEMONIC_EXCOL_RATING , 20014)
PROPUI_ENTRY("DocTemplate" , SCID_Template , IDS_EXCOL_TEMPLATEPROP , IDS_MNEMONIC_EXCOL_TEMPLATE , 20015)
PROPUI_ENTRY("DocWordCount" , SCID_WordCount , IDS_EXCOL_WORDCOUNT , IDS_MNEMONIC_EXCOL_WORDCOUNT , 20016)
PROPUI_ENTRY("DocCharCount" , SCID_CharCount , IDS_EXCOL_CHARCOUNT , IDS_MNEMONIC_EXCOL_CHARCOUNT , 20017)
PROPUI_ENTRY("DocLastSavedTm" , SCID_LastSaveDTM , IDS_EXCOL_LASTSAVEDTM , IDS_MNEMONIC_EXCOL_LASTSAVEDTM , 20018)
PROPUI_ENTRY("DocLastPrinted" , SCID_LastPrinted , IDS_EXCOL_LASTPRINTED , IDS_MNEMONIC_EXCOL_LASTPRINTED , 20019)
PROPUI_ENTRY("DocEditTime" , SCID_EditTime , IDS_EXCOL_EDITTIME , IDS_MNEMONIC_EXCOL_EDITTIME , 20020)
PROPUI_ENTRY("DocByteCount" , SCID_ByteCount , IDS_EXCOL_BYTECOUNT , IDS_MNEMONIC_EXCOL_BYTECOUNT , 20021)
PROPUI_ENTRY("DocLineCount" , SCID_LineCount , IDS_EXCOL_LINECOUNT , IDS_MNEMONIC_EXCOL_LINECOUNT , 20022)
PROPUI_ENTRY("DocParaCount" , SCID_ParagraphCount , IDS_EXCOL_PARCOUNT , IDS_MNEMONIC_EXCOL_PARCOUNT , 20023)
PROPUI_ENTRY("DocSlideCount" , SCID_SlideCount , IDS_EXCOL_SLIDECOUNT , IDS_MNEMONIC_EXCOL_SLIDECOUNT , 20024)
PROPUI_ENTRY("DocNoteCount" , SCID_NoteCount , IDS_EXCOL_NOTECOUNT , IDS_MNEMONIC_EXCOL_NOTECOUNT , 20025)
PROPUI_ENTRY("DocHiddenCount" , SCID_HiddenCount , IDS_EXCOL_HIDDENCOUNT , IDS_MNEMONIC_EXCOL_HIDDENCOUNT , 20026)
PROPUI_ENTRY("MMClipCount" , SCID_MMClipCount , IDS_EXCOL_MMCLIPCOUNT , IDS_MNEMONIC_EXCOL_MMCLIPCOUNT , 20027)
PROPUI_ENTRY("Scale" , SCID_Scale , IDS_EXCOL_SCALE , IDS_MNEMONIC_EXCOL_SCALE , 20028)
PROPUI_ENTRY("LinksUpToDate" , SCID_LinksDirty , IDS_EXCOL_LINKSDIRTY , IDS_MNEMONIC_EXCOL_LINKSDIRTY , 20029)
PROPUI_ENTRY("CameraModel" , SCID_CameraModel , IDS_EXCOL_CAMERAMODEL , IDS_MNEMONIC_EXCOL_CAMERAMODEL , 10037)
PROPUI_ENTRY("Copyright" , SCID_TagCopyright , IDS_EXCOL_COPYRIGHT , IDS_MNEMONIC_EXCOL_COPYRIGHT , 20030)
PROPUI_ENTRY("Software" , SCID_TagSoftwareUsed , IDS_EXCOL_SOFTWARE , IDS_MNEMONIC_EXCOL_SOFTWARE , 20031)
PROPUI_ENTRY("WhenTaken" , SCID_WhenTaken , IDS_EXCOL_WHENTAKEN , IDS_MNEMONIC_EXCOL_WHENTAKEN , 10038)
PROPUI_ENTRY("FileType" , SCID_FileType , IDS_EXCOL_FILETYPE , IDS_MNEMONIC_EXCOL_FILETYPE , 20032)
PROPUI_ENTRY("ImageX" , SCID_ImageCX , IDS_EXCOL_IMAGECX , IDS_MNEMONIC_EXCOL_IMAGECX , 20033)
PROPUI_ENTRY("ImageY" , SCID_ImageCY , IDS_EXCOL_IMAGECY , IDS_MNEMONIC_EXCOL_IMAGECY , 20034)
PROPUI_ENTRY("ResolutionX" , SCID_ResolutionX , IDS_EXCOL_RESOLUTIONX , IDS_MNEMONIC_EXCOL_RESOLUTIONX , 20035)
PROPUI_ENTRY("ResolutionY" , SCID_ResolutionY , IDS_EXCOL_RESOLUTIONY , IDS_MNEMONIC_EXCOL_RESOLUTIONY , 20036)
PROPUI_ENTRY("BitDepth" , SCID_BitDepth , IDS_EXCOL_BITDEPTH , IDS_MNEMONIC_EXCOL_BITDEPTH , 20037)
PROPUI_ENTRY("ColorSpace" , SCID_ColorSpace , IDS_EXCOL_COLORSPACE , IDS_MNEMONIC_EXCOL_COLORSPACE , 20038)
PROPUI_ENTRY("ColorSpace" , SCID_Colorspace , IDS_EXCOL_COLORSPACE , IDS_MNEMONIC_EXCOL_COLORSPACE , 20038)
PROPUI_ENTRY("Compression" , SCID_Compression , IDS_EXCOL_ACOMPRESSION , IDS_MNEMONIC_EXCOL_ACOMPRESSION , 20039)
PROPUI_ENTRY("Transparency" , SCID_Transparency , IDS_EXCOL_TRANSPARENCY , IDS_MNEMONIC_EXCOL_TRANSPARENCY , 20040)
PROPUI_ENTRY("Gamma" , SCID_GammaValue , IDS_EXCOL_GAMMAVALUE , IDS_MNEMONIC_EXCOL_GAMMAVALUE , 20041)
PROPUI_ENTRY("FrameCount" , SCID_FrameCount , IDS_EXCOL_FRAMECOUNT , IDS_MNEMONIC_EXCOL_FRAMECOUNT , 10046)
PROPUI_ENTRY("Dimensions" , SCID_ImageDimensions , IDS_EXCOL_DIMENSIONS , IDS_MNEMONIC_EXCOL_DIMENSIONS , 10059)
PROPUI_ENTRY("Flash" , SCID_Flash , IDS_EXCOL_FLASH , IDS_MNEMONIC_EXCOL_FLASH , 20042)
PROPUI_ENTRY("ShutterSpeed" , SCID_ShutterSpeed , IDS_EXCOL_SHUTTERSPEED , IDS_NMEMONIC_EXCOL_SHUTTERSPEED , 20043)
PROPUI_ENTRY("Aperture" , SCID_Aperture , IDS_EXCOL_APERTURE , IDS_NMEMONIC_EXCOL_APERTURE , 20044)
PROPUI_ENTRY("Distance" , SCID_SubjectDist , IDS_EXCOL_DISTANCE , IDS_NMEMONIC_EXCOL_DISTANCE , 20046)
PROPUI_ENTRY("FocalLength" , SCID_FocalLength , IDS_EXCOL_FOCALLENGTH , IDS_MNEMONIC_EXCOL_FOCALLENGTH , 20047)
PROPUI_ENTRY("FNumber" , SCID_FNumber , IDS_EXCOL_FNUMBER , IDS_MNEMONIC_EXCOL_FNUMBER , 20049)
PROPUI_ENTRY("ExposureTime" , SCID_ExposureTime , IDS_EXCOL_EXPOSURETIME , IDS_MNEMONIC_EXCOL_EXPOSURETIME , 20049)
PROPUI_ENTRY("FlashEnergy" , SCID_FlashEnergy ,IDS_EXCOL_FLASHENERGY , IDS_MNEMONIC_EXCOL_FLASHENERGY , 20080)
PROPUI_ENTRY("ISOSpeed" , SCID_ISOSpeed ,IDS_EXCOL_ISOSPEED , IDS_MNEMONIC_EXCOL_ISOSPEED , 20081)
PROPUI_ENTRY("MeteringMode" , SCID_MeteringMode ,IDS_EXCOL_METERINGMODE , IDS_MNEMONIC_EXCOL_METERINGMODE , 20082)
PROPUI_ENTRY("LightSource" , SCID_LightSource ,IDS_EXCOL_LIGHTSOURCE , IDS_MNEMONIC_EXCOL_LIGHTSOURCE , 20083)
PROPUI_ENTRY("ExposureProg" , SCID_ExposureProg ,IDS_EXCOL_EXPOSUREPROG , IDS_MNEMONIC_EXCOL_EXPOSUREPROG , 20084)
PROPUI_ENTRY("ExposureBias" , SCID_ExposureBias ,IDS_EXCOL_EXPOSUREBIAS , IDS_MNEMONIC_EXCOL_EXPOSUREBIAS , 20085)
PROPUI_ENTRY("Artist" , SCID_MUSIC_Artist , IDS_EXCOL_ARTIST , IDS_MNEMONIC_EXCOL_ARTIST , 10028)
PROPUI_ENTRY("Album" , SCID_MUSIC_Album , IDS_EXCOL_ALBUM , IDS_MNEMONIC_EXCOL_ALBUM , 10029)
PROPUI_ENTRY("Year" , SCID_MUSIC_Year , IDS_EXCOL_YEAR , IDS_MNEMONIC_EXCOL_YEAR , 10030)
PROPUI_ENTRY("Track" , SCID_MUSIC_Track , IDS_EXCOL_TRACK , IDS_MNEMONIC_EXCOL_TRACK , 10031)
PROPUI_ENTRY("Duration" , SCID_AUDIO_Duration , IDS_EXCOL_DURATION , IDS_MNEMONIC_EXCOL_DURATION , 10032)
PROPUI_ENTRY("Bitrate" , SCID_AUDIO_Bitrate , IDS_EXCOL_BITRATE , IDS_MNEMONIC_EXCOL_BITRATE , 10033)
PROPUI_ENTRY("Sample Rate" , SCID_AUDIO_SampleRate , IDS_EXCOL_SAMPLERATE , IDS_MNEMONIC_EXCOL_SAMPLERATE , 20050)
PROPUI_ENTRY("Audio Sample Size" , SCID_AUDIO_SampleSize , IDS_EXCOL_ASAMPLESIZE , IDS_MNEMONIC_EXCOL_ASAMPLESIZE , 10041)
PROPUI_ENTRY("Channels" , SCID_AUDIO_ChannelCount , IDS_EXCOL_CHANNELS , IDS_MNEMONIC_EXCOL_CHANNELS , 10047)
PROPUI_ENTRY("Audio Format" , SCID_AUDIO_Format , IDS_EXCOL_FORMAT , IDS_MNEMONIC_EXCOL_FORMAT , 10039)
PROPUI_ENTRY("Data Rate" , SCID_VIDEO_Bitrate , IDS_EXCOL_DATARATE , IDS_MNEMONIC_EXCOL_DATARATE , 20050)
PROPUI_ENTRY("Frame Rate" , SCID_VIDEO_FrameRate , IDS_EXCOL_FRAMERATE , IDS_MNEMONIC_EXCOL_FRAMERATE , 10045)
PROPUI_ENTRY("Video Sample Size" , SCID_VIDEO_SampleSize , IDS_EXCOL_VSAMPLESIZE , IDS_MNEMONIC_EXCOL_VSAMPLESIZE , 10044)
PROPUI_ENTRY("Compression" , SCID_VIDEO_Compression , IDS_EXCOL_VCOMPRESSION , IDS_MNEMONIC_EXCOL_VCOMPRESSION , 10043)
PROPUI_ENTRY("Stream Name" , SCID_VIDEO_StreamName , IDS_EXCOL_STREAMNAME , IDS_MNEMONIC_EXCOL_STREAMNAME , 20051)
PROPUI_ENTRY("Genre" , SCID_MUSIC_Genre , IDS_EXCOL_GENRE , IDS_MNEMONIC_EXCOL_GENRE , 20052)
PROPUI_ENTRY("Lyrics" , SCID_MUSIC_Lyrics , IDS_EXCOL_LYRICS , IDS_EXCOL_LYRICS , 0)
PROPUI_ENTRY("Protected" , SCID_DRM_Protected , IDS_EXCOL_PROTECTED , IDS_MNEMONIC_EXCOL_PROTECTED , 20074)
PROPUI_ENTRY("DRM Description" , SCID_DRM_Description , IDS_EXCOL_DRMDESCRIPTION , IDS_MNEMONIC_EXCOL_DRMDESCRIPTION , 20075)
PROPUI_ENTRY("Play Count" , SCID_DRM_PlayCount , IDS_EXCOL_PLAYCOUNT , IDS_MNEMONIC_EXCOL_PLAYCOUNT , 20076)
PROPUI_ENTRY("Play Starts" , SCID_DRM_PlayStarts , IDS_EXCOL_PLAYSTARTS , IDS_MNEMONIC_EXCOL_PLAYSTARTS , 20077)
PROPUI_ENTRY("Play Expires" , SCID_DRM_PlayExpires , IDS_EXCOL_PLAYEXPIRES , IDS_MNEMONIC_EXCOL_PLAYEXPIRES , 20078)
PROPUI_ENTRY("FaxTime" , SCID_FaxEndTime , IDS_EXCOL_FAXENDTIME , IDS_MNEMONIC_EXCOL_FAXENDTIME , 20053)
PROPUI_ENTRY("FaxSenderName" , SCID_FaxSenderName , IDS_EXCOL_FAXSENDERNAME , IDS_MNEMONIC_EXCOL_FAXSENDERNAME , 20054)
PROPUI_ENTRY("FaxTSID" , SCID_FaxTSID , IDS_EXCOL_FAXTSID , IDS_MNEMONIC_EXCOL_FAXTSID , 20055)
PROPUI_ENTRY("FaxCallerID" , SCID_FaxCallerId , IDS_EXCOL_FAXCALLERID , IDS_MNEMONIC_EXCOL_FAXCALLERID , 20056)
PROPUI_ENTRY("FaxRecipientName" , SCID_FaxRecipName , IDS_EXCOL_FAXRECIPNAME , IDS_MNEMONIC_EXCOL_FAXRECIPNAME , 20057)
PROPUI_ENTRY("FaxRecipientNumber" , SCID_FaxRecipNumber , IDS_EXCOL_FAXRECIPNUMBER , IDS_MNEMONIC_EXCOL_FAXRECIPNUMBER , 20058)
PROPUI_ENTRY("FaxCSID" , SCID_FaxCSID , IDS_EXCOL_FAXCSID , IDS_MNEMONIC_EXCOL_FAXCSID , 20059)
PROPUI_ENTRY("FaxRouting" , SCID_FaxRouting , IDS_EXCOL_FAXROUTING , IDS_MNEMONIC_EXCOL_FAXROUTING , 20060)
PROPUI_ENTRY("EquipMake" , SCID_TagEquipMake , IDS_EXCOL_TAGEQUIPMAKE , IDS_MNEMONIC_EXCOL_TAGEQUIPMAKE , 20061)
PROPUI_ENTRY("SequenceNo" , SCID_Media_SequenceNumber , IDS_EXCOL_SEQUENCENUMBER , IDS_MNEMONIC_EXCOL_SEQUENCENUMBER , 20062)
PROPUI_ENTRY("Owner" , SCID_Media_Owner , IDS_EXCOL_OWNER , IDS_MNEMONIC_EXCOL_OWNER , 20063)
PROPUI_ENTRY("Editor" , SCID_Media_Editor , IDS_EXCOL_EDITOR , IDS_MNEMONIC_EXCOL_EDITOR , 20064)
PROPUI_ENTRY("Supplier" , SCID_Media_Supplier , IDS_EXCOL_SUPPLIER , IDS_MNEMONIC_EXCOL_SUPPLIER , 20065)
PROPUI_ENTRY("Source" , SCID_Media_Source , IDS_EXCOL_SOURCE , IDS_MNEMONIC_EXCOL_SOURCE , 20066)
PROPUI_ENTRY("Copyright" , SCID_Media_Copyright , IDS_EXCOL_COPYRIGHT , IDS_MNEMONIC_EXCOL_COPYRIGHT , 20067)
PROPUI_ENTRY("Project" , SCID_Media_Project , IDS_EXCOL_PROJECT , IDS_MNEMONIC_EXCOL_PROJECT , 20068)
PROPUI_ENTRY("Status" , SCID_Media_Status , IDS_EXCOL_STATUS , IDS_MNEMONIC_EXCOL_STATUS , 20069)
PROPUI_ENTRY("Production" , SCID_Media_Production , IDS_EXCOL_PRODUCTION , IDS_MNEMONIC_EXCOL_PRODUCTION , 20070)
PROPUI_ENTRY("Company" , SCID_CompanyName , IDS_VN_COMPANYNAME , IDS_MNEMONIC_VN_COMPANYNAME , 10034)
PROPUI_ENTRY("Manager" , SCID_Manager , IDS_EXCOL_MANAGER , IDS_MNEMONIC_EXCOL_MANAGER , 20071)
PROPUI_ENTRY("PresentationTarget" , SCID_PresFormat , IDS_EXCOL_PRESFORMAT , IDS_MNEMONIC_EXCOL_PRESFORMAT , 20072)
PROPUI_ENTRY("FileDescription" , SCID_FileDescription , IDS_VN_FILEDESCRIPTION , IDS_MNEMONIC_VN_FILEDESCRIPTION , 10056)
PROPUI_ENTRY("FileVersion" , SCID_FileVersion , IDS_VN_FILEVERSION , IDS_MNEMONIC_VN_FILEVERSION , 10057)
PROPUI_ENTRY("ProductName" , SCID_ProductName , IDS_VN_PRODUCTNAME , IDS_MNEMONIC_VN_PRODUCTNAME , 10035)
PROPUI_ENTRY("ProductVersion" , SCID_ProductVersion , IDS_VN_PRODUCTVERSION , IDS_MNEMONIC_VN_PRODUCTVERSION , 10036)
PROPUI_ENTRY("DeletedFrom" , SCID_DELETEDFROM , IDS_DELETEDFROM_COL , IDS_MNEMONIC_DELETEDFROM_COL , 10048)
PROPUI_ENTRY("DateDeleted" , SCID_DATEDELETED , IDS_DATEDELETED_COL , IDS_MNEMONIC_DATEDELETED_COL , 10049)
PROPUI_ENTRY("SyncCopyIn" , SCID_SYNCCOPYIN , IDS_SYNCCOPYIN_COL , IDS_MNEMONIC_SYNCCOPYIN_COL , 10060)
PROPUI_ENTRY("Status" , SCID_STATUS , IDS_STATUS_COL , IDS_MNEMONIC_STATUS_COL , 0) // do we need help for this? What is it?
PROPUI_ENTRY("FreeSpace" , SCID_FREESPACE , IDS_DRIVES_FREE , IDS_MNEMONIC_DRIVES_FREE , 10051)
PROPUI_ENTRY("Capacity" , SCID_CAPACITY , IDS_DRIVES_CAPACITY , IDS_MNEMONIC_DRIVES_CAPACITY , 10050)
PROPUI_ENTRY("FileSystem" , SCID_FILESYSTEM , IDS_DRIVES_FILESYSTEM , IDS_MNEMONIC_DRIVES_FILESYSTEM , 10062)
PROPUI_ENTRY("" , SCID_PRN_QUEUESIZE , IDS_PSD_QUEUESIZE , IDS_MNEMONIC_PSD_QUEUESIZE , 10063)
PROPUI_ENTRY("" , SCID_PRN_LOCATION , IDS_PSD_LOCATION , IDS_MNEMONIC_PSD_LOCATION , 10064)
PROPUI_ENTRY("" , SCID_PRN_MODEL , IDS_PSD_MODEL , IDS_MNEMONIC_PSD_MODEL , 10066)
PROPUI_ENTRY("" , SCID_PRN_STATUS , IDS_PRQ_STATUS , IDS_MNEMONIC_PRQ_STATUS , 10065)
PROPUI_ENTRY("Directory" , SCID_DIRECTORY , IDS_PATH_COL , IDS_MNEMONIC_PATH_COL , 10053)
PROPUI_ENTRY("Rank" , SCID_RANK , IDS_RANK_COL , IDS_MNEMONIC_RANK_COL , 10054)
PROPUI_ENTRY("" , SCID_WHICHFOLDER , IDS_WHICHFOLDER_COL , IDS_MNEMONIC_WHICHFOLDER_COL , 10067)
PROPUI_ENTRY("CSCStatus" , SCID_CSC_STATUS , IDS_CSC_STATUS , IDS_MNEMONIC_CSC_STATUS , 20073)
PROPUI_ENTRY_NORES("LinkTarget" , SCID_LINKTARGET)
};
// String resource mapping block
struct STRING_MAP
{
ULONG uVal;
UINT idStr;
};
static const STRING_MAP g_cLightSourceStrings[] =
{
{ 1, IDS_PROPERTYUI_IMAGE_DAYLIGHT},
{ 2, IDS_PROPERTYUI_IMAGE_FLOURESCENT},
{ 3, IDS_PROPERTYUI_IMAGE_TUNGSTEN},
{17, IDS_PROPERTYUI_IMAGE_STANDARDA},
{18, IDS_PROPERTYUI_IMAGE_STANDARDB},
{19, IDS_PROPERTYUI_IMAGE_STANDARDC},
{20, IDS_PROPERTYUI_IMAGE_D55},
{21, IDS_PROPERTYUI_IMAGE_D65},
{22, IDS_PROPERTYUI_IMAGE_D75},
{ 0, IDS_PROPERTYUI_IMAGE_UNKNOWN}, // Last entry is default
};
static const STRING_MAP g_cExposureProgStrings[] =
{
{1, IDS_PROPERTYUI_IMAGE_MANUAL},
{2, IDS_PROPERTYUI_IMAGE_NORMAL},
{3, IDS_PROPERTYUI_IMAGE_APERTUREPRI},
{4, IDS_PROPERTYUI_IMAGE_SHUTTERPRI},
{5, IDS_PROPERTYUI_IMAGE_CREATIVE},
{6, IDS_PROPERTYUI_IMAGE_ACTION},
{7, IDS_PROPERTYUI_IMAGE_PORTRAIT},
{8, IDS_PROPERTYUI_IMAGE_LANDSCAPE},
{0, IDS_PROPERTYUI_IMAGE_UNKNOWN}, // Last entry is default
};
static const STRING_MAP g_cMeteringModeStrings[] =
{
{1, IDS_PROPERTYUI_IMAGE_AVERAGE},
{2, IDS_PROPERTYUI_IMAGE_CWA},
{3, IDS_PROPERTYUI_IMAGE_SPOT},
{4, IDS_PROPERTYUI_IMAGE_MULTISPOT},
{5, IDS_PROPERTYUI_IMAGE_PATTERN},
{6, IDS_PROPERTYUI_IMAGE_PARTIAL},
{0, IDS_PROPERTYUI_IMAGE_UNKNOWN}, // Last entry is default
};
static const STRING_MAP g_cFlashStrings[] =
{
{0, IDS_PROPERTYUI_IMAGE_NOFLASH},
{1, IDS_PROPERTYUI_IMAGE_FLASHFIRED},
{5, IDS_PROPERTYUI_IMAGE_NOSTROBERETURN},
{7, IDS_PROPERTYUI_IMAGE_STROBERETURN},
{0, 0},
};
static const STRING_MAP g_cColorStrings[] =
{
{1, IDS_PROPERTYUI_IMAGE_SRGB},
{0xffff, IDS_PROPERTYUI_IMAGE_UNCALIBRATED},
{0,0},
};
static const STRING_MAP g_cMediaStatus[] =
{
{ PIDMSI_STATUS_NORMAL , IDS_STATUSVAL_NORMAL },
{ PIDMSI_STATUS_NEW , IDS_STATUSVAL_NEW },
{ PIDMSI_STATUS_PRELIM , IDS_STATUSVAL_PRELIM },
{ PIDMSI_STATUS_DRAFT , IDS_STATUSVAL_DRAFT },
{ PIDMSI_STATUS_EDIT , IDS_STATUSVAL_EDIT },
{ PIDMSI_STATUS_INPROGRESS , IDS_STATUSVAL_INPROGRESS },
{ PIDMSI_STATUS_REVIEW , IDS_STATUSVAL_REVIEW },
{ PIDMSI_STATUS_PROOF , IDS_STATUSVAL_PROOF },
{ PIDMSI_STATUS_FINAL , IDS_STATUSVAL_FINAL },
{ PIDMSI_STATUS_OTHER , IDS_STATUSVAL_OTHER },
{ 0,0 }
};
STDAPI SCIDCannonicalName(SHCOLUMNID *pscid, LPTSTR pszName, int cch)
{
HRESULT hr = E_FAIL;
pszName[0] = 0;
for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
{
if (IsEqualSCID(*pscid, *c_rgPropUIInfo[i].pscid))
{
SHUnicodeToTChar(c_rgPropUIInfo[i].pwszName, pszName, cch);
hr = S_OK;
break;
}
}
return hr;
}
LPCTSTR TrimLeadingWhiteSpaces(LPCTSTR pszString)
{
LPCTSTR psz = pszString;
while (psz && ((*psz == TEXT(' ')) || (*psz == TEXT('\n')) || (*psz == TEXT('\t'))))
{
psz++;
}
return psz;
}
STDAPI_(BOOL) ParseSCIDString(LPCTSTR pszString, SHCOLUMNID *pscid, UINT *pidRes)
{
BOOL bRet = FALSE;
if (GUIDFromString(pszString, &pscid->fmtid))
{
// GUIDSTR_MAX includes space for the terminating NULL
LPCTSTR pszPid = &pszString[GUIDSTR_MAX - 1];
// Skip past any leading white space
pszPid = TrimLeadingWhiteSpaces(pszPid);
pscid->pid = StrToInt(pszPid);
bRet = TRUE;
if (pidRes)
*pidRes = 0;
}
else
{
WCHAR szName[64];
SHTCharToUnicode(pszString, szName, ARRAYSIZE(szName));
for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
{
if (StrCmpIW(szName, c_rgPropUIInfo[i].pwszName) == 0)
{
*pscid = *c_rgPropUIInfo[i].pscid;
if (pidRes)
*pidRes = c_rgPropUIInfo[i].idDisplayName;
bRet = TRUE;
break;
}
}
}
return bRet;
}
//
// Function converts a SCID into a string.
// The string format is "{scid.fmtid} scid.pid" (There is a space in between)
// So for example, SCID_Category will yield the following string -
// "{d5cdd502-2e9c-101b-9397-08002b2cf9ae} 2"
//
// See ParseSCIDString() above for the the complimentary function.
// Also see CFolderItem::ExtendedProperty() in sdflditm.cpp if you are curious
// as to where is ParseSCIDString() used and see CtrlFldr.cpp and RegFldr.cpp for
// usage of StringFromSCID().
//
STDAPI_(int) StringFromSCID(const SHCOLUMNID *pscid, LPTSTR psz, UINT cch)
{
TCHAR ach[GUIDSTR_MAX];
if (0 != SHStringFromGUID(pscid->fmtid, ach, ARRAYSIZE(ach)))
{
return wnsprintf(psz, cch, TEXT("%s %d"), ach, pscid->pid);
}
*psz = 0;
return 0;
}
STDAPI MapColumnToSCIDImpl(const COLUMN_INFO* pcol, UINT nCols, UINT iColumn, SHCOLUMNID* pscid)
{
HRESULT hr;
if (iColumn < nCols)
{
*pscid = *pcol[iColumn].pscid;
hr = S_OK;
}
else
{
ZeroMemory(pscid, sizeof(*pscid));
hr = E_INVALIDARG;
}
return hr;
}
STDAPI_(int) FindSCID(const COLUMN_INFO* pcol, UINT nCols, const SHCOLUMNID* pscid)
{
for (UINT i = 0; i < nCols; i++)
{
if (IsEqualSCID(*pscid, *pcol[i].pscid))
return (int)i;
}
return -1;
}
STDAPI GetDetailsOfInfo(const COLUMN_INFO* pcol_data, UINT nCols, UINT iColumn, SHELLDETAILS *pdi)
{
HRESULT hr;
if (iColumn < nCols)
{
pdi->fmt = pcol_data[iColumn].fmt;
pdi->cxChar = pcol_data[iColumn].cChars;
hr = ResToStrRet(pcol_data[iColumn].idTitle, &pdi->str);
}
else
{
hr = E_NOTIMPL; // we don't support his column
}
return hr;
}
// dead export
STDAPI SHStgOpenStorageW(LPCWSTR pwszPath, DWORD grfMode, DWORD grfAttr, DWORD grfFileAttr, REFIID riid, void **ppv)
{
*ppv = NULL;
return E_NOTIMPL;
}
// dead export
STDAPI SHStgOpenStorageA(LPCSTR pwszPath, DWORD grfMode, DWORD grfAttr, DWORD grfFileAttr, REFIID riid, void **ppv)
{
*ppv = NULL;
return E_NOTIMPL;
}
const PROPSPEC codepage_spec = { PRSPEC_PROPID, PID_CODEPAGE } ;
// Retrieves the codepage value from an existing property set storage.
STDAPI SHPropStgReadCP(IPropertyStorage* ppss, UINT* puCodePage)
{
*puCodePage = 0; // CP_ACP == 0, assume failure here
PROPVARIANT varCP;
if (S_OK == ppss->ReadMultiple(1, &codepage_spec, &varCP))
{
if (VT_I2 == varCP.vt)
{
*puCodePage = (UINT)MAKELONG(varCP.iVal, 0);
}
}
return (0 == *puCodePage) ? E_FAIL : S_OK;
}
// Modifies the property set codepage on a new property set storage.
//
// Note: this function will fail if the property set already
// contains properties.
STDAPI SHPropStgWriteCP(IPropertyStorage* ppss, IN UINT uCodePage)
{
PROPVARIANT varCP;
varCP.iVal = (SHORT)uCodePage;
varCP.vt = VT_I2;
return ppss->WriteMultiple(1, &codepage_spec, &varCP, PID_CODEPAGE);
}
// IPropertySetStorage::Open/Create wrapper.
// The wrap properly retrieves/assigns the set's codepage value.
STDAPI SHPropStgCreate(
IPropertySetStorage* psstg, // Address of IPropertySetStorage vtable
REFFMTID fmtid, // property set ID
CLSID* pclsid, // class ID associated with the set. This can be NULL
DWORD grfFlags, // PROPSETFLAG_xxx. All sets containing ansi bytes should be created with
// PROPSETFLAG_ANSI, otherwise PROPSETFLAG_DEFAULT
DWORD grfMode, // STGM_ flags. Must contain STGM_DIRECT|STGM_EXCLUSIVE.
DWORD dwDisposition, // OPEN_EXISTING. OPEN_ALWAYS, CREATE_NEW, CREATE_ALWAYS
OUT IPropertyStorage** ppstg, // Address to receive requested vtable
OUT UINT* puCodePage) // Optional address to receive the code page ID for the set.
{
ASSERT(psstg);
ASSERT(ppstg);
if (puCodePage)
*puCodePage = 0;
*ppstg = NULL;
// Check legacy sets. These MUST be flagged ANSI
if (IsEqualGUID(fmtid, FMTID_SummaryInformation) ||
IsEqualGUID(fmtid, FMTID_DocSummaryInformation) ||
IsEqualGUID(fmtid, FMTID_UserDefinedProperties))
{
grfFlags |= PROPSETFLAG_ANSI; // these legacy sets MUST be ansi.
}
// Attempt opening the set
HRESULT hr = psstg->Open(fmtid, grfMode, ppstg);
if (SUCCEEDED(hr)) // opened the set
{
// If a new set was requested, fail.
if (CREATE_NEW == dwDisposition)
{
(*ppstg)->Release();
*ppstg = NULL;
return STG_E_FILEALREADYEXISTS;
}
// If the request was to overwrite any existing set, delete the current one.
if (CREATE_ALWAYS == dwDisposition)
{
(*ppstg)->Release();
*ppstg = NULL;
if (FAILED((hr = psstg->Delete(fmtid))))
return hr;
hr = STG_E_FILENOTFOUND; // falls through to create
}
}
else // failed to open the set
{
// if an existing set is requested, fail
if (OPEN_EXISTING == dwDisposition)
return hr;
}
if (STG_E_FILENOTFOUND == hr) // set doesn't exist, so create it.
{
hr = psstg->Create(fmtid, pclsid, grfFlags, grfMode, ppstg);
}
// If we haven't assigned a codepage, then read it from PID_CODEPAGE.
if (SUCCEEDED(hr) && puCodePage)
{
ASSERT(*ppstg);
SHPropStgReadCP(*ppstg, puCodePage);
}
return hr;
}
STDAPI_(BOOL) _IsAnsiPropertySet(REFFMTID fmtid);
STDAPI_(BOOL) _DoesStringRoundTripCPW(UINT uCodePage, LPCWSTR pwszIn, LPSTR pszOut, UINT cchOut);
STDAPI _DoLegacyPropertiesRoundTrip(REFFMTID fmtid, UINT uCodePage, ULONG cvar, PROPVARIANT rgvar[]);
STDAPI _UniversalizeSet(IPropertyStorage* pstg, IN OUT UINT* puCodePage, PROPID propidNameFirst);
STDAPI _LegacyPropertiesToUnicode(REFFMTID fmtid, UINT uCodePage, ULONG cpspec, PROPSPEC const rgpspec[], PROPVARIANT rgvar[]);
STDAPI _LegacyPropertiesToAnsi(REFFMTID fmtid, UINT uCodePage, ULONG cpspec, PROPSPEC const rgpspec[], PROPVARIANT rgvar[]);
// IPropertyStorage::ReadMultiple wrap
//
// The wrap ensures ANSI/UNICODE translations are handled properly for
// legacy property sets.
STDAPI SHPropStgReadMultiple(
IPropertyStorage* pps, // address of IPropertyStorage vtable.
UINT uCodePage, // Code page value retrieved from SHCreatePropertySet
ULONG cpspec, // Count of properties being read
PROPSPEC const rgpspec[], // Array of the properties to be read
PROPVARIANT rgvar[]) // Array of PROPVARIANTs containing the
// property values on return
{
// read the requested properties
HRESULT hr = pps->ReadMultiple(cpspec, rgpspec, rgvar);
if (S_OK == hr)
{
HRESULT hrTmp = S_OK;
// grab the set's ANSI codepage if not provided.
if (0 == uCodePage)
{
hrTmp = SHPropStgReadCP(pps, &uCodePage);
}
if (SUCCEEDED(hrTmp))
{
STATPROPSETSTG stat;
if (SUCCEEDED(pps->Stat(&stat)))
{
hr = _LegacyPropertiesToUnicode(stat.fmtid, uCodePage, cpspec, rgpspec, rgvar);
}
}
}
return hr;
}
// IPropertyStorage::WriteMultiple wrap
//
// The wrap ensures ANSI/UNICODE translations are handled properly for
// legacy property sets.
STDAPI SHPropStgWriteMultiple(
IPropertyStorage* pps, // address of IPropertyStorage vtable.
UINT* puCodePage, // code page retrieved from SHCreatePropertySet.
ULONG cpspec, // The number of properties being set
PROPSPEC const rgpspec[], // Property specifiers
PROPVARIANT rgvar[], // Array of PROPVARIANT values
PROPID propidNameFirst) // Minimum value for property identifiers
// when they must be allocated
{
UINT uCodePage = 0;
if (!puCodePage)
puCodePage = &uCodePage;
ASSERT(propidNameFirst >= PID_FIRST_USABLE); // you're walking on OLE PIDs.
STATPROPSETSTG stat;
HRESULT hr = pps->Stat(&stat); // need the FMTID
if (SUCCEEDED(hr))
{
// read in the codepage if it isn't provided.
if (0 == *puCodePage)
{
hr = SHPropStgReadCP(pps, puCodePage);
}
if (SUCCEEDED(hr) )
{
// test for round-trippability
hr = _DoLegacyPropertiesRoundTrip(stat.fmtid, *puCodePage, cpspec, rgvar);
if (SUCCEEDED(hr))
{
if (S_FALSE == hr)
{
hr = _UniversalizeSet(pps, puCodePage, propidNameFirst);
}
if (SUCCEEDED(hr))
{
// convert legacy properties back to ansi
hr = _LegacyPropertiesToAnsi(stat.fmtid, *puCodePage, cpspec, rgpspec, rgvar);
if (SUCCEEDED(hr))
{
// write em.
hr = pps->WriteMultiple(cpspec, rgpspec, rgvar, propidNameFirst);
if (FAILED(hr))
_LegacyPropertiesToUnicode(stat.fmtid, *puCodePage, cpspec, rgpspec, rgvar);
}
}
}
}
}
return hr;
}
// Helper: converts LPWSTR to LPSTR using the indicated codepage and returns
// TRUE if the LPSTR can be converted back to LPWSTR without unacceptible data loss
STDAPI_(BOOL) _DoesStringRoundTripCPW(UINT uCodePage, LPCWSTR pwszIn, LPSTR pszOut, UINT cchOut)
{
BOOL fRet = FALSE;
// if we're being asked to roundtrip UTF8, don't bother test, it'll work.
if (CP_UTF8 == uCodePage)
{
SHUnicodeToAnsiCP(uCodePage, pwszIn, pszOut, cchOut);
fRet = TRUE;
}
else
{
WCHAR wszTemp[MAX_PATH];
LPWSTR pwszTemp = wszTemp;
UINT cchTemp = ARRAYSIZE(wszTemp);
// We better have enough room for the buffer.
if (ARRAYSIZE(wszTemp) < cchOut)
{
pwszTemp = (LPWSTR)LocalAlloc(LPTR, cchOut*sizeof(WCHAR));
cchTemp = cchOut;
}
if (pwszTemp)
{
SHUnicodeToAnsiCP(uCodePage, pwszIn, pszOut, cchOut);
SHAnsiToUnicodeCP(uCodePage, pszOut, pwszTemp, cchTemp);
fRet = StrCmpW(pwszIn, pwszTemp) == 0; // are they the same?
if (pwszTemp != wszTemp)
{
LocalFree(pwszTemp);
}
}
}
return fRet;
}
// Helper: determines whether the specified string properties of the indicate property set
// can round-trip to ansi and back.
// Returns S_OK if all strings can round-trip, S_FALSE if not all strings can round trip,
// or an error code.
STDAPI _DoLegacyPropertiesRoundTrip(
REFFMTID fmtid,
UINT uCodePage,
ULONG cvar,
PROPVARIANT rgvar[])
{
ASSERT(uCodePage);
HRESULT hr = S_OK; // assume all strings round-trip.
if (uCodePage != CP_UTF8 && uCodePage != CP_WINUNICODE && _IsAnsiPropertySet(fmtid))
{
ASSERT (uCodePage != CP_WINUNICODE);
// either the set's creator is whacked, or this is simply an invalid arg.
for (ULONG i = 0; i < cvar && S_OK == hr ; i++)
{
if (rgvar[i].vt == VT_LPWSTR && rgvar[i].pwszVal && *rgvar[i].pwszVal)
{
LPSTR pszVal;
// make plenty of room for UTF-8 conversions. each WCHAR
// can turn into as many as three ANSI chars
int cb = MAX_UTF8_CHAR_SIZE * (lstrlenW(rgvar[i].pwszVal) + 1);
if ((pszVal = new CHAR[cb]) != NULL)
{
// Test round-trip to ANSI and back.
if (!_DoesStringRoundTripCPW(uCodePage, rgvar[i].pwszVal, pszVal, cb))
{
hr = S_FALSE;
}
delete pszVal;
}
else
hr = E_OUTOFMEMORY;
}
}
}
return hr;
}
// Helper: Reports whether the specified FMTID is a legacy ANSI property set.
STDAPI_(BOOL) _IsAnsiPropertySet(REFFMTID fmtid)
{
const FMTID* _ansi_propertysets[] =
{
&FMTID_SummaryInformation,
&FMTID_DocSummaryInformation,
&FMTID_UserDefinedProperties,
};
for (int i = 0; i < ARRAYSIZE(_ansi_propertysets); i++)
{
if (IsEqualGUID(fmtid, *_ansi_propertysets[i]))
return TRUE;
}
return FALSE;
}
// Determine whether the property is a legacy ANSI property, and if so,
// compute a conversion type for the property.
typedef struct {
PROPID propid;
VARTYPE vt;
VARTYPE vtConvert;
} ANSIPROPDEF;
// (public) ansi SummaryInformation properties
const ANSIPROPDEF si_lpstr_pids[] =
{
{ PIDSI_TITLE, VT_LPSTR, VT_LPWSTR },
{ PIDSI_SUBJECT, VT_LPSTR, VT_LPWSTR },
{ PIDSI_AUTHOR, VT_LPSTR, VT_LPWSTR },
{ PIDSI_KEYWORDS, VT_LPSTR, VT_LPWSTR },
{ PIDSI_COMMENTS, VT_LPSTR, VT_LPWSTR },
{ PIDSI_TEMPLATE, VT_LPSTR, VT_LPWSTR },
{ PIDSI_LASTAUTHOR, VT_LPSTR, VT_LPWSTR },
{ PIDSI_REVNUMBER, VT_LPSTR, VT_LPWSTR },
{ PIDSI_APPNAME, VT_LPSTR, VT_LPWSTR },
};
// (public) ansi DocSummaryInformation properties
const ANSIPROPDEF dsi_lpstr_pids[] =
{
{ PIDDSI_CATEGORY, VT_LPSTR, VT_LPWSTR },
{ PIDDSI_PRESFORMAT,VT_LPSTR, VT_LPWSTR },
{ PIDDSI_DOCPARTS, VT_LPSTR|VT_VECTOR, VT_LPWSTR|VT_VECTOR },
{ PIDDSI_MANAGER, VT_LPSTR, VT_LPWSTR },
{ PIDDSI_COMPANY, VT_LPSTR, VT_LPWSTR },
};
STDAPI_(BOOL) SHIsLegacyAnsiProperty(REFFMTID fmtid, PROPID propid, IN OUT OPTIONAL VARTYPE* pvt)
{
const ANSIPROPDEF* rgapd = NULL;
UINT capd = 0;
if (IsEqualGUID(fmtid, FMTID_SummaryInformation))
{
rgapd = si_lpstr_pids;
capd = ARRAYSIZE(si_lpstr_pids);
}
else if (IsEqualGUID(fmtid, FMTID_DocSummaryInformation))
{
rgapd = dsi_lpstr_pids;
capd = ARRAYSIZE(dsi_lpstr_pids);
}
else if (IsEqualGUID(fmtid, FMTID_UserDefinedProperties))
{
// Note: User defined properties are, by defintion, not defined
// by the system. We simply will convert any VT_LPSTR values to VT_LPWSTR.
if (pvt)
{
if ((*pvt) & VT_LPSTR) // forward conversion?
{
(*pvt) &= ~VT_LPSTR;
(*pvt) |= VT_LPWSTR;
return TRUE;
}
else if ((*pvt) & VT_LPWSTR) // reverse conversion?
{
(*pvt) &= ~VT_LPWSTR;
(*pvt) |= VT_LPSTR;
return TRUE;
}
}
}
if (rgapd) // search among pre-defined property ids:
{
for (UINT i = 0; i < capd; i++)
{
if (propid == rgapd[i].propid)
{
if (pvt)
{
if (*pvt == rgapd[i].vtConvert) // reverse conversion?
*pvt = rgapd[i].vt;
else // forward conversion?
*pvt = rgapd[i].vtConvert;
}
return TRUE;
}
}
}
return FALSE;
}
// Helper: Properly converts a block of legacy ansi properties read from a
// prop storage to unicode
STDAPI _LegacyPropertiesToUnicode(
REFFMTID fmtid,
UINT uCodePage,
ULONG cpspec,
PROPSPEC const rgpspec[],
PROPVARIANT rgvar[])
{
ASSERT(uCodePage);
HRESULT hr = S_OK;
if (_IsAnsiPropertySet(fmtid) && (uCodePage != CP_WINUNICODE))
{
for (ULONG i = 0; i < cpspec; i++)
{
if (VT_LPSTR == rgvar[i].vt)
{
// convert in-place to VT_LPWSTR.
if (rgvar[i].pszVal)
{
LPWSTR pwszVal;
int cch = lstrlenA(rgvar[i].pszVal) + 1;
if (NULL == (pwszVal = (LPWSTR)CoTaskMemAlloc(CbFromCchW(cch))))
{
hr = E_OUTOFMEMORY;
// reverse what we've already done
if (i > 0)
_LegacyPropertiesToAnsi(fmtid, uCodePage, i, rgpspec, rgvar);
break ;
}
if (*rgvar[i].pszVal) // non-empty
{
// if we can't convert using the set's codepage, fall back on CP_UTF8
if (!MultiByteToWideChar(uCodePage, 0, rgvar[i].pszVal, -1, pwszVal, cch))
SHAnsiToUnicodeCP(CP_UTF8, rgvar[i].pszVal, pwszVal, cch);
}
else // empty string; why bother converting?
*pwszVal = 0;
CoTaskMemFree(rgvar[i].pszVal);
// assign propvalue.
rgvar[i].pwszVal = pwszVal;
}
rgvar[i].vt = VT_LPWSTR;
}
}
}
return hr;
}
// Helper: Properly converts a block of legacy ansi properties from unicode to
// ansi in preparation for writing back to the storage stream.
STDAPI _LegacyPropertiesToAnsi(
REFFMTID fmtid,
UINT uCodePage,
ULONG cpspec,
PROPSPEC const rgpspec[],
PROPVARIANT rgvar[])
{
ASSERT(uCodePage);
HRESULT hr = S_OK;
if (_IsAnsiPropertySet(fmtid) && (uCodePage != CP_WINUNICODE))
{
for (ULONG i = 0; i < cpspec; i++)
{
if (rgvar[i].vt == VT_LPWSTR)
{
// Revert back to ANSI in place
if (rgvar[i].pwszVal)
{
LPSTR pszVal;
// make plenty of room for UTF-8 conversions. each WCHAR
// can turn into as many as three ANSI chars
int cb = MAX_UTF8_CHAR_SIZE * (lstrlenW(rgvar[i].pwszVal) + 1);
if (NULL == (pszVal = (LPSTR)CoTaskMemAlloc(cb)))
{
hr = E_OUTOFMEMORY;
if (i > 0) // try to reverse what we've done.
_LegacyPropertiesToUnicode(fmtid, uCodePage, i, rgpspec, rgvar);
break;
}
if (*rgvar[i].pwszVal)
{
// Test round-trip to ANSI and back. If fails, fall back on CP_UTF8.
if (!_DoesStringRoundTripCPW(uCodePage, rgvar[i].pwszVal, pszVal, cb))
SHUnicodeToAnsiCP(CP_UTF8, rgvar[i].pwszVal, pszVal, cb);
}
else
*pszVal = 0;
CoTaskMemFree(rgvar[i].pwszVal);
rgvar[i].pszVal = pszVal;
}
rgvar[i].vt = VT_LPSTR;
}
}
}
return hr;
}
// Helper: Converts the specified ansi string to a universal code page.
STDAPI _UniversalizeAnsiString(IN OUT LPSTR* ppszSrc, IN UINT uCodePage)
{
ASSERT(ppszSrc);
ASSERT(uCodePage != CP_UTF8);
if (!(*ppszSrc)) // NULL string
return S_FALSE;
if (!(*ppszSrc)[0]) // empty string; nothing to do.
return S_OK;
HRESULT hr = E_FAIL;
LPSTR pszDest = NULL;
WCHAR wszVal[MAX_PATH];
LPWSTR pwszVal = wszVal;
*wszVal = 0;
UINT cch = lstrlenA(*ppszSrc) + 1;
if (cch > ARRAYSIZE(wszVal))
pwszVal = new WCHAR[cch];
if (pwszVal != NULL)
{
// convert to Unicode using original codepage
if (SHAnsiToUnicodeCP(uCodePage, *ppszSrc, pwszVal, cch))
{
int cb = MAX_UTF8_CHAR_SIZE * cch;
if ((pszDest = (LPSTR)CoTaskMemAlloc(cb)) != NULL)
{
// convert to ANSI using UTF_8
if (SHUnicodeToAnsiCP(CP_UTF8, pwszVal, pszDest, cb))
{
CoTaskMemFree(*ppszSrc);
*ppszSrc = pszDest;
hr = S_OK;
}
else
{
CoTaskMemFree(pszDest);
hr = E_FAIL;
}
}
else
hr = E_OUTOFMEMORY;
}
if (pwszVal != wszVal)
delete [] pwszVal;
}
else
hr = E_OUTOFMEMORY;
return hr;
}
// Helper: Ensures that any ansi strings in the specified property
// are converted to a universal code page.
STDAPI _UniversalizeProperty(IN OUT PROPVARIANT* pvar, UINT uCodePage)
{
ASSERT(uCodePage != CP_UTF8);
HRESULT hr = S_OK;
if (VT_LPSTR == pvar->vt)
{
hr = _UniversalizeAnsiString(&pvar->pszVal, uCodePage);
}
else if ((VT_LPSTR | VT_VECTOR) == pvar->vt)
{
for (ULONG i = 0; i < pvar->calpstr.cElems; i++)
{
HRESULT hrElem = _UniversalizeAnsiString(&pvar->calpstr.pElems[i], uCodePage);
if (FAILED(hrElem))
hr = hrElem;
}
}
return hr;
}
// Helper: counts properties in the indicated property set.
ULONG _CountProperties(IEnumSTATPROPSTG* pEnum)
{
ULONG cRet = 0;
pEnum->Reset();
STATPROPSTG stat[20] = {0};
HRESULT hr;
do
{
ULONG cFetched;
hr = pEnum->Next(ARRAYSIZE(stat), stat, &cFetched);
if (SUCCEEDED(hr))
cRet += cFetched;
} while (S_OK == hr);
pEnum->Reset();
return cRet;
}
// Helper: Ensures that all ansi properties in the indicate set are converted to a
// universal code page.
STDAPI _UniversalizeSet(IPropertyStorage* pstg, IN OUT UINT* puCodePage, PROPID propidNameFirst)
{
UINT uCP = *puCodePage;
if (CP_UTF8 == uCP)
return S_OK;
// Enumerate property values
IEnumSTATPROPSTG* pEnum;
HRESULT hr = pstg->Enum(&pEnum);
if (SUCCEEDED(hr))
{
ULONG cProps = _CountProperties(pEnum);
if (cProps > 0)
{
STATPROPSTG* rgstat = NULL;
PROPSPEC* rgpspec = NULL;
PROPVARIANT* rgvar = NULL;
if ((rgstat = new STATPROPSTG[cProps]) != NULL &&
(rgpspec = new PROPSPEC[cProps]) != NULL &&
(rgvar = new PROPVARIANT[cProps]) != NULL)
{
ULONG cFetched = 0;
ZeroMemory(rgstat, cProps * sizeof(*rgstat));
hr = pEnum->Next(cProps, rgstat, &cFetched);
if (SUCCEEDED(hr) && cFetched > 0)
{
for (ULONG i = 0; i < cFetched; i++)
{
rgpspec[i].ulKind = PRSPEC_PROPID;
rgpspec[i].propid = rgstat[i].propid;
}
ZeroMemory(rgvar, sizeof(rgvar));
// Read properties
hr = pstg->ReadMultiple(cFetched, rgpspec, rgvar);
if (S_OK == hr)
{
BOOL bConversionError = FALSE;
// Convert properties
for (i = 0; i < cFetched; i++)
{
hr = _UniversalizeProperty(rgvar + i, uCP);
if (FAILED(hr))
{
bConversionError = TRUE;
break;
}
}
// Delete set, write out converted values and update PID_CODEPAGE
if (!bConversionError)
{
hr = pstg->DeleteMultiple(cFetched, rgpspec);
if (SUCCEEDED(hr))
{
hr = SHPropStgWriteCP(pstg, CP_UTF8);
if (SUCCEEDED(hr))
{
*puCodePage = CP_UTF8;
hr = pstg->WriteMultiple(cFetched, rgpspec, rgvar, propidNameFirst);
}
}
}
for (i = 0; i < cFetched; i++)
PropVariantClear(rgvar + i);
}
}
}
if (rgstat) delete [] rgstat;
if (rgpspec) delete [] rgpspec;
if (rgvar) delete [] rgvar;
}
else if (0 == cProps) // no properties: brand-new, empty set.
{
hr = SHPropStgWriteCP(pstg, CP_UTF8);
if (SUCCEEDED(hr))
{
*puCodePage = CP_UTF8;
}
}
pEnum->Release();
}
return hr;
}
// A PROPVARIANT can hold a few more types than a VARIANT can. We convert the types that are
// only supported by a PROPVARIANT into equivalent VARIANT types.
HRESULT PropVariantToVariant(const PROPVARIANT *pPropVar, VARIANT *pVar)
{
HRESULT hr = E_OUTOFMEMORY;
ASSERT(pPropVar && pVar);
// if pVar isn't empty, this will properly free before overwriting it
VariantClear(pVar);
switch (pPropVar->vt)
{
case VT_LPSTR:
pVar->bstrVal = SysAllocStringA(pPropVar->pszVal);
if (pVar->bstrVal)
{
pVar->vt = VT_BSTR;
hr = S_OK;
}
break;
case VT_LPWSTR:
pVar->bstrVal = SysAllocString(pPropVar->pwszVal);
if (pVar->bstrVal)
{
pVar->vt = VT_BSTR;
hr = S_OK;
}
break;
case VT_FILETIME:
{
SYSTEMTIME st;
if (FileTimeToSystemTime(&pPropVar->filetime, &st) &&
SystemTimeToVariantTime(&st, &pVar->date)) // delay load...
{
pVar->vt = VT_DATE;
hr = S_OK;
}
break;
}
case VT_CLSID:
if (pVar->bstrVal = SysAllocStringLen(NULL, GUIDSTR_MAX))
{
if (SUCCEEDED(SHStringFromGUIDW(*pPropVar->puuid, pVar->bstrVal, GUIDSTR_MAX)))
{
pVar->vt = VT_BSTR;
hr = S_OK;
}
else
{
SysFreeString(pVar->bstrVal);
pVar->bstrVal = NULL;
}
}
break;
case VT_BLOB:
case VT_STREAM:
case VT_STORAGE:
case VT_BLOB_OBJECT:
case VT_STREAMED_OBJECT:
case VT_STORED_OBJECT:
case VT_CF:
ASSERT(0); // leave the output cleared
break;
case VT_UI4:
pVar->vt = VT_I4;
pVar->lVal = (INT)pPropVar->ulVal;
hr = S_OK;
break;
default:
hr = VariantCopy(pVar, (VARIANT *)pPropVar);
break;
}
return hr;
}
class CPropertyUI : public IPropertyUI
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IPropertyUI
STDMETHODIMP ParsePropertyName(LPCWSTR pwszProperties, FMTID *pfmtid, PROPID *ppid, ULONG *pchEaten);
STDMETHODIMP GetCannonicalName(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText);
STDMETHODIMP GetDisplayName(REFFMTID fmtid, PROPID pid, PROPERTYUI_NAME_FLAGS flags, LPWSTR pwszText, DWORD cchText);
STDMETHODIMP GetPropertyDescription(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText);
STDMETHODIMP GetDefaultWidth(REFFMTID fmtid, PROPID pid, ULONG *pcxChars);
STDMETHODIMP GetFlags(REFFMTID fmtid, PROPID pid, PROPERTYUI_FLAGS *pdwFlags);
STDMETHODIMP FormatForDisplay(REFFMTID fmtid, PROPID pid, const PROPVARIANT *pvar,
PROPERTYUI_FORMAT_FLAGS flags, LPWSTR pwszText, DWORD cchText);
STDMETHODIMP GetHelpInfo(REFFMTID fmtid, PROPID pid, LPWSTR pwszHelpFile, DWORD cch, UINT *puHelpID);
CPropertyUI();
private:
~CPropertyUI();
const PROPUI_INFO *_FindInfoByName(LPCWSTR pszName);
long _cRef;
};
const PROPUI_INFO *_FindInfoByFMTIDPID(REFFMTID fmtid, PROPID pid);
CPropertyUI::CPropertyUI() : _cRef(1)
{
DllAddRef();
}
CPropertyUI::~CPropertyUI()
{
DllRelease();
}
HRESULT CPropertyUI::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CPropertyUI, IPropertyUI),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CPropertyUI::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CPropertyUI::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
const PROPUI_INFO *CPropertyUI::_FindInfoByName(LPCWSTR pszName)
{
const PROPUI_INFO *pinfo = NULL;
for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
{
if (StrCmpIW(pszName, c_rgPropUIInfo[i].pwszName) == 0)
{
pinfo = &c_rgPropUIInfo[i];
break;
}
}
return pinfo;
}
const PROPUI_INFO *_FindInfoByFMTIDPID(REFFMTID fmtid, PROPID pid)
{
const PROPUI_INFO *pinfo = NULL;
for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
{
if ((pid == c_rgPropUIInfo[i].pscid->pid) &&
(fmtid == c_rgPropUIInfo[i].pscid->fmtid))
{
pinfo = &c_rgPropUIInfo[i];
break;
}
}
return pinfo;
}
HRESULT _NextProp(LPCWSTR pwszProperties, ULONG *pchEaten, LPWSTR pwszProp, UINT cchProp)
{
HRESULT hr = E_FAIL;
ULONG ulStrLen = lstrlenW(pwszProperties);
*pwszProp = L'\0';
if (*pchEaten < ulStrLen)
{
LPCWSTR pwszStart = pwszProperties + (*pchEaten);
LPCWSTR pwszSemi = StrChrW(pwszStart, L';');
if (pwszSemi)
{
// make sure its well formed (no dbl slashes)
if (pwszSemi > pwszStart)
{
// Make sure we don't overrun the prop buffer size
ULONG ulPropLen = (ULONG)(pwszSemi - pwszStart) + 1; // includes L'\0'
if (ulPropLen > cchProp)
{
ulPropLen = cchProp;
}
StrCpyNW(pwszProp, pwszStart, ulPropLen);
// Make sure that there is another segment to return
if (!*(pwszSemi + 1))
{
pwszSemi = NULL;
}
hr = S_OK;
}
else
{
pwszSemi = NULL;
hr = E_INVALIDARG; // bad input
}
}
else
{
// No semi-colon; so copy till the end
StrCpyNW(pwszProp, pwszStart, cchProp);
hr = S_OK;
}
// Set *pchEaten
if (pwszSemi)
{
*pchEaten = (int)(pwszSemi - pwszProperties) + 1; // Skip ;
}
else
{
*pchEaten = ulStrLen;
}
}
else
{
hr = S_FALSE; // done with loop
}
return hr;
}
#define PROP_PREFIX TEXT("prop:")
#define PROP_PREFIX_LEN (ARRAYSIZE(PROP_PREFIX) - 1)
// [in/out] *pchEaten used to sequence through the property names
STDMETHODIMP CPropertyUI::ParsePropertyName(LPCWSTR pwszProperties, FMTID *pfmtid, PROPID *ppid, ULONG *pchEaten)
{
// Nobody should call us without a reason
ASSERT(pfmtid && ppid);
HRESULT hr = E_FAIL;
WCHAR wszProp[MAX_PATH];
SHCOLUMNID scid;
// If pwszProperties starts with prop:, skip it
if ((*pchEaten == 0)
&& (StrCmpNIW(pwszProperties, PROP_PREFIX, PROP_PREFIX_LEN) == 0))
{
*pchEaten += PROP_PREFIX_LEN;
}
if ((_NextProp(pwszProperties, pchEaten, wszProp, ARRAYSIZE(wszProp)) == S_OK)
&& ParseSCIDString(wszProp, &scid, NULL))
{
*pfmtid = scid.fmtid;
*ppid = scid.pid;
hr = S_OK;
}
return hr;
}
STDMETHODIMP CPropertyUI::GetCannonicalName(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText)
{
HRESULT hr = E_FAIL;
*pwszText = NULL;
const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
if (pinfo)
{
hr = S_OK;
StrCpyNW(pwszText, pinfo->pwszName, cchText);
}
else if (SHStringFromGUIDW(fmtid, pwszText, cchText))
{
WCHAR wszPid[20]; // Pid's can't be longer than 20 chars
wnsprintfW(wszPid, ARRAYSIZE(wszPid), L"%lu", pid);
StrCatBuffW(pwszText, wszPid, cchText);
hr = S_OK;
}
return hr;
}
STDMETHODIMP CPropertyUI::GetDisplayName(REFFMTID fmtid, PROPID pid, PROPERTYUI_NAME_FLAGS flags, LPWSTR pwszText, DWORD cchText)
{
HRESULT hr = E_FAIL;
*pwszText = NULL;
const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
if (pinfo)
{
UINT uID;
if (flags & PUIFNF_MNEMONIC)
{
// Name with mnemonic requested.
if (pinfo->idMnemonicName)
{
// Name with mnemonic defined for scid.
uID = pinfo->idMnemonicName;
hr = S_OK;
}
else
{
// Name with mnemonic NOT defined for scid -- use name without mnemonic as fallback.
uID = pinfo->idDisplayName;
hr = S_FALSE;
}
}
else
{
// Name without mnemonic requested.
uID = pinfo->idDisplayName;
hr = S_OK;
}
LoadStringW(HINST_THISDLL, uID, pwszText, cchText);
}
return hr;
}
STDMETHODIMP CPropertyUI::GetPropertyDescription(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText)
{
HRESULT hr = E_FAIL;
*pwszText = NULL;
const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
if (pinfo)
{
*pwszText = 0;
// LoadStringW(HINST_THISDLL, pinfo->idPropertyDescription, pwszText, cchText);
hr = S_OK;
}
return hr;
}
STDMETHODIMP CPropertyUI::GetDefaultWidth(REFFMTID fmtid, PROPID pid, ULONG *pcxChars)
{
HRESULT hr = E_FAIL;
*pcxChars = 0;
const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
if (pinfo)
{
*pcxChars = 20; // pinfo->nWidth;
hr = S_OK;
}
return hr;
}
STDMETHODIMP CPropertyUI::GetFlags(REFFMTID fmtid, PROPID pid, PROPERTYUI_FLAGS *pdwFlags)
{
HRESULT hr = E_FAIL;
*pdwFlags = PUIF_DEFAULT;
const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
if (pinfo)
{
*pdwFlags = PUIF_DEFAULT; // pinfo->dwFlags;
hr = S_OK;
}
return hr;
}
HRESULT _LookupStringFromLong(const STRING_MAP *pMap, ULONG ulVal, LPWSTR pszText, DWORD cchText)
{
HRESULT hr = E_FAIL;
while (pMap->idStr && pMap->uVal != ulVal)
{
pMap++;
}
if (pMap->idStr)
{
LoadString(HINST_THISDLL, pMap->idStr, pszText, cchText);
hr = S_OK;
}
return hr;
}
// expose this method as an API as this is very commonly needed
STDAPI SHFormatForDisplay(REFFMTID fmtid, PROPID pid, const PROPVARIANT *pPropVar,
PROPERTYUI_FORMAT_FLAGS flags, LPWSTR pwszText, DWORD cchText)
{
HRESULT hr = S_OK;
*pwszText = 0;
TCHAR szBuffer[MAX_PATH];
// Property-specific:
if (CompareSCIDFMTIDPID(fmtid, pid, SCID_SIZE) ||
CompareSCIDFMTIDPID(fmtid, pid, SCID_CAPACITY) ||
CompareSCIDFMTIDPID(fmtid, pid, SCID_FREESPACE))
{
ASSERT(pPropVar->vt == VT_UI8);
StrFormatByteSizeW(pPropVar->uhVal.QuadPart, pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_Duration))
{
if (pPropVar->vt == VT_EMPTY)
{
StrCpyN(pwszText, L"", cchText);
}
else
{
ASSERT(pPropVar->vt == VT_UI8);
FILETIME ft = {pPropVar->uhVal.LowPart, pPropVar->uhVal.HighPart};
SYSTEMTIME st;
FileTimeToSystemTime(&ft, &st);
GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER,
&st, NULL, pwszText, cchText);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_Bitrate) || CompareSCIDFMTIDPID(fmtid, pid, SCID_VIDEO_Bitrate))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_MUSIC_BITRATE, szBuffer, ARRAYSIZE(szBuffer));
ASSERT(pPropVar->vt == VT_UI4 || pPropVar->vt == VT_I4)
wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal / 1000);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_DRM_Protected)
||CompareSCIDFMTIDPID(fmtid, pid, SCID_Scale))
{
ASSERT(pPropVar->vt == VT_BOOL);
UINT uID = (pPropVar->boolVal) ? IDS_PROPERTYUI_YES : IDS_PROPERTYUI_NO;
LoadString(HINST_THISDLL, uID, pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_SampleSize) || CompareSCIDFMTIDPID(fmtid, pid, SCID_VIDEO_SampleSize))
{
ASSERT(pPropVar->vt == VT_UI4);
LoadString(HINST_THISDLL, IDS_PROPERTYUI_AV_SAMPLESIZE, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_SampleRate))
{
ASSERT(pPropVar->vt == VT_UI4);
LoadString(HINST_THISDLL, IDS_PROPERTYUI_AUDIO_SAMPLERATE, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal / 1000); // 1000: Hz -> kHz
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_ChannelCount))
{
ASSERT(pPropVar->vt == VT_UI4);
switch (pPropVar->ulVal)
{
case 1:
LoadString(HINST_THISDLL, IDS_PROPERTYUI_AUDIO_CHANNELCOUNT1, pwszText, cchText);
break;
case 2:
LoadString(HINST_THISDLL, IDS_PROPERTYUI_AUDIO_CHANNELCOUNT2, pwszText, cchText);
break;
default:
wnsprintf(pwszText, cchText, L"%u", pPropVar->ulVal);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_VIDEO_FrameRate))
{
ASSERT(pPropVar->vt == VT_UI4);
LoadString(HINST_THISDLL, IDS_PROPERTYUI_VIDEO_FRAMERATE, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal/1000); // 1000 -> convert to frames/second
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ImageCX) || CompareSCIDFMTIDPID(fmtid, pid, SCID_ImageCY))
{
ASSERT(pPropVar->vt == VT_UI4);
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_PIXELS, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_Flash))
{
ASSERT(pPropVar->vt == VT_UI2);
hr = _LookupStringFromLong(g_cFlashStrings,pPropVar->uiVal,pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ColorSpace))
{
ASSERT(pPropVar->vt == VT_UI2);
hr = _LookupStringFromLong(g_cColorStrings,pPropVar->uiVal,pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_Media_Status))
{
hr = _LookupStringFromLong(g_cMediaStatus, pPropVar->ulVal, pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_MeteringMode))
{
ASSERT(pPropVar->vt == VT_UI2);
hr = _LookupStringFromLong(g_cMeteringModeStrings, pPropVar->uiVal, pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_LightSource))
{
ASSERT(pPropVar->vt == VT_UI2);
hr = _LookupStringFromLong(g_cLightSourceStrings, pPropVar->uiVal, pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ExposureProg))
{
ASSERT(pPropVar->vt == VT_UI2);
hr = _LookupStringFromLong(g_cExposureProgStrings, pPropVar->uiVal, pwszText, cchText);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ISOSpeed))
{
ASSERT(pPropVar->vt == VT_UI2);
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_ISO, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ShutterSpeed))
{
ASSERT(pPropVar->vt == VT_R8);
// ShutterSpeed is stored as an APEX value Tv = -log2(Et)
// we want to display the exposure time so we calculate it as follows
// Et = 2^(-Tv) then if the value is less than 0.5 then take the inverse
// so we can represent like 1/250
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vTv = {0};
hr = PropVariantToVariant(pPropVar, &vTv);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
VARIANT vTemp2 = {0};
VARIANT vTemp3 = {0};
hr = VarNeg(&vTv, &vTemp);
if (SUCCEEDED(hr))
{
V_VT(&vTemp2) = VT_R8;
V_R8(&vTemp2) = 2;
hr = VarPow(&vTemp2, &vTemp, &vTemp3);
if (SUCCEEDED(hr))
{
if (V_R8(&vTemp3) > 0.5)
{
hr = VarRound(&vTemp3, 2, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
}
else
{
V_VT(&vTemp) = VT_R8;
V_R8(&vTemp) = 1;
hr = VarDiv(&vTemp, &vTemp3, &vTemp2);
if (SUCCEEDED(hr))
{
hr = VarRound(&vTemp2, 0, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC_FRAC, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
}
}
}
}
VariantClear(&vTv);
VariantClear(&vTemp);
VariantClear(&vTemp2);
VariantClear(&vTemp3);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ExposureTime))
{
ASSERT(pPropVar->vt == VT_R8);
// ExposureTime is store as a R8 value if the value is less
// than 0.5 then take the inverse so we can represent like 1/250
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vEt = {0};
hr = PropVariantToVariant(pPropVar, &vEt);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
VARIANT vTemp2 = {0};
if (V_R8(&vEt) > 0.5)
{
hr = VarRound(&vEt, 2, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
}
else
{
V_VT(&vTemp) = VT_R8;
V_R8(&vTemp) = 1;
hr = VarDiv(&vTemp, &vEt, &vTemp2);
if (SUCCEEDED(hr))
{
hr = VarRound(&vTemp2, 0, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC_FRAC, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
}
}
VariantClear(&vEt);
VariantClear(&vTemp);
VariantClear(&vTemp2);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_Aperture))
{
ASSERT(pPropVar->vt == VT_R8);
// Aperture is stored as an APEX value Av = 2*log2(Fn)
// we want to display the F-number so we calculate it as follows
// Fn = 2^(Av/2)
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vAv = {0};
hr = PropVariantToVariant(pPropVar, &vAv);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
VARIANT vTemp2 = {0};
VARIANT vTemp3 = {0};
V_VT(&vTemp) = VT_R8;
V_R8(&vTemp) = 2;
hr = VarDiv(&vAv, &vTemp, &vTemp2);
if (SUCCEEDED(hr))
{
hr = VarPow(&vTemp, &vTemp2, &vTemp3);
if (SUCCEEDED(hr))
{
hr = VarRound(&vTemp3, 1, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_F, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
}
}
VariantClear(&vAv);
VariantClear(&vTemp);
VariantClear(&vTemp2);
VariantClear(&vTemp3);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_FNumber))
{
ASSERT(pPropVar->vt == VT_R8);
// Fn is stored as a R8 value that needs to be rounded
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vFn = {0};
hr = PropVariantToVariant(pPropVar, &vFn);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
V_VT(&vTemp) = VT_R8;
V_R8(&vTemp) = 2;
hr = VarRound(&vFn, 1, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_F, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
VariantClear(&vFn);
VariantClear(&vTemp);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_SubjectDist))
{
ASSERT(pPropVar->vt == VT_R8);
// Distance is store as a R8 value in meters if the value is less
// than 1 then multiple by 1000 to convert to mm
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vD = {0};
hr = PropVariantToVariant(pPropVar, &vD);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
VARIANT vTemp2 = {0};
if (V_R8(&vD) >= 1.0)
{
hr = VarRound(&vD, 1, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_M, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
}
else
{
V_VT(&vTemp) = VT_R8;
V_R8(&vTemp) = 1000;
hr = VarMul(&vTemp, &vD, &vTemp2);
if (SUCCEEDED(hr))
{
hr = VarRound(&vTemp2, 0, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_MM, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
}
}
VariantClear(&vD);
VariantClear(&vTemp);
VariantClear(&vTemp2);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_FocalLength))
{
ASSERT(pPropVar->vt == VT_R8);
// Focal Length is store as a R8 value in mm
// so round it and display it
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vLen = {0};
hr = PropVariantToVariant(pPropVar, &vLen);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
hr = VarRound(&vLen, 0, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_MM, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
VariantClear(&vLen);
VariantClear(&vTemp);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_FlashEnergy))
{
ASSERT(pPropVar->vt == VT_R8);
// Flash Energy is store as a R8 value in bcps
// so round it and display it
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vBCPS = {0};
hr = PropVariantToVariant(pPropVar, &vBCPS);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
hr = VarRound(&vBCPS, 0, &vTemp);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_BCPS, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
}
}
VariantClear(&vBCPS);
VariantClear(&vTemp);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ExposureBias))
{
ASSERT(pPropVar->vt == VT_R8);
// ExposureBias is store as a R8 value in steps
// so round it to the nearest tenth and display
// it with a + or minus
TCHAR szFloatBuffer[MAX_PATH];
VARIANT vBias = {0};
hr = PropVariantToVariant(pPropVar, &vBias);
if (SUCCEEDED(hr))
{
VARIANT vTemp = {0};
hr = VarRound(&vBias, 1, &vTemp);
if (SUCCEEDED(hr))
{
TCHAR* pszSign;
if (V_R8(&vBias) > 0)
pszSign = L"+";
else
pszSign = L"";
hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_STEP, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, pszSign, szFloatBuffer);
}
}
VariantClear(&vBias);
VariantClear(&vTemp);
}
}
else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ResolutionX) || CompareSCIDFMTIDPID(fmtid, pid, SCID_ResolutionY))
{
ASSERT(pPropVar->vt == VT_UI4);
LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_DPI, szBuffer, ARRAYSIZE(szBuffer));
wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
}
else if ((pPropVar->vt == VT_DATE) || (pPropVar->vt == VT_FILETIME))
{
FILETIME ft;
if (pPropVar->vt == VT_DATE)
{
WORD wDosDate, wDosTime;
if (VariantTimeToDosDateTime(pPropVar->date, &wDosDate, &wDosTime) && wDosDate)
{
DosDateTimeToFileTime(wDosDate, wDosTime, &ft);
hr = S_OK;
}
else
hr = E_FAIL;
}
else
{
ft = pPropVar->filetime;
hr = S_OK;
}
if (SUCCEEDED(hr))
{
DWORD dwFlags = FDTF_DEFAULT;
if (flags & PUIFFDF_RIGHTTOLEFT)
{
dwFlags |= FDTF_RTLDATE;
}
if (flags & PUIFFDF_SHORTFORMAT)
{
dwFlags |= FDTF_SHORTDATE;
}
if (flags & PUIFFDF_NOTIME)
{
dwFlags |= FDTF_LONGDATE;
}
if (flags & PUIFFDF_FRIENDLYDATE)
{
dwFlags |= (FDTF_RELATIVE | FDTF_LONGDATE);
}
SHFormatDateTime(&ft, &dwFlags, pwszText, cchText);
}
}
else
{
VARIANT var = {0};
hr = PropVariantToVariant(pPropVar, &var);
if (SUCCEEDED(hr))
{
hr = VariantToStr(&var, pwszText, cchText) ? S_OK : E_OUTOFMEMORY;
VariantClear(&var);
}
}
return hr;
}
STDMETHODIMP CPropertyUI::FormatForDisplay(REFFMTID fmtid, PROPID pid, const PROPVARIANT *pPropVar,
PROPERTYUI_FORMAT_FLAGS flags, LPWSTR pwszText, DWORD cchText)
{
return SHFormatForDisplay(fmtid, pid, pPropVar, flags, pwszText, cchText);
}
STDMETHODIMP CPropertyUI::GetHelpInfo(REFFMTID fmtid, PROPID pid, LPWSTR pwszHelpFile, DWORD cch, UINT *puHelpID)
{
HRESULT hr = E_INVALIDARG; // assume failure
if (pwszHelpFile && puHelpID)
{
*pwszHelpFile = 0;
*puHelpID = 0;
const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
if (pinfo)
{
*puHelpID = pinfo->idHelp;
StrCpyN(pwszHelpFile, L"filefold.hlp", cch);
hr = S_OK;
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // close approximation
}
}
return hr;
}
STDAPI CPropertyUI_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
HRESULT hr;
CPropertyUI *ppui = new CPropertyUI();
if (ppui)
{
hr = ppui->QueryInterface(riid, ppv);
ppui->Release();
}
else
{
*ppv = NULL;
hr = E_OUTOFMEMORY;
}
return hr;
}
#if 0
// this table defines the CI names for properties that we don't yet have CPropertyUI support for
// Storage Propset
{ 0, L"ClassId", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_CLASSID }, 36, TRUE, TRUE, DBTYPE_GUID },
{ 0, L"FileIndex", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_FILEINDEX }, 8, TRUE, TRUE, DBTYPE_UI8 },
{ 0, L"USN", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_LASTCHANGEUSN }, 8, TRUE, TRUE, DBTYPE_I8 },
{ 0, L"Filename", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_NAME }, 15, TRUE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
{ 0, L"Path", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_PATH }, 50, TRUE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
{ 0, L"Attrib", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_ATTRIBUTES }, 7, TRUE, TRUE, DBTYPE_UI4 },
{ 0, L"AllocSize", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)18 }, 11, TRUE, TRUE, DBTYPE_I8 },
{ 0, L"Contents", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)19 }, 0, FALSE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
// Query Propset
{ 0, L"RankVector", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)2 }, 20, TRUE, TRUE, DBTYPE_UI4|DBTYPE_VECTOR },
{ 0, L"Rank", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)3 }, 7, TRUE, TRUE, DBTYPE_I4 },
{ 0, L"HitCount", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)4 }, 10, TRUE, TRUE, DBTYPE_I4 },
{ 0, L"WorkId", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)5 }, 10, TRUE, TRUE, DBTYPE_I4 },
{ 0, L"All", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)6 }, 0, FALSE,TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
{ 0, L"VPath", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)9 }, 50, TRUE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
// standard document
{ 0, L"DocSecurity", {PSGUID_SUMMARYINFORMATION, DBKIND_GUID_PROPID, (LPWSTR)PIDSI_DOC_SECURITY }, 10, TRUE, TRUE, DBTYPE_I4 },
// who invented these?
{ 0, L"DocPresentationTarget", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)3 }, 10, TRUE, TRUE, DBTYPE_STR|DBTYPE_BYREF },
{ 0, L"DocPartTitles", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)13 }, 10, TRUE, TRUE, DBTYPE_STR|DBTYPE_VECTOR },
{ 0, L"DocManager", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)14 }, 10, TRUE, TRUE, DBTYPE_STR|DBTYPE_BYREF },
{ 0, L"DocCompany", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)15 }, 10, TRUE,
#endif