2263 lines
97 KiB
C++
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
|