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.

546 lines
16 KiB

  1. /*
  2. #include <stdio.h>
  3. #include "PStgServ.h"
  4. #include "PropMshl.hxx"
  5. #include "CPropVar.hxx"
  6. #include "CHResult.hxx"
  7. #include "proptest.hxx"
  8. */
  9. #include "pch.cxx"
  10. #include <shellapi.h>
  11. const IID IID_IPropertyStorageServer = {0xaf4ae0d0,0xa37f,0x11cf,{0x8d,0x73,0x00,0xaa,0x00,0x4c,0xd0,0x1a}};
  12. const IID IID_IPropertyStorageServerApp = {0xaf4ae0d1,0xa37f,0x11cf,{0x8d,0x73,0x00,0xaa,0x00,0x4c,0xd0,0x1a}};
  13. CPropSpec g_rgcpropspecVariant[] = { OLESTR("SafeArray") };
  14. CPropStgMarshalTest::CPropStgMarshalTest( )
  15. {
  16. m_cAllProperties = 0;
  17. m_cSimpleProperties = 0;
  18. m_rgpropspec = NULL;
  19. m_rgpropvar = NULL;
  20. m_pwszDocFileName = NULL;
  21. m_fInitialized = FALSE;
  22. }
  23. CPropStgMarshalTest::~CPropStgMarshalTest()
  24. {
  25. if( m_pwszDocFileName != NULL )
  26. delete m_pwszDocFileName;
  27. }
  28. CPropStgMarshalTest::Init( OLECHAR *pwszDocFileName,
  29. PROPVARIANT rgpropvar[],
  30. PROPSPEC rgpropspec[],
  31. ULONG cAllProperties,
  32. ULONG cSimpleProperties )
  33. {
  34. HRESULT hr = E_FAIL;
  35. // Validate the input.
  36. if( pwszDocFileName == NULL )
  37. {
  38. hr = STG_E_INVALIDPARAMETER;
  39. goto Exit;
  40. }
  41. m_cAllProperties = cAllProperties;
  42. m_cSimpleProperties = cSimpleProperties;
  43. m_rgpropvar = rgpropvar;
  44. m_rgpropspec = rgpropspec;
  45. // Copy the docfile name.
  46. m_pwszDocFileName = new WCHAR[ wcslen(pwszDocFileName) + 1 ];
  47. if( m_pwszDocFileName != NULL )
  48. {
  49. wcscpy( m_pwszDocFileName, pwszDocFileName );
  50. }
  51. else
  52. {
  53. hr = E_OUTOFMEMORY;
  54. goto Exit;
  55. }
  56. // Register the local server. We assume that it's either in
  57. // the local directory or in the path.
  58. if( g_fRegisterLocalServer )
  59. {
  60. HINSTANCE hinst = 0;
  61. DWORD dwWait;
  62. PROCESS_INFORMATION ProcessInformation;
  63. STARTUPINFO StartupInfo;
  64. memset( &StartupInfo, 0, sizeof(StartupInfo) );
  65. StartupInfo.cb = sizeof(StartupInfo);
  66. TCHAR tszCommand[] = TEXT("PStgServ.exe /RegServer");
  67. if( !CreateProcess( NULL,
  68. tszCommand,
  69. NULL, NULL,
  70. FALSE,
  71. 0,
  72. NULL,
  73. NULL,
  74. &StartupInfo,
  75. &ProcessInformation ))
  76. {
  77. hr = HRESULT_FROM_WIN32( GetLastError() );
  78. goto Exit;
  79. }
  80. if( WAIT_OBJECT_0 != WaitForSingleObject( ProcessInformation.hProcess, INFINITE ))
  81. {
  82. hr = HRESULT_FROM_WIN32( GetLastError() );
  83. goto Exit;
  84. }
  85. }
  86. hr = S_OK;
  87. Exit:
  88. return( hr );
  89. }
  90. CPropStgMarshalTest::Run()
  91. {
  92. HRESULT hr = S_OK;
  93. IPropertyStorageServer *pserver = NULL;
  94. IStorage *pstg = NULL;
  95. IPropertySetStorage *ppsstg = NULL;
  96. IPropertyStorage *ppstg = NULL;
  97. DWORD grfFlags=0;
  98. // ------------------------
  99. // Create a PropSet locally
  100. // ------------------------
  101. // Create a local IPropertySetStorage
  102. hr = g_pfnStgCreateStorageEx (
  103. m_pwszDocFileName,
  104. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  105. DetermineStgFmt( g_enumImplementation ),
  106. 0,
  107. NULL,
  108. NULL,
  109. PROPIMP_NTFS == g_enumImplementation ? IID_IFlatStorage : IID_IStorage,
  110. (void**) &pstg );
  111. if(FAILED(hr)) ERROR_EXIT( TEXT("Failed open of local Storage") );
  112. hr = StgToPropSetStg( pstg, &ppsstg );
  113. if( FAILED(hr) ) ERROR_EXIT( TEXT("Couldn't create local IPropertySetStorage") );
  114. // Create an IPropertyStorage
  115. grfFlags = PROPSETFLAG_ANSI | PROPSETFLAG_NONSIMPLE;
  116. hr = ppsstg->Create( IID_IPropertyStorageServer, NULL,
  117. grfFlags,
  118. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  119. &ppstg );
  120. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't create a local IPropertyStorage") );
  121. RELEASE_INTERFACE( ppsstg );
  122. // Write properties to it and close it.
  123. hr = WriteProperties( ppstg, FALSE /* Not Marshaled */ );
  124. if(FAILED(hr)) ERROR_EXIT( TEXT("Failed to write properties to local PropStg") );
  125. RELEASE_INTERFACE( ppstg );
  126. RELEASE_INTERFACE( pstg );
  127. // -----------------------------------------
  128. // Verify the properties through a marshaled
  129. // IPropertySetStorage
  130. // -----------------------------------------
  131. // Get a remote IPropertySetStorage
  132. Status( TEXT("Starting Server") );
  133. hr = CoCreateInstance( IID_IPropertyStorageServerApp,
  134. NULL,
  135. CLSCTX_LOCAL_SERVER,
  136. IID_IPropertyStorageServer,
  137. (void **)&pserver );
  138. if(FAILED(hr)) ERROR_EXIT( TEXT("Failed CoCreateInstance") );
  139. hr = pserver->Initialize( g_enumImplementation, g_Restrictions );
  140. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't initialize property set storage server") );
  141. Status( TEXT("Requesting remote IPropertySetStorage") );
  142. hr = pserver->StgOpenPropSetStg( m_pwszDocFileName,
  143. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  144. &ppsstg );
  145. if(FAILED(hr)) ERROR_EXIT( TEXT("Failed to open remote PropSetStg") );
  146. // Get an IPropertyStorage
  147. hr = ppsstg->Open( IID_IPropertyStorageServer,
  148. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  149. &ppstg );
  150. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't create a local IPropertyStorage") );
  151. RELEASE_INTERFACE( ppsstg );
  152. // Read from the marshalled Storage and compare the properties against
  153. // the local copy we kept.
  154. Status( TEXT("Reading/verifying properties from marshalled IPropertySetStorage") );
  155. hr = ReadAndCompareProperties( ppstg, TRUE /* Marshaled */ );
  156. if(FAILED(hr)) ERROR_EXIT( TEXT("Failed marshalled read and compare") );
  157. // Remove the existing properties via the marhsalled interface, and
  158. // re-write them.
  159. hr = DeleteProperties( ppstg, TRUE /* Marshaled */ );
  160. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't delete properties from remote IPropertySetStorage") );
  161. // Write the properties back to the remote storage.
  162. Status( TEXT("Writing properties through marshalled IPropertySetStorage") );
  163. hr = WriteProperties( ppstg, TRUE /* Marshaled */ );
  164. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't write properties to remote Storage") );
  165. RELEASE_INTERFACE( ppstg );
  166. // -----------------------------------------
  167. // Verify the properties through a marshaled
  168. // IPropertyStorage
  169. // -----------------------------------------
  170. // Get a remote IPropertyStorage
  171. Status( TEXT("Requesting remote IPropertyStorage") );
  172. hr = pserver->StgOpenPropStg( m_pwszDocFileName,
  173. IID_IPropertyStorageServer,
  174. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  175. &ppstg );
  176. if(FAILED(hr)) ERROR_EXIT( TEXT("Failed to open remote PropStg") );
  177. // Read from the marshalled Storage and compare the properties against
  178. // the local copy we kept.
  179. Status( TEXT("Reading/verifying properties from marshalled IPropertyStorage") );
  180. hr = ReadAndCompareProperties( ppstg, TRUE /* Marshaled */ );
  181. if(FAILED(hr)) ERROR_EXIT( TEXT("Failed marshalled read and compare") );
  182. // Remove the existing properties via the marhsalled interface, and
  183. // re-write them.
  184. hr = DeleteProperties( ppstg, TRUE /* Marshaled */ );
  185. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't delete properties from remote Storage") );
  186. // Write the properties back to the remote storage.
  187. Status( TEXT("Writing properties through marshalled IPropertyStorage") );
  188. hr = WriteProperties( ppstg, TRUE /* Marshaled */ );
  189. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't write properties to remote Storage") );
  190. RELEASE_INTERFACE( ppstg );
  191. RELEASE_INTERFACE( pserver );
  192. // --------------------------------
  193. // Re-verify the properties locally
  194. // --------------------------------
  195. // Re-open the DocFile locally.
  196. hr = g_pfnStgOpenStorageEx( m_pwszDocFileName,
  197. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  198. STGFMT_ANY, //DetermineStgFmt( g_enumImplementation )
  199. 0L,
  200. NULL,
  201. NULL,
  202. PROPIMP_NTFS == g_enumImplementation ? IID_IFlatStorage : IID_IStorage,
  203. (PVOID*)&pstg );
  204. if (SUCCEEDED(hr))
  205. {
  206. hr = StgToPropSetStg( pstg, &ppsstg );
  207. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't create IPropertySetStorage on local DocFile") );
  208. }
  209. else
  210. {
  211. hr = g_pfnStgOpenStorageEx( m_pwszDocFileName,
  212. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  213. STGFMT_ANY, //DetermineStgFmt( g_enumImplementation )
  214. 0L,
  215. NULL,
  216. NULL,
  217. IID_IPropertySetStorage,
  218. (PVOID*)&ppsstg );
  219. }
  220. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't re-open the File locally") );
  221. hr = ppsstg->Open( IID_IPropertyStorageServer,
  222. STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  223. &ppstg );
  224. if(FAILED(hr)) ERROR_EXIT( TEXT("Couldn't open load IPropertyStorage") );
  225. RELEASE_INTERFACE( ppsstg );
  226. // Compare the properties in the property set, which we wrote through
  227. // the marshalled interface, against what they should be.
  228. Status( TEXT("Reading/verifying properties from local IPropertyStorage") );
  229. hr = ReadAndCompareProperties( ppstg, FALSE /* Not Marshaled */ );
  230. if(FAILED(hr)) ERROR_EXIT( TEXT("Properties written through marshalled interface do not appear correct") );
  231. RELEASE_INTERFACE( ppstg );
  232. RELEASE_INTERFACE( pstg );
  233. Exit:
  234. RELEASE_INTERFACE( pstg );
  235. RELEASE_INTERFACE( ppsstg );
  236. RELEASE_INTERFACE( ppstg );
  237. RELEASE_INTERFACE( pserver );
  238. return( hr );
  239. }
  240. HRESULT CPropStgMarshalTest::WriteProperties( IPropertyStorage *ppstg, BOOL fMarshaled )
  241. {
  242. HRESULT hr = E_FAIL;
  243. // Are we restricted to simple properties?
  244. if( RESTRICT_SIMPLE_ONLY & g_Restrictions )
  245. {
  246. // Write the simple properties
  247. hr = ppstg->WriteMultiple( m_cSimpleProperties, m_rgpropspec, m_rgpropvar, PID_FIRST_USABLE );
  248. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed WriteMultiple") );
  249. }
  250. // Or, are we marshaling with IProp (where non-simple properties don't work)?
  251. else if( fMarshaled && g_SystemInfo.fIPropMarshaling )
  252. {
  253. // Verify that we can't write the non-simple properties
  254. hr = ppstg->WriteMultiple( m_cAllProperties, m_rgpropspec, m_rgpropvar, PID_FIRST_USABLE );
  255. if( RPC_E_CLIENT_CANTMARSHAL_DATA != hr )
  256. {
  257. hr = E_FAIL;
  258. ERROR_EXIT( TEXT("Failed WriteMultiple") );
  259. }
  260. // Write the simple properties
  261. hr = ppstg->WriteMultiple( m_cSimpleProperties, m_rgpropspec, m_rgpropvar, PID_FIRST_USABLE );
  262. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed WriteMultiple") );
  263. }
  264. // Otherwise, write all the properties
  265. else
  266. {
  267. hr = ppstg->WriteMultiple( m_cAllProperties, m_rgpropspec, m_rgpropvar, PID_FIRST_USABLE );
  268. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed WriteMultiple") );
  269. Check( S_OK, ResetRGPropVar( (CPropVariant*)m_rgpropvar ));
  270. // Test with a SafeArray too.
  271. PROPVARIANT propvar;
  272. SAFEARRAY *psa = NULL;
  273. SAFEARRAYBOUND rgsaBound[] = { {2, 0} };
  274. psa = SafeArrayCreateEx( VT_I4, 1, rgsaBound, NULL );
  275. LONG rgIndices[] = {0};
  276. LONG lVal = 0;
  277. Check( S_OK, SafeArrayPutElement( psa, rgIndices, &lVal ));
  278. rgIndices[0] = lVal = 1;
  279. Check( S_OK, SafeArrayPutElement( psa, rgIndices, &lVal ));
  280. PropVariantInit( &propvar );
  281. propvar.vt = VT_ARRAY | VT_I4;
  282. propvar.parray = psa;
  283. psa = NULL;
  284. hr = ppstg->WriteMultiple( 1, g_rgcpropspecVariant, &propvar, PID_FIRST_USABLE );
  285. PropVariantClear( &propvar );
  286. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed WriteMultiple") );
  287. }
  288. // ----
  289. // Exit
  290. // ----
  291. hr = S_OK;
  292. Exit:
  293. return( hr );
  294. }
  295. HRESULT CPropStgMarshalTest::ReadAndCompareProperties( IPropertyStorage *ppstg, BOOL fMarshaled )
  296. {
  297. HRESULT hr = E_FAIL;
  298. ULONG i;
  299. ULONG cProperties = 0;
  300. // Allocate a PROPVARIANT[] into which we can read the
  301. // properties
  302. PROPVARIANT *rgpropvar = new PROPVARIANT[ m_cAllProperties ];
  303. if( NULL == rgpropvar )
  304. {
  305. hr = E_OUTOFMEMORY;
  306. goto Exit;
  307. }
  308. // Are we restricted to only simple properties?
  309. if( RESTRICT_SIMPLE_ONLY & g_Restrictions )
  310. {
  311. cProperties = m_cSimpleProperties;
  312. // Read just the simple properties
  313. hr = ppstg->ReadMultiple( cProperties, m_rgpropspec, rgpropvar );
  314. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed ReadMultiple") );
  315. }
  316. // Or, are we marshaling with IProp (where non-simple properties don't work)?
  317. else if( fMarshaled && g_SystemInfo.fIPropMarshaling )
  318. {
  319. cProperties = m_cSimpleProperties;
  320. // Try to read all the properties, including the non-simples.
  321. hr = ppstg->ReadMultiple( m_cAllProperties, m_rgpropspec, rgpropvar );
  322. if( RPC_E_SERVER_CANTMARSHAL_DATA != hr )
  323. {
  324. hr = E_FAIL;
  325. ERROR_EXIT( TEXT("Failed ReadMultiple") );
  326. }
  327. // Now read just the simple properties
  328. hr = ppstg->ReadMultiple( cProperties, m_rgpropspec, rgpropvar );
  329. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed ReadMultiple") );
  330. }
  331. // Otherwise, read all the properties
  332. else
  333. {
  334. cProperties = m_cAllProperties;
  335. // Read the properties
  336. hr = ppstg->ReadMultiple( cProperties, m_rgpropspec, rgpropvar );
  337. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed ReadMultiple") );
  338. // Read and compare the safearray property
  339. PROPVARIANT propvar;
  340. PropVariantInit( &propvar );
  341. hr = ppstg->ReadMultiple( 1, g_rgcpropspecVariant, &propvar );
  342. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed ReadMultiple") );
  343. if( (VT_ARRAY | VT_I4) != propvar.vt
  344. ||
  345. NULL == propvar.parray
  346. ||
  347. 1 != SafeArrayGetDim(propvar.parray) )
  348. {
  349. ERROR_EXIT( TEXT("Invalid type returned in ReadMultiple") );
  350. }
  351. LONG rgIndices[] = { 0 };
  352. LONG rglVal[] = { -1, -1 };
  353. hr = SafeArrayGetElement( propvar.parray, rgIndices, &rglVal[0] );
  354. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed SafeArrayGetElement") );
  355. rgIndices[0] = 1;
  356. hr = SafeArrayGetElement( propvar.parray, rgIndices, &rglVal[1] );
  357. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed SafeArrayGetElement") );
  358. if( 0 != rglVal[0] || 1 != rglVal[1] )
  359. ERROR_EXIT( TEXT("SafeArray types don't match") );
  360. PropVariantClear( &propvar );
  361. }
  362. // Compare the properties with what we expect.
  363. for( i = 0; i < cProperties; i++ )
  364. {
  365. hr = CPropVariant::Compare( &rgpropvar[i], &m_rgpropvar[i] );
  366. if( S_OK != hr )
  367. {
  368. hr = E_FAIL;
  369. ERROR_EXIT( TEXT("Property mismatch") );
  370. }
  371. }
  372. // ----
  373. // Exit
  374. // ----
  375. hr = S_OK;
  376. Exit:
  377. if( NULL != rgpropvar )
  378. {
  379. g_pfnFreePropVariantArray( m_cAllProperties, rgpropvar );
  380. delete[]( rgpropvar );
  381. }
  382. return( hr );
  383. }
  384. HRESULT CPropStgMarshalTest::DeleteProperties( IPropertyStorage *ppstg, BOOL fMarshaled )
  385. {
  386. HRESULT hr = E_FAIL;
  387. ULONG cProperties;
  388. // Determine the correct number of properties to delete.
  389. if( (RESTRICT_SIMPLE_ONLY & g_Restrictions)
  390. ||
  391. (fMarshaled && g_SystemInfo.fIPropMarshaling) )
  392. {
  393. cProperties = m_cSimpleProperties;
  394. }
  395. else
  396. cProperties = m_cAllProperties;
  397. // Delete the properties
  398. hr = ppstg->DeleteMultiple( cProperties, m_rgpropspec );
  399. if( FAILED(hr) ) ERROR_EXIT( TEXT("Failed DeleteMultiple") );
  400. hr = S_OK;
  401. Exit:
  402. return( hr );
  403. }