Leaked source code of windows server 2003
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.

202 lines
6.0 KiB

  1. //
  2. // PropSheetExtArray implementation, use for control panel applets to extend their pages
  3. //
  4. // Manipulates a group of property sheet extension objects (see PSXA.H)
  5. //
  6. #include "shellprv.h"
  7. #pragma hdrstop
  8. // header for an array of IShellPropSheetExt interface pointers
  9. typedef struct
  10. {
  11. UINT count, alloc;
  12. IShellPropSheetExt *interfaces[ 0 ];
  13. } PSXA;
  14. // used to forward LPFNADDPROPSHEETPAGE calls with added error checking
  15. typedef struct
  16. {
  17. LPFNADDPROPSHEETPAGE pfn;
  18. LPARAM lparam;
  19. UINT count;
  20. BOOL allowmulti;
  21. BOOL alreadycalled;
  22. } _PSXACALLINFO;
  23. // forwards an LPFNADDPROPSHEETPAGE call with added error checking
  24. BOOL CALLBACK _PsxaCallOwner(HPROPSHEETPAGE hpage, LPARAM lparam)
  25. {
  26. _PSXACALLINFO *callinfo = (_PSXACALLINFO *)lparam;
  27. if (callinfo)
  28. {
  29. if (!callinfo->allowmulti && callinfo->alreadycalled)
  30. return FALSE;
  31. if (callinfo->pfn(hpage, callinfo->lparam))
  32. {
  33. callinfo->alreadycalled = TRUE;
  34. callinfo->count++;
  35. return TRUE;
  36. }
  37. }
  38. return FALSE;
  39. }
  40. // creates an instance of the property sheet extension referred to by szCLSID
  41. // initializes it via the IShellExtInit (if IShellExtInit is supported)
  42. BOOL InitPropSheetExt(IShellPropSheetExt **ppspx, LPCTSTR pszCLSID, HKEY hKey, IDataObject *pDataObj)
  43. {
  44. if (SUCCEEDED(SHExtCoCreateInstance(pszCLSID, NULL, NULL, &IID_IShellPropSheetExt, ppspx)))
  45. {
  46. IShellExtInit *psxi;
  47. if (SUCCEEDED((*ppspx)->lpVtbl->QueryInterface(*ppspx, &IID_IShellExtInit, &psxi)))
  48. {
  49. if (FAILED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey)))
  50. {
  51. (*ppspx)->lpVtbl->Release(*ppspx);
  52. *ppspx = NULL;
  53. }
  54. psxi->lpVtbl->Release(psxi);
  55. }
  56. }
  57. return BOOLFROMPTR(*ppspx);
  58. }
  59. // uses hKey and pszSubKey to find property sheet handlers in the registry
  60. // loads up to max_iface IShellPropSheetExt interfaces (so I'm lazy...)
  61. // returns a handle (pointer) to a newly allocated PSXA
  62. HPSXA SHCreatePropSheetExtArrayEx(HKEY hKey, LPCTSTR pszLocation, UINT max_iface, IDataObject *pDataObj)
  63. {
  64. BOOL success = FALSE;
  65. PSXA *psxa = LocalAlloc(LPTR, sizeof(*psxa) + sizeof(IShellPropSheetExt *) * max_iface);
  66. if (psxa)
  67. {
  68. IShellPropSheetExt **spsx = psxa->interfaces;
  69. HKEY hkLocation;
  70. UINT i;
  71. psxa->count = 0;
  72. psxa->alloc = max_iface;
  73. for (i = 0; i < psxa->alloc; i++, spsx++)
  74. *spsx = NULL;
  75. if (ERROR_SUCCESS == RegOpenKeyEx(hKey, pszLocation, 0, KEY_QUERY_VALUE, &hkLocation))
  76. {
  77. HKEY hkHandlers;
  78. if (ERROR_SUCCESS == RegOpenKeyEx(hkLocation, STRREG_SHEX_PROPSHEET, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hkHandlers))
  79. {
  80. TCHAR szChild[64]; // yes, this is totally arbitrary...
  81. // fill until there's no room or no more subkeys to get
  82. for (i = 0;
  83. (psxa->count < psxa->alloc) &&
  84. (RegEnumKey(hkHandlers, (int)i, szChild,
  85. ARRAYSIZE(szChild)) == ERROR_SUCCESS);
  86. i++)
  87. {
  88. TCHAR szCLSID[ MAX_PATH ];
  89. DWORD cbCLSID = sizeof(szCLSID);
  90. if (SHRegGetValue(hkHandlers, szChild, NULL, SRRF_RT_REG_SZ, NULL, szCLSID,
  91. &cbCLSID) == ERROR_SUCCESS)
  92. {
  93. if (InitPropSheetExt(&psxa->interfaces[ psxa->count ],
  94. szCLSID, hKey, pDataObj))
  95. {
  96. psxa->count++;
  97. }
  98. }
  99. }
  100. RegCloseKey(hkHandlers);
  101. success = TRUE;
  102. }
  103. RegCloseKey(hkLocation);
  104. }
  105. }
  106. if (!success && psxa)
  107. {
  108. SHDestroyPropSheetExtArray((HPSXA)psxa);
  109. psxa = NULL;
  110. }
  111. return (HPSXA)psxa;
  112. }
  113. HPSXA SHCreatePropSheetExtArray(HKEY hKey, LPCTSTR pszLocation, UINT max_iface)
  114. {
  115. return SHCreatePropSheetExtArrayEx(hKey, pszLocation, max_iface, NULL);
  116. }
  117. // releases interfaces in a PSXA and frees the memory it occupies
  118. void SHDestroyPropSheetExtArray(HPSXA hpsxa)
  119. {
  120. PSXA *psxa = (PSXA *)hpsxa;
  121. IShellPropSheetExt **spsx = psxa->interfaces;
  122. UINT i;
  123. // release the interfaces
  124. for (i = 0; i < psxa->count; i++, spsx++)
  125. (*spsx)->lpVtbl->Release(*spsx);
  126. LocalFree(psxa);
  127. }
  128. // asks each interface in a PSXA to add pages for a proprty sheet
  129. // returns the number of pages actually added
  130. UINT SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
  131. {
  132. PSXA *psxa = (PSXA *)hpsxa;
  133. IShellPropSheetExt **spsx = psxa->interfaces;
  134. _PSXACALLINFO callinfo = { lpfnAddPage, lParam, 0, TRUE, FALSE };
  135. UINT i;
  136. for (i = 0; i < psxa->count; i++, spsx++)
  137. (*spsx)->lpVtbl->AddPages(*spsx, _PsxaCallOwner, (LPARAM)&callinfo);
  138. return callinfo.count;
  139. }
  140. // asks each interface in a PSXA to replace a page in a prop sheet
  141. // each interface is only allowed to add up to one replacement
  142. // returns the total number of replacements added
  143. UINT SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID,
  144. LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
  145. {
  146. PSXA *psxa = (PSXA *)hpsxa;
  147. IShellPropSheetExt **spsx = psxa->interfaces;
  148. _PSXACALLINFO callinfo = { lpfnReplaceWith, lParam, 0, FALSE, FALSE };
  149. UINT i;
  150. for (i = 0; i < psxa->count; i++, spsx++)
  151. {
  152. // reset the call flag so that each provider gets a chance
  153. callinfo.alreadycalled = FALSE;
  154. if ((*spsx)->lpVtbl->ReplacePage)
  155. (*spsx)->lpVtbl->ReplacePage(*spsx, uPageID, _PsxaCallOwner, (LPARAM)&callinfo);
  156. }
  157. return callinfo.count;
  158. }