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.

1600 lines
47 KiB

  1. // Copyright (c) 1998-2001 Microsoft Corporation
  2. // Object.cpp : Implementations of CObject and CClass
  3. #include "dmusici.h"
  4. #include "loader.h"
  5. #include "debug.h"
  6. #include "miscutil.h"
  7. #include <strsafe.h>
  8. #ifdef UNDER_CE
  9. #include "dragon.h"
  10. #else
  11. extern BOOL g_fIsUnicode;
  12. #endif
  13. CDescriptor::CDescriptor()
  14. {
  15. m_fCSInitialized = FALSE;
  16. InitializeCriticalSection(&m_CriticalSection);
  17. // Note: on pre-Blackcomb OS's, this call can raise an exception; if it
  18. // ever pops in stress, we can add an exception handler and retry loop.
  19. m_fCSInitialized = TRUE;
  20. m_llMemLength = 0;
  21. m_pbMemData = NULL; // Null pointer to memory.
  22. m_dwValidData = 0; // Flags indicating which of above is valid.
  23. m_guidObject = GUID_NULL; // Unique ID for this object.
  24. m_guidClass = GUID_NULL; // GUID for the class of object.
  25. ZeroMemory( &m_ftDate, sizeof(FILETIME) ); // File date of object.
  26. ZeroMemory( &m_vVersion, sizeof(DMUS_VERSION) ); // Version, as set by authoring tool.
  27. m_pwzName = NULL; // Name of object.
  28. m_pwzCategory = NULL; // Category for object (optional).
  29. m_pwzFileName = NULL; // File path.
  30. m_dwFileSize = 0; // Size of file.
  31. m_pIStream = NULL;
  32. m_liStartPosition.QuadPart = 0;
  33. }
  34. CDescriptor::~CDescriptor()
  35. {
  36. if (m_fCSInitialized)
  37. {
  38. // If critical section never initialized, never got a chance
  39. // to do any other initializations
  40. //
  41. if (m_pwzFileName) delete[] m_pwzFileName;
  42. if (m_pwzCategory) delete[] m_pwzCategory;
  43. if (m_pwzName) delete[] m_pwzName;
  44. if (m_pIStream) m_pIStream->Release();
  45. DeleteCriticalSection(&m_CriticalSection);
  46. }
  47. }
  48. void CDescriptor::ClearName()
  49. {
  50. if (m_pwzName) delete[] m_pwzName;
  51. m_pwzName = NULL;
  52. m_dwValidData &= ~DMUS_OBJ_NAME;
  53. }
  54. void CDescriptor::SetName(WCHAR *pwzName)
  55. {
  56. if(pwzName == NULL)
  57. {
  58. return;
  59. }
  60. HRESULT hr = S_OK;
  61. WCHAR wszName[DMUS_MAX_NAME] = L"";
  62. ClearName();
  63. hr = StringCchCopyW(wszName, DMUS_MAX_NAME, pwzName);
  64. if(SUCCEEDED(hr))
  65. {
  66. size_t cLen = wcslen(wszName);
  67. m_pwzName = new WCHAR[cLen + 1];
  68. if(m_pwzName == NULL)
  69. {
  70. hr = E_OUTOFMEMORY;
  71. }
  72. if(SUCCEEDED(hr))
  73. {
  74. wcsncpy(m_pwzName, wszName, cLen + 1);
  75. }
  76. }
  77. if(SUCCEEDED(hr))
  78. {
  79. m_dwValidData |= DMUS_OBJ_NAME;
  80. }
  81. else
  82. {
  83. m_dwValidData &= ~DMUS_OBJ_NAME;
  84. }
  85. }
  86. void CDescriptor::ClearCategory()
  87. {
  88. if (m_pwzCategory) delete[] m_pwzCategory;
  89. m_pwzCategory = NULL;
  90. m_dwValidData &= ~DMUS_OBJ_CATEGORY;
  91. }
  92. void CDescriptor::SetCategory(WCHAR* pwzCategory)
  93. {
  94. if(pwzCategory == NULL)
  95. {
  96. return;
  97. }
  98. HRESULT hr = S_OK;
  99. WCHAR wszCategory[DMUS_MAX_CATEGORY] = L"";
  100. ClearCategory();
  101. hr = StringCchCopyW(wszCategory, DMUS_MAX_CATEGORY, pwzCategory);
  102. if(SUCCEEDED(hr))
  103. {
  104. size_t cLen = wcslen(wszCategory);
  105. m_pwzCategory = new WCHAR[cLen + 1];
  106. if(m_pwzCategory == NULL)
  107. {
  108. hr = E_OUTOFMEMORY;
  109. }
  110. if(SUCCEEDED(hr))
  111. {
  112. wcsncpy(m_pwzCategory, wszCategory, cLen + 1);
  113. }
  114. }
  115. if(SUCCEEDED(hr))
  116. {
  117. m_dwValidData |= DMUS_OBJ_CATEGORY;
  118. }
  119. else
  120. {
  121. m_dwValidData &= ~DMUS_OBJ_CATEGORY;
  122. }
  123. }
  124. void CDescriptor::ClearFileName()
  125. {
  126. if (m_pwzFileName) delete[] m_pwzFileName;
  127. m_pwzFileName = NULL;
  128. m_dwValidData &= ~DMUS_OBJ_FILENAME;
  129. }
  130. // return S_FALSE if the filename is already set to this
  131. HRESULT CDescriptor::SetFileName(WCHAR *pwzFileName)
  132. {
  133. if(pwzFileName == NULL)
  134. {
  135. return E_POINTER;
  136. }
  137. HRESULT hr = E_FAIL;
  138. WCHAR wszFileName[DMUS_MAX_FILENAME] = L"";
  139. // Make a safe copy of the passed string
  140. hr = StringCchCopyW(wszFileName, DMUS_MAX_FILENAME, pwzFileName);
  141. if(FAILED(hr))
  142. {
  143. return E_INVALIDARG;
  144. }
  145. // We return without touching the valid data flags if we fail here
  146. if( m_pwzFileName )
  147. {
  148. if( !_wcsicmp( m_pwzFileName, wszFileName ))
  149. {
  150. return S_FALSE;
  151. }
  152. }
  153. // This is actually unnecessary since we're returning on failure above
  154. // But then that code might change. So to keep it absolutely clear...
  155. if(SUCCEEDED(hr))
  156. {
  157. ClearFileName();
  158. size_t cLen = wcslen(wszFileName);
  159. m_pwzFileName = new WCHAR[cLen + 1];
  160. if (m_pwzFileName == NULL)
  161. {
  162. hr = E_OUTOFMEMORY;
  163. }
  164. if(SUCCEEDED(hr))
  165. {
  166. hr = StringCchCopyW(m_pwzFileName, cLen + 1, wszFileName);
  167. }
  168. }
  169. if(SUCCEEDED(hr))
  170. {
  171. m_dwValidData |= DMUS_OBJ_FILENAME;
  172. }
  173. else
  174. {
  175. m_dwValidData &= ~DMUS_OBJ_FILENAME;
  176. }
  177. return hr;
  178. }
  179. void CDescriptor::ClearIStream()
  180. {
  181. EnterCriticalSection(&m_CriticalSection);
  182. if (m_pIStream)
  183. {
  184. m_pIStream->Release();
  185. }
  186. m_pIStream = NULL;
  187. m_liStartPosition.QuadPart = 0;
  188. m_dwValidData &= ~DMUS_OBJ_STREAM;
  189. LeaveCriticalSection(&m_CriticalSection);
  190. }
  191. void CDescriptor::SetIStream(IStream *pIStream)
  192. {
  193. EnterCriticalSection(&m_CriticalSection);
  194. ClearIStream();
  195. m_pIStream = pIStream;
  196. if (m_pIStream)
  197. {
  198. ULARGE_INTEGER libNewPosition;
  199. m_liStartPosition.QuadPart = 0;
  200. m_pIStream->Seek( m_liStartPosition, STREAM_SEEK_CUR, &libNewPosition );
  201. m_liStartPosition.QuadPart = libNewPosition.QuadPart;
  202. m_pIStream->AddRef();
  203. m_dwValidData |= DMUS_OBJ_STREAM;
  204. }
  205. LeaveCriticalSection(&m_CriticalSection);
  206. }
  207. BOOL CDescriptor::IsExtension(WCHAR *pwzExtension)
  208. {
  209. if (pwzExtension && m_pwzFileName)
  210. {
  211. DWORD dwX;
  212. DWORD dwLen = wcslen(m_pwzFileName);
  213. for (dwX = 0; dwX < dwLen; dwX++)
  214. {
  215. if (m_pwzFileName[dwX] == L'.') break;
  216. }
  217. dwX++;
  218. if (dwX < dwLen)
  219. {
  220. return !_wcsicmp(pwzExtension,&m_pwzFileName[dwX]);
  221. }
  222. }
  223. return FALSE;
  224. }
  225. void CDescriptor::Get(LPDMUS_OBJECTDESC pDesc)
  226. {
  227. if(pDesc == NULL)
  228. {
  229. return;
  230. }
  231. // Don't return the IStream insterface. Once set, this becomes private to the loader.
  232. pDesc->dwValidData = m_dwValidData & ~DMUS_OBJ_STREAM;
  233. pDesc->guidObject = m_guidObject;
  234. pDesc->guidClass = m_guidClass;
  235. pDesc->ftDate = m_ftDate;
  236. pDesc->vVersion = m_vVersion;
  237. pDesc->llMemLength = m_llMemLength;
  238. pDesc->pbMemData = m_pbMemData;
  239. if (m_pwzName)
  240. {
  241. wcsncpy( pDesc->wszName, m_pwzName, DMUS_MAX_NAME );
  242. }
  243. if (m_pwzCategory)
  244. {
  245. wcsncpy( pDesc->wszCategory,m_pwzCategory, DMUS_MAX_CATEGORY );
  246. }
  247. if (m_pwzFileName)
  248. {
  249. wcsncpy( pDesc->wszFileName, m_pwzFileName, DMUS_MAX_FILENAME);
  250. }
  251. }
  252. void CDescriptor::Set(LPDMUS_OBJECTDESC pDesc)
  253. {
  254. m_dwValidData = pDesc->dwValidData;
  255. m_guidObject = pDesc->guidObject;
  256. m_guidClass = pDesc->guidClass;
  257. m_ftDate = pDesc->ftDate;
  258. m_vVersion = pDesc->vVersion;
  259. m_llMemLength = pDesc->llMemLength;
  260. m_pbMemData = pDesc->pbMemData;
  261. ClearName();
  262. if (pDesc->dwValidData & DMUS_OBJ_NAME)
  263. {
  264. pDesc->wszName[DMUS_MAX_NAME - 1] = 0; // Force string length, in case of error.
  265. SetName(pDesc->wszName);
  266. }
  267. ClearCategory();
  268. if (pDesc->dwValidData & DMUS_OBJ_CATEGORY)
  269. {
  270. pDesc->wszCategory[DMUS_MAX_CATEGORY - 1] = 0; // Force string length, in case of error.
  271. SetCategory(pDesc->wszCategory);
  272. }
  273. ClearFileName();
  274. if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
  275. {
  276. pDesc->wszFileName[DMUS_MAX_FILENAME - 1] = 0; // Force string length, in case of error.
  277. SetFileName(pDesc->wszFileName);
  278. }
  279. ClearIStream();
  280. if (pDesc->dwValidData & DMUS_OBJ_STREAM)
  281. {
  282. SetIStream(pDesc->pStream);
  283. }
  284. }
  285. void CDescriptor::Copy(CDescriptor *pDesc)
  286. {
  287. m_dwValidData = pDesc->m_dwValidData;
  288. m_guidObject = pDesc->m_guidObject;
  289. m_guidClass = pDesc->m_guidClass;
  290. m_ftDate = pDesc->m_ftDate;
  291. m_vVersion = pDesc->m_vVersion;
  292. m_llMemLength = pDesc->m_llMemLength;
  293. m_pbMemData = pDesc->m_pbMemData;
  294. ClearName();
  295. if (pDesc->m_dwValidData & DMUS_OBJ_NAME)
  296. {
  297. SetName(pDesc->m_pwzName);
  298. }
  299. ClearCategory();
  300. if (pDesc->m_dwValidData & DMUS_OBJ_CATEGORY)
  301. {
  302. SetCategory(pDesc->m_pwzCategory);
  303. }
  304. ClearFileName();
  305. if (pDesc->m_dwValidData & DMUS_OBJ_FILENAME)
  306. {
  307. SetFileName(pDesc->m_pwzFileName);
  308. }
  309. ClearIStream();
  310. if (pDesc->m_dwValidData & DMUS_OBJ_STREAM)
  311. {
  312. SetIStream(pDesc->m_pIStream);
  313. }
  314. }
  315. void CDescriptor::Merge(CDescriptor *pSource)
  316. {
  317. if (pSource->m_dwValidData & DMUS_OBJ_OBJECT)
  318. {
  319. m_dwValidData |= DMUS_OBJ_OBJECT;
  320. m_guidObject = pSource->m_guidObject;
  321. }
  322. if (pSource->m_dwValidData & DMUS_OBJ_CLASS)
  323. {
  324. m_dwValidData |= DMUS_OBJ_CLASS;
  325. m_guidClass = pSource->m_guidClass;
  326. }
  327. if (pSource->m_dwValidData & DMUS_OBJ_NAME)
  328. {
  329. m_dwValidData |= DMUS_OBJ_NAME;
  330. SetName(pSource->m_pwzName);
  331. }
  332. if (pSource->m_dwValidData & DMUS_OBJ_CATEGORY)
  333. {
  334. m_dwValidData |= DMUS_OBJ_CATEGORY;
  335. SetCategory(pSource->m_pwzCategory);
  336. }
  337. if (pSource->m_dwValidData & DMUS_OBJ_VERSION)
  338. {
  339. m_dwValidData |= DMUS_OBJ_VERSION;
  340. m_vVersion = pSource->m_vVersion;
  341. }
  342. if (pSource->m_dwValidData & DMUS_OBJ_DATE)
  343. {
  344. m_dwValidData |= DMUS_OBJ_DATE;
  345. m_ftDate = pSource->m_ftDate;
  346. }
  347. if (pSource->m_dwValidData & DMUS_OBJ_FILENAME)
  348. {
  349. if (!(m_dwValidData & DMUS_OBJ_FILENAME))
  350. {
  351. if (SUCCEEDED(SetFileName(pSource->m_pwzFileName)))
  352. {
  353. m_dwValidData |= (pSource->m_dwValidData &
  354. (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_URL));
  355. }
  356. }
  357. }
  358. if (pSource->m_dwValidData & DMUS_OBJ_MEMORY)
  359. {
  360. m_pbMemData = pSource->m_pbMemData;
  361. m_llMemLength = pSource->m_llMemLength;
  362. if (m_llMemLength && m_pbMemData)
  363. {
  364. m_dwValidData |= DMUS_OBJ_MEMORY;
  365. }
  366. else
  367. {
  368. m_dwValidData &= ~DMUS_OBJ_MEMORY;
  369. }
  370. }
  371. if (pSource->m_dwValidData & DMUS_OBJ_STREAM)
  372. {
  373. SetIStream(pSource->m_pIStream);
  374. }
  375. }
  376. CObject::CObject(CClass *pClass)
  377. {
  378. m_dwScanBits = 0;
  379. m_pClass = pClass;
  380. m_pIDMObject = NULL;
  381. m_pvecReferences = NULL;
  382. }
  383. CObject::CObject(CClass *pClass, CDescriptor *pDesc)
  384. {
  385. m_dwScanBits = 0;
  386. m_pClass = pClass;
  387. m_pIDMObject = NULL;
  388. m_ObjectDesc.Copy(pDesc);
  389. m_ObjectDesc.m_dwValidData &= ~DMUS_OBJ_LOADED;
  390. if (!(m_ObjectDesc.m_dwValidData & DMUS_OBJ_CLASS))
  391. {
  392. m_ObjectDesc.m_guidClass = pClass->m_ClassDesc.m_guidClass;
  393. m_ObjectDesc.m_dwValidData |=
  394. (pClass->m_ClassDesc.m_dwValidData & DMUS_OBJ_CLASS);
  395. }
  396. m_pvecReferences = NULL;
  397. }
  398. CObject::~CObject()
  399. {
  400. if (m_pIDMObject)
  401. {
  402. m_pIDMObject->Release();
  403. m_pIDMObject = NULL;
  404. }
  405. delete m_pvecReferences;
  406. }
  407. HRESULT CObject::Parse()
  408. {
  409. if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_FILENAME)
  410. {
  411. return ParseFromFile();
  412. }
  413. else if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_MEMORY)
  414. {
  415. return ParseFromMemory();
  416. }
  417. else if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_STREAM)
  418. {
  419. return ParseFromStream();
  420. }
  421. assert(false);
  422. return E_FAIL;
  423. }
  424. HRESULT CObject::ParseFromFile()
  425. {
  426. HRESULT hr;
  427. IDirectMusicObject *pIObject;
  428. hr = CoCreateInstance(m_ObjectDesc.m_guidClass,
  429. NULL,CLSCTX_INPROC_SERVER,IID_IDirectMusicObject,
  430. (void **) &pIObject);
  431. if (SUCCEEDED(hr))
  432. {
  433. WCHAR wzFullPath[DMUS_MAX_FILENAME];
  434. ZeroMemory( wzFullPath, sizeof(WCHAR) * DMUS_MAX_FILENAME );
  435. CFileStream *pStream = new CFileStream ( m_pClass->m_pLoader );
  436. if (pStream)
  437. {
  438. if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_FULLPATH)
  439. {
  440. wcsncpy(wzFullPath, m_ObjectDesc.m_pwzFileName, DMUS_MAX_FILENAME);
  441. }
  442. else
  443. {
  444. m_pClass->GetPath(wzFullPath);
  445. wcsncat(wzFullPath, m_ObjectDesc.m_pwzFileName, DMUS_MAX_FILENAME - wcslen(wzFullPath) - 1);
  446. }
  447. hr = pStream->Open(wzFullPath,GENERIC_READ);
  448. if (SUCCEEDED(hr))
  449. {
  450. DMUS_OBJECTDESC DESC;
  451. memset((void *)&DESC,0,sizeof(DESC));
  452. DESC.dwSize = sizeof (DMUS_OBJECTDESC);
  453. hr = pIObject->ParseDescriptor(pStream,&DESC);
  454. if (SUCCEEDED(hr))
  455. {
  456. CDescriptor ParseDesc;
  457. ParseDesc.Set(&DESC);
  458. m_ObjectDesc.Merge(&ParseDesc);
  459. }
  460. }
  461. pStream->Release();
  462. }
  463. pIObject->Release();
  464. }
  465. return hr;
  466. }
  467. HRESULT CObject::ParseFromMemory()
  468. {
  469. HRESULT hr;
  470. IDirectMusicObject *pIObject;
  471. hr = CoCreateInstance(m_ObjectDesc.m_guidClass,
  472. NULL,CLSCTX_INPROC_SERVER,IID_IDirectMusicObject,
  473. (void **) &pIObject);
  474. if (SUCCEEDED(hr))
  475. {
  476. CMemStream *pStream = new CMemStream ( m_pClass->m_pLoader );
  477. if (pStream)
  478. {
  479. hr = pStream->Open(m_ObjectDesc.m_pbMemData,m_ObjectDesc.m_llMemLength);
  480. if (SUCCEEDED(hr))
  481. {
  482. DMUS_OBJECTDESC DESC;
  483. memset((void *)&DESC,0,sizeof(DESC));
  484. DESC.dwSize = sizeof (DMUS_OBJECTDESC);
  485. hr = pIObject->ParseDescriptor(pStream,&DESC);
  486. if (SUCCEEDED(hr))
  487. {
  488. CDescriptor ParseDesc;
  489. ParseDesc.Set(&DESC);
  490. m_ObjectDesc.Merge(&ParseDesc);
  491. }
  492. }
  493. pStream->Release();
  494. }
  495. pIObject->Release();
  496. }
  497. return hr;
  498. }
  499. HRESULT CObject::ParseFromStream()
  500. {
  501. HRESULT hr;
  502. IDirectMusicObject *pIObject;
  503. hr = CoCreateInstance(m_ObjectDesc.m_guidClass,
  504. NULL,CLSCTX_INPROC_SERVER,IID_IDirectMusicObject,
  505. (void **) &pIObject);
  506. if (SUCCEEDED(hr))
  507. {
  508. CStream *pStream = new CStream ( m_pClass->m_pLoader );
  509. if (pStream)
  510. {
  511. hr = pStream->Open(m_ObjectDesc.m_pIStream,
  512. m_ObjectDesc.m_liStartPosition);
  513. if (SUCCEEDED(hr))
  514. {
  515. DMUS_OBJECTDESC DESC;
  516. memset((void *)&DESC,0,sizeof(DESC));
  517. DESC.dwSize = sizeof (DMUS_OBJECTDESC);
  518. hr = pIObject->ParseDescriptor(pStream,&DESC);
  519. if (SUCCEEDED(hr))
  520. {
  521. CDescriptor ParseDesc;
  522. ParseDesc.Set(&DESC);
  523. m_ObjectDesc.Merge(&ParseDesc);
  524. }
  525. }
  526. pStream->Release();
  527. }
  528. pIObject->Release();
  529. }
  530. return hr;
  531. }
  532. // Record that this object can be garbage collected and prepare to store its references.
  533. // Must be called before any of CObject's other routines.
  534. HRESULT CObject::GC_Collectable()
  535. {
  536. m_dwScanBits |= SCAN_GC;
  537. assert(!m_pvecReferences);
  538. m_pvecReferences = new SmartRef::Vector<CObject*>;
  539. if (!m_pvecReferences)
  540. return E_OUTOFMEMORY;
  541. return S_OK;
  542. }
  543. HRESULT CObject::GC_AddReference(CObject *pObject)
  544. {
  545. if(pObject == NULL)
  546. {
  547. return E_POINTER;
  548. }
  549. assert(m_dwScanBits & SCAN_GC && m_pvecReferences);
  550. // don't track references to objects that aren't garbage collected
  551. if (!(pObject->m_dwScanBits & SCAN_GC))
  552. return S_OK;
  553. UINT uiPosNext = m_pvecReferences->size();
  554. for (UINT i = 0; i < uiPosNext; ++i)
  555. {
  556. if ((*m_pvecReferences)[i] == pObject)
  557. return S_OK;
  558. }
  559. if (!m_pvecReferences->AccessTo(uiPosNext))
  560. return E_OUTOFMEMORY;
  561. (*m_pvecReferences)[uiPosNext] = pObject;
  562. return S_OK;
  563. }
  564. HRESULT CObject::GC_RemoveReference(CObject *pObject)
  565. {
  566. assert(m_dwScanBits & SCAN_GC && m_pvecReferences);
  567. SmartRef::Vector<CObject*> &vecRefs = *m_pvecReferences;
  568. UINT iEnd = vecRefs.size();
  569. for (UINT i = 0; i < iEnd; ++i)
  570. {
  571. if (vecRefs[i] == pObject)
  572. {
  573. // Remove by clearing the pointer.
  574. // The open slot will be compacted during garbage collection (GC_Mark).
  575. vecRefs[i] = NULL;
  576. return S_OK;
  577. }
  578. }
  579. return S_FALSE;
  580. }
  581. // Helper method used to implement ReleaseObject.
  582. HRESULT CObject::GC_RemoveAndDuplicateInParentList()
  583. {
  584. CObject* pObjectToFind = NULL;
  585. HRESULT hr = m_pClass->FindObject(&m_ObjectDesc, &pObjectToFind, this);
  586. if (SUCCEEDED(hr) && pObjectToFind)
  587. {
  588. m_pClass->GC_Replace(this, NULL);
  589. }
  590. else
  591. {
  592. CObject *pObjectUnloaded = new CObject(m_pClass, &m_ObjectDesc);
  593. if (!pObjectUnloaded)
  594. {
  595. return E_OUTOFMEMORY;
  596. }
  597. m_pClass->GC_Replace(this, pObjectUnloaded);
  598. }
  599. return S_OK;
  600. }
  601. HRESULT CObject::Load()
  602. {
  603. // See if we have one of the fields we need to load
  604. if (!(m_ObjectDesc.m_dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_MEMORY | DMUS_OBJ_STREAM)))
  605. {
  606. Trace(1, "Error: GetObject failed because the requested object was not already cached and the supplied desciptor did not specify a source to load the object from (DMUS_OBJ_FILENAME, DMUS_OBJ_MEMORY, or DMUS_OBJ_STREAM).");
  607. return DMUS_E_LOADER_NOFILENAME;
  608. }
  609. // Create the object
  610. SmartRef::ComPtr<IDirectMusicObject> scomIObject = NULL;
  611. HRESULT hr = CoCreateInstance(m_ObjectDesc.m_guidClass, NULL, CLSCTX_INPROC_SERVER, IID_IDirectMusicObject, reinterpret_cast<void**>(&scomIObject));
  612. if (FAILED(hr))
  613. return hr;
  614. // Create the stream the object will load from
  615. SmartRef::ComPtr<IStream> scomIStream;
  616. if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_FILENAME)
  617. {
  618. WCHAR wzFullPath[DMUS_MAX_FILENAME];
  619. ZeroMemory( wzFullPath, sizeof(WCHAR) * DMUS_MAX_FILENAME );
  620. CFileStream *pStream = new CFileStream ( m_pClass->m_pLoader );
  621. if (!pStream)
  622. return E_OUTOFMEMORY;
  623. scomIStream = pStream;
  624. if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_FULLPATH)
  625. {
  626. wcsncpy(wzFullPath, m_ObjectDesc.m_pwzFileName, DMUS_MAX_FILENAME);
  627. }
  628. else
  629. {
  630. m_pClass->GetPath(wzFullPath);
  631. wcsncat(wzFullPath,m_ObjectDesc.m_pwzFileName, DMUS_MAX_FILENAME - wcslen(wzFullPath) - 1);
  632. }
  633. hr = pStream->Open(wzFullPath,GENERIC_READ);
  634. if (FAILED(hr))
  635. return hr;
  636. }
  637. else if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_MEMORY)
  638. {
  639. CMemStream *pStream = new CMemStream ( m_pClass->m_pLoader );
  640. if (!pStream)
  641. return E_OUTOFMEMORY;
  642. scomIStream = pStream;
  643. hr = pStream->Open(m_ObjectDesc.m_pbMemData, m_ObjectDesc.m_llMemLength);
  644. if (FAILED(hr))
  645. return hr;
  646. }
  647. else if (m_ObjectDesc.m_dwValidData & DMUS_OBJ_STREAM)
  648. {
  649. CStream *pStream = new CStream ( m_pClass->m_pLoader );
  650. if (!pStream)
  651. return E_OUTOFMEMORY;
  652. scomIStream = pStream;
  653. hr = pStream->Open(m_ObjectDesc.m_pIStream, m_ObjectDesc.m_liStartPosition);
  654. if (FAILED(hr))
  655. return hr;
  656. }
  657. // Load the object
  658. IPersistStream* pIPS = NULL;
  659. hr = scomIObject->QueryInterface( IID_IPersistStream, (void**)&pIPS );
  660. if (FAILED(hr))
  661. return hr;
  662. // Save the new object. Needs to be done before loading because of circular references. While this object
  663. // loads it could get other objects and those other objects could need to get this object.
  664. SafeRelease(m_pIDMObject);
  665. m_pIDMObject = scomIObject.disown();
  666. hr = pIPS->Load( scomIStream );
  667. pIPS->Release();
  668. if (FAILED(hr))
  669. {
  670. // Clear the object we set above.
  671. SafeRelease(m_pIDMObject);
  672. return hr;
  673. }
  674. // Merge in descriptor information from the object
  675. CDescriptor Desc;
  676. DMUS_OBJECTDESC DESC;
  677. memset((void *)&DESC,0,sizeof(DESC));
  678. DESC.dwSize = sizeof (DMUS_OBJECTDESC);
  679. m_pIDMObject->GetDescriptor(&DESC);
  680. Desc.Set(&DESC);
  681. m_ObjectDesc.Merge(&Desc);
  682. m_ObjectDesc.m_dwValidData |= DMUS_OBJ_LOADED;
  683. m_ObjectDesc.Get(&DESC);
  684. m_pIDMObject->SetDescriptor(&DESC);
  685. return hr;
  686. }
  687. // Collect everything that is unmarked.
  688. void CObjectList::GC_Sweep(BOOL bOnlyScripts)
  689. {
  690. // sweep through looking for unmarked GC objects
  691. CObject *pObjectPrev = NULL;
  692. CObject *pObjectNext = NULL;
  693. for (CObject *pObject = this->GetHead(); pObject; pObject = pObjectNext)
  694. {
  695. // get the next item now since we could be messing with the list
  696. pObjectNext = pObject->GetNext();
  697. bool fRemoved = false;
  698. if(bOnlyScripts && pObject->m_ObjectDesc.m_guidClass != CLSID_DirectMusicScript)
  699. {
  700. pObjectPrev = pObject;
  701. continue;
  702. }
  703. if (pObject->m_dwScanBits & SCAN_GC)
  704. {
  705. if (!(pObject->m_dwScanBits & SCAN_GC_MARK))
  706. {
  707. // the object is unused
  708. // Zombie it to break any cyclic references
  709. IDirectMusicObject *pIDMO = pObject->m_pIDMObject;
  710. if (pIDMO)
  711. {
  712. IDirectMusicObjectP *pIDMO8 = NULL;
  713. HRESULT hr = pIDMO->QueryInterface(IID_IDirectMusicObjectP, reinterpret_cast<void**>(&pIDMO8));
  714. if (SUCCEEDED(hr))
  715. {
  716. pIDMO8->Zombie();
  717. pIDMO8->Release();
  718. }
  719. #ifdef DBG
  720. DebugTrace(4, SUCCEEDED(hr) ? " *%08X Zombied\n" : " *%08X no IDirectMusicObjectP interface\n", pObject);
  721. #endif
  722. }
  723. // remove it from the list
  724. if (pObjectPrev)
  725. pObjectPrev->Remove(pObject);
  726. else
  727. this->RemoveHead();
  728. delete pObject;
  729. fRemoved = true;
  730. }
  731. else
  732. {
  733. // clear mark for next time
  734. pObject->m_dwScanBits &= ~SCAN_GC_MARK;
  735. }
  736. }
  737. if (!fRemoved)
  738. pObjectPrev = pObject;
  739. }
  740. }
  741. CClass::CClass(CLoader *pLoader)
  742. {
  743. assert(pLoader);
  744. m_fDirSearched = FALSE;
  745. m_pLoader = pLoader;
  746. m_fKeepObjects = pLoader->m_fKeepObjects;
  747. m_dwLastIndex = NULL;
  748. m_pLastObject = NULL;
  749. }
  750. CClass::CClass(CLoader *pLoader, CDescriptor *pDesc)
  751. {
  752. assert(pLoader);
  753. assert(pDesc);
  754. m_fDirSearched = FALSE;
  755. m_pLoader = pLoader;
  756. m_fKeepObjects = pLoader->m_fKeepObjects;
  757. m_dwLastIndex = NULL;
  758. m_pLastObject = NULL;
  759. // Set up this class's descritor with just the class id.
  760. m_ClassDesc.m_guidClass = pDesc->m_guidClass;
  761. m_ClassDesc.m_dwValidData = DMUS_OBJ_CLASS;
  762. }
  763. CClass::~CClass()
  764. {
  765. ClearObjects(FALSE,NULL);
  766. }
  767. void CClass::ClearObjects(BOOL fKeepCache, WCHAR *pwzExtension)
  768. // Clear objects from the class list, optionally keep
  769. // cached objects or objects that are not of the requested extension.
  770. {
  771. m_fDirSearched = FALSE;
  772. CObjectList KeepList; // Use to store objects to keep.
  773. while (!m_ObjectList.IsEmpty())
  774. {
  775. CObject *pObject = m_ObjectList.RemoveHead();
  776. DMUS_OBJECTDESC DESC;
  777. pObject->m_ObjectDesc.Get(&DESC);
  778. // If the keepCache flag is set, we want to hang on to the object
  779. // if it is GM.dls, an object that's currently cached, or
  780. // an object with a different extension from what we are looking for.
  781. if (fKeepCache &&
  782. ((DESC.guidObject == GUID_DefaultGMCollection)
  783. #ifdef DRAGON
  784. || (DESC.guidObject == GUID_DefaultGMDrums)
  785. #endif
  786. || pObject->m_pIDMObject
  787. || !pObject->m_ObjectDesc.IsExtension(pwzExtension)))
  788. {
  789. KeepList.AddHead(pObject);
  790. }
  791. else
  792. {
  793. delete pObject;
  794. }
  795. }
  796. // Now put cached objects back in list.
  797. while (!KeepList.IsEmpty())
  798. {
  799. CObject *pObject = KeepList.RemoveHead();
  800. m_ObjectList.AddHead(pObject);
  801. }
  802. m_pLastObject = NULL;
  803. }
  804. HRESULT CClass::FindObject(CDescriptor *pDesc,CObject ** ppObject, CObject *pNotThis)
  805. {
  806. if(pDesc == NULL)
  807. {
  808. return E_POINTER;
  809. }
  810. DWORD dwSearchBy = pDesc->m_dwValidData;
  811. CObject *pObject = NULL;
  812. if (dwSearchBy & DMUS_OBJ_OBJECT)
  813. {
  814. pObject = m_ObjectList.GetHead();
  815. for (;pObject != NULL; pObject = pObject->GetNext())
  816. {
  817. if (pObject == pNotThis) continue;
  818. if (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_OBJECT)
  819. {
  820. if (pObject->m_ObjectDesc.m_guidObject == pDesc->m_guidObject)
  821. {
  822. *ppObject = pObject;
  823. return S_OK;
  824. }
  825. }
  826. }
  827. }
  828. if (dwSearchBy & DMUS_OBJ_MEMORY)
  829. {
  830. pObject = m_ObjectList.GetHead();
  831. for (;pObject != NULL; pObject = pObject->GetNext())
  832. {
  833. if (pObject == pNotThis) continue;
  834. if (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_MEMORY)
  835. {
  836. if (pObject->m_ObjectDesc.m_pbMemData == pDesc->m_pbMemData)
  837. {
  838. *ppObject = pObject;
  839. return S_OK;
  840. }
  841. }
  842. }
  843. }
  844. if (dwSearchBy & DMUS_OBJ_STREAM)
  845. {
  846. pObject = m_ObjectList.GetHead();
  847. for (;pObject != NULL; pObject = pObject->GetNext())
  848. {
  849. if (pObject == pNotThis) continue;
  850. if (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_STREAM)
  851. {
  852. if (pObject->m_ObjectDesc.m_pIStream == pDesc->m_pIStream)
  853. {
  854. *ppObject = pObject;
  855. return S_OK;
  856. }
  857. }
  858. }
  859. }
  860. if ((dwSearchBy & DMUS_OBJ_FILENAME) && (dwSearchBy & DMUS_OBJ_FULLPATH))
  861. {
  862. pObject = m_ObjectList.GetHead();
  863. for (;pObject != NULL; pObject = pObject->GetNext())
  864. {
  865. if (pObject == pNotThis) continue;
  866. if ((pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_FILENAME) &&
  867. (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_FULLPATH))
  868. {
  869. if (!_wcsicmp(pObject->m_ObjectDesc.m_pwzFileName, pDesc->m_pwzFileName))
  870. {
  871. *ppObject = pObject;
  872. return S_OK;
  873. }
  874. }
  875. }
  876. }
  877. if ((dwSearchBy & DMUS_OBJ_NAME) && (dwSearchBy & DMUS_OBJ_CATEGORY))
  878. {
  879. pObject = m_ObjectList.GetHead();
  880. for (;pObject != NULL; pObject = pObject->GetNext())
  881. {
  882. if (pObject == pNotThis) continue;
  883. if ((pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_NAME) &&
  884. (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_CATEGORY))
  885. {
  886. if (!_wcsicmp(pObject->m_ObjectDesc.m_pwzCategory,pDesc->m_pwzCategory))
  887. {
  888. if (!_wcsicmp(pObject->m_ObjectDesc.m_pwzName, pDesc->m_pwzName))
  889. {
  890. *ppObject = pObject;
  891. return S_OK;
  892. }
  893. }
  894. }
  895. }
  896. }
  897. if (dwSearchBy & DMUS_OBJ_NAME)
  898. {
  899. pObject = m_ObjectList.GetHead();
  900. for (;pObject != NULL; pObject = pObject->GetNext())
  901. {
  902. if (pObject == pNotThis) continue;
  903. if (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_NAME)
  904. {
  905. if (!_wcsicmp(pObject->m_ObjectDesc.m_pwzName, pDesc->m_pwzName))
  906. {
  907. *ppObject = pObject;
  908. return S_OK;
  909. }
  910. }
  911. }
  912. }
  913. if (dwSearchBy & DMUS_OBJ_FILENAME)
  914. {
  915. pObject = m_ObjectList.GetHead();
  916. for (;pObject != NULL; pObject = pObject->GetNext())
  917. {
  918. if (pObject == pNotThis) continue;
  919. if (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_FILENAME)
  920. {
  921. if ((dwSearchBy & DMUS_OBJ_FULLPATH) == (pObject->m_ObjectDesc.m_dwValidData & DMUS_OBJ_FULLPATH))
  922. {
  923. if (!_wcsicmp(pObject->m_ObjectDesc.m_pwzFileName, pDesc->m_pwzFileName))
  924. {
  925. *ppObject = pObject;
  926. return S_OK;
  927. }
  928. }
  929. else
  930. {
  931. WCHAR *pC1 = pObject->m_ObjectDesc.m_pwzFileName;
  932. WCHAR *pC2 = pDesc->m_pwzFileName;
  933. if (dwSearchBy & DMUS_OBJ_FULLPATH)
  934. {
  935. pC1 = wcsrchr(pObject->m_ObjectDesc.m_pwzFileName, L'\\');
  936. }
  937. else
  938. {
  939. pC2 = wcsrchr(pDesc->m_pwzFileName, '\\');
  940. }
  941. if (pC1 && pC2)
  942. {
  943. if (!_wcsicmp(pC1,pC2))
  944. {
  945. *ppObject = pObject;
  946. return S_OK;
  947. }
  948. }
  949. }
  950. }
  951. }
  952. }
  953. *ppObject = NULL;
  954. return DMUS_E_LOADER_OBJECTNOTFOUND;
  955. }
  956. HRESULT CClass::EnumerateObjects(DWORD dwIndex,CDescriptor *pDesc)
  957. {
  958. if(pDesc == NULL)
  959. {
  960. return E_POINTER;
  961. }
  962. if (m_fDirSearched == FALSE)
  963. {
  964. // SearchDirectory();
  965. }
  966. if ((dwIndex < m_dwLastIndex) || (m_pLastObject == NULL))
  967. {
  968. m_dwLastIndex = 0;
  969. m_pLastObject = m_ObjectList.GetHead();
  970. }
  971. while (m_dwLastIndex < dwIndex)
  972. {
  973. if (!m_pLastObject) break;
  974. m_dwLastIndex++;
  975. m_pLastObject = m_pLastObject->GetNext();
  976. }
  977. if (m_pLastObject)
  978. {
  979. pDesc->Copy(&m_pLastObject->m_ObjectDesc);
  980. return S_OK;
  981. }
  982. return S_FALSE;
  983. }
  984. HRESULT CClass::GetPath(WCHAR* pwzPath)
  985. {
  986. if(pwzPath == NULL)
  987. {
  988. return E_POINTER;
  989. }
  990. if (m_ClassDesc.m_dwValidData & DMUS_OBJ_FILENAME)
  991. {
  992. wcsncpy(pwzPath, m_ClassDesc.m_pwzFileName, DMUS_MAX_FILENAME);
  993. return S_OK;
  994. }
  995. else
  996. {
  997. return m_pLoader->GetPath(pwzPath);
  998. }
  999. }
  1000. // returns S_FALSE if the search directory is already set to this.
  1001. HRESULT CClass::SetSearchDirectory(WCHAR * pwzPath,BOOL fClear)
  1002. {
  1003. if(pwzPath == NULL)
  1004. {
  1005. return E_POINTER;
  1006. }
  1007. HRESULT hr;
  1008. hr = m_ClassDesc.SetFileName(pwzPath);
  1009. if (SUCCEEDED(hr))
  1010. {
  1011. m_ClassDesc.m_dwValidData |= DMUS_OBJ_FULLPATH;
  1012. }
  1013. if (fClear)
  1014. {
  1015. CObjectList KeepList; // Use to store objects to keep.
  1016. while (!m_ObjectList.IsEmpty())
  1017. {
  1018. CObject *pObject = m_ObjectList.RemoveHead();
  1019. if (pObject->m_pIDMObject)
  1020. {
  1021. KeepList.AddHead(pObject);
  1022. }
  1023. else
  1024. {
  1025. // check for the special case of the default gm collection.
  1026. // don't clear that one out.
  1027. DMUS_OBJECTDESC DESC;
  1028. pObject->m_ObjectDesc.Get(&DESC);
  1029. if( DESC.guidObject == GUID_DefaultGMCollection )
  1030. {
  1031. KeepList.AddHead(pObject);
  1032. }
  1033. else
  1034. {
  1035. delete pObject;
  1036. }
  1037. }
  1038. }
  1039. // Now put cached objects back in list.
  1040. while (!KeepList.IsEmpty())
  1041. {
  1042. CObject *pObject = KeepList.RemoveHead();
  1043. m_ObjectList.AddHead(pObject);
  1044. }
  1045. m_pLastObject = NULL;
  1046. }
  1047. return hr;
  1048. }
  1049. HRESULT CClass::GetObject(CDescriptor *pDesc, CObject ** ppObject)
  1050. {
  1051. if(pDesc == NULL)
  1052. {
  1053. return E_POINTER;
  1054. }
  1055. HRESULT hr = FindObject(pDesc,ppObject);
  1056. if (SUCCEEDED(hr)) // Okay, found object in list.
  1057. {
  1058. return hr;
  1059. }
  1060. *ppObject = new CObject (this, pDesc);
  1061. if (*ppObject)
  1062. {
  1063. m_ObjectList.AddHead(*ppObject);
  1064. return S_OK;
  1065. }
  1066. return E_OUTOFMEMORY;
  1067. }
  1068. void CClass::RemoveObject(CObject* pRemoveObject)
  1069. // Remove an object from the class list
  1070. {
  1071. CObjectList KeepList; // Use to store objects to keep.
  1072. while (!m_ObjectList.IsEmpty())
  1073. {
  1074. CObject *pObject = m_ObjectList.RemoveHead();
  1075. if( pObject == pRemoveObject )
  1076. {
  1077. delete pObject;
  1078. // we can assume no duplicates, and we should avoid comparing the deleted
  1079. // object to the remainder of the list
  1080. break;
  1081. }
  1082. else
  1083. {
  1084. KeepList.AddHead(pObject);
  1085. }
  1086. }
  1087. // Now put cached objects back in list.
  1088. while (!KeepList.IsEmpty())
  1089. {
  1090. CObject *pObject = KeepList.RemoveHead();
  1091. m_ObjectList.AddHead(pObject);
  1092. }
  1093. m_pLastObject = NULL;
  1094. }
  1095. HRESULT CClass::ClearCache(bool fClearStreams)
  1096. {
  1097. CObject *pObject = m_ObjectList.GetHead();
  1098. CObject *pObjectPrev = NULL; // remember the previous object -- needed to quickly remove the current object from the list
  1099. CObject *pObjectNext = NULL; // remember the next object -- needed because the current object may be removed from the list
  1100. for (;pObject;pObject = pObjectNext)
  1101. {
  1102. if (fClearStreams)
  1103. pObject->m_ObjectDesc.ClearIStream();
  1104. pObjectNext = pObject->GetNext();
  1105. if (pObject->m_pIDMObject)
  1106. {
  1107. if (pObject->m_dwScanBits & SCAN_GC)
  1108. {
  1109. // Other objects may have references to this one so we need to keep this object around
  1110. // and track its references. We'll hold onto the DMObject pointer too because we may
  1111. // later need to Zombie the object in order to break a cyclic reference.
  1112. // We'll place an unloaded object with a duplicate descriptor in the cache to match the
  1113. // non-GC behavior and then move the original object into a list of released objects that
  1114. // will eventually be reclaimed by CollectGarbage.
  1115. CObject *pObjectUnloaded = new CObject(this, &pObject->m_ObjectDesc);
  1116. if (!pObjectUnloaded)
  1117. {
  1118. return E_OUTOFMEMORY;
  1119. }
  1120. if (!pObjectPrev)
  1121. m_ObjectList.Remove(pObject);
  1122. else
  1123. pObjectPrev->Remove(pObject);
  1124. m_ObjectList.AddHead(pObjectUnloaded);
  1125. m_pLoader->GC_UpdateForReleasedObject(pObject);
  1126. }
  1127. else
  1128. {
  1129. pObject->m_pIDMObject->Release();
  1130. pObject->m_pIDMObject = NULL;
  1131. pObject->m_ObjectDesc.m_dwValidData &= ~DMUS_OBJ_LOADED;
  1132. pObjectPrev = pObject;
  1133. }
  1134. }
  1135. }
  1136. return S_OK;
  1137. }
  1138. // return S_FALSE if the cache is already enabled according to fEnable,
  1139. // indicating it's already been done.
  1140. HRESULT CClass::EnableCache(BOOL fEnable)
  1141. {
  1142. HRESULT hr = S_FALSE;
  1143. if (!fEnable)
  1144. {
  1145. ClearCache(false);
  1146. }
  1147. if( m_fKeepObjects != fEnable )
  1148. {
  1149. hr = S_OK;
  1150. m_fKeepObjects = fEnable;
  1151. }
  1152. return hr;
  1153. }
  1154. typedef struct ioClass
  1155. {
  1156. GUID guidClass;
  1157. } ioClass;
  1158. HRESULT CClass::SaveToCache(IRIFFStream *pRiff)
  1159. {
  1160. if(pRiff == NULL)
  1161. {
  1162. return E_POINTER;
  1163. }
  1164. HRESULT hr = S_OK;
  1165. IStream* pIStream = NULL;
  1166. MMCKINFO ck;
  1167. WORD wStructSize = 0;
  1168. DWORD dwBytesWritten = 0;
  1169. // DWORD dwBufferSize;
  1170. ioClass oClass;
  1171. ZeroMemory(&ck, sizeof(MMCKINFO));
  1172. pIStream = pRiff->GetStream();
  1173. if( pIStream == NULL )
  1174. {
  1175. // I don't think anybody should actually be calling this function
  1176. // if they don't have a stream. Currently, this is only called by
  1177. // SaveToCache file. It definitely has a stream when it calls
  1178. // AllocRIFFStream and the stream should still be there when
  1179. // we arrive here.
  1180. assert(false);
  1181. return DMUS_E_LOADER_NOFILENAME;
  1182. }
  1183. // Write class chunk header
  1184. ck.ckid = FOURCC_CLASSHEADER;
  1185. if( pRiff->CreateChunk( &ck, 0 ) == S_OK )
  1186. {
  1187. wStructSize = sizeof(ioClass);
  1188. hr = pIStream->Write( &wStructSize, sizeof(wStructSize), &dwBytesWritten );
  1189. if( FAILED( hr ) || dwBytesWritten != sizeof(wStructSize) )
  1190. {
  1191. pIStream->Release();
  1192. return DMUS_E_CANNOTWRITE;
  1193. }
  1194. // Prepare ioClass structure
  1195. // memset( &oClass, 0, sizeof(ioClass) );
  1196. memcpy( &oClass.guidClass, &m_ClassDesc.m_guidClass, sizeof(GUID) );
  1197. // Write Class header data
  1198. hr = pIStream->Write( &oClass, sizeof(oClass), &dwBytesWritten);
  1199. if( FAILED( hr ) || dwBytesWritten != sizeof(oClass) )
  1200. {
  1201. hr = DMUS_E_CANNOTWRITE;
  1202. }
  1203. else
  1204. {
  1205. if( pRiff->Ascend( &ck, 0 ) != S_OK )
  1206. {
  1207. hr = DMUS_E_CANNOTSEEK;
  1208. }
  1209. }
  1210. }
  1211. else
  1212. {
  1213. hr = DMUS_E_CANNOTSEEK;
  1214. }
  1215. pIStream->Release();
  1216. return hr;
  1217. }
  1218. void CClass::PreScan()
  1219. /* Prior to scanning a directory, mark all currently loaded objects
  1220. so they won't be confused with objects loaded in the scan or
  1221. referenced by the cache file.
  1222. */
  1223. {
  1224. CObject *pObject = m_ObjectList.GetHead();
  1225. for (;pObject != NULL; pObject = pObject->GetNext())
  1226. {
  1227. // clear the lower fields and set SCAN_PRIOR
  1228. pObject->m_dwScanBits &= ~(SCAN_CACHE | SCAN_PARSED | SCAN_SEARCH);
  1229. pObject->m_dwScanBits |= SCAN_PRIOR;
  1230. }
  1231. }
  1232. // Helper method used to implement RemoveAndDuplicateInParentList.
  1233. void CClass::GC_Replace(CObject *pObject, CObject *pObjectReplacement)
  1234. {
  1235. m_ObjectList.Remove(pObject);
  1236. if (pObjectReplacement)
  1237. {
  1238. m_ObjectList.AddHead(pObjectReplacement);
  1239. }
  1240. }
  1241. HRESULT CClass::SearchDirectory(WCHAR *pwzExtension)
  1242. {
  1243. HRESULT hr;
  1244. IDirectMusicObject *pIObject;
  1245. hr = CoCreateInstance(m_ClassDesc.m_guidClass,
  1246. NULL,CLSCTX_INPROC_SERVER,IID_IDirectMusicObject,
  1247. (void **) &pIObject);
  1248. if (SUCCEEDED(hr))
  1249. {
  1250. CFileStream *pStream = new CFileStream ( m_pLoader );
  1251. if (pStream)
  1252. {
  1253. // We need the double the MAX_PATH size since we'll be catenating strings of MAX_PATH
  1254. const int nBufferSize = 2 * MAX_PATH;
  1255. WCHAR wzPath[nBufferSize];
  1256. memset(wzPath, 0, sizeof(WCHAR) * nBufferSize);
  1257. hr = GetPath(wzPath);
  1258. if (SUCCEEDED(hr))
  1259. {
  1260. hr = S_FALSE;
  1261. CObjectList TempList;
  1262. #ifndef UNDER_CE
  1263. char szPath[nBufferSize];
  1264. WIN32_FIND_DATAA fileinfoA;
  1265. #endif
  1266. WIN32_FIND_DATAW fileinfoW;
  1267. HANDLE hFindFile;
  1268. CObject * pObject;
  1269. // GetPath copies at most MAX_PATH number of chars to wzPath
  1270. // This means that we have enough space to do a cat safely
  1271. WCHAR wszWildCard[3] = L"*.";
  1272. wcsncat(wzPath, wszWildCard, wcslen(wszWildCard));
  1273. if (pwzExtension)
  1274. {
  1275. // Make sure there's enough space left in wzPath to cat pwzExtension
  1276. size_t cPathLen = wcslen(wzPath);
  1277. size_t cExtLen = wcslen(pwzExtension);
  1278. // Do we have enough space to write the extension + the NULL char?
  1279. if((nBufferSize - cPathLen - 1) > cExtLen)
  1280. {
  1281. wcsncat(wzPath, pwzExtension, nBufferSize - wcslen(pwzExtension) - 1);
  1282. }
  1283. }
  1284. #ifndef UNDER_CE
  1285. if (g_fIsUnicode)
  1286. #endif
  1287. {
  1288. hFindFile = FindFirstFileW( wzPath, &fileinfoW );
  1289. }
  1290. #ifndef UNDER_CE
  1291. else
  1292. {
  1293. wcstombs( szPath, wzPath, nBufferSize );
  1294. hFindFile = FindFirstFileA( szPath, &fileinfoA );
  1295. }
  1296. #endif
  1297. if( hFindFile == INVALID_HANDLE_VALUE )
  1298. {
  1299. pStream->Release();
  1300. pIObject->Release();
  1301. return S_FALSE;
  1302. }
  1303. ClearObjects(TRUE, pwzExtension); // Clear everything but the objects currently loaded.
  1304. for (;;)
  1305. {
  1306. BOOL fGoParse = FALSE;
  1307. CDescriptor Desc;
  1308. GetPath(wzPath);
  1309. #ifndef UNDER_CE
  1310. if (g_fIsUnicode)
  1311. #endif
  1312. {
  1313. Desc.m_ftDate = fileinfoW.ftLastWriteTime;
  1314. wcsncat(wzPath, fileinfoW.cFileName, DMUS_MAX_FILENAME);
  1315. }
  1316. #ifndef UNDER_CE
  1317. else
  1318. {
  1319. Desc.m_ftDate = fileinfoA.ftLastWriteTime;
  1320. WCHAR wzFileName[MAX_PATH];
  1321. mbstowcs( wzFileName, fileinfoA.cFileName, MAX_PATH );
  1322. wcsncat(wzPath, wzFileName, DMUS_MAX_FILENAME);
  1323. }
  1324. #endif
  1325. HRESULT hrTemp = Desc.SetFileName(wzPath);
  1326. if (SUCCEEDED(hrTemp))
  1327. {
  1328. Desc.m_dwValidData = (DMUS_OBJ_DATE | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH);
  1329. }
  1330. else
  1331. {
  1332. // If we couldn't set the file name, we probably don't want to continue
  1333. hr = hrTemp;
  1334. break;
  1335. }
  1336. if (SUCCEEDED(FindObject(&Desc,&pObject))) // Make sure we don't already have it.
  1337. {
  1338. #ifndef UNDER_CE
  1339. if (g_fIsUnicode)
  1340. #endif
  1341. {
  1342. fGoParse = (fileinfoW.nFileSizeLow != pObject->m_ObjectDesc.m_dwFileSize);
  1343. if (!fGoParse)
  1344. {
  1345. fGoParse = !memcmp(&fileinfoW.ftLastWriteTime,&pObject->m_ObjectDesc.m_ftDate,sizeof(FILETIME));
  1346. }
  1347. }
  1348. #ifndef UNDER_CE
  1349. else
  1350. {
  1351. fGoParse = (fileinfoA.nFileSizeLow != pObject->m_ObjectDesc.m_dwFileSize);
  1352. if (!fGoParse)
  1353. {
  1354. fGoParse = !memcmp(&fileinfoA.ftLastWriteTime,&pObject->m_ObjectDesc.m_ftDate,sizeof(FILETIME));
  1355. }
  1356. }
  1357. #endif
  1358. // Yet, disregard if it is already loaded.
  1359. if (pObject->m_pIDMObject) fGoParse = FALSE;
  1360. }
  1361. else fGoParse = TRUE;
  1362. if (fGoParse)
  1363. {
  1364. hrTemp = pStream->Open(Desc.m_pwzFileName,GENERIC_READ);
  1365. if (SUCCEEDED(hrTemp))
  1366. {
  1367. DMUS_OBJECTDESC DESC;
  1368. memset((void *)&DESC,0,sizeof(DESC));
  1369. DESC.dwSize = sizeof (DMUS_OBJECTDESC);
  1370. hrTemp = pIObject->ParseDescriptor(pStream,&DESC);
  1371. if (SUCCEEDED(hrTemp))
  1372. {
  1373. hr = S_OK;
  1374. CDescriptor ParseDesc;
  1375. ParseDesc.Set(&DESC);
  1376. Desc.Merge(&ParseDesc);
  1377. #ifndef UNDER_CE
  1378. if (g_fIsUnicode)
  1379. #endif
  1380. {
  1381. Desc.m_dwFileSize = fileinfoW.nFileSizeLow;
  1382. Desc.m_ftDate = fileinfoW.ftLastWriteTime;
  1383. }
  1384. #ifndef UNDER_CE
  1385. else
  1386. {
  1387. Desc.m_dwFileSize = fileinfoA.nFileSizeLow;
  1388. Desc.m_ftDate = fileinfoA.ftLastWriteTime;
  1389. }
  1390. #endif
  1391. if (pObject)
  1392. {
  1393. pObject->m_ObjectDesc.Copy(&Desc);
  1394. pObject->m_dwScanBits |= SCAN_PARSED | SCAN_SEARCH;
  1395. }
  1396. else
  1397. {
  1398. pObject = new CObject(this, &Desc);
  1399. if (pObject)
  1400. {
  1401. TempList.AddHead(pObject);
  1402. pObject->m_dwScanBits |= SCAN_PARSED | SCAN_SEARCH;
  1403. }
  1404. }
  1405. }
  1406. pStream->Close();
  1407. }
  1408. }
  1409. #ifndef UNDER_CE
  1410. if (g_fIsUnicode)
  1411. #endif
  1412. {
  1413. if ( !FindNextFileW( hFindFile, &fileinfoW ) ) break;
  1414. }
  1415. #ifndef UNDER_CE
  1416. else
  1417. {
  1418. if ( !FindNextFileA( hFindFile, &fileinfoA ) ) break;
  1419. }
  1420. #endif
  1421. }
  1422. FindClose(hFindFile );
  1423. while (!TempList.IsEmpty())
  1424. {
  1425. pObject = TempList.RemoveHead();
  1426. m_ObjectList.AddHead(pObject);
  1427. }
  1428. m_fDirSearched = TRUE;
  1429. }
  1430. pStream->Release();
  1431. }
  1432. pIObject->Release();
  1433. }
  1434. return hr;
  1435. }