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.

447 lines
13 KiB

  1. // V410File.cpp Implementation of Version 4.10 data file methods.
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. #include "DataSrc.h"
  5. #ifndef IDS_V410FILENODE
  6. #include "resource.h"
  7. #endif
  8. #include "resrc1.h"
  9. //-----------------------------------------------------------------------------
  10. // This struct is used to read the internals of a 4.10 data file.
  11. //-----------------------------------------------------------------------------
  12. typedef struct
  13. {
  14. char szCLSID[40];
  15. char szStreamName[12];
  16. char szName[_MAX_PATH];
  17. char szVersion[20];
  18. DWORD dwSize;
  19. } SAVED_CONTROL_INFO;
  20. /*
  21. * CBufferV410DataSource - Stub
  22. *
  23. * History: a-jsari 9/17/97 Initial version
  24. */
  25. CBufferV410DataSource::CBufferV410DataSource(CMSInfoFile *pFileSink)
  26. :CBufferDataSource(pFileSink)
  27. {
  28. }
  29. //-----------------------------------------------------------------------------
  30. // The constructor for the version 4.10 NFO file data source reads information
  31. // from an IStream in a compound file.
  32. //-----------------------------------------------------------------------------
  33. CBufferV410DataSource::CBufferV410DataSource(IStorage * pStorage, IStream * pStream)
  34. : CBufferDataSource(NULL)
  35. {
  36. ReadMSInfo410Stream(pStream);
  37. m_pStorage = pStorage;
  38. m_pStorage->AddRef();
  39. }
  40. //-----------------------------------------------------------------------------
  41. // The destructor should release the pointer to the compound doc we saved.
  42. //-----------------------------------------------------------------------------
  43. CBufferV410DataSource::~CBufferV410DataSource()
  44. {
  45. if (m_pStorage)
  46. {
  47. m_pStorage->Release();
  48. m_pStorage = NULL;
  49. }
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Read in the information from the "msinfo" stream. The most vital things
  53. // in this file are the tree structure of categories, and the map from
  54. // CLSID to stream name.
  55. //-----------------------------------------------------------------------------
  56. BOOL CBufferV410DataSource::ReadMSInfo410Stream(IStream *pStream)
  57. {
  58. const DWORD MSI_FILE_VER = 0x03000000;
  59. DWORD dwVersion, dwCount;
  60. // First, read and check the version number in the stream.
  61. if (FAILED(pStream->Read((void *) &dwVersion, sizeof(DWORD), &dwCount)) || dwCount != sizeof(DWORD))
  62. return FALSE;
  63. if (dwVersion != MSI_FILE_VER)
  64. return FALSE;
  65. // The next thing in the stream is a set of three strings, each terminated by
  66. // a newline character. These three strings are the time/date, machine name and
  67. // user name from the saving system. The length of the total string precedes
  68. // the string.
  69. DWORD dwSize;
  70. if (FAILED(pStream->Read((void *) &dwSize, sizeof(DWORD), &dwCount)) || dwCount != sizeof(DWORD))
  71. return FALSE;
  72. char * szBuffer = new char[dwSize];
  73. if (szBuffer == NULL)
  74. return FALSE;
  75. if (FAILED(pStream->Read((void *) szBuffer, dwSize, &dwCount)) || (int)dwCount != dwSize)
  76. {
  77. delete szBuffer;
  78. return FALSE;
  79. }
  80. // We don't actually care about these values (now at least).
  81. #if FALSE
  82. CString strData(szBuffer, dwSize);
  83. m_strTimeDateStamp = strData.SpanExcluding("\n");
  84. strData = strData.Right(strData.GetLength() - m_strTimeDateStamp.GetLength() - 1);
  85. m_strMachineName = strData.SpanExcluding("\n");
  86. strData = strData.Right(strData.GetLength() - m_strMachineName.GetLength() - 1);
  87. m_strUserName = strData.SpanExcluding("\n");
  88. #endif
  89. delete szBuffer;
  90. // Next, read the map from CLSIDs to stream names. This also includes some
  91. // other information about the controls. First we should find a DWORD with
  92. // the count of controls.
  93. DWORD dwControlCount;
  94. if (FAILED(pStream->Read((void *) &dwControlCount, sizeof(DWORD), &dwCount)) || dwCount != sizeof(int))
  95. return FALSE;
  96. SAVED_CONTROL_INFO controlInfo;
  97. CString strCLSID, strStreamName;
  98. for (DWORD i = 0; i < dwControlCount; i++)
  99. {
  100. if (FAILED(pStream->Read((void *) &controlInfo, sizeof(SAVED_CONTROL_INFO), &dwCount)) || dwCount != sizeof(SAVED_CONTROL_INFO))
  101. return FALSE;
  102. strCLSID = controlInfo.szCLSID;
  103. strStreamName = controlInfo.szStreamName;
  104. // We don't currently care about this information...
  105. #if FALSE
  106. strSize.Format("%ld", controlInfo.dwSize);
  107. strInfo.FormatMessage(IDS_OCX_INFO, controlInfo.szName, controlInfo.szVersion, strSize);
  108. m_mapCLSIDToInfo.SetAt(strCLSID, strInfo);
  109. #endif
  110. m_mapStreams.SetAt(strCLSID, strStreamName);
  111. }
  112. // Read and build the category tree. Read the first level, which must be 0.
  113. int iLevel;
  114. if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int))
  115. return FALSE;
  116. if (iLevel == 0)
  117. {
  118. LARGE_INTEGER li; li.HighPart = -1; li.LowPart = (ULONG)(0 - sizeof(int));
  119. if (FAILED(pStream->Seek(li, STREAM_SEEK_CUR, NULL)))
  120. return FALSE;
  121. if (!RecurseLoad410Tree(pStream))
  122. return FALSE;
  123. // After RecurseLoadTree is through, we should be able to read a -1
  124. // for the next level.
  125. if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int) || iLevel != -1)
  126. return FALSE;
  127. }
  128. else
  129. return FALSE;
  130. return TRUE;
  131. }
  132. //-----------------------------------------------------------------------------
  133. // This function creates a COCXFolder object based on the information read
  134. // from the stream.
  135. //-----------------------------------------------------------------------------
  136. COCXFolder * CBufferV410DataSource::ReadOCXFolder(IStream *pStream, COCXFolder * pParent, COCXFolder * pPrevious)
  137. {
  138. // Read in the values from the stream. Make sure they're all there before
  139. // we create the COCXFolder.
  140. BOOL fUsesView = FALSE;
  141. BOOL fControl = FALSE;
  142. DWORD dwView = 0;
  143. CLSID clsidCategory;
  144. char szName[100];
  145. if (FAILED(pStream->Read((void *) &fUsesView, sizeof(BOOL), NULL))) return NULL;
  146. if (FAILED(pStream->Read((void *) &fControl, sizeof(BOOL), NULL))) return NULL;
  147. if (FAILED(pStream->Read((void *) &dwView, sizeof(DWORD), NULL))) return NULL;
  148. if (FAILED(pStream->Read((void *) &clsidCategory, sizeof(CLSID), NULL))) return NULL;
  149. if (FAILED(pStream->Read((void *) &szName, sizeof(char) * 100, NULL))) return NULL;
  150. USES_CONVERSION;
  151. LPOLESTR lpName = A2W(szName);
  152. COCXFolder * pFolder = new COCXFolder(this, clsidCategory, pParent, pPrevious, dwView, lpName);
  153. return pFolder;
  154. }
  155. //-----------------------------------------------------------------------------
  156. // This function (which doesn't really use recursion - the name is left over
  157. // from 4.10 MSInfo) read the category tree from the MSInfo stream and creates
  158. // the necessary COCXFolder objects to represent it.
  159. //-----------------------------------------------------------------------------
  160. BOOL CBufferV410DataSource::RecurseLoad410Tree(IStream *pStream)
  161. {
  162. m_RootFolder = NULL;
  163. // This array of folders is used to keep track of the last folder read
  164. // on each level. This is useful for getting the parent and previous
  165. // sibling when reading a new folder.
  166. COCXFolder * aFolderHistory[20];
  167. for (int i = 0; i < 20; i++) aFolderHistory[i] = NULL;
  168. // The iLevel variable keeps track of the current tree level we are
  169. // reading a folder for. A -1 indicates the end of the tree.
  170. DWORD dwCount;
  171. int iLevel = 0;
  172. if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int))
  173. return FALSE;
  174. int iLastLevel = iLevel;
  175. while (iLevel >= 0 && iLevel < 20)
  176. {
  177. aFolderHistory[iLevel] = ReadOCXFolder(pStream, ((iLevel) ? aFolderHistory[iLevel - 1] : NULL), ((iLevel <= iLastLevel) ? aFolderHistory[iLevel] : NULL));
  178. iLastLevel = iLevel;
  179. if (FAILED(pStream->Read((void *) &iLevel, sizeof(int), &dwCount)) || dwCount != sizeof(int))
  180. return FALSE;
  181. }
  182. m_RootFolder = aFolderHistory[0];
  183. // The root OCX folder will not show up in version 5.0, so we need to make
  184. // the first child folder contain the same values as the root.
  185. COCXFolder * pRootFolder = reinterpret_cast<COCXFolder *>(m_RootFolder);
  186. if (pRootFolder)
  187. {
  188. CFolder * pOriginalChild = pRootFolder->m_ChildFolder;
  189. pRootFolder->m_ChildFolder = new COCXFolder(this, pRootFolder->m_clsid, pRootFolder, NULL, pRootFolder->m_dwView, L"");
  190. reinterpret_cast<COCXFolder *>(pRootFolder->m_ChildFolder)->m_strName.LoadString(IDS_410SUMMARY_NODE);
  191. pRootFolder->m_ChildFolder->m_NextFolder = pOriginalChild;
  192. }
  193. // We read a -1 to exit the loop, then we are through with the
  194. // category tree. Backup (so any other recursion trees will read
  195. // the -1 as well) and return TRUE.
  196. if (iLevel == -1)
  197. {
  198. LARGE_INTEGER li; li.HighPart = -1; li.LowPart = (ULONG)(0 - sizeof(int));
  199. if (FAILED(pStream->Seek(li, STREAM_SEEK_CUR, NULL)))
  200. return FALSE;
  201. }
  202. return TRUE;
  203. }
  204. /*
  205. * GetNodeName -
  206. *
  207. * History: a-jsari 1/16/98 Initial version.
  208. */
  209. BOOL CBufferV410DataSource::GetNodeName(CString &strNodeName)
  210. {
  211. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  212. strNodeName.Format(IDS_V410FILENODE);
  213. return TRUE;
  214. }
  215. /*
  216. * GetRootNode - Stub
  217. *
  218. * History: a-jsari 9/17/97 Initial version
  219. */
  220. CFolder *CBufferV410DataSource::GetRootNode()
  221. {
  222. return CDataSource::GetRootNode();
  223. }
  224. /*
  225. * ReadHeader - Stub
  226. *
  227. * History: a-jsari 9/17/97 Initial version
  228. */
  229. void CBufferV410DataSource::ReadHeader(CMSInfoFile *)
  230. {
  231. }
  232. /*
  233. * ReadFolder - Stub
  234. *
  235. * History: a-jsari 9/17/97 Initial version
  236. */
  237. void CBufferV410DataSource::ReadFolder(CMSInfoFile *, CFolder * & /* pParentFolder */, CFolder * /* pFolder */)
  238. {
  239. }
  240. /*
  241. * Save - Stub
  242. *
  243. * History: a-jsari 11/13/97 Initial version
  244. */
  245. HRESULT CBufferV410DataSource::Save(IStream * /* pStm */)
  246. {
  247. return E_NOTIMPL;
  248. }
  249. /*
  250. * Find - Stub
  251. *
  252. * History: a-jsari 12/11/97 Initial version
  253. */
  254. BOOL CBufferV410DataSource::Find(const CString & /* strSearch */, long /* lFindOptions */)
  255. {
  256. return FALSE;
  257. }
  258. //-----------------------------------------------------------------------------
  259. // When the OCX folder is refreshed, we should call the appropriate methods
  260. // in the OCX (if it is there).
  261. //-----------------------------------------------------------------------------
  262. BOOL COCXFolder::Refresh(IUnknown * pUnknown)
  263. {
  264. // Get the CLSID as a string (since all our tables are based on the string).
  265. LPOLESTR lpCLSID;
  266. if (FAILED(StringFromCLSID(m_clsid, &lpCLSID)))
  267. return FALSE;
  268. CString strCLSID(lpCLSID);
  269. CBufferV410DataSource * pV410Source = reinterpret_cast<CBufferV410DataSource *>(DataSource());
  270. if (pV410Source == NULL)
  271. return FALSE;
  272. if (pUnknown == NULL)
  273. return FALSE;
  274. // Get the stream for this control, and load it.
  275. CString strStream;
  276. if (pV410Source->m_pStorage && pV410Source->m_mapStreams.Lookup(strCLSID, strStream))
  277. {
  278. DWORD grfMode = STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  279. IStream * pStream = NULL;
  280. if (SUCCEEDED(pV410Source->m_pStorage->OpenStream(strStream, NULL, grfMode, 0, &pStream)))
  281. {
  282. IPersistStreamInit * pPersistStream = NULL;
  283. if (SUCCEEDED(pUnknown->QueryInterface(IID_IPersistStreamInit, reinterpret_cast<void **>(&pPersistStream))) && pPersistStream)
  284. {
  285. if (SUCCEEDED(pPersistStream->Load(pStream)))
  286. {
  287. // Delete the entry for the this stream (so that we don't keep
  288. // loading the stream into the control).
  289. pV410Source->m_mapStreams.RemoveKey(strCLSID);
  290. }
  291. pPersistStream->Release();
  292. }
  293. pStream->Release();
  294. }
  295. }
  296. // Set the view index for the OCX.
  297. SetOCXView(pUnknown, m_dwView);
  298. return TRUE;
  299. }
  300. //---------------------------------------------------------------------------
  301. // Use the OCX's IDispatch interface to set the view index and call the
  302. // function to refresh the control (for the new index).
  303. //---------------------------------------------------------------------------
  304. void COCXFolder::SetOCXView(IUnknown * pUnknown, DWORD dwView)
  305. {
  306. IDispatch * pDispatch = NULL;
  307. if (SUCCEEDED(pUnknown->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&pDispatch))) && pDispatch)
  308. {
  309. DISPID viewdispid, updatedispid;
  310. if (!GetDISPID(pDispatch, _T("MSInfoView"), &viewdispid) || !GetDISPID(pDispatch, _T("MSInfoUpdateView"), &updatedispid))
  311. return;
  312. DISPID mydispid = DISPID_PROPERTYPUT;
  313. DISPPARAMS dispparams;
  314. VARIANTARG disparg;
  315. disparg.vt = VT_I4;
  316. disparg.lVal = m_dwView;
  317. dispparams.rgvarg = &disparg;
  318. dispparams.rgdispidNamedArgs = &mydispid;
  319. dispparams.cArgs = 1;
  320. dispparams.cNamedArgs = 1;
  321. pDispatch->Invoke(viewdispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
  322. DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
  323. pDispatch->Invoke(updatedispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, NULL, NULL, NULL);
  324. pDispatch->Release();
  325. }
  326. }
  327. //---------------------------------------------------------------------------
  328. // GetDISPID returns the DISPID for a given string, by looking it up using
  329. // IDispatch->GetIDsOfNames. This avoids hardcoding DISPIDs in this class.
  330. //---------------------------------------------------------------------------
  331. BOOL COCXFolder::GetDISPID(IDispatch * pDispatch, LPOLESTR szMember, DISPID *pID)
  332. {
  333. BOOL result = FALSE;
  334. DISPID dispid;
  335. if (SUCCEEDED(pDispatch->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT, &dispid)))
  336. {
  337. *pID = dispid;
  338. result = TRUE;
  339. }
  340. return result;
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Return the folder's CLSID as string.
  344. //-----------------------------------------------------------------------------
  345. BOOL COCXFolder::GetCLSIDString(CString & strCLSID)
  346. {
  347. LPOLESTR lpCLSID;
  348. if (FAILED(StringFromCLSID(m_clsid, &lpCLSID)))
  349. return FALSE;
  350. strCLSID = lpCLSID;
  351. CoTaskMemFree(lpCLSID);
  352. return TRUE;
  353. };