Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2262 lines
97 KiB

  1. #include "shellprv.h"
  2. #include "prop.h"
  3. #include <ntquery.h> // defines some values used for fmtid and pid
  4. #include "findfilter.h" // includes oledb (which defines some values used for fmtid and pid) properly
  5. #include "ids.h"
  6. #include "imgprop.h"
  7. #include <gdiplus\gdiplus.h> // for PropertyTag* definitions
  8. #define MAX_UTF8_CHAR_SIZE (sizeof(CHAR) * 3)
  9. // FMTID_ExeDllInformation,
  10. //// {0CEF7D53-FA64-11d1-A203-0000F81FEDEE}
  11. #define PSFMTID_VERSION { 0xcef7d53, 0xfa64, 0x11d1, 0xa2, 0x3, 0x0, 0x0, 0xf8, 0x1f, 0xed, 0xee }
  12. #define PIDVSI_FileDescription 0x003
  13. #define PIDVSI_FileVersion 0x004
  14. #define PIDVSI_InternalName 0x005
  15. #define PIDVSI_OriginalFileName 0x006
  16. #define PIDVSI_ProductName 0x007
  17. #define PIDVSI_ProductVersion 0x008
  18. #define TIFFTAG_FAX_END_TIME 40052
  19. #define TIFFTAG_SENDER_NAME 40021
  20. #define TIFFTAG_TSID 40002
  21. #define TIFFTAG_CALLERID 40005
  22. #define TIFFTAG_RECIP_NAME 40006
  23. #define TIFFTAG_RECIP_NUMBER 40007
  24. #define TIFFTAG_CSID 40001
  25. #define TIFFTAG_ROUTING 40004
  26. // Internal PSGUID/PIDs
  27. //
  28. // Note:
  29. // This section was added to allow SCIDs to be defined without exposing them
  30. // externally (via public header files). In this way, we can define SCIDs
  31. // without having to worry about maintaining external support for them in
  32. // future.
  33. // {8D72ACA1-0716-419a-9AC1-ACB07B18DC32}
  34. #define PSGUID_PRV_STORAGE {0x8d72aca1, 0x716, 0x419a, 0x9a, 0xc1, 0xac, 0xb0, 0x7b, 0x18, 0xdc, 0x32}
  35. #define PID_PRV_STG_ATTRIBUTES_DESCRIPTION 2
  36. DEFINE_SCID(SCID_Author , PSGUID_SUMMARYINFORMATION , PIDSI_AUTHOR);
  37. DEFINE_SCID(SCID_LastAuthor , PSGUID_SUMMARYINFORMATION , PIDSI_LASTAUTHOR);
  38. DEFINE_SCID(SCID_RevNumber , PSGUID_SUMMARYINFORMATION , PIDSI_REVNUMBER);
  39. DEFINE_SCID(SCID_AppName , PSGUID_SUMMARYINFORMATION , PIDSI_APPNAME);
  40. DEFINE_SCID(SCID_Title , PSGUID_SUMMARYINFORMATION , PIDSI_TITLE);
  41. DEFINE_SCID(SCID_Subject , PSGUID_SUMMARYINFORMATION , PIDSI_SUBJECT);
  42. DEFINE_SCID(SCID_Category , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_CATEGORY);
  43. DEFINE_SCID(SCID_Keywords , PSGUID_SUMMARYINFORMATION , PIDSI_KEYWORDS );
  44. DEFINE_SCID(SCID_Rating , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_RATING );
  45. DEFINE_SCID(SCID_Template , PSGUID_SUMMARYINFORMATION , PIDSI_TEMPLATE );
  46. DEFINE_SCID(SCID_Copyright , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_COPYRIGHT);
  47. DEFINE_SCID(SCID_CompanyName , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_COMPANY);
  48. DEFINE_SCID(SCID_Manager , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_MANAGER);
  49. DEFINE_SCID(SCID_PresFormat , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_PRESFORMAT);
  50. DEFINE_SCID(SCID_PageCount , PSGUID_SUMMARYINFORMATION , PIDSI_PAGECOUNT);
  51. DEFINE_SCID(SCID_Comment , PSGUID_SUMMARYINFORMATION , PIDSI_COMMENTS);
  52. DEFINE_SCID(SCID_DocCreated , PSGUID_SUMMARYINFORMATION , PIDSI_CREATE_DTM); // in the doc, not file system
  53. DEFINE_SCID(SCID_WordCount , PSGUID_SUMMARYINFORMATION , PIDSI_WORDCOUNT);
  54. DEFINE_SCID(SCID_CharCount , PSGUID_SUMMARYINFORMATION , PIDSI_CHARCOUNT);
  55. DEFINE_SCID(SCID_LastSaveDTM , PSGUID_SUMMARYINFORMATION , PIDSI_LASTSAVE_DTM);
  56. DEFINE_SCID(SCID_LastPrinted , PSGUID_SUMMARYINFORMATION , PIDSI_LASTPRINTED);
  57. DEFINE_SCID(SCID_EditTime , PSGUID_SUMMARYINFORMATION , PIDSI_EDITTIME);
  58. DEFINE_SCID(SCID_ByteCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_BYTECOUNT);
  59. DEFINE_SCID(SCID_LineCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_LINECOUNT);
  60. DEFINE_SCID(SCID_ParagraphCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_PARCOUNT);
  61. DEFINE_SCID(SCID_SlideCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_SLIDECOUNT);
  62. DEFINE_SCID(SCID_NoteCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_NOTECOUNT);
  63. DEFINE_SCID(SCID_HiddenCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_HIDDENCOUNT);
  64. DEFINE_SCID(SCID_MMClipCount , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_MMCLIPCOUNT);
  65. DEFINE_SCID(SCID_Scale , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_SCALE);
  66. DEFINE_SCID(SCID_LinksDirty , PSGUID_DOCUMENTSUMMARYINFORMATION , PIDDSI_LINKSDIRTY);
  67. DEFINE_SCID(SCID_TYPE , PSGUID_STORAGE , PID_STG_STORAGETYPE);
  68. DEFINE_SCID(SCID_NAME , PSGUID_STORAGE , PID_STG_NAME);
  69. DEFINE_SCID(SCID_SIZE , PSGUID_STORAGE , PID_STG_SIZE);
  70. DEFINE_SCID(SCID_ATTRIBUTES , PSGUID_STORAGE , PID_STG_ATTRIBUTES);
  71. DEFINE_SCID(SCID_WRITETIME , PSGUID_STORAGE , PID_STG_WRITETIME);
  72. DEFINE_SCID(SCID_CREATETIME , PSGUID_STORAGE , PID_STG_CREATETIME);
  73. DEFINE_SCID(SCID_ACCESSTIME , PSGUID_STORAGE , PID_STG_ACCESSTIME);
  74. DEFINE_SCID(SCID_DIRECTORY , PSGUID_STORAGE , PID_STG_DIRECTORY);
  75. DEFINE_SCID(SCID_FREESPACE , PSGUID_VOLUME , PID_VOLUME_FREE);
  76. DEFINE_SCID(SCID_CAPACITY , PSGUID_VOLUME , PID_VOLUME_CAPACITY);
  77. DEFINE_SCID(SCID_FILESYSTEM , PSGUID_VOLUME , PID_VOLUME_FILESYSTEM);
  78. DEFINE_SCID(SCID_DELETEDFROM , PSGUID_DISPLACED , PID_DISPLACED_FROM);
  79. DEFINE_SCID(SCID_DATEDELETED , PSGUID_DISPLACED , PID_DISPLACED_DATE);
  80. DEFINE_SCID(SCID_SYNCCOPYIN , PSGUID_BRIEFCASE , PID_SYNC_COPY_IN);
  81. DEFINE_SCID(SCID_RANK , PSGUID_QUERY_D , PID_QUERY_RANK);
  82. DEFINE_SCID(SCID_LASTVISITED , PSGUID_INTERNETSITE , PID_INTSITE_LASTVISIT);
  83. DEFINE_SCID(SCID_LASTMODIFIED , PSGUID_INTERNETSITE , PID_INTSITE_LASTMOD);
  84. DEFINE_SCID(SCID_VISITCOUNT , PSGUID_INTERNETSITE , PID_INTSITE_VISITCOUNT);
  85. DEFINE_SCID(SCID_STATUS , PSGUID_INTERNETSITE , PID_INTSITE_FLAGS);
  86. DEFINE_SCID(SCID_FINDDATA , PSGUID_SHELLDETAILS , PID_FINDDATA);
  87. DEFINE_SCID(SCID_NETRESOURCE , PSGUID_SHELLDETAILS , PID_NETRESOURCE);
  88. DEFINE_SCID(SCID_DESCRIPTIONID , PSGUID_SHELLDETAILS , PID_DESCRIPTIONID);
  89. DEFINE_SCID(SCID_WHICHFOLDER , PSGUID_SHELLDETAILS , PID_WHICHFOLDER);
  90. DEFINE_SCID(SCID_NETWORKLOCATION , PSGUID_SHELLDETAILS , PID_NETWORKLOCATION);
  91. DEFINE_SCID(SCID_COMPUTERNAME , PSGUID_SHELLDETAILS , PID_COMPUTERNAME);
  92. DEFINE_SCID(SCID_OWNER , PSGUID_MISC , PID_MISC_OWNER);
  93. // DEFINE_SCID(SCID_STATUS , PSGUID_MISC , PID_MISC_STATUS);
  94. // DEFINE_SCID(SCID_ACCESSCOUNT , PSGUID_MISC , PID_MISC_ACCESSCOUNT);
  95. DEFINE_SCID(SCID_DetailsProperties , PSGUID_WEBVIEW , PID_DISPLAY_PROPERTIES);
  96. DEFINE_SCID(SCID_FolderIntroText , PSGUID_WEBVIEW , PID_INTROTEXT);
  97. DEFINE_SCID(SCID_CONTROLPANELCATEGORY , PSGUID_CONTROLPANEL , PID_CONTROLPANEL_CATEGORY);
  98. DEFINE_SCID(SCID_MUSIC_Artist , PSGUID_MUSIC , PIDSI_ARTIST);
  99. DEFINE_SCID(SCID_MUSIC_Album , PSGUID_MUSIC , PIDSI_ALBUM);
  100. DEFINE_SCID(SCID_MUSIC_Year , PSGUID_MUSIC , PIDSI_YEAR);
  101. DEFINE_SCID(SCID_MUSIC_Track , PSGUID_MUSIC , PIDSI_TRACK);
  102. DEFINE_SCID(SCID_MUSIC_Genre , PSGUID_MUSIC , PIDSI_GENRE);
  103. DEFINE_SCID(SCID_MUSIC_Lyrics , PSGUID_MUSIC , PIDSI_LYRICS);
  104. DEFINE_SCID(SCID_DRM_Protected , PSGUID_DRM , PIDDRSI_PROTECTED);
  105. DEFINE_SCID(SCID_DRM_Description , PSGUID_DRM , PIDDRSI_DESCRIPTION);
  106. DEFINE_SCID(SCID_DRM_PlayCount , PSGUID_DRM , PIDDRSI_PLAYCOUNT);
  107. DEFINE_SCID(SCID_DRM_PlayStarts , PSGUID_DRM , PIDDRSI_PLAYSTARTS);
  108. DEFINE_SCID(SCID_DRM_PlayExpires , PSGUID_DRM , PIDDRSI_PLAYEXPIRES);
  109. DEFINE_SCID(SCID_AUDIO_Duration , PSGUID_AUDIO , PIDASI_TIMELENGTH); //100ns units, not milliseconds. VT_UI8, not VT_UI4
  110. DEFINE_SCID(SCID_AUDIO_Bitrate , PSGUID_AUDIO , PIDASI_AVG_DATA_RATE); // bits per second
  111. DEFINE_SCID(SCID_AUDIO_SampleRate , PSGUID_AUDIO , PIDASI_SAMPLE_RATE); // samples per second
  112. DEFINE_SCID(SCID_AUDIO_SampleSize , PSGUID_AUDIO , PIDASI_SAMPLE_SIZE); // bits per sample
  113. DEFINE_SCID(SCID_AUDIO_ChannelCount , PSGUID_AUDIO , PIDASI_CHANNEL_COUNT); // 1 (mono), 2(stero)
  114. DEFINE_SCID(SCID_AUDIO_Format , PSGUID_AUDIO , PIDASI_FORMAT);
  115. DEFINE_SCID(SCID_VIDEO_Bitrate , PSGUID_VIDEO , PIDVSI_DATA_RATE); // bits per second
  116. DEFINE_SCID(SCID_VIDEO_FrameRate , PSGUID_VIDEO , PIDVSI_FRAME_RATE); // frames per 1000s
  117. DEFINE_SCID(SCID_VIDEO_SampleSize , PSGUID_VIDEO , PIDVSI_SAMPLE_SIZE); // bits
  118. DEFINE_SCID(SCID_VIDEO_Compression , PSGUID_VIDEO , PIDVSI_COMPRESSION);
  119. DEFINE_SCID(SCID_VIDEO_StreamName , PSGUID_VIDEO , PIDVSI_STREAM_NAME);
  120. DEFINE_SCID(SCID_FileType , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_FILETYPE);
  121. DEFINE_SCID(SCID_ImageCX , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_CX);
  122. DEFINE_SCID(SCID_ImageCY , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_CY);
  123. DEFINE_SCID(SCID_ResolutionX , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_RESOLUTIONX);
  124. DEFINE_SCID(SCID_ResolutionY , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_RESOLUTIONY);
  125. DEFINE_SCID(SCID_BitDepth , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_BITDEPTH);
  126. DEFINE_SCID(SCID_Colorspace , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_COLORSPACE);
  127. DEFINE_SCID(SCID_Compression , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_COMPRESSION);
  128. DEFINE_SCID(SCID_Transparency , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_TRANSPARENCY);
  129. DEFINE_SCID(SCID_GammaValue , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_GAMMAVALUE);
  130. DEFINE_SCID(SCID_FrameCount , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_FRAMECOUNT);
  131. DEFINE_SCID(SCID_ImageDimensions , PSGUID_IMAGESUMMARYINFORMATION , PIDISI_DIMENSIONS);
  132. DEFINE_SCID(SCID_CameraModel , PSGUID_IMAGEPROPERTIES , PropertyTagEquipModel);
  133. DEFINE_SCID(SCID_TagCopyright , PSGUID_IMAGEPROPERTIES , PropertyTagCopyright);
  134. DEFINE_SCID(SCID_TagSoftwareUsed , PSGUID_IMAGEPROPERTIES , PropertyTagSoftwareUsed);
  135. DEFINE_SCID(SCID_WhenTaken , PSGUID_IMAGEPROPERTIES , PropertyTagExifDTOrig);
  136. DEFINE_SCID(SCID_Flash , PSGUID_IMAGEPROPERTIES , PropertyTagExifFlash);
  137. DEFINE_SCID(SCID_ColorSpace , PSGUID_IMAGEPROPERTIES , PropertyTagExifColorSpace);
  138. DEFINE_SCID(SCID_ShutterSpeed , PSGUID_IMAGEPROPERTIES , PropertyTagExifShutterSpeed);
  139. DEFINE_SCID(SCID_Aperture , PSGUID_IMAGEPROPERTIES , PropertyTagExifAperture);
  140. DEFINE_SCID(SCID_SubjectDist , PSGUID_IMAGEPROPERTIES , PropertyTagExifSubjectDist);
  141. DEFINE_SCID(SCID_FocalLength , PSGUID_IMAGEPROPERTIES , PropertyTagExifFocalLength);
  142. DEFINE_SCID(SCID_FNumber , PSGUID_IMAGEPROPERTIES , PropertyTagExifFNumber);
  143. DEFINE_SCID(SCID_ExposureTime , PSGUID_IMAGEPROPERTIES , PropertyTagExifExposureTime);
  144. DEFINE_SCID(SCID_FlashEnergy , PSGUID_IMAGEPROPERTIES , PropertyTagExifFlashEnergy);
  145. DEFINE_SCID(SCID_ISOSpeed , PSGUID_IMAGEPROPERTIES , PropertyTagExifISOSpeed);
  146. DEFINE_SCID(SCID_MeteringMode , PSGUID_IMAGEPROPERTIES , PropertyTagExifMeteringMode);
  147. DEFINE_SCID(SCID_LightSource , PSGUID_IMAGEPROPERTIES , PropertyTagExifLightSource);
  148. DEFINE_SCID(SCID_ExposureProg , PSGUID_IMAGEPROPERTIES , PropertyTagExifExposureProg);
  149. DEFINE_SCID(SCID_ExposureBias , PSGUID_IMAGEPROPERTIES , PropertyTagExifExposureBias);
  150. DEFINE_SCID(SCID_FaxEndTime , PSGUID_IMAGEPROPERTIES , TIFFTAG_FAX_END_TIME);
  151. DEFINE_SCID(SCID_FaxSenderName , PSGUID_IMAGEPROPERTIES , TIFFTAG_SENDER_NAME);
  152. DEFINE_SCID(SCID_FaxTSID , PSGUID_IMAGEPROPERTIES , TIFFTAG_TSID);
  153. DEFINE_SCID(SCID_FaxCallerId , PSGUID_IMAGEPROPERTIES , TIFFTAG_CALLERID);
  154. DEFINE_SCID(SCID_FaxRecipName , PSGUID_IMAGEPROPERTIES , TIFFTAG_RECIP_NAME);
  155. DEFINE_SCID(SCID_FaxRecipNumber , PSGUID_IMAGEPROPERTIES , TIFFTAG_RECIP_NUMBER);
  156. DEFINE_SCID(SCID_FaxCSID , PSGUID_IMAGEPROPERTIES , TIFFTAG_CSID);
  157. DEFINE_SCID(SCID_FaxRouting , PSGUID_IMAGEPROPERTIES , TIFFTAG_ROUTING);
  158. DEFINE_SCID(SCID_TagEquipMake , PSGUID_IMAGEPROPERTIES , PropertyTagEquipMake);
  159. DEFINE_SCID(SCID_Media_SequenceNumber , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_SEQUENCE_NO);
  160. DEFINE_SCID(SCID_Media_Owner , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_OWNER);
  161. DEFINE_SCID(SCID_Media_Editor , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_EDITOR);
  162. DEFINE_SCID(SCID_Media_Supplier , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_SUPPLIER);
  163. DEFINE_SCID(SCID_Media_Source , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_SOURCE);
  164. DEFINE_SCID(SCID_Media_Copyright , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_COPYRIGHT);
  165. DEFINE_SCID(SCID_Media_Project , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_PROJECT);
  166. DEFINE_SCID(SCID_Media_Status , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_STATUS);
  167. DEFINE_SCID(SCID_Media_Production , PSGUID_MEDIAFILESUMMARYINFORMATION , PIDMSI_PRODUCTION);
  168. DEFINE_SCID(SCID_CSC_STATUS , PSGUID_SHARE , PID_SHARE_CSC_STATUS);
  169. DEFINE_SCID(SCID_LINKTARGET , PSGUID_LINK , PID_LINK_TARGET);
  170. DEFINE_SCID(SCID_ATTRIBUTES_DESCRIPTION , PSGUID_PRV_STORAGE , PID_PRV_STG_ATTRIBUTES_DESCRIPTION);
  171. typedef struct
  172. {
  173. LPCWSTR pwszName;
  174. const SHCOLUMNID *pscid;
  175. UINT idDisplayName;
  176. UINT idMnemonicName;
  177. UINT idHelp; // IDH_ values
  178. } PROPUI_INFO;
  179. #define PROPUI_ENTRY_NORES(name, scid) {L ## name, &scid, 0, 0, 0},
  180. #define PROPUI_ENTRY(name, scid, idDisplayName, idMnemonicName, idHelp) {L ## name, &scid, idDisplayName, idMnemonicName, idHelp},
  181. const PROPUI_INFO c_rgPropUIInfo[] =
  182. {
  183. PROPUI_ENTRY("Name" , SCID_NAME , IDS_NAME_COL , IDS_MNEMONIC_NAME_COL , 10114)
  184. PROPUI_ENTRY("Type" , SCID_TYPE , IDS_TYPE_COL , IDS_MNEMONIC_TYPE_COL , 10015)
  185. PROPUI_ENTRY("Size" , SCID_SIZE , IDS_SIZE_COL , IDS_MNEMONIC_SIZE_COL , 10115)
  186. PROPUI_ENTRY("Write" , SCID_WRITETIME , IDS_MODIFIED_COL , IDS_MNEMONIC_MODIFIED_COL , 10016)
  187. PROPUI_ENTRY("Attributes" , SCID_ATTRIBUTES , IDS_ATTRIB_COL , IDS_MNEMONIC_ATTRIB_COL , 10019)
  188. PROPUI_ENTRY("AttributesDescription", SCID_ATTRIBUTES_DESCRIPTION , IDS_ATTRIB_COL , IDS_MNEMONIC_ATTRIB_COL , 10019)
  189. PROPUI_ENTRY("Owner" , SCID_OWNER , IDS_EXCOL_OWNER , IDS_MNEMONIC_EXCOL_OWNER , 10021)
  190. PROPUI_ENTRY("Create" , SCID_CREATETIME , IDS_EXCOL_CREATE , IDS_MNEMONIC_EXCOL_CREATE , 10017)
  191. PROPUI_ENTRY("Access" , SCID_ACCESSTIME , IDS_EXCOL_ACCESSTIME , IDS_MNEMONIC_EXCOL_ACCESSTIME , 10018)
  192. PROPUI_ENTRY("DocCreatedTm" , SCID_DocCreated , IDS_EXCOL_CREATE , IDS_MNEMONIC_EXCOL_CREATE , 10068)
  193. PROPUI_ENTRY("DocTitle" , SCID_Title , IDS_EXCOL_TITLE , IDS_MNEMONIC_EXCOL_TITLE , 10023)
  194. PROPUI_ENTRY("DocSubject" , SCID_Subject , IDS_EXCOL_SUBJECT , IDS_MNEMONIC_EXCOL_SUBJECT , 10024)
  195. PROPUI_ENTRY("DocAuthor" , SCID_Author , IDS_EXCOL_AUTHOR , IDS_MNEMONIC_EXCOL_AUTHOR , 10022)
  196. PROPUI_ENTRY("DocLastAuthor" , SCID_LastAuthor , IDS_EXCOL_LASTAUTHOR , IDS_MNEMONIC_EXCOL_LASTAUTHOR , 20010)
  197. PROPUI_ENTRY("DocRevNumber" , SCID_RevNumber , IDS_EXCOL_REVNUMBER , IDS_MNEMONIC_EXCOL_REVNUMBER , 20011)
  198. PROPUI_ENTRY("DocAppName" , SCID_AppName , IDS_EXCOL_APPNAME , IDS_MNEMONIC_EXCOL_APPNAME , 20012)
  199. PROPUI_ENTRY("DocPageCount" , SCID_PageCount , IDS_EXCOL_PAGECOUNT , IDS_MNEMONIC_EXCOL_PAGECOUNT , 10026)
  200. PROPUI_ENTRY("DocComments" , SCID_Comment , IDS_EXCOL_COMMENT , IDS_MNEMONIC_EXCOL_COMMENT , 10020)
  201. PROPUI_ENTRY("Copyright" , SCID_Copyright , IDS_EXCOL_COPYRIGHT , IDS_MNEMONIC_EXCOL_COPYRIGHT , 10027)
  202. PROPUI_ENTRY("DocCategory" , SCID_Category , IDS_EXCOL_CATEGORY , IDS_MNEMONIC_EXCOL_CATEGORY , 10025)
  203. PROPUI_ENTRY("DocKeywords" , SCID_Keywords , IDS_EXCOL_KEYWORDS , IDS_MNEMONIC_EXCOL_KEYWORDS , 20013)
  204. PROPUI_ENTRY("Rating" , SCID_Rating , IDS_EXCOL_RATING , IDS_MNEMONIC_EXCOL_RATING , 20014)
  205. PROPUI_ENTRY("DocTemplate" , SCID_Template , IDS_EXCOL_TEMPLATEPROP , IDS_MNEMONIC_EXCOL_TEMPLATE , 20015)
  206. PROPUI_ENTRY("DocWordCount" , SCID_WordCount , IDS_EXCOL_WORDCOUNT , IDS_MNEMONIC_EXCOL_WORDCOUNT , 20016)
  207. PROPUI_ENTRY("DocCharCount" , SCID_CharCount , IDS_EXCOL_CHARCOUNT , IDS_MNEMONIC_EXCOL_CHARCOUNT , 20017)
  208. PROPUI_ENTRY("DocLastSavedTm" , SCID_LastSaveDTM , IDS_EXCOL_LASTSAVEDTM , IDS_MNEMONIC_EXCOL_LASTSAVEDTM , 20018)
  209. PROPUI_ENTRY("DocLastPrinted" , SCID_LastPrinted , IDS_EXCOL_LASTPRINTED , IDS_MNEMONIC_EXCOL_LASTPRINTED , 20019)
  210. PROPUI_ENTRY("DocEditTime" , SCID_EditTime , IDS_EXCOL_EDITTIME , IDS_MNEMONIC_EXCOL_EDITTIME , 20020)
  211. PROPUI_ENTRY("DocByteCount" , SCID_ByteCount , IDS_EXCOL_BYTECOUNT , IDS_MNEMONIC_EXCOL_BYTECOUNT , 20021)
  212. PROPUI_ENTRY("DocLineCount" , SCID_LineCount , IDS_EXCOL_LINECOUNT , IDS_MNEMONIC_EXCOL_LINECOUNT , 20022)
  213. PROPUI_ENTRY("DocParaCount" , SCID_ParagraphCount , IDS_EXCOL_PARCOUNT , IDS_MNEMONIC_EXCOL_PARCOUNT , 20023)
  214. PROPUI_ENTRY("DocSlideCount" , SCID_SlideCount , IDS_EXCOL_SLIDECOUNT , IDS_MNEMONIC_EXCOL_SLIDECOUNT , 20024)
  215. PROPUI_ENTRY("DocNoteCount" , SCID_NoteCount , IDS_EXCOL_NOTECOUNT , IDS_MNEMONIC_EXCOL_NOTECOUNT , 20025)
  216. PROPUI_ENTRY("DocHiddenCount" , SCID_HiddenCount , IDS_EXCOL_HIDDENCOUNT , IDS_MNEMONIC_EXCOL_HIDDENCOUNT , 20026)
  217. PROPUI_ENTRY("MMClipCount" , SCID_MMClipCount , IDS_EXCOL_MMCLIPCOUNT , IDS_MNEMONIC_EXCOL_MMCLIPCOUNT , 20027)
  218. PROPUI_ENTRY("Scale" , SCID_Scale , IDS_EXCOL_SCALE , IDS_MNEMONIC_EXCOL_SCALE , 20028)
  219. PROPUI_ENTRY("LinksUpToDate" , SCID_LinksDirty , IDS_EXCOL_LINKSDIRTY , IDS_MNEMONIC_EXCOL_LINKSDIRTY , 20029)
  220. PROPUI_ENTRY("CameraModel" , SCID_CameraModel , IDS_EXCOL_CAMERAMODEL , IDS_MNEMONIC_EXCOL_CAMERAMODEL , 10037)
  221. PROPUI_ENTRY("Copyright" , SCID_TagCopyright , IDS_EXCOL_COPYRIGHT , IDS_MNEMONIC_EXCOL_COPYRIGHT , 20030)
  222. PROPUI_ENTRY("Software" , SCID_TagSoftwareUsed , IDS_EXCOL_SOFTWARE , IDS_MNEMONIC_EXCOL_SOFTWARE , 20031)
  223. PROPUI_ENTRY("WhenTaken" , SCID_WhenTaken , IDS_EXCOL_WHENTAKEN , IDS_MNEMONIC_EXCOL_WHENTAKEN , 10038)
  224. PROPUI_ENTRY("FileType" , SCID_FileType , IDS_EXCOL_FILETYPE , IDS_MNEMONIC_EXCOL_FILETYPE , 20032)
  225. PROPUI_ENTRY("ImageX" , SCID_ImageCX , IDS_EXCOL_IMAGECX , IDS_MNEMONIC_EXCOL_IMAGECX , 20033)
  226. PROPUI_ENTRY("ImageY" , SCID_ImageCY , IDS_EXCOL_IMAGECY , IDS_MNEMONIC_EXCOL_IMAGECY , 20034)
  227. PROPUI_ENTRY("ResolutionX" , SCID_ResolutionX , IDS_EXCOL_RESOLUTIONX , IDS_MNEMONIC_EXCOL_RESOLUTIONX , 20035)
  228. PROPUI_ENTRY("ResolutionY" , SCID_ResolutionY , IDS_EXCOL_RESOLUTIONY , IDS_MNEMONIC_EXCOL_RESOLUTIONY , 20036)
  229. PROPUI_ENTRY("BitDepth" , SCID_BitDepth , IDS_EXCOL_BITDEPTH , IDS_MNEMONIC_EXCOL_BITDEPTH , 20037)
  230. PROPUI_ENTRY("ColorSpace" , SCID_ColorSpace , IDS_EXCOL_COLORSPACE , IDS_MNEMONIC_EXCOL_COLORSPACE , 20038)
  231. PROPUI_ENTRY("ColorSpace" , SCID_Colorspace , IDS_EXCOL_COLORSPACE , IDS_MNEMONIC_EXCOL_COLORSPACE , 20038)
  232. PROPUI_ENTRY("Compression" , SCID_Compression , IDS_EXCOL_ACOMPRESSION , IDS_MNEMONIC_EXCOL_ACOMPRESSION , 20039)
  233. PROPUI_ENTRY("Transparency" , SCID_Transparency , IDS_EXCOL_TRANSPARENCY , IDS_MNEMONIC_EXCOL_TRANSPARENCY , 20040)
  234. PROPUI_ENTRY("Gamma" , SCID_GammaValue , IDS_EXCOL_GAMMAVALUE , IDS_MNEMONIC_EXCOL_GAMMAVALUE , 20041)
  235. PROPUI_ENTRY("FrameCount" , SCID_FrameCount , IDS_EXCOL_FRAMECOUNT , IDS_MNEMONIC_EXCOL_FRAMECOUNT , 10046)
  236. PROPUI_ENTRY("Dimensions" , SCID_ImageDimensions , IDS_EXCOL_DIMENSIONS , IDS_MNEMONIC_EXCOL_DIMENSIONS , 10059)
  237. PROPUI_ENTRY("Flash" , SCID_Flash , IDS_EXCOL_FLASH , IDS_MNEMONIC_EXCOL_FLASH , 20042)
  238. PROPUI_ENTRY("ShutterSpeed" , SCID_ShutterSpeed , IDS_EXCOL_SHUTTERSPEED , IDS_NMEMONIC_EXCOL_SHUTTERSPEED , 20043)
  239. PROPUI_ENTRY("Aperture" , SCID_Aperture , IDS_EXCOL_APERTURE , IDS_NMEMONIC_EXCOL_APERTURE , 20044)
  240. PROPUI_ENTRY("Distance" , SCID_SubjectDist , IDS_EXCOL_DISTANCE , IDS_NMEMONIC_EXCOL_DISTANCE , 20046)
  241. PROPUI_ENTRY("FocalLength" , SCID_FocalLength , IDS_EXCOL_FOCALLENGTH , IDS_MNEMONIC_EXCOL_FOCALLENGTH , 20047)
  242. PROPUI_ENTRY("FNumber" , SCID_FNumber , IDS_EXCOL_FNUMBER , IDS_MNEMONIC_EXCOL_FNUMBER , 20049)
  243. PROPUI_ENTRY("ExposureTime" , SCID_ExposureTime , IDS_EXCOL_EXPOSURETIME , IDS_MNEMONIC_EXCOL_EXPOSURETIME , 20049)
  244. PROPUI_ENTRY("FlashEnergy" , SCID_FlashEnergy ,IDS_EXCOL_FLASHENERGY , IDS_MNEMONIC_EXCOL_FLASHENERGY , 20080)
  245. PROPUI_ENTRY("ISOSpeed" , SCID_ISOSpeed ,IDS_EXCOL_ISOSPEED , IDS_MNEMONIC_EXCOL_ISOSPEED , 20081)
  246. PROPUI_ENTRY("MeteringMode" , SCID_MeteringMode ,IDS_EXCOL_METERINGMODE , IDS_MNEMONIC_EXCOL_METERINGMODE , 20082)
  247. PROPUI_ENTRY("LightSource" , SCID_LightSource ,IDS_EXCOL_LIGHTSOURCE , IDS_MNEMONIC_EXCOL_LIGHTSOURCE , 20083)
  248. PROPUI_ENTRY("ExposureProg" , SCID_ExposureProg ,IDS_EXCOL_EXPOSUREPROG , IDS_MNEMONIC_EXCOL_EXPOSUREPROG , 20084)
  249. PROPUI_ENTRY("ExposureBias" , SCID_ExposureBias ,IDS_EXCOL_EXPOSUREBIAS , IDS_MNEMONIC_EXCOL_EXPOSUREBIAS , 20085)
  250. PROPUI_ENTRY("Artist" , SCID_MUSIC_Artist , IDS_EXCOL_ARTIST , IDS_MNEMONIC_EXCOL_ARTIST , 10028)
  251. PROPUI_ENTRY("Album" , SCID_MUSIC_Album , IDS_EXCOL_ALBUM , IDS_MNEMONIC_EXCOL_ALBUM , 10029)
  252. PROPUI_ENTRY("Year" , SCID_MUSIC_Year , IDS_EXCOL_YEAR , IDS_MNEMONIC_EXCOL_YEAR , 10030)
  253. PROPUI_ENTRY("Track" , SCID_MUSIC_Track , IDS_EXCOL_TRACK , IDS_MNEMONIC_EXCOL_TRACK , 10031)
  254. PROPUI_ENTRY("Duration" , SCID_AUDIO_Duration , IDS_EXCOL_DURATION , IDS_MNEMONIC_EXCOL_DURATION , 10032)
  255. PROPUI_ENTRY("Bitrate" , SCID_AUDIO_Bitrate , IDS_EXCOL_BITRATE , IDS_MNEMONIC_EXCOL_BITRATE , 10033)
  256. PROPUI_ENTRY("Sample Rate" , SCID_AUDIO_SampleRate , IDS_EXCOL_SAMPLERATE , IDS_MNEMONIC_EXCOL_SAMPLERATE , 20050)
  257. PROPUI_ENTRY("Audio Sample Size" , SCID_AUDIO_SampleSize , IDS_EXCOL_ASAMPLESIZE , IDS_MNEMONIC_EXCOL_ASAMPLESIZE , 10041)
  258. PROPUI_ENTRY("Channels" , SCID_AUDIO_ChannelCount , IDS_EXCOL_CHANNELS , IDS_MNEMONIC_EXCOL_CHANNELS , 10047)
  259. PROPUI_ENTRY("Audio Format" , SCID_AUDIO_Format , IDS_EXCOL_FORMAT , IDS_MNEMONIC_EXCOL_FORMAT , 10039)
  260. PROPUI_ENTRY("Data Rate" , SCID_VIDEO_Bitrate , IDS_EXCOL_DATARATE , IDS_MNEMONIC_EXCOL_DATARATE , 20050)
  261. PROPUI_ENTRY("Frame Rate" , SCID_VIDEO_FrameRate , IDS_EXCOL_FRAMERATE , IDS_MNEMONIC_EXCOL_FRAMERATE , 10045)
  262. PROPUI_ENTRY("Video Sample Size" , SCID_VIDEO_SampleSize , IDS_EXCOL_VSAMPLESIZE , IDS_MNEMONIC_EXCOL_VSAMPLESIZE , 10044)
  263. PROPUI_ENTRY("Compression" , SCID_VIDEO_Compression , IDS_EXCOL_VCOMPRESSION , IDS_MNEMONIC_EXCOL_VCOMPRESSION , 10043)
  264. PROPUI_ENTRY("Stream Name" , SCID_VIDEO_StreamName , IDS_EXCOL_STREAMNAME , IDS_MNEMONIC_EXCOL_STREAMNAME , 20051)
  265. PROPUI_ENTRY("Genre" , SCID_MUSIC_Genre , IDS_EXCOL_GENRE , IDS_MNEMONIC_EXCOL_GENRE , 20052)
  266. PROPUI_ENTRY("Lyrics" , SCID_MUSIC_Lyrics , IDS_EXCOL_LYRICS , IDS_EXCOL_LYRICS , 0)
  267. PROPUI_ENTRY("Protected" , SCID_DRM_Protected , IDS_EXCOL_PROTECTED , IDS_MNEMONIC_EXCOL_PROTECTED , 20074)
  268. PROPUI_ENTRY("DRM Description" , SCID_DRM_Description , IDS_EXCOL_DRMDESCRIPTION , IDS_MNEMONIC_EXCOL_DRMDESCRIPTION , 20075)
  269. PROPUI_ENTRY("Play Count" , SCID_DRM_PlayCount , IDS_EXCOL_PLAYCOUNT , IDS_MNEMONIC_EXCOL_PLAYCOUNT , 20076)
  270. PROPUI_ENTRY("Play Starts" , SCID_DRM_PlayStarts , IDS_EXCOL_PLAYSTARTS , IDS_MNEMONIC_EXCOL_PLAYSTARTS , 20077)
  271. PROPUI_ENTRY("Play Expires" , SCID_DRM_PlayExpires , IDS_EXCOL_PLAYEXPIRES , IDS_MNEMONIC_EXCOL_PLAYEXPIRES , 20078)
  272. PROPUI_ENTRY("FaxTime" , SCID_FaxEndTime , IDS_EXCOL_FAXENDTIME , IDS_MNEMONIC_EXCOL_FAXENDTIME , 20053)
  273. PROPUI_ENTRY("FaxSenderName" , SCID_FaxSenderName , IDS_EXCOL_FAXSENDERNAME , IDS_MNEMONIC_EXCOL_FAXSENDERNAME , 20054)
  274. PROPUI_ENTRY("FaxTSID" , SCID_FaxTSID , IDS_EXCOL_FAXTSID , IDS_MNEMONIC_EXCOL_FAXTSID , 20055)
  275. PROPUI_ENTRY("FaxCallerID" , SCID_FaxCallerId , IDS_EXCOL_FAXCALLERID , IDS_MNEMONIC_EXCOL_FAXCALLERID , 20056)
  276. PROPUI_ENTRY("FaxRecipientName" , SCID_FaxRecipName , IDS_EXCOL_FAXRECIPNAME , IDS_MNEMONIC_EXCOL_FAXRECIPNAME , 20057)
  277. PROPUI_ENTRY("FaxRecipientNumber" , SCID_FaxRecipNumber , IDS_EXCOL_FAXRECIPNUMBER , IDS_MNEMONIC_EXCOL_FAXRECIPNUMBER , 20058)
  278. PROPUI_ENTRY("FaxCSID" , SCID_FaxCSID , IDS_EXCOL_FAXCSID , IDS_MNEMONIC_EXCOL_FAXCSID , 20059)
  279. PROPUI_ENTRY("FaxRouting" , SCID_FaxRouting , IDS_EXCOL_FAXROUTING , IDS_MNEMONIC_EXCOL_FAXROUTING , 20060)
  280. PROPUI_ENTRY("EquipMake" , SCID_TagEquipMake , IDS_EXCOL_TAGEQUIPMAKE , IDS_MNEMONIC_EXCOL_TAGEQUIPMAKE , 20061)
  281. PROPUI_ENTRY("SequenceNo" , SCID_Media_SequenceNumber , IDS_EXCOL_SEQUENCENUMBER , IDS_MNEMONIC_EXCOL_SEQUENCENUMBER , 20062)
  282. PROPUI_ENTRY("Owner" , SCID_Media_Owner , IDS_EXCOL_OWNER , IDS_MNEMONIC_EXCOL_OWNER , 20063)
  283. PROPUI_ENTRY("Editor" , SCID_Media_Editor , IDS_EXCOL_EDITOR , IDS_MNEMONIC_EXCOL_EDITOR , 20064)
  284. PROPUI_ENTRY("Supplier" , SCID_Media_Supplier , IDS_EXCOL_SUPPLIER , IDS_MNEMONIC_EXCOL_SUPPLIER , 20065)
  285. PROPUI_ENTRY("Source" , SCID_Media_Source , IDS_EXCOL_SOURCE , IDS_MNEMONIC_EXCOL_SOURCE , 20066)
  286. PROPUI_ENTRY("Copyright" , SCID_Media_Copyright , IDS_EXCOL_COPYRIGHT , IDS_MNEMONIC_EXCOL_COPYRIGHT , 20067)
  287. PROPUI_ENTRY("Project" , SCID_Media_Project , IDS_EXCOL_PROJECT , IDS_MNEMONIC_EXCOL_PROJECT , 20068)
  288. PROPUI_ENTRY("Status" , SCID_Media_Status , IDS_EXCOL_STATUS , IDS_MNEMONIC_EXCOL_STATUS , 20069)
  289. PROPUI_ENTRY("Production" , SCID_Media_Production , IDS_EXCOL_PRODUCTION , IDS_MNEMONIC_EXCOL_PRODUCTION , 20070)
  290. PROPUI_ENTRY("Company" , SCID_CompanyName , IDS_VN_COMPANYNAME , IDS_MNEMONIC_VN_COMPANYNAME , 10034)
  291. PROPUI_ENTRY("Manager" , SCID_Manager , IDS_EXCOL_MANAGER , IDS_MNEMONIC_EXCOL_MANAGER , 20071)
  292. PROPUI_ENTRY("PresentationTarget" , SCID_PresFormat , IDS_EXCOL_PRESFORMAT , IDS_MNEMONIC_EXCOL_PRESFORMAT , 20072)
  293. PROPUI_ENTRY("FileDescription" , SCID_FileDescription , IDS_VN_FILEDESCRIPTION , IDS_MNEMONIC_VN_FILEDESCRIPTION , 10056)
  294. PROPUI_ENTRY("FileVersion" , SCID_FileVersion , IDS_VN_FILEVERSION , IDS_MNEMONIC_VN_FILEVERSION , 10057)
  295. PROPUI_ENTRY("ProductName" , SCID_ProductName , IDS_VN_PRODUCTNAME , IDS_MNEMONIC_VN_PRODUCTNAME , 10035)
  296. PROPUI_ENTRY("ProductVersion" , SCID_ProductVersion , IDS_VN_PRODUCTVERSION , IDS_MNEMONIC_VN_PRODUCTVERSION , 10036)
  297. PROPUI_ENTRY("DeletedFrom" , SCID_DELETEDFROM , IDS_DELETEDFROM_COL , IDS_MNEMONIC_DELETEDFROM_COL , 10048)
  298. PROPUI_ENTRY("DateDeleted" , SCID_DATEDELETED , IDS_DATEDELETED_COL , IDS_MNEMONIC_DATEDELETED_COL , 10049)
  299. PROPUI_ENTRY("SyncCopyIn" , SCID_SYNCCOPYIN , IDS_SYNCCOPYIN_COL , IDS_MNEMONIC_SYNCCOPYIN_COL , 10060)
  300. PROPUI_ENTRY("Status" , SCID_STATUS , IDS_STATUS_COL , IDS_MNEMONIC_STATUS_COL , 0) // do we need help for this? What is it?
  301. PROPUI_ENTRY("FreeSpace" , SCID_FREESPACE , IDS_DRIVES_FREE , IDS_MNEMONIC_DRIVES_FREE , 10051)
  302. PROPUI_ENTRY("Capacity" , SCID_CAPACITY , IDS_DRIVES_CAPACITY , IDS_MNEMONIC_DRIVES_CAPACITY , 10050)
  303. PROPUI_ENTRY("FileSystem" , SCID_FILESYSTEM , IDS_DRIVES_FILESYSTEM , IDS_MNEMONIC_DRIVES_FILESYSTEM , 10062)
  304. PROPUI_ENTRY("" , SCID_PRN_QUEUESIZE , IDS_PSD_QUEUESIZE , IDS_MNEMONIC_PSD_QUEUESIZE , 10063)
  305. PROPUI_ENTRY("" , SCID_PRN_LOCATION , IDS_PSD_LOCATION , IDS_MNEMONIC_PSD_LOCATION , 10064)
  306. PROPUI_ENTRY("" , SCID_PRN_MODEL , IDS_PSD_MODEL , IDS_MNEMONIC_PSD_MODEL , 10066)
  307. PROPUI_ENTRY("" , SCID_PRN_STATUS , IDS_PRQ_STATUS , IDS_MNEMONIC_PRQ_STATUS , 10065)
  308. PROPUI_ENTRY("Directory" , SCID_DIRECTORY , IDS_PATH_COL , IDS_MNEMONIC_PATH_COL , 10053)
  309. PROPUI_ENTRY("Rank" , SCID_RANK , IDS_RANK_COL , IDS_MNEMONIC_RANK_COL , 10054)
  310. PROPUI_ENTRY("" , SCID_WHICHFOLDER , IDS_WHICHFOLDER_COL , IDS_MNEMONIC_WHICHFOLDER_COL , 10067)
  311. PROPUI_ENTRY("CSCStatus" , SCID_CSC_STATUS , IDS_CSC_STATUS , IDS_MNEMONIC_CSC_STATUS , 20073)
  312. PROPUI_ENTRY_NORES("LinkTarget" , SCID_LINKTARGET)
  313. };
  314. // String resource mapping block
  315. struct STRING_MAP
  316. {
  317. ULONG uVal;
  318. UINT idStr;
  319. };
  320. static const STRING_MAP g_cLightSourceStrings[] =
  321. {
  322. { 1, IDS_PROPERTYUI_IMAGE_DAYLIGHT},
  323. { 2, IDS_PROPERTYUI_IMAGE_FLOURESCENT},
  324. { 3, IDS_PROPERTYUI_IMAGE_TUNGSTEN},
  325. {17, IDS_PROPERTYUI_IMAGE_STANDARDA},
  326. {18, IDS_PROPERTYUI_IMAGE_STANDARDB},
  327. {19, IDS_PROPERTYUI_IMAGE_STANDARDC},
  328. {20, IDS_PROPERTYUI_IMAGE_D55},
  329. {21, IDS_PROPERTYUI_IMAGE_D65},
  330. {22, IDS_PROPERTYUI_IMAGE_D75},
  331. { 0, IDS_PROPERTYUI_IMAGE_UNKNOWN}, // Last entry is default
  332. };
  333. static const STRING_MAP g_cExposureProgStrings[] =
  334. {
  335. {1, IDS_PROPERTYUI_IMAGE_MANUAL},
  336. {2, IDS_PROPERTYUI_IMAGE_NORMAL},
  337. {3, IDS_PROPERTYUI_IMAGE_APERTUREPRI},
  338. {4, IDS_PROPERTYUI_IMAGE_SHUTTERPRI},
  339. {5, IDS_PROPERTYUI_IMAGE_CREATIVE},
  340. {6, IDS_PROPERTYUI_IMAGE_ACTION},
  341. {7, IDS_PROPERTYUI_IMAGE_PORTRAIT},
  342. {8, IDS_PROPERTYUI_IMAGE_LANDSCAPE},
  343. {0, IDS_PROPERTYUI_IMAGE_UNKNOWN}, // Last entry is default
  344. };
  345. static const STRING_MAP g_cMeteringModeStrings[] =
  346. {
  347. {1, IDS_PROPERTYUI_IMAGE_AVERAGE},
  348. {2, IDS_PROPERTYUI_IMAGE_CWA},
  349. {3, IDS_PROPERTYUI_IMAGE_SPOT},
  350. {4, IDS_PROPERTYUI_IMAGE_MULTISPOT},
  351. {5, IDS_PROPERTYUI_IMAGE_PATTERN},
  352. {6, IDS_PROPERTYUI_IMAGE_PARTIAL},
  353. {0, IDS_PROPERTYUI_IMAGE_UNKNOWN}, // Last entry is default
  354. };
  355. static const STRING_MAP g_cFlashStrings[] =
  356. {
  357. {0, IDS_PROPERTYUI_IMAGE_NOFLASH},
  358. {1, IDS_PROPERTYUI_IMAGE_FLASHFIRED},
  359. {5, IDS_PROPERTYUI_IMAGE_NOSTROBERETURN},
  360. {7, IDS_PROPERTYUI_IMAGE_STROBERETURN},
  361. {0, 0},
  362. };
  363. static const STRING_MAP g_cColorStrings[] =
  364. {
  365. {1, IDS_PROPERTYUI_IMAGE_SRGB},
  366. {0xffff, IDS_PROPERTYUI_IMAGE_UNCALIBRATED},
  367. {0,0},
  368. };
  369. static const STRING_MAP g_cMediaStatus[] =
  370. {
  371. { PIDMSI_STATUS_NORMAL , IDS_STATUSVAL_NORMAL },
  372. { PIDMSI_STATUS_NEW , IDS_STATUSVAL_NEW },
  373. { PIDMSI_STATUS_PRELIM , IDS_STATUSVAL_PRELIM },
  374. { PIDMSI_STATUS_DRAFT , IDS_STATUSVAL_DRAFT },
  375. { PIDMSI_STATUS_EDIT , IDS_STATUSVAL_EDIT },
  376. { PIDMSI_STATUS_INPROGRESS , IDS_STATUSVAL_INPROGRESS },
  377. { PIDMSI_STATUS_REVIEW , IDS_STATUSVAL_REVIEW },
  378. { PIDMSI_STATUS_PROOF , IDS_STATUSVAL_PROOF },
  379. { PIDMSI_STATUS_FINAL , IDS_STATUSVAL_FINAL },
  380. { PIDMSI_STATUS_OTHER , IDS_STATUSVAL_OTHER },
  381. { 0,0 }
  382. };
  383. STDAPI SCIDCannonicalName(SHCOLUMNID *pscid, LPTSTR pszName, int cch)
  384. {
  385. HRESULT hr = E_FAIL;
  386. pszName[0] = 0;
  387. for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
  388. {
  389. if (IsEqualSCID(*pscid, *c_rgPropUIInfo[i].pscid))
  390. {
  391. SHUnicodeToTChar(c_rgPropUIInfo[i].pwszName, pszName, cch);
  392. hr = S_OK;
  393. break;
  394. }
  395. }
  396. return hr;
  397. }
  398. LPCTSTR TrimLeadingWhiteSpaces(LPCTSTR pszString)
  399. {
  400. LPCTSTR psz = pszString;
  401. while (psz && ((*psz == TEXT(' ')) || (*psz == TEXT('\n')) || (*psz == TEXT('\t'))))
  402. {
  403. psz++;
  404. }
  405. return psz;
  406. }
  407. STDAPI_(BOOL) ParseSCIDString(LPCTSTR pszString, SHCOLUMNID *pscid, UINT *pidRes)
  408. {
  409. BOOL bRet = FALSE;
  410. if (GUIDFromString(pszString, &pscid->fmtid))
  411. {
  412. // GUIDSTR_MAX includes space for the terminating NULL
  413. LPCTSTR pszPid = &pszString[GUIDSTR_MAX - 1];
  414. // Skip past any leading white space
  415. pszPid = TrimLeadingWhiteSpaces(pszPid);
  416. pscid->pid = StrToInt(pszPid);
  417. bRet = TRUE;
  418. if (pidRes)
  419. *pidRes = 0;
  420. }
  421. else
  422. {
  423. WCHAR szName[64];
  424. SHTCharToUnicode(pszString, szName, ARRAYSIZE(szName));
  425. for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
  426. {
  427. if (StrCmpIW(szName, c_rgPropUIInfo[i].pwszName) == 0)
  428. {
  429. *pscid = *c_rgPropUIInfo[i].pscid;
  430. if (pidRes)
  431. *pidRes = c_rgPropUIInfo[i].idDisplayName;
  432. bRet = TRUE;
  433. break;
  434. }
  435. }
  436. }
  437. return bRet;
  438. }
  439. //
  440. // Function converts a SCID into a string.
  441. // The string format is "{scid.fmtid} scid.pid" (There is a space in between)
  442. // So for example, SCID_Category will yield the following string -
  443. // "{d5cdd502-2e9c-101b-9397-08002b2cf9ae} 2"
  444. //
  445. // See ParseSCIDString() above for the the complimentary function.
  446. // Also see CFolderItem::ExtendedProperty() in sdflditm.cpp if you are curious
  447. // as to where is ParseSCIDString() used and see CtrlFldr.cpp and RegFldr.cpp for
  448. // usage of StringFromSCID().
  449. //
  450. STDAPI_(int) StringFromSCID(const SHCOLUMNID *pscid, LPTSTR psz, UINT cch)
  451. {
  452. TCHAR ach[GUIDSTR_MAX];
  453. if (0 != SHStringFromGUID(pscid->fmtid, ach, ARRAYSIZE(ach)))
  454. {
  455. return wnsprintf(psz, cch, TEXT("%s %d"), ach, pscid->pid);
  456. }
  457. *psz = 0;
  458. return 0;
  459. }
  460. STDAPI MapColumnToSCIDImpl(const COLUMN_INFO* pcol, UINT nCols, UINT iColumn, SHCOLUMNID* pscid)
  461. {
  462. HRESULT hr;
  463. if (iColumn < nCols)
  464. {
  465. *pscid = *pcol[iColumn].pscid;
  466. hr = S_OK;
  467. }
  468. else
  469. {
  470. ZeroMemory(pscid, sizeof(*pscid));
  471. hr = E_INVALIDARG;
  472. }
  473. return hr;
  474. }
  475. STDAPI_(int) FindSCID(const COLUMN_INFO* pcol, UINT nCols, const SHCOLUMNID* pscid)
  476. {
  477. for (UINT i = 0; i < nCols; i++)
  478. {
  479. if (IsEqualSCID(*pscid, *pcol[i].pscid))
  480. return (int)i;
  481. }
  482. return -1;
  483. }
  484. STDAPI GetDetailsOfInfo(const COLUMN_INFO* pcol_data, UINT nCols, UINT iColumn, SHELLDETAILS *pdi)
  485. {
  486. HRESULT hr;
  487. if (iColumn < nCols)
  488. {
  489. pdi->fmt = pcol_data[iColumn].fmt;
  490. pdi->cxChar = pcol_data[iColumn].cChars;
  491. hr = ResToStrRet(pcol_data[iColumn].idTitle, &pdi->str);
  492. }
  493. else
  494. {
  495. hr = E_NOTIMPL; // we don't support his column
  496. }
  497. return hr;
  498. }
  499. // dead export
  500. STDAPI SHStgOpenStorageW(LPCWSTR pwszPath, DWORD grfMode, DWORD grfAttr, DWORD grfFileAttr, REFIID riid, void **ppv)
  501. {
  502. *ppv = NULL;
  503. return E_NOTIMPL;
  504. }
  505. // dead export
  506. STDAPI SHStgOpenStorageA(LPCSTR pwszPath, DWORD grfMode, DWORD grfAttr, DWORD grfFileAttr, REFIID riid, void **ppv)
  507. {
  508. *ppv = NULL;
  509. return E_NOTIMPL;
  510. }
  511. const PROPSPEC codepage_spec = { PRSPEC_PROPID, PID_CODEPAGE } ;
  512. // Retrieves the codepage value from an existing property set storage.
  513. STDAPI SHPropStgReadCP(IPropertyStorage* ppss, UINT* puCodePage)
  514. {
  515. *puCodePage = 0; // CP_ACP == 0, assume failure here
  516. PROPVARIANT varCP;
  517. if (S_OK == ppss->ReadMultiple(1, &codepage_spec, &varCP))
  518. {
  519. if (VT_I2 == varCP.vt)
  520. {
  521. *puCodePage = (UINT)MAKELONG(varCP.iVal, 0);
  522. }
  523. }
  524. return (0 == *puCodePage) ? E_FAIL : S_OK;
  525. }
  526. // Modifies the property set codepage on a new property set storage.
  527. //
  528. // Note: this function will fail if the property set already
  529. // contains properties.
  530. STDAPI SHPropStgWriteCP(IPropertyStorage* ppss, IN UINT uCodePage)
  531. {
  532. PROPVARIANT varCP;
  533. varCP.iVal = (SHORT)uCodePage;
  534. varCP.vt = VT_I2;
  535. return ppss->WriteMultiple(1, &codepage_spec, &varCP, PID_CODEPAGE);
  536. }
  537. // IPropertySetStorage::Open/Create wrapper.
  538. // The wrap properly retrieves/assigns the set's codepage value.
  539. STDAPI SHPropStgCreate(
  540. IPropertySetStorage* psstg, // Address of IPropertySetStorage vtable
  541. REFFMTID fmtid, // property set ID
  542. CLSID* pclsid, // class ID associated with the set. This can be NULL
  543. DWORD grfFlags, // PROPSETFLAG_xxx. All sets containing ansi bytes should be created with
  544. // PROPSETFLAG_ANSI, otherwise PROPSETFLAG_DEFAULT
  545. DWORD grfMode, // STGM_ flags. Must contain STGM_DIRECT|STGM_EXCLUSIVE.
  546. DWORD dwDisposition, // OPEN_EXISTING. OPEN_ALWAYS, CREATE_NEW, CREATE_ALWAYS
  547. OUT IPropertyStorage** ppstg, // Address to receive requested vtable
  548. OUT UINT* puCodePage) // Optional address to receive the code page ID for the set.
  549. {
  550. ASSERT(psstg);
  551. ASSERT(ppstg);
  552. if (puCodePage)
  553. *puCodePage = 0;
  554. *ppstg = NULL;
  555. // Check legacy sets. These MUST be flagged ANSI
  556. if (IsEqualGUID(fmtid, FMTID_SummaryInformation) ||
  557. IsEqualGUID(fmtid, FMTID_DocSummaryInformation) ||
  558. IsEqualGUID(fmtid, FMTID_UserDefinedProperties))
  559. {
  560. grfFlags |= PROPSETFLAG_ANSI; // these legacy sets MUST be ansi.
  561. }
  562. // Attempt opening the set
  563. HRESULT hr = psstg->Open(fmtid, grfMode, ppstg);
  564. if (SUCCEEDED(hr)) // opened the set
  565. {
  566. // If a new set was requested, fail.
  567. if (CREATE_NEW == dwDisposition)
  568. {
  569. (*ppstg)->Release();
  570. *ppstg = NULL;
  571. return STG_E_FILEALREADYEXISTS;
  572. }
  573. // If the request was to overwrite any existing set, delete the current one.
  574. if (CREATE_ALWAYS == dwDisposition)
  575. {
  576. (*ppstg)->Release();
  577. *ppstg = NULL;
  578. if (FAILED((hr = psstg->Delete(fmtid))))
  579. return hr;
  580. hr = STG_E_FILENOTFOUND; // falls through to create
  581. }
  582. }
  583. else // failed to open the set
  584. {
  585. // if an existing set is requested, fail
  586. if (OPEN_EXISTING == dwDisposition)
  587. return hr;
  588. }
  589. if (STG_E_FILENOTFOUND == hr) // set doesn't exist, so create it.
  590. {
  591. hr = psstg->Create(fmtid, pclsid, grfFlags, grfMode, ppstg);
  592. }
  593. // If we haven't assigned a codepage, then read it from PID_CODEPAGE.
  594. if (SUCCEEDED(hr) && puCodePage)
  595. {
  596. ASSERT(*ppstg);
  597. SHPropStgReadCP(*ppstg, puCodePage);
  598. }
  599. return hr;
  600. }
  601. STDAPI_(BOOL) _IsAnsiPropertySet(REFFMTID fmtid);
  602. STDAPI_(BOOL) _DoesStringRoundTripCPW(UINT uCodePage, LPCWSTR pwszIn, LPSTR pszOut, UINT cchOut);
  603. STDAPI _DoLegacyPropertiesRoundTrip(REFFMTID fmtid, UINT uCodePage, ULONG cvar, PROPVARIANT rgvar[]);
  604. STDAPI _UniversalizeSet(IPropertyStorage* pstg, IN OUT UINT* puCodePage, PROPID propidNameFirst);
  605. STDAPI _LegacyPropertiesToUnicode(REFFMTID fmtid, UINT uCodePage, ULONG cpspec, PROPSPEC const rgpspec[], PROPVARIANT rgvar[]);
  606. STDAPI _LegacyPropertiesToAnsi(REFFMTID fmtid, UINT uCodePage, ULONG cpspec, PROPSPEC const rgpspec[], PROPVARIANT rgvar[]);
  607. // IPropertyStorage::ReadMultiple wrap
  608. //
  609. // The wrap ensures ANSI/UNICODE translations are handled properly for
  610. // legacy property sets.
  611. STDAPI SHPropStgReadMultiple(
  612. IPropertyStorage* pps, // address of IPropertyStorage vtable.
  613. UINT uCodePage, // Code page value retrieved from SHCreatePropertySet
  614. ULONG cpspec, // Count of properties being read
  615. PROPSPEC const rgpspec[], // Array of the properties to be read
  616. PROPVARIANT rgvar[]) // Array of PROPVARIANTs containing the
  617. // property values on return
  618. {
  619. // read the requested properties
  620. HRESULT hr = pps->ReadMultiple(cpspec, rgpspec, rgvar);
  621. if (S_OK == hr)
  622. {
  623. HRESULT hrTmp = S_OK;
  624. // grab the set's ANSI codepage if not provided.
  625. if (0 == uCodePage)
  626. {
  627. hrTmp = SHPropStgReadCP(pps, &uCodePage);
  628. }
  629. if (SUCCEEDED(hrTmp))
  630. {
  631. STATPROPSETSTG stat;
  632. if (SUCCEEDED(pps->Stat(&stat)))
  633. {
  634. hr = _LegacyPropertiesToUnicode(stat.fmtid, uCodePage, cpspec, rgpspec, rgvar);
  635. }
  636. }
  637. }
  638. return hr;
  639. }
  640. // IPropertyStorage::WriteMultiple wrap
  641. //
  642. // The wrap ensures ANSI/UNICODE translations are handled properly for
  643. // legacy property sets.
  644. STDAPI SHPropStgWriteMultiple(
  645. IPropertyStorage* pps, // address of IPropertyStorage vtable.
  646. UINT* puCodePage, // code page retrieved from SHCreatePropertySet.
  647. ULONG cpspec, // The number of properties being set
  648. PROPSPEC const rgpspec[], // Property specifiers
  649. PROPVARIANT rgvar[], // Array of PROPVARIANT values
  650. PROPID propidNameFirst) // Minimum value for property identifiers
  651. // when they must be allocated
  652. {
  653. UINT uCodePage = 0;
  654. if (!puCodePage)
  655. puCodePage = &uCodePage;
  656. ASSERT(propidNameFirst >= PID_FIRST_USABLE); // you're walking on OLE PIDs.
  657. STATPROPSETSTG stat;
  658. HRESULT hr = pps->Stat(&stat); // need the FMTID
  659. if (SUCCEEDED(hr))
  660. {
  661. // read in the codepage if it isn't provided.
  662. if (0 == *puCodePage)
  663. {
  664. hr = SHPropStgReadCP(pps, puCodePage);
  665. }
  666. if (SUCCEEDED(hr) )
  667. {
  668. // test for round-trippability
  669. hr = _DoLegacyPropertiesRoundTrip(stat.fmtid, *puCodePage, cpspec, rgvar);
  670. if (SUCCEEDED(hr))
  671. {
  672. if (S_FALSE == hr)
  673. {
  674. hr = _UniversalizeSet(pps, puCodePage, propidNameFirst);
  675. }
  676. if (SUCCEEDED(hr))
  677. {
  678. // convert legacy properties back to ansi
  679. hr = _LegacyPropertiesToAnsi(stat.fmtid, *puCodePage, cpspec, rgpspec, rgvar);
  680. if (SUCCEEDED(hr))
  681. {
  682. // write em.
  683. hr = pps->WriteMultiple(cpspec, rgpspec, rgvar, propidNameFirst);
  684. if (FAILED(hr))
  685. _LegacyPropertiesToUnicode(stat.fmtid, *puCodePage, cpspec, rgpspec, rgvar);
  686. }
  687. }
  688. }
  689. }
  690. }
  691. return hr;
  692. }
  693. // Helper: converts LPWSTR to LPSTR using the indicated codepage and returns
  694. // TRUE if the LPSTR can be converted back to LPWSTR without unacceptible data loss
  695. STDAPI_(BOOL) _DoesStringRoundTripCPW(UINT uCodePage, LPCWSTR pwszIn, LPSTR pszOut, UINT cchOut)
  696. {
  697. BOOL fRet = FALSE;
  698. // if we're being asked to roundtrip UTF8, don't bother test, it'll work.
  699. if (CP_UTF8 == uCodePage)
  700. {
  701. SHUnicodeToAnsiCP(uCodePage, pwszIn, pszOut, cchOut);
  702. fRet = TRUE;
  703. }
  704. else
  705. {
  706. WCHAR wszTemp[MAX_PATH];
  707. LPWSTR pwszTemp = wszTemp;
  708. UINT cchTemp = ARRAYSIZE(wszTemp);
  709. // We better have enough room for the buffer.
  710. if (ARRAYSIZE(wszTemp) < cchOut)
  711. {
  712. pwszTemp = (LPWSTR)LocalAlloc(LPTR, cchOut*sizeof(WCHAR));
  713. cchTemp = cchOut;
  714. }
  715. if (pwszTemp)
  716. {
  717. SHUnicodeToAnsiCP(uCodePage, pwszIn, pszOut, cchOut);
  718. SHAnsiToUnicodeCP(uCodePage, pszOut, pwszTemp, cchTemp);
  719. fRet = StrCmpW(pwszIn, pwszTemp) == 0; // are they the same?
  720. if (pwszTemp != wszTemp)
  721. {
  722. LocalFree(pwszTemp);
  723. }
  724. }
  725. }
  726. return fRet;
  727. }
  728. // Helper: determines whether the specified string properties of the indicate property set
  729. // can round-trip to ansi and back.
  730. // Returns S_OK if all strings can round-trip, S_FALSE if not all strings can round trip,
  731. // or an error code.
  732. STDAPI _DoLegacyPropertiesRoundTrip(
  733. REFFMTID fmtid,
  734. UINT uCodePage,
  735. ULONG cvar,
  736. PROPVARIANT rgvar[])
  737. {
  738. ASSERT(uCodePage);
  739. HRESULT hr = S_OK; // assume all strings round-trip.
  740. if (uCodePage != CP_UTF8 && uCodePage != CP_WINUNICODE && _IsAnsiPropertySet(fmtid))
  741. {
  742. ASSERT (uCodePage != CP_WINUNICODE);
  743. // either the set's creator is whacked, or this is simply an invalid arg.
  744. for (ULONG i = 0; i < cvar && S_OK == hr ; i++)
  745. {
  746. if (rgvar[i].vt == VT_LPWSTR && rgvar[i].pwszVal && *rgvar[i].pwszVal)
  747. {
  748. LPSTR pszVal;
  749. // make plenty of room for UTF-8 conversions. each WCHAR
  750. // can turn into as many as three ANSI chars
  751. int cb = MAX_UTF8_CHAR_SIZE * (lstrlenW(rgvar[i].pwszVal) + 1);
  752. if ((pszVal = new CHAR[cb]) != NULL)
  753. {
  754. // Test round-trip to ANSI and back.
  755. if (!_DoesStringRoundTripCPW(uCodePage, rgvar[i].pwszVal, pszVal, cb))
  756. {
  757. hr = S_FALSE;
  758. }
  759. delete pszVal;
  760. }
  761. else
  762. hr = E_OUTOFMEMORY;
  763. }
  764. }
  765. }
  766. return hr;
  767. }
  768. // Helper: Reports whether the specified FMTID is a legacy ANSI property set.
  769. STDAPI_(BOOL) _IsAnsiPropertySet(REFFMTID fmtid)
  770. {
  771. const FMTID* _ansi_propertysets[] =
  772. {
  773. &FMTID_SummaryInformation,
  774. &FMTID_DocSummaryInformation,
  775. &FMTID_UserDefinedProperties,
  776. };
  777. for (int i = 0; i < ARRAYSIZE(_ansi_propertysets); i++)
  778. {
  779. if (IsEqualGUID(fmtid, *_ansi_propertysets[i]))
  780. return TRUE;
  781. }
  782. return FALSE;
  783. }
  784. // Determine whether the property is a legacy ANSI property, and if so,
  785. // compute a conversion type for the property.
  786. typedef struct {
  787. PROPID propid;
  788. VARTYPE vt;
  789. VARTYPE vtConvert;
  790. } ANSIPROPDEF;
  791. // (public) ansi SummaryInformation properties
  792. const ANSIPROPDEF si_lpstr_pids[] =
  793. {
  794. { PIDSI_TITLE, VT_LPSTR, VT_LPWSTR },
  795. { PIDSI_SUBJECT, VT_LPSTR, VT_LPWSTR },
  796. { PIDSI_AUTHOR, VT_LPSTR, VT_LPWSTR },
  797. { PIDSI_KEYWORDS, VT_LPSTR, VT_LPWSTR },
  798. { PIDSI_COMMENTS, VT_LPSTR, VT_LPWSTR },
  799. { PIDSI_TEMPLATE, VT_LPSTR, VT_LPWSTR },
  800. { PIDSI_LASTAUTHOR, VT_LPSTR, VT_LPWSTR },
  801. { PIDSI_REVNUMBER, VT_LPSTR, VT_LPWSTR },
  802. { PIDSI_APPNAME, VT_LPSTR, VT_LPWSTR },
  803. };
  804. // (public) ansi DocSummaryInformation properties
  805. const ANSIPROPDEF dsi_lpstr_pids[] =
  806. {
  807. { PIDDSI_CATEGORY, VT_LPSTR, VT_LPWSTR },
  808. { PIDDSI_PRESFORMAT,VT_LPSTR, VT_LPWSTR },
  809. { PIDDSI_DOCPARTS, VT_LPSTR|VT_VECTOR, VT_LPWSTR|VT_VECTOR },
  810. { PIDDSI_MANAGER, VT_LPSTR, VT_LPWSTR },
  811. { PIDDSI_COMPANY, VT_LPSTR, VT_LPWSTR },
  812. };
  813. STDAPI_(BOOL) SHIsLegacyAnsiProperty(REFFMTID fmtid, PROPID propid, IN OUT OPTIONAL VARTYPE* pvt)
  814. {
  815. const ANSIPROPDEF* rgapd = NULL;
  816. UINT capd = 0;
  817. if (IsEqualGUID(fmtid, FMTID_SummaryInformation))
  818. {
  819. rgapd = si_lpstr_pids;
  820. capd = ARRAYSIZE(si_lpstr_pids);
  821. }
  822. else if (IsEqualGUID(fmtid, FMTID_DocSummaryInformation))
  823. {
  824. rgapd = dsi_lpstr_pids;
  825. capd = ARRAYSIZE(dsi_lpstr_pids);
  826. }
  827. else if (IsEqualGUID(fmtid, FMTID_UserDefinedProperties))
  828. {
  829. // Note: User defined properties are, by defintion, not defined
  830. // by the system. We simply will convert any VT_LPSTR values to VT_LPWSTR.
  831. if (pvt)
  832. {
  833. if ((*pvt) & VT_LPSTR) // forward conversion?
  834. {
  835. (*pvt) &= ~VT_LPSTR;
  836. (*pvt) |= VT_LPWSTR;
  837. return TRUE;
  838. }
  839. else if ((*pvt) & VT_LPWSTR) // reverse conversion?
  840. {
  841. (*pvt) &= ~VT_LPWSTR;
  842. (*pvt) |= VT_LPSTR;
  843. return TRUE;
  844. }
  845. }
  846. }
  847. if (rgapd) // search among pre-defined property ids:
  848. {
  849. for (UINT i = 0; i < capd; i++)
  850. {
  851. if (propid == rgapd[i].propid)
  852. {
  853. if (pvt)
  854. {
  855. if (*pvt == rgapd[i].vtConvert) // reverse conversion?
  856. *pvt = rgapd[i].vt;
  857. else // forward conversion?
  858. *pvt = rgapd[i].vtConvert;
  859. }
  860. return TRUE;
  861. }
  862. }
  863. }
  864. return FALSE;
  865. }
  866. // Helper: Properly converts a block of legacy ansi properties read from a
  867. // prop storage to unicode
  868. STDAPI _LegacyPropertiesToUnicode(
  869. REFFMTID fmtid,
  870. UINT uCodePage,
  871. ULONG cpspec,
  872. PROPSPEC const rgpspec[],
  873. PROPVARIANT rgvar[])
  874. {
  875. ASSERT(uCodePage);
  876. HRESULT hr = S_OK;
  877. if (_IsAnsiPropertySet(fmtid) && (uCodePage != CP_WINUNICODE))
  878. {
  879. for (ULONG i = 0; i < cpspec; i++)
  880. {
  881. if (VT_LPSTR == rgvar[i].vt)
  882. {
  883. // convert in-place to VT_LPWSTR.
  884. if (rgvar[i].pszVal)
  885. {
  886. LPWSTR pwszVal;
  887. int cch = lstrlenA(rgvar[i].pszVal) + 1;
  888. if (NULL == (pwszVal = (LPWSTR)CoTaskMemAlloc(CbFromCchW(cch))))
  889. {
  890. hr = E_OUTOFMEMORY;
  891. // reverse what we've already done
  892. if (i > 0)
  893. _LegacyPropertiesToAnsi(fmtid, uCodePage, i, rgpspec, rgvar);
  894. break ;
  895. }
  896. if (*rgvar[i].pszVal) // non-empty
  897. {
  898. // if we can't convert using the set's codepage, fall back on CP_UTF8
  899. if (!MultiByteToWideChar(uCodePage, 0, rgvar[i].pszVal, -1, pwszVal, cch))
  900. SHAnsiToUnicodeCP(CP_UTF8, rgvar[i].pszVal, pwszVal, cch);
  901. }
  902. else // empty string; why bother converting?
  903. *pwszVal = 0;
  904. CoTaskMemFree(rgvar[i].pszVal);
  905. // assign propvalue.
  906. rgvar[i].pwszVal = pwszVal;
  907. }
  908. rgvar[i].vt = VT_LPWSTR;
  909. }
  910. }
  911. }
  912. return hr;
  913. }
  914. // Helper: Properly converts a block of legacy ansi properties from unicode to
  915. // ansi in preparation for writing back to the storage stream.
  916. STDAPI _LegacyPropertiesToAnsi(
  917. REFFMTID fmtid,
  918. UINT uCodePage,
  919. ULONG cpspec,
  920. PROPSPEC const rgpspec[],
  921. PROPVARIANT rgvar[])
  922. {
  923. ASSERT(uCodePage);
  924. HRESULT hr = S_OK;
  925. if (_IsAnsiPropertySet(fmtid) && (uCodePage != CP_WINUNICODE))
  926. {
  927. for (ULONG i = 0; i < cpspec; i++)
  928. {
  929. if (rgvar[i].vt == VT_LPWSTR)
  930. {
  931. // Revert back to ANSI in place
  932. if (rgvar[i].pwszVal)
  933. {
  934. LPSTR pszVal;
  935. // make plenty of room for UTF-8 conversions. each WCHAR
  936. // can turn into as many as three ANSI chars
  937. int cb = MAX_UTF8_CHAR_SIZE * (lstrlenW(rgvar[i].pwszVal) + 1);
  938. if (NULL == (pszVal = (LPSTR)CoTaskMemAlloc(cb)))
  939. {
  940. hr = E_OUTOFMEMORY;
  941. if (i > 0) // try to reverse what we've done.
  942. _LegacyPropertiesToUnicode(fmtid, uCodePage, i, rgpspec, rgvar);
  943. break;
  944. }
  945. if (*rgvar[i].pwszVal)
  946. {
  947. // Test round-trip to ANSI and back. If fails, fall back on CP_UTF8.
  948. if (!_DoesStringRoundTripCPW(uCodePage, rgvar[i].pwszVal, pszVal, cb))
  949. SHUnicodeToAnsiCP(CP_UTF8, rgvar[i].pwszVal, pszVal, cb);
  950. }
  951. else
  952. *pszVal = 0;
  953. CoTaskMemFree(rgvar[i].pwszVal);
  954. rgvar[i].pszVal = pszVal;
  955. }
  956. rgvar[i].vt = VT_LPSTR;
  957. }
  958. }
  959. }
  960. return hr;
  961. }
  962. // Helper: Converts the specified ansi string to a universal code page.
  963. STDAPI _UniversalizeAnsiString(IN OUT LPSTR* ppszSrc, IN UINT uCodePage)
  964. {
  965. ASSERT(ppszSrc);
  966. ASSERT(uCodePage != CP_UTF8);
  967. if (!(*ppszSrc)) // NULL string
  968. return S_FALSE;
  969. if (!(*ppszSrc)[0]) // empty string; nothing to do.
  970. return S_OK;
  971. HRESULT hr = E_FAIL;
  972. LPSTR pszDest = NULL;
  973. WCHAR wszVal[MAX_PATH];
  974. LPWSTR pwszVal = wszVal;
  975. *wszVal = 0;
  976. UINT cch = lstrlenA(*ppszSrc) + 1;
  977. if (cch > ARRAYSIZE(wszVal))
  978. pwszVal = new WCHAR[cch];
  979. if (pwszVal != NULL)
  980. {
  981. // convert to Unicode using original codepage
  982. if (SHAnsiToUnicodeCP(uCodePage, *ppszSrc, pwszVal, cch))
  983. {
  984. int cb = MAX_UTF8_CHAR_SIZE * cch;
  985. if ((pszDest = (LPSTR)CoTaskMemAlloc(cb)) != NULL)
  986. {
  987. // convert to ANSI using UTF_8
  988. if (SHUnicodeToAnsiCP(CP_UTF8, pwszVal, pszDest, cb))
  989. {
  990. CoTaskMemFree(*ppszSrc);
  991. *ppszSrc = pszDest;
  992. hr = S_OK;
  993. }
  994. else
  995. {
  996. CoTaskMemFree(pszDest);
  997. hr = E_FAIL;
  998. }
  999. }
  1000. else
  1001. hr = E_OUTOFMEMORY;
  1002. }
  1003. if (pwszVal != wszVal)
  1004. delete [] pwszVal;
  1005. }
  1006. else
  1007. hr = E_OUTOFMEMORY;
  1008. return hr;
  1009. }
  1010. // Helper: Ensures that any ansi strings in the specified property
  1011. // are converted to a universal code page.
  1012. STDAPI _UniversalizeProperty(IN OUT PROPVARIANT* pvar, UINT uCodePage)
  1013. {
  1014. ASSERT(uCodePage != CP_UTF8);
  1015. HRESULT hr = S_OK;
  1016. if (VT_LPSTR == pvar->vt)
  1017. {
  1018. hr = _UniversalizeAnsiString(&pvar->pszVal, uCodePage);
  1019. }
  1020. else if ((VT_LPSTR | VT_VECTOR) == pvar->vt)
  1021. {
  1022. for (ULONG i = 0; i < pvar->calpstr.cElems; i++)
  1023. {
  1024. HRESULT hrElem = _UniversalizeAnsiString(&pvar->calpstr.pElems[i], uCodePage);
  1025. if (FAILED(hrElem))
  1026. hr = hrElem;
  1027. }
  1028. }
  1029. return hr;
  1030. }
  1031. // Helper: counts properties in the indicated property set.
  1032. ULONG _CountProperties(IEnumSTATPROPSTG* pEnum)
  1033. {
  1034. ULONG cRet = 0;
  1035. pEnum->Reset();
  1036. STATPROPSTG stat[20] = {0};
  1037. HRESULT hr;
  1038. do
  1039. {
  1040. ULONG cFetched;
  1041. hr = pEnum->Next(ARRAYSIZE(stat), stat, &cFetched);
  1042. if (SUCCEEDED(hr))
  1043. cRet += cFetched;
  1044. } while (S_OK == hr);
  1045. pEnum->Reset();
  1046. return cRet;
  1047. }
  1048. // Helper: Ensures that all ansi properties in the indicate set are converted to a
  1049. // universal code page.
  1050. STDAPI _UniversalizeSet(IPropertyStorage* pstg, IN OUT UINT* puCodePage, PROPID propidNameFirst)
  1051. {
  1052. UINT uCP = *puCodePage;
  1053. if (CP_UTF8 == uCP)
  1054. return S_OK;
  1055. // Enumerate property values
  1056. IEnumSTATPROPSTG* pEnum;
  1057. HRESULT hr = pstg->Enum(&pEnum);
  1058. if (SUCCEEDED(hr))
  1059. {
  1060. ULONG cProps = _CountProperties(pEnum);
  1061. if (cProps > 0)
  1062. {
  1063. STATPROPSTG* rgstat = NULL;
  1064. PROPSPEC* rgpspec = NULL;
  1065. PROPVARIANT* rgvar = NULL;
  1066. if ((rgstat = new STATPROPSTG[cProps]) != NULL &&
  1067. (rgpspec = new PROPSPEC[cProps]) != NULL &&
  1068. (rgvar = new PROPVARIANT[cProps]) != NULL)
  1069. {
  1070. ULONG cFetched = 0;
  1071. ZeroMemory(rgstat, cProps * sizeof(*rgstat));
  1072. hr = pEnum->Next(cProps, rgstat, &cFetched);
  1073. if (SUCCEEDED(hr) && cFetched > 0)
  1074. {
  1075. for (ULONG i = 0; i < cFetched; i++)
  1076. {
  1077. rgpspec[i].ulKind = PRSPEC_PROPID;
  1078. rgpspec[i].propid = rgstat[i].propid;
  1079. }
  1080. ZeroMemory(rgvar, sizeof(rgvar));
  1081. // Read properties
  1082. hr = pstg->ReadMultiple(cFetched, rgpspec, rgvar);
  1083. if (S_OK == hr)
  1084. {
  1085. BOOL bConversionError = FALSE;
  1086. // Convert properties
  1087. for (i = 0; i < cFetched; i++)
  1088. {
  1089. hr = _UniversalizeProperty(rgvar + i, uCP);
  1090. if (FAILED(hr))
  1091. {
  1092. bConversionError = TRUE;
  1093. break;
  1094. }
  1095. }
  1096. // Delete set, write out converted values and update PID_CODEPAGE
  1097. if (!bConversionError)
  1098. {
  1099. hr = pstg->DeleteMultiple(cFetched, rgpspec);
  1100. if (SUCCEEDED(hr))
  1101. {
  1102. hr = SHPropStgWriteCP(pstg, CP_UTF8);
  1103. if (SUCCEEDED(hr))
  1104. {
  1105. *puCodePage = CP_UTF8;
  1106. hr = pstg->WriteMultiple(cFetched, rgpspec, rgvar, propidNameFirst);
  1107. }
  1108. }
  1109. }
  1110. for (i = 0; i < cFetched; i++)
  1111. PropVariantClear(rgvar + i);
  1112. }
  1113. }
  1114. }
  1115. if (rgstat) delete [] rgstat;
  1116. if (rgpspec) delete [] rgpspec;
  1117. if (rgvar) delete [] rgvar;
  1118. }
  1119. else if (0 == cProps) // no properties: brand-new, empty set.
  1120. {
  1121. hr = SHPropStgWriteCP(pstg, CP_UTF8);
  1122. if (SUCCEEDED(hr))
  1123. {
  1124. *puCodePage = CP_UTF8;
  1125. }
  1126. }
  1127. pEnum->Release();
  1128. }
  1129. return hr;
  1130. }
  1131. // A PROPVARIANT can hold a few more types than a VARIANT can. We convert the types that are
  1132. // only supported by a PROPVARIANT into equivalent VARIANT types.
  1133. HRESULT PropVariantToVariant(const PROPVARIANT *pPropVar, VARIANT *pVar)
  1134. {
  1135. HRESULT hr = E_OUTOFMEMORY;
  1136. ASSERT(pPropVar && pVar);
  1137. // if pVar isn't empty, this will properly free before overwriting it
  1138. VariantClear(pVar);
  1139. switch (pPropVar->vt)
  1140. {
  1141. case VT_LPSTR:
  1142. pVar->bstrVal = SysAllocStringA(pPropVar->pszVal);
  1143. if (pVar->bstrVal)
  1144. {
  1145. pVar->vt = VT_BSTR;
  1146. hr = S_OK;
  1147. }
  1148. break;
  1149. case VT_LPWSTR:
  1150. pVar->bstrVal = SysAllocString(pPropVar->pwszVal);
  1151. if (pVar->bstrVal)
  1152. {
  1153. pVar->vt = VT_BSTR;
  1154. hr = S_OK;
  1155. }
  1156. break;
  1157. case VT_FILETIME:
  1158. {
  1159. SYSTEMTIME st;
  1160. if (FileTimeToSystemTime(&pPropVar->filetime, &st) &&
  1161. SystemTimeToVariantTime(&st, &pVar->date)) // delay load...
  1162. {
  1163. pVar->vt = VT_DATE;
  1164. hr = S_OK;
  1165. }
  1166. break;
  1167. }
  1168. case VT_CLSID:
  1169. if (pVar->bstrVal = SysAllocStringLen(NULL, GUIDSTR_MAX))
  1170. {
  1171. if (SUCCEEDED(SHStringFromGUIDW(*pPropVar->puuid, pVar->bstrVal, GUIDSTR_MAX)))
  1172. {
  1173. pVar->vt = VT_BSTR;
  1174. hr = S_OK;
  1175. }
  1176. else
  1177. {
  1178. SysFreeString(pVar->bstrVal);
  1179. pVar->bstrVal = NULL;
  1180. }
  1181. }
  1182. break;
  1183. case VT_BLOB:
  1184. case VT_STREAM:
  1185. case VT_STORAGE:
  1186. case VT_BLOB_OBJECT:
  1187. case VT_STREAMED_OBJECT:
  1188. case VT_STORED_OBJECT:
  1189. case VT_CF:
  1190. ASSERT(0); // leave the output cleared
  1191. break;
  1192. case VT_UI4:
  1193. pVar->vt = VT_I4;
  1194. pVar->lVal = (INT)pPropVar->ulVal;
  1195. hr = S_OK;
  1196. break;
  1197. default:
  1198. hr = VariantCopy(pVar, (VARIANT *)pPropVar);
  1199. break;
  1200. }
  1201. return hr;
  1202. }
  1203. class CPropertyUI : public IPropertyUI
  1204. {
  1205. public:
  1206. // IUnknown
  1207. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  1208. STDMETHODIMP_(ULONG) AddRef(void);
  1209. STDMETHODIMP_(ULONG) Release(void);
  1210. // IPropertyUI
  1211. STDMETHODIMP ParsePropertyName(LPCWSTR pwszProperties, FMTID *pfmtid, PROPID *ppid, ULONG *pchEaten);
  1212. STDMETHODIMP GetCannonicalName(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText);
  1213. STDMETHODIMP GetDisplayName(REFFMTID fmtid, PROPID pid, PROPERTYUI_NAME_FLAGS flags, LPWSTR pwszText, DWORD cchText);
  1214. STDMETHODIMP GetPropertyDescription(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText);
  1215. STDMETHODIMP GetDefaultWidth(REFFMTID fmtid, PROPID pid, ULONG *pcxChars);
  1216. STDMETHODIMP GetFlags(REFFMTID fmtid, PROPID pid, PROPERTYUI_FLAGS *pdwFlags);
  1217. STDMETHODIMP FormatForDisplay(REFFMTID fmtid, PROPID pid, const PROPVARIANT *pvar,
  1218. PROPERTYUI_FORMAT_FLAGS flags, LPWSTR pwszText, DWORD cchText);
  1219. STDMETHODIMP GetHelpInfo(REFFMTID fmtid, PROPID pid, LPWSTR pwszHelpFile, DWORD cch, UINT *puHelpID);
  1220. CPropertyUI();
  1221. private:
  1222. ~CPropertyUI();
  1223. const PROPUI_INFO *_FindInfoByName(LPCWSTR pszName);
  1224. long _cRef;
  1225. };
  1226. const PROPUI_INFO *_FindInfoByFMTIDPID(REFFMTID fmtid, PROPID pid);
  1227. CPropertyUI::CPropertyUI() : _cRef(1)
  1228. {
  1229. DllAddRef();
  1230. }
  1231. CPropertyUI::~CPropertyUI()
  1232. {
  1233. DllRelease();
  1234. }
  1235. HRESULT CPropertyUI::QueryInterface(REFIID riid, void **ppv)
  1236. {
  1237. static const QITAB qit[] = {
  1238. QITABENT(CPropertyUI, IPropertyUI),
  1239. { 0 },
  1240. };
  1241. return QISearch(this, qit, riid, ppv);
  1242. }
  1243. ULONG CPropertyUI::AddRef()
  1244. {
  1245. return InterlockedIncrement(&_cRef);
  1246. }
  1247. ULONG CPropertyUI::Release()
  1248. {
  1249. if (InterlockedDecrement(&_cRef))
  1250. return _cRef;
  1251. delete this;
  1252. return 0;
  1253. }
  1254. const PROPUI_INFO *CPropertyUI::_FindInfoByName(LPCWSTR pszName)
  1255. {
  1256. const PROPUI_INFO *pinfo = NULL;
  1257. for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
  1258. {
  1259. if (StrCmpIW(pszName, c_rgPropUIInfo[i].pwszName) == 0)
  1260. {
  1261. pinfo = &c_rgPropUIInfo[i];
  1262. break;
  1263. }
  1264. }
  1265. return pinfo;
  1266. }
  1267. const PROPUI_INFO *_FindInfoByFMTIDPID(REFFMTID fmtid, PROPID pid)
  1268. {
  1269. const PROPUI_INFO *pinfo = NULL;
  1270. for (int i = 0; i < ARRAYSIZE(c_rgPropUIInfo); i++)
  1271. {
  1272. if ((pid == c_rgPropUIInfo[i].pscid->pid) &&
  1273. (fmtid == c_rgPropUIInfo[i].pscid->fmtid))
  1274. {
  1275. pinfo = &c_rgPropUIInfo[i];
  1276. break;
  1277. }
  1278. }
  1279. return pinfo;
  1280. }
  1281. HRESULT _NextProp(LPCWSTR pwszProperties, ULONG *pchEaten, LPWSTR pwszProp, UINT cchProp)
  1282. {
  1283. HRESULT hr = E_FAIL;
  1284. ULONG ulStrLen = lstrlenW(pwszProperties);
  1285. *pwszProp = L'\0';
  1286. if (*pchEaten < ulStrLen)
  1287. {
  1288. LPCWSTR pwszStart = pwszProperties + (*pchEaten);
  1289. LPCWSTR pwszSemi = StrChrW(pwszStart, L';');
  1290. if (pwszSemi)
  1291. {
  1292. // make sure its well formed (no dbl slashes)
  1293. if (pwszSemi > pwszStart)
  1294. {
  1295. // Make sure we don't overrun the prop buffer size
  1296. ULONG ulPropLen = (ULONG)(pwszSemi - pwszStart) + 1; // includes L'\0'
  1297. if (ulPropLen > cchProp)
  1298. {
  1299. ulPropLen = cchProp;
  1300. }
  1301. StrCpyNW(pwszProp, pwszStart, ulPropLen);
  1302. // Make sure that there is another segment to return
  1303. if (!*(pwszSemi + 1))
  1304. {
  1305. pwszSemi = NULL;
  1306. }
  1307. hr = S_OK;
  1308. }
  1309. else
  1310. {
  1311. pwszSemi = NULL;
  1312. hr = E_INVALIDARG; // bad input
  1313. }
  1314. }
  1315. else
  1316. {
  1317. // No semi-colon; so copy till the end
  1318. StrCpyNW(pwszProp, pwszStart, cchProp);
  1319. hr = S_OK;
  1320. }
  1321. // Set *pchEaten
  1322. if (pwszSemi)
  1323. {
  1324. *pchEaten = (int)(pwszSemi - pwszProperties) + 1; // Skip ;
  1325. }
  1326. else
  1327. {
  1328. *pchEaten = ulStrLen;
  1329. }
  1330. }
  1331. else
  1332. {
  1333. hr = S_FALSE; // done with loop
  1334. }
  1335. return hr;
  1336. }
  1337. #define PROP_PREFIX TEXT("prop:")
  1338. #define PROP_PREFIX_LEN (ARRAYSIZE(PROP_PREFIX) - 1)
  1339. // [in/out] *pchEaten used to sequence through the property names
  1340. STDMETHODIMP CPropertyUI::ParsePropertyName(LPCWSTR pwszProperties, FMTID *pfmtid, PROPID *ppid, ULONG *pchEaten)
  1341. {
  1342. // Nobody should call us without a reason
  1343. ASSERT(pfmtid && ppid);
  1344. HRESULT hr = E_FAIL;
  1345. WCHAR wszProp[MAX_PATH];
  1346. SHCOLUMNID scid;
  1347. // If pwszProperties starts with prop:, skip it
  1348. if ((*pchEaten == 0)
  1349. && (StrCmpNIW(pwszProperties, PROP_PREFIX, PROP_PREFIX_LEN) == 0))
  1350. {
  1351. *pchEaten += PROP_PREFIX_LEN;
  1352. }
  1353. if ((_NextProp(pwszProperties, pchEaten, wszProp, ARRAYSIZE(wszProp)) == S_OK)
  1354. && ParseSCIDString(wszProp, &scid, NULL))
  1355. {
  1356. *pfmtid = scid.fmtid;
  1357. *ppid = scid.pid;
  1358. hr = S_OK;
  1359. }
  1360. return hr;
  1361. }
  1362. STDMETHODIMP CPropertyUI::GetCannonicalName(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText)
  1363. {
  1364. HRESULT hr = E_FAIL;
  1365. *pwszText = NULL;
  1366. const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
  1367. if (pinfo)
  1368. {
  1369. hr = S_OK;
  1370. StrCpyNW(pwszText, pinfo->pwszName, cchText);
  1371. }
  1372. else if (SHStringFromGUIDW(fmtid, pwszText, cchText))
  1373. {
  1374. WCHAR wszPid[20]; // Pid's can't be longer than 20 chars
  1375. wnsprintfW(wszPid, ARRAYSIZE(wszPid), L"%lu", pid);
  1376. StrCatBuffW(pwszText, wszPid, cchText);
  1377. hr = S_OK;
  1378. }
  1379. return hr;
  1380. }
  1381. STDMETHODIMP CPropertyUI::GetDisplayName(REFFMTID fmtid, PROPID pid, PROPERTYUI_NAME_FLAGS flags, LPWSTR pwszText, DWORD cchText)
  1382. {
  1383. HRESULT hr = E_FAIL;
  1384. *pwszText = NULL;
  1385. const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
  1386. if (pinfo)
  1387. {
  1388. UINT uID;
  1389. if (flags & PUIFNF_MNEMONIC)
  1390. {
  1391. // Name with mnemonic requested.
  1392. if (pinfo->idMnemonicName)
  1393. {
  1394. // Name with mnemonic defined for scid.
  1395. uID = pinfo->idMnemonicName;
  1396. hr = S_OK;
  1397. }
  1398. else
  1399. {
  1400. // Name with mnemonic NOT defined for scid -- use name without mnemonic as fallback.
  1401. uID = pinfo->idDisplayName;
  1402. hr = S_FALSE;
  1403. }
  1404. }
  1405. else
  1406. {
  1407. // Name without mnemonic requested.
  1408. uID = pinfo->idDisplayName;
  1409. hr = S_OK;
  1410. }
  1411. LoadStringW(HINST_THISDLL, uID, pwszText, cchText);
  1412. }
  1413. return hr;
  1414. }
  1415. STDMETHODIMP CPropertyUI::GetPropertyDescription(REFFMTID fmtid, PROPID pid, LPWSTR pwszText, DWORD cchText)
  1416. {
  1417. HRESULT hr = E_FAIL;
  1418. *pwszText = NULL;
  1419. const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
  1420. if (pinfo)
  1421. {
  1422. *pwszText = 0;
  1423. // LoadStringW(HINST_THISDLL, pinfo->idPropertyDescription, pwszText, cchText);
  1424. hr = S_OK;
  1425. }
  1426. return hr;
  1427. }
  1428. STDMETHODIMP CPropertyUI::GetDefaultWidth(REFFMTID fmtid, PROPID pid, ULONG *pcxChars)
  1429. {
  1430. HRESULT hr = E_FAIL;
  1431. *pcxChars = 0;
  1432. const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
  1433. if (pinfo)
  1434. {
  1435. *pcxChars = 20; // pinfo->nWidth;
  1436. hr = S_OK;
  1437. }
  1438. return hr;
  1439. }
  1440. STDMETHODIMP CPropertyUI::GetFlags(REFFMTID fmtid, PROPID pid, PROPERTYUI_FLAGS *pdwFlags)
  1441. {
  1442. HRESULT hr = E_FAIL;
  1443. *pdwFlags = PUIF_DEFAULT;
  1444. const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
  1445. if (pinfo)
  1446. {
  1447. *pdwFlags = PUIF_DEFAULT; // pinfo->dwFlags;
  1448. hr = S_OK;
  1449. }
  1450. return hr;
  1451. }
  1452. HRESULT _LookupStringFromLong(const STRING_MAP *pMap, ULONG ulVal, LPWSTR pszText, DWORD cchText)
  1453. {
  1454. HRESULT hr = E_FAIL;
  1455. while (pMap->idStr && pMap->uVal != ulVal)
  1456. {
  1457. pMap++;
  1458. }
  1459. if (pMap->idStr)
  1460. {
  1461. LoadString(HINST_THISDLL, pMap->idStr, pszText, cchText);
  1462. hr = S_OK;
  1463. }
  1464. return hr;
  1465. }
  1466. // expose this method as an API as this is very commonly needed
  1467. STDAPI SHFormatForDisplay(REFFMTID fmtid, PROPID pid, const PROPVARIANT *pPropVar,
  1468. PROPERTYUI_FORMAT_FLAGS flags, LPWSTR pwszText, DWORD cchText)
  1469. {
  1470. HRESULT hr = S_OK;
  1471. *pwszText = 0;
  1472. TCHAR szBuffer[MAX_PATH];
  1473. // Property-specific:
  1474. if (CompareSCIDFMTIDPID(fmtid, pid, SCID_SIZE) ||
  1475. CompareSCIDFMTIDPID(fmtid, pid, SCID_CAPACITY) ||
  1476. CompareSCIDFMTIDPID(fmtid, pid, SCID_FREESPACE))
  1477. {
  1478. ASSERT(pPropVar->vt == VT_UI8);
  1479. StrFormatByteSizeW(pPropVar->uhVal.QuadPart, pwszText, cchText);
  1480. }
  1481. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_Duration))
  1482. {
  1483. if (pPropVar->vt == VT_EMPTY)
  1484. {
  1485. StrCpyN(pwszText, L"", cchText);
  1486. }
  1487. else
  1488. {
  1489. ASSERT(pPropVar->vt == VT_UI8);
  1490. FILETIME ft = {pPropVar->uhVal.LowPart, pPropVar->uhVal.HighPart};
  1491. SYSTEMTIME st;
  1492. FileTimeToSystemTime(&ft, &st);
  1493. GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER,
  1494. &st, NULL, pwszText, cchText);
  1495. }
  1496. }
  1497. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_Bitrate) || CompareSCIDFMTIDPID(fmtid, pid, SCID_VIDEO_Bitrate))
  1498. {
  1499. LoadString(HINST_THISDLL, IDS_PROPERTYUI_MUSIC_BITRATE, szBuffer, ARRAYSIZE(szBuffer));
  1500. ASSERT(pPropVar->vt == VT_UI4 || pPropVar->vt == VT_I4)
  1501. wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal / 1000);
  1502. }
  1503. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_DRM_Protected)
  1504. ||CompareSCIDFMTIDPID(fmtid, pid, SCID_Scale))
  1505. {
  1506. ASSERT(pPropVar->vt == VT_BOOL);
  1507. UINT uID = (pPropVar->boolVal) ? IDS_PROPERTYUI_YES : IDS_PROPERTYUI_NO;
  1508. LoadString(HINST_THISDLL, uID, pwszText, cchText);
  1509. }
  1510. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_SampleSize) || CompareSCIDFMTIDPID(fmtid, pid, SCID_VIDEO_SampleSize))
  1511. {
  1512. ASSERT(pPropVar->vt == VT_UI4);
  1513. LoadString(HINST_THISDLL, IDS_PROPERTYUI_AV_SAMPLESIZE, szBuffer, ARRAYSIZE(szBuffer));
  1514. wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
  1515. }
  1516. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_SampleRate))
  1517. {
  1518. ASSERT(pPropVar->vt == VT_UI4);
  1519. LoadString(HINST_THISDLL, IDS_PROPERTYUI_AUDIO_SAMPLERATE, szBuffer, ARRAYSIZE(szBuffer));
  1520. wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal / 1000); // 1000: Hz -> kHz
  1521. }
  1522. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_AUDIO_ChannelCount))
  1523. {
  1524. ASSERT(pPropVar->vt == VT_UI4);
  1525. switch (pPropVar->ulVal)
  1526. {
  1527. case 1:
  1528. LoadString(HINST_THISDLL, IDS_PROPERTYUI_AUDIO_CHANNELCOUNT1, pwszText, cchText);
  1529. break;
  1530. case 2:
  1531. LoadString(HINST_THISDLL, IDS_PROPERTYUI_AUDIO_CHANNELCOUNT2, pwszText, cchText);
  1532. break;
  1533. default:
  1534. wnsprintf(pwszText, cchText, L"%u", pPropVar->ulVal);
  1535. }
  1536. }
  1537. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_VIDEO_FrameRate))
  1538. {
  1539. ASSERT(pPropVar->vt == VT_UI4);
  1540. LoadString(HINST_THISDLL, IDS_PROPERTYUI_VIDEO_FRAMERATE, szBuffer, ARRAYSIZE(szBuffer));
  1541. wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal/1000); // 1000 -> convert to frames/second
  1542. }
  1543. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ImageCX) || CompareSCIDFMTIDPID(fmtid, pid, SCID_ImageCY))
  1544. {
  1545. ASSERT(pPropVar->vt == VT_UI4);
  1546. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_PIXELS, szBuffer, ARRAYSIZE(szBuffer));
  1547. wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
  1548. }
  1549. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_Flash))
  1550. {
  1551. ASSERT(pPropVar->vt == VT_UI2);
  1552. hr = _LookupStringFromLong(g_cFlashStrings,pPropVar->uiVal,pwszText, cchText);
  1553. }
  1554. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ColorSpace))
  1555. {
  1556. ASSERT(pPropVar->vt == VT_UI2);
  1557. hr = _LookupStringFromLong(g_cColorStrings,pPropVar->uiVal,pwszText, cchText);
  1558. }
  1559. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_Media_Status))
  1560. {
  1561. hr = _LookupStringFromLong(g_cMediaStatus, pPropVar->ulVal, pwszText, cchText);
  1562. }
  1563. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_MeteringMode))
  1564. {
  1565. ASSERT(pPropVar->vt == VT_UI2);
  1566. hr = _LookupStringFromLong(g_cMeteringModeStrings, pPropVar->uiVal, pwszText, cchText);
  1567. }
  1568. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_LightSource))
  1569. {
  1570. ASSERT(pPropVar->vt == VT_UI2);
  1571. hr = _LookupStringFromLong(g_cLightSourceStrings, pPropVar->uiVal, pwszText, cchText);
  1572. }
  1573. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ExposureProg))
  1574. {
  1575. ASSERT(pPropVar->vt == VT_UI2);
  1576. hr = _LookupStringFromLong(g_cExposureProgStrings, pPropVar->uiVal, pwszText, cchText);
  1577. }
  1578. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ISOSpeed))
  1579. {
  1580. ASSERT(pPropVar->vt == VT_UI2);
  1581. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_ISO, szBuffer, ARRAYSIZE(szBuffer));
  1582. wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
  1583. }
  1584. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ShutterSpeed))
  1585. {
  1586. ASSERT(pPropVar->vt == VT_R8);
  1587. // ShutterSpeed is stored as an APEX value Tv = -log2(Et)
  1588. // we want to display the exposure time so we calculate it as follows
  1589. // Et = 2^(-Tv) then if the value is less than 0.5 then take the inverse
  1590. // so we can represent like 1/250
  1591. TCHAR szFloatBuffer[MAX_PATH];
  1592. VARIANT vTv = {0};
  1593. hr = PropVariantToVariant(pPropVar, &vTv);
  1594. if (SUCCEEDED(hr))
  1595. {
  1596. VARIANT vTemp = {0};
  1597. VARIANT vTemp2 = {0};
  1598. VARIANT vTemp3 = {0};
  1599. hr = VarNeg(&vTv, &vTemp);
  1600. if (SUCCEEDED(hr))
  1601. {
  1602. V_VT(&vTemp2) = VT_R8;
  1603. V_R8(&vTemp2) = 2;
  1604. hr = VarPow(&vTemp2, &vTemp, &vTemp3);
  1605. if (SUCCEEDED(hr))
  1606. {
  1607. if (V_R8(&vTemp3) > 0.5)
  1608. {
  1609. hr = VarRound(&vTemp3, 2, &vTemp);
  1610. if (SUCCEEDED(hr))
  1611. {
  1612. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1613. if (SUCCEEDED(hr))
  1614. {
  1615. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC, szBuffer, ARRAYSIZE(szBuffer));
  1616. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1617. }
  1618. }
  1619. }
  1620. else
  1621. {
  1622. V_VT(&vTemp) = VT_R8;
  1623. V_R8(&vTemp) = 1;
  1624. hr = VarDiv(&vTemp, &vTemp3, &vTemp2);
  1625. if (SUCCEEDED(hr))
  1626. {
  1627. hr = VarRound(&vTemp2, 0, &vTemp);
  1628. if (SUCCEEDED(hr))
  1629. {
  1630. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1631. if (SUCCEEDED(hr))
  1632. {
  1633. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC_FRAC, szBuffer, ARRAYSIZE(szBuffer));
  1634. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1635. }
  1636. }
  1637. }
  1638. }
  1639. }
  1640. }
  1641. VariantClear(&vTv);
  1642. VariantClear(&vTemp);
  1643. VariantClear(&vTemp2);
  1644. VariantClear(&vTemp3);
  1645. }
  1646. }
  1647. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ExposureTime))
  1648. {
  1649. ASSERT(pPropVar->vt == VT_R8);
  1650. // ExposureTime is store as a R8 value if the value is less
  1651. // than 0.5 then take the inverse so we can represent like 1/250
  1652. TCHAR szFloatBuffer[MAX_PATH];
  1653. VARIANT vEt = {0};
  1654. hr = PropVariantToVariant(pPropVar, &vEt);
  1655. if (SUCCEEDED(hr))
  1656. {
  1657. VARIANT vTemp = {0};
  1658. VARIANT vTemp2 = {0};
  1659. if (V_R8(&vEt) > 0.5)
  1660. {
  1661. hr = VarRound(&vEt, 2, &vTemp);
  1662. if (SUCCEEDED(hr))
  1663. {
  1664. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1665. if (SUCCEEDED(hr))
  1666. {
  1667. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC, szBuffer, ARRAYSIZE(szBuffer));
  1668. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1669. }
  1670. }
  1671. }
  1672. else
  1673. {
  1674. V_VT(&vTemp) = VT_R8;
  1675. V_R8(&vTemp) = 1;
  1676. hr = VarDiv(&vTemp, &vEt, &vTemp2);
  1677. if (SUCCEEDED(hr))
  1678. {
  1679. hr = VarRound(&vTemp2, 0, &vTemp);
  1680. if (SUCCEEDED(hr))
  1681. {
  1682. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1683. if (SUCCEEDED(hr))
  1684. {
  1685. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_SEC_FRAC, szBuffer, ARRAYSIZE(szBuffer));
  1686. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1687. }
  1688. }
  1689. }
  1690. }
  1691. VariantClear(&vEt);
  1692. VariantClear(&vTemp);
  1693. VariantClear(&vTemp2);
  1694. }
  1695. }
  1696. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_Aperture))
  1697. {
  1698. ASSERT(pPropVar->vt == VT_R8);
  1699. // Aperture is stored as an APEX value Av = 2*log2(Fn)
  1700. // we want to display the F-number so we calculate it as follows
  1701. // Fn = 2^(Av/2)
  1702. TCHAR szFloatBuffer[MAX_PATH];
  1703. VARIANT vAv = {0};
  1704. hr = PropVariantToVariant(pPropVar, &vAv);
  1705. if (SUCCEEDED(hr))
  1706. {
  1707. VARIANT vTemp = {0};
  1708. VARIANT vTemp2 = {0};
  1709. VARIANT vTemp3 = {0};
  1710. V_VT(&vTemp) = VT_R8;
  1711. V_R8(&vTemp) = 2;
  1712. hr = VarDiv(&vAv, &vTemp, &vTemp2);
  1713. if (SUCCEEDED(hr))
  1714. {
  1715. hr = VarPow(&vTemp, &vTemp2, &vTemp3);
  1716. if (SUCCEEDED(hr))
  1717. {
  1718. hr = VarRound(&vTemp3, 1, &vTemp);
  1719. if (SUCCEEDED(hr))
  1720. {
  1721. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1722. if (SUCCEEDED(hr))
  1723. {
  1724. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_F, szBuffer, ARRAYSIZE(szBuffer));
  1725. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1726. }
  1727. }
  1728. }
  1729. }
  1730. VariantClear(&vAv);
  1731. VariantClear(&vTemp);
  1732. VariantClear(&vTemp2);
  1733. VariantClear(&vTemp3);
  1734. }
  1735. }
  1736. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_FNumber))
  1737. {
  1738. ASSERT(pPropVar->vt == VT_R8);
  1739. // Fn is stored as a R8 value that needs to be rounded
  1740. TCHAR szFloatBuffer[MAX_PATH];
  1741. VARIANT vFn = {0};
  1742. hr = PropVariantToVariant(pPropVar, &vFn);
  1743. if (SUCCEEDED(hr))
  1744. {
  1745. VARIANT vTemp = {0};
  1746. V_VT(&vTemp) = VT_R8;
  1747. V_R8(&vTemp) = 2;
  1748. hr = VarRound(&vFn, 1, &vTemp);
  1749. if (SUCCEEDED(hr))
  1750. {
  1751. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1752. if (SUCCEEDED(hr))
  1753. {
  1754. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_F, szBuffer, ARRAYSIZE(szBuffer));
  1755. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1756. }
  1757. }
  1758. VariantClear(&vFn);
  1759. VariantClear(&vTemp);
  1760. }
  1761. }
  1762. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_SubjectDist))
  1763. {
  1764. ASSERT(pPropVar->vt == VT_R8);
  1765. // Distance is store as a R8 value in meters if the value is less
  1766. // than 1 then multiple by 1000 to convert to mm
  1767. TCHAR szFloatBuffer[MAX_PATH];
  1768. VARIANT vD = {0};
  1769. hr = PropVariantToVariant(pPropVar, &vD);
  1770. if (SUCCEEDED(hr))
  1771. {
  1772. VARIANT vTemp = {0};
  1773. VARIANT vTemp2 = {0};
  1774. if (V_R8(&vD) >= 1.0)
  1775. {
  1776. hr = VarRound(&vD, 1, &vTemp);
  1777. if (SUCCEEDED(hr))
  1778. {
  1779. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1780. if (SUCCEEDED(hr))
  1781. {
  1782. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_M, szBuffer, ARRAYSIZE(szBuffer));
  1783. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1784. }
  1785. }
  1786. }
  1787. else
  1788. {
  1789. V_VT(&vTemp) = VT_R8;
  1790. V_R8(&vTemp) = 1000;
  1791. hr = VarMul(&vTemp, &vD, &vTemp2);
  1792. if (SUCCEEDED(hr))
  1793. {
  1794. hr = VarRound(&vTemp2, 0, &vTemp);
  1795. if (SUCCEEDED(hr))
  1796. {
  1797. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1798. if (SUCCEEDED(hr))
  1799. {
  1800. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_MM, szBuffer, ARRAYSIZE(szBuffer));
  1801. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1802. }
  1803. }
  1804. }
  1805. }
  1806. VariantClear(&vD);
  1807. VariantClear(&vTemp);
  1808. VariantClear(&vTemp2);
  1809. }
  1810. }
  1811. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_FocalLength))
  1812. {
  1813. ASSERT(pPropVar->vt == VT_R8);
  1814. // Focal Length is store as a R8 value in mm
  1815. // so round it and display it
  1816. TCHAR szFloatBuffer[MAX_PATH];
  1817. VARIANT vLen = {0};
  1818. hr = PropVariantToVariant(pPropVar, &vLen);
  1819. if (SUCCEEDED(hr))
  1820. {
  1821. VARIANT vTemp = {0};
  1822. hr = VarRound(&vLen, 0, &vTemp);
  1823. if (SUCCEEDED(hr))
  1824. {
  1825. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1826. if (SUCCEEDED(hr))
  1827. {
  1828. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_MM, szBuffer, ARRAYSIZE(szBuffer));
  1829. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1830. }
  1831. }
  1832. VariantClear(&vLen);
  1833. VariantClear(&vTemp);
  1834. }
  1835. }
  1836. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_FlashEnergy))
  1837. {
  1838. ASSERT(pPropVar->vt == VT_R8);
  1839. // Flash Energy is store as a R8 value in bcps
  1840. // so round it and display it
  1841. TCHAR szFloatBuffer[MAX_PATH];
  1842. VARIANT vBCPS = {0};
  1843. hr = PropVariantToVariant(pPropVar, &vBCPS);
  1844. if (SUCCEEDED(hr))
  1845. {
  1846. VARIANT vTemp = {0};
  1847. hr = VarRound(&vBCPS, 0, &vTemp);
  1848. if (SUCCEEDED(hr))
  1849. {
  1850. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1851. if (SUCCEEDED(hr))
  1852. {
  1853. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_BCPS, szBuffer, ARRAYSIZE(szBuffer));
  1854. wnsprintf(pwszText, cchText, szBuffer, szFloatBuffer);
  1855. }
  1856. }
  1857. VariantClear(&vBCPS);
  1858. VariantClear(&vTemp);
  1859. }
  1860. }
  1861. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ExposureBias))
  1862. {
  1863. ASSERT(pPropVar->vt == VT_R8);
  1864. // ExposureBias is store as a R8 value in steps
  1865. // so round it to the nearest tenth and display
  1866. // it with a + or minus
  1867. TCHAR szFloatBuffer[MAX_PATH];
  1868. VARIANT vBias = {0};
  1869. hr = PropVariantToVariant(pPropVar, &vBias);
  1870. if (SUCCEEDED(hr))
  1871. {
  1872. VARIANT vTemp = {0};
  1873. hr = VarRound(&vBias, 1, &vTemp);
  1874. if (SUCCEEDED(hr))
  1875. {
  1876. TCHAR* pszSign;
  1877. if (V_R8(&vBias) > 0)
  1878. pszSign = L"+";
  1879. else
  1880. pszSign = L"";
  1881. hr = VariantToStr(&vTemp, szFloatBuffer, ARRAYSIZE(szFloatBuffer)) ? S_OK : E_OUTOFMEMORY;
  1882. if (SUCCEEDED(hr))
  1883. {
  1884. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_STEP, szBuffer, ARRAYSIZE(szBuffer));
  1885. wnsprintf(pwszText, cchText, szBuffer, pszSign, szFloatBuffer);
  1886. }
  1887. }
  1888. VariantClear(&vBias);
  1889. VariantClear(&vTemp);
  1890. }
  1891. }
  1892. else if (CompareSCIDFMTIDPID(fmtid, pid, SCID_ResolutionX) || CompareSCIDFMTIDPID(fmtid, pid, SCID_ResolutionY))
  1893. {
  1894. ASSERT(pPropVar->vt == VT_UI4);
  1895. LoadString(HINST_THISDLL, IDS_PROPERTYUI_IMAGE_DPI, szBuffer, ARRAYSIZE(szBuffer));
  1896. wnsprintf(pwszText, cchText, szBuffer, pPropVar->ulVal);
  1897. }
  1898. else if ((pPropVar->vt == VT_DATE) || (pPropVar->vt == VT_FILETIME))
  1899. {
  1900. FILETIME ft;
  1901. if (pPropVar->vt == VT_DATE)
  1902. {
  1903. WORD wDosDate, wDosTime;
  1904. if (VariantTimeToDosDateTime(pPropVar->date, &wDosDate, &wDosTime) && wDosDate)
  1905. {
  1906. DosDateTimeToFileTime(wDosDate, wDosTime, &ft);
  1907. hr = S_OK;
  1908. }
  1909. else
  1910. hr = E_FAIL;
  1911. }
  1912. else
  1913. {
  1914. ft = pPropVar->filetime;
  1915. hr = S_OK;
  1916. }
  1917. if (SUCCEEDED(hr))
  1918. {
  1919. DWORD dwFlags = FDTF_DEFAULT;
  1920. if (flags & PUIFFDF_RIGHTTOLEFT)
  1921. {
  1922. dwFlags |= FDTF_RTLDATE;
  1923. }
  1924. if (flags & PUIFFDF_SHORTFORMAT)
  1925. {
  1926. dwFlags |= FDTF_SHORTDATE;
  1927. }
  1928. if (flags & PUIFFDF_NOTIME)
  1929. {
  1930. dwFlags |= FDTF_LONGDATE;
  1931. }
  1932. if (flags & PUIFFDF_FRIENDLYDATE)
  1933. {
  1934. dwFlags |= (FDTF_RELATIVE | FDTF_LONGDATE);
  1935. }
  1936. SHFormatDateTime(&ft, &dwFlags, pwszText, cchText);
  1937. }
  1938. }
  1939. else
  1940. {
  1941. VARIANT var = {0};
  1942. hr = PropVariantToVariant(pPropVar, &var);
  1943. if (SUCCEEDED(hr))
  1944. {
  1945. hr = VariantToStr(&var, pwszText, cchText) ? S_OK : E_OUTOFMEMORY;
  1946. VariantClear(&var);
  1947. }
  1948. }
  1949. return hr;
  1950. }
  1951. STDMETHODIMP CPropertyUI::FormatForDisplay(REFFMTID fmtid, PROPID pid, const PROPVARIANT *pPropVar,
  1952. PROPERTYUI_FORMAT_FLAGS flags, LPWSTR pwszText, DWORD cchText)
  1953. {
  1954. return SHFormatForDisplay(fmtid, pid, pPropVar, flags, pwszText, cchText);
  1955. }
  1956. STDMETHODIMP CPropertyUI::GetHelpInfo(REFFMTID fmtid, PROPID pid, LPWSTR pwszHelpFile, DWORD cch, UINT *puHelpID)
  1957. {
  1958. HRESULT hr = E_INVALIDARG; // assume failure
  1959. if (pwszHelpFile && puHelpID)
  1960. {
  1961. *pwszHelpFile = 0;
  1962. *puHelpID = 0;
  1963. const PROPUI_INFO *pinfo = _FindInfoByFMTIDPID(fmtid, pid);
  1964. if (pinfo)
  1965. {
  1966. *puHelpID = pinfo->idHelp;
  1967. StrCpyN(pwszHelpFile, L"filefold.hlp", cch);
  1968. hr = S_OK;
  1969. }
  1970. else
  1971. {
  1972. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // close approximation
  1973. }
  1974. }
  1975. return hr;
  1976. }
  1977. STDAPI CPropertyUI_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  1978. {
  1979. HRESULT hr;
  1980. CPropertyUI *ppui = new CPropertyUI();
  1981. if (ppui)
  1982. {
  1983. hr = ppui->QueryInterface(riid, ppv);
  1984. ppui->Release();
  1985. }
  1986. else
  1987. {
  1988. *ppv = NULL;
  1989. hr = E_OUTOFMEMORY;
  1990. }
  1991. return hr;
  1992. }
  1993. #if 0
  1994. // this table defines the CI names for properties that we don't yet have CPropertyUI support for
  1995. // Storage Propset
  1996. { 0, L"ClassId", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_CLASSID }, 36, TRUE, TRUE, DBTYPE_GUID },
  1997. { 0, L"FileIndex", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_FILEINDEX }, 8, TRUE, TRUE, DBTYPE_UI8 },
  1998. { 0, L"USN", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_LASTCHANGEUSN }, 8, TRUE, TRUE, DBTYPE_I8 },
  1999. { 0, L"Filename", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_NAME }, 15, TRUE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
  2000. { 0, L"Path", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_PATH }, 50, TRUE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
  2001. { 0, L"Attrib", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)PID_STG_ATTRIBUTES }, 7, TRUE, TRUE, DBTYPE_UI4 },
  2002. { 0, L"AllocSize", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)18 }, 11, TRUE, TRUE, DBTYPE_I8 },
  2003. { 0, L"Contents", {PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR)19 }, 0, FALSE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
  2004. // Query Propset
  2005. { 0, L"RankVector", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)2 }, 20, TRUE, TRUE, DBTYPE_UI4|DBTYPE_VECTOR },
  2006. { 0, L"Rank", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)3 }, 7, TRUE, TRUE, DBTYPE_I4 },
  2007. { 0, L"HitCount", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)4 }, 10, TRUE, TRUE, DBTYPE_I4 },
  2008. { 0, L"WorkId", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)5 }, 10, TRUE, TRUE, DBTYPE_I4 },
  2009. { 0, L"All", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)6 }, 0, FALSE,TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
  2010. { 0, L"VPath", {QueryGuid, DBKIND_GUID_PROPID, (LPWSTR)9 }, 50, TRUE, TRUE, DBTYPE_WSTR|DBTYPE_BYREF },
  2011. // standard document
  2012. { 0, L"DocSecurity", {PSGUID_SUMMARYINFORMATION, DBKIND_GUID_PROPID, (LPWSTR)PIDSI_DOC_SECURITY }, 10, TRUE, TRUE, DBTYPE_I4 },
  2013. // who invented these?
  2014. { 0, L"DocPresentationTarget", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)3 }, 10, TRUE, TRUE, DBTYPE_STR|DBTYPE_BYREF },
  2015. { 0, L"DocPartTitles", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)13 }, 10, TRUE, TRUE, DBTYPE_STR|DBTYPE_VECTOR },
  2016. { 0, L"DocManager", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)14 }, 10, TRUE, TRUE, DBTYPE_STR|DBTYPE_BYREF },
  2017. { 0, L"DocCompany", {DocPropSetGuid2, DBKIND_GUID_PROPID, (LPWSTR)15 }, 10, TRUE,
  2018. #endif