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.

1020 lines
28 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  4. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  5. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  6. // PARTICULAR PURPOSE.
  7. //
  8. // Copyright 1998 - 1999 Microsoft Corporation. All Rights Reserved.
  9. //
  10. // PROGRAM: htmlprop.cxx
  11. //
  12. // PURPOSE: Sits on the Indexing Service HTML filter to translate string
  13. // meta properties into specified data types.
  14. //
  15. // PLATFORM: Windows 2000
  16. //
  17. //--------------------------------------------------------------------------
  18. #define UNICODE
  19. #include <stdio.h>
  20. #include <wchar.h>
  21. #include <windows.h>
  22. #include <oledb.h>
  23. #include <cmdtree.h>
  24. #include <filterr.h>
  25. #include <filter.h>
  26. #include "htmlprop.hxx"
  27. #include "filtreg.hxx"
  28. // The typid of the html filter
  29. CLSID TYPID_HtmlPropIFilter =
  30. {
  31. 0xc8e2ab80, 0xa1db, 0x11d1,
  32. { 0xa8, 0xfb, 0x00, 0xe0, 0x98, 0x00, 0x6e, 0xd3 }
  33. };
  34. // The CLSID for the html property filter
  35. CLSID CLSID_HtmlPropIFilter =
  36. {
  37. 0xf4309e80, 0xa1db, 0x11d1,
  38. { 0xa8, 0xfb, 0x00, 0xe0, 0x98, 0x00, 0x6e, 0xd3 }
  39. };
  40. // Class of the html property filter
  41. CLSID CLSID_HtmlPropClass =
  42. {
  43. 0x4cbd1020, 0xa1db, 0x11d1,
  44. { 0xa8, 0xfb, 0x00, 0xe0, 0x98, 0x00, 0x6e, 0xd3 }
  45. };
  46. // The built-in html filter
  47. CLSID CLSID_HtmlIFilter =
  48. {
  49. 0xe0ca5340, 0x4534, 0x11cf,
  50. { 0xb9, 0x52, 0x00, 0xaa, 0x00, 0x51, 0xfe, 0x20 }
  51. };
  52. // The guid for html meta properties
  53. CLSID CLSID_MetaProperty =
  54. {
  55. 0xd1b5d3f0, 0xc0b3, 0x11cf,
  56. { 0x9a, 0x92, 0x00, 0xa0, 0xc9, 0x08, 0xdb, 0xf1 }
  57. };
  58. // The guid for html meta properties in string form
  59. const WCHAR * pwcMetaProperty = L"d1b5d3f0-c0b3-11cf-9a92-00a0c908dbf1";
  60. struct SPropertyEntry
  61. {
  62. WCHAR awcName[cwcMaxName]; // name of the meta property
  63. DBTYPE dbType; // data type of property
  64. };
  65. const SPropertyEntry aTypeEntries[] =
  66. {
  67. { L"DBTYPE_I1", DBTYPE_I1 }, // 0: signed char
  68. { L"DBTYPE_UI1", DBTYPE_UI1 }, // 1: unsigned char
  69. { L"DBTYPE_I2", DBTYPE_I2 }, // 2: 2 byte signed int
  70. { L"DBTYPE_UI2", DBTYPE_UI2 }, // 3: 2 byte unsigned int
  71. { L"DBTYPE_I4", DBTYPE_I4 }, // 4: 4 byte signed int
  72. { L"DBTYPE_UI4", DBTYPE_UI4 }, // 5: 4 byte unsigned int
  73. { L"DBTYPE_I8", DBTYPE_I8 }, // 6: 8 byte signed int
  74. { L"DBTYPE_UI8", DBTYPE_UI8 }, // 7: 8 byte unsigned int
  75. { L"DBTYPE_R4", DBTYPE_R4 }, // 8: 4 byte float
  76. { L"DBTYPE_R8", DBTYPE_R8 }, // 9: 8 byte float
  77. { L"DBTYPE_BOOL", DBTYPE_BOOL }, // 12: BOOL (true=-1, false=0)
  78. { L"DBTYPE_WSTR", DBTYPE_WSTR }, // 14: wide null terminated string
  79. { L"VT_FILETIME", VT_FILETIME } // 19: I8 filetime
  80. };
  81. const ULONG cTypeEntries = sizeof aTypeEntries / sizeof aTypeEntries[0];
  82. const WCHAR * pwcHTMLPropertyFile = L"htmlprop.ini";
  83. const ULONG maxEntries = 500;
  84. SPropertyEntry g_aEntries[ maxEntries ];
  85. ULONG g_cEntries = 0; // count of entries in g_aEntries
  86. long g_cInstances = 0;
  87. HMODULE g_hHtmlDll = 0; // module handle for nlhtml.dll
  88. // htmlfilt.dll for IS 1.x and nlhtml.dll for IS 2.x
  89. const WCHAR * pwcHTMLFilter = L"nlhtml.dll";
  90. //+-------------------------------------------------------------------------
  91. //
  92. // Method: HtmlPropIFilter::HtmlPropIFilter
  93. //
  94. // Synopsis: Constructor
  95. //
  96. //--------------------------------------------------------------------------
  97. HtmlPropIFilter::HtmlPropIFilter() :
  98. _pHtmlFilter( 0 ),
  99. _pPersistFile( 0 ),
  100. _lRefs( 1 )
  101. {
  102. InterlockedIncrement( &g_cInstances );
  103. } //HtmlPropIFilter
  104. //+-------------------------------------------------------------------------
  105. //
  106. // Method: HtmlPropIFilter::~HtmlPropIFilter
  107. //
  108. // Synopsis: Destructor
  109. //
  110. //--------------------------------------------------------------------------
  111. HtmlPropIFilter::~HtmlPropIFilter()
  112. {
  113. InterlockedDecrement( &g_cInstances );
  114. if ( _pHtmlFilter )
  115. _pHtmlFilter->Release();
  116. if ( _pPersistFile )
  117. _pPersistFile->Release();
  118. } //~HtmlPropIFilter
  119. //+-------------------------------------------------------------------------
  120. //
  121. // Method: HtmlPropIFilter::QueryInterface
  122. //
  123. // Synopsis: Rebind to other interface
  124. //
  125. // Arguments: [riid] -- IID of new interface
  126. // [ppvObject] -- New interface * returned here
  127. //
  128. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  129. //
  130. //--------------------------------------------------------------------------
  131. SCODE STDMETHODCALLTYPE HtmlPropIFilter::QueryInterface(
  132. REFIID riid,
  133. void ** ppvObject)
  134. {
  135. if ( IID_IFilter == riid )
  136. *ppvObject = (IFilter *)this;
  137. else if ( IID_IPersist == riid )
  138. *ppvObject = (IPersist *)(IPersistFile *)this;
  139. else if ( IID_IPersistFile == riid )
  140. *ppvObject = (IPersistFile *)this;
  141. else if ( IID_IUnknown == riid )
  142. *ppvObject = (IUnknown *)(IPersist *)(IPersistFile *)this;
  143. else
  144. {
  145. *ppvObject = 0;
  146. return E_NOINTERFACE;
  147. }
  148. AddRef();
  149. return S_OK;
  150. } //QueryInterface
  151. //+-------------------------------------------------------------------------
  152. //
  153. // Method: HtmlPropIFilter::AddRef
  154. //
  155. // Synopsis: Increments refcount
  156. //
  157. //--------------------------------------------------------------------------
  158. ULONG STDMETHODCALLTYPE HtmlPropIFilter::AddRef()
  159. {
  160. return InterlockedIncrement( &_lRefs );
  161. } //AddRef
  162. //+-------------------------------------------------------------------------
  163. //
  164. // Method: HtmlPropIFilter::Release
  165. //
  166. // Synopsis: Decrement refcount. Delete if necessary.
  167. //
  168. //--------------------------------------------------------------------------
  169. ULONG STDMETHODCALLTYPE HtmlPropIFilter::Release()
  170. {
  171. long lTmp = InterlockedDecrement( &_lRefs );
  172. if ( 0 == lTmp )
  173. delete this;
  174. return lTmp;
  175. } //Release
  176. //+-------------------------------------------------------------------------
  177. //
  178. // Member: HtmlPropIFilter::Init, public
  179. //
  180. // Synopsis: Initializes instance of property filter
  181. //
  182. // Arguments: [grfFlags] -- flags for filter behavior
  183. // [cAttributes] -- number of attributes in array aAttributes
  184. // [aAttributes] -- array of attributes
  185. // [pFlags] -- flags
  186. //
  187. //----------------------------------------------------------------------------
  188. SCODE STDMETHODCALLTYPE HtmlPropIFilter::Init(
  189. ULONG grfFlags,
  190. ULONG cAttributes,
  191. FULLPROPSPEC const * aAttributes,
  192. ULONG * pFlags )
  193. {
  194. return _pHtmlFilter->Init( grfFlags, cAttributes, aAttributes, pFlags );
  195. } //Init
  196. //+-------------------------------------------------------------------------
  197. //
  198. // Method: HtmlPropIFilter::GetChunk
  199. //
  200. // Synopsis: Gets the next chunk
  201. //
  202. // Arguments: [pStat] -- Chunk info
  203. //
  204. //--------------------------------------------------------------------------
  205. SCODE STDMETHODCALLTYPE HtmlPropIFilter::GetChunk(
  206. STAT_CHUNK * pStat )
  207. {
  208. SCODE sc = _pHtmlFilter->GetChunk( pStat );
  209. // If we got a chunk, it's a value chunk, and it's a meta property with
  210. // a string identifier, store away the name so it's available when the
  211. // value is retrieved.
  212. if ( ( SUCCEEDED( sc ) ) &&
  213. ( 0 != ( pStat->flags & CHUNK_VALUE ) ) &&
  214. ( PRSPEC_LPWSTR == pStat->attribute.psProperty.ulKind ) &&
  215. ( CLSID_MetaProperty == pStat->attribute.guidPropSet ) &&
  216. ( 0 != pStat->attribute.psProperty.lpwstr ) &&
  217. ( wcslen( pStat->attribute.psProperty.lpwstr ) < cwcMaxName ) )
  218. {
  219. _fMetaProperty = TRUE;
  220. wcscpy( _awcName, pStat->attribute.psProperty.lpwstr );
  221. }
  222. else
  223. {
  224. _fMetaProperty = FALSE;
  225. }
  226. return sc;
  227. } //GetChunk
  228. //+-------------------------------------------------------------------------
  229. //
  230. // Function: ParseDateTime
  231. //
  232. // Synopsis: Parse the string and return a date/time
  233. // n.b. If the date is ill-formed and this function returns
  234. // an error code, the file will be unfiltered, and can be
  235. // found by using the unfiltered admin query.
  236. // The date parsing is very strict.
  237. // Times are in any time zone you like, but .htx will interpret
  238. // all dates as GMT. You can always use .asp script to munge
  239. // dates as you like.
  240. //
  241. // Arguments: [pwcDate] -- String form of the date/time
  242. // [ft] -- Returns the date/time
  243. //
  244. //--------------------------------------------------------------------------
  245. SCODE ParseDateTime(
  246. WCHAR * pwcDate,
  247. FILETIME & ft )
  248. {
  249. SYSTEMTIME stValue = { 0, 0, 0, 0, 0, 0, 0, 0 };
  250. // Some day add more flexible date formats!
  251. int cItems = swscanf( pwcDate,
  252. L"%4hd/%2hd/%2hd %2hd:%2hd:%2hd:%3hd",
  253. &stValue.wYear,
  254. &stValue.wMonth,
  255. &stValue.wDay,
  256. &stValue.wHour,
  257. &stValue.wMinute,
  258. &stValue.wSecond,
  259. &stValue.wMilliseconds );
  260. if ( 1 == cItems )
  261. cItems = swscanf( pwcDate,
  262. L"%4hd-%2hd-%2hd %2hd:%2hd:%2hd:%3hd",
  263. &stValue.wYear,
  264. &stValue.wMonth,
  265. &stValue.wDay,
  266. &stValue.wHour,
  267. &stValue.wMinute,
  268. &stValue.wSecond,
  269. &stValue.wMilliseconds );
  270. if( cItems != 3 && cItems != 6 && cItems != 7)
  271. return E_INVALIDARG;
  272. // Make a sensible split for Year 2000
  273. if (stValue.wYear < 30)
  274. stValue.wYear += 2000;
  275. else if (stValue.wYear < 100)
  276. stValue.wYear += 1900;
  277. if( !SystemTimeToFileTime( &stValue, &ft ) )
  278. return HRESULT_FROM_WIN32( GetLastError() );
  279. return S_OK;
  280. } //ParseDateTime
  281. //+-------------------------------------------------------------------------
  282. //
  283. // Function: Translate
  284. //
  285. // Synopsis: Translates the string property value to the given type
  286. //
  287. // Arguments: [v] -- The variant to translate
  288. // [dbType] -- The resulting data type
  289. //
  290. //--------------------------------------------------------------------------
  291. SCODE Translate(
  292. PROPVARIANT & v,
  293. DBTYPE dbType )
  294. {
  295. PROPVARIANT varCopy = v;
  296. BOOL fChange = TRUE;
  297. SCODE sc = S_OK;
  298. WCHAR *p = v.pwszVal;
  299. // The source must be a string variant
  300. if ( 0 == p || VT_LPWSTR != v.vt )
  301. return S_OK;
  302. v.vt = dbType;
  303. // Eat leading white space
  304. while ( ' ' == *p )
  305. p++;
  306. int base = 10;
  307. // Is this a hex number?
  308. if ( '0' == *p && ( 'x' == *(p+1) || 'X' == *(p+1) ) )
  309. {
  310. p += 2;
  311. base = 16;
  312. }
  313. WCHAR * pwc;
  314. // DBTYPE_I1 isn't an official OLE property type, so it isn't supported.
  315. //
  316. // Note: range checking could be added and a failure code could be
  317. // returned if the check failed. That would put the file in the
  318. // unfiltered list.
  319. switch ( dbType )
  320. {
  321. case DBTYPE_UI1 :
  322. v.bVal = (BYTE) wcstoul( v.pwszVal, &pwc, base );
  323. break;
  324. case DBTYPE_I2 :
  325. v.iVal = (SHORT) wcstol( v.pwszVal, &pwc, base );
  326. break;
  327. case DBTYPE_UI2 :
  328. v.uiVal = (USHORT) wcstoul( v.pwszVal, &pwc, base );
  329. break;
  330. case DBTYPE_I4 :
  331. v.lVal = (LONG) wcstol( v.pwszVal, &pwc, base );
  332. break;
  333. case DBTYPE_UI4 :
  334. v.ulVal = (ULONG) wcstoul( v.pwszVal, &pwc, base );
  335. break;
  336. case DBTYPE_I8 :
  337. swscanf( v.pwszVal, L"%I64d", &v.fltVal );
  338. break;
  339. case DBTYPE_UI8 :
  340. swscanf( v.pwszVal, L"%I64u", &v.fltVal );
  341. break;
  342. case DBTYPE_R4 :
  343. swscanf( v.pwszVal, L"%f", &v.fltVal );
  344. break;
  345. case DBTYPE_R8 :
  346. swscanf( v.pwszVal, L"%lf", &v.dblVal );
  347. break;
  348. case DBTYPE_BOOL :
  349. // If the first character is t or 1, assume VARIANT_TRUE
  350. if ( 't' == *v.pwszVal ||
  351. 'T' == *v.pwszVal ||
  352. '1' == *v.pwszVal )
  353. v.boolVal = VARIANT_TRUE;
  354. else
  355. v.boolVal = VARIANT_FALSE;
  356. break;
  357. case VT_FILETIME :
  358. sc = ParseDateTime( p, v.filetime );
  359. break;
  360. default :
  361. // leave the property as it was
  362. fChange = FALSE;
  363. v.vt = varCopy.vt;
  364. break;
  365. }
  366. // Free the memory for the (now converted) string value
  367. if ( fChange )
  368. PropVariantClear( &varCopy );
  369. return sc;
  370. } //Translate
  371. //+-------------------------------------------------------------------------
  372. //
  373. // Method: HtmlPropIFilter::GetValue
  374. //
  375. // Synopsis: Retrieves the current value
  376. //
  377. // Arguments: [ppPropValue] -- Where the value is stored
  378. //
  379. //--------------------------------------------------------------------------
  380. SCODE STDMETHODCALLTYPE HtmlPropIFilter::GetValue(
  381. PROPVARIANT ** ppPropValue )
  382. {
  383. SCODE sc = _pHtmlFilter->GetValue( ppPropValue );
  384. // Is this a value that must be translated?
  385. if ( SUCCEEDED( sc ) && _fMetaProperty && 0 != *ppPropValue )
  386. {
  387. // lookup the datatype of the translation based on property name
  388. for ( ULONG i = 0; i < g_cEntries; i++ )
  389. {
  390. if ( !_wcsicmp( g_aEntries[i].awcName, _awcName ) )
  391. {
  392. // found it, so translate it
  393. sc = Translate( **ppPropValue,
  394. g_aEntries[i].dbType );
  395. break;
  396. }
  397. }
  398. }
  399. return sc;
  400. } //GetValue
  401. //+-------------------------------------------------------------------------
  402. //
  403. // Method: HtmlPropIFilter::GetText
  404. //
  405. // Synopsis: Gets text from the filter
  406. //
  407. // Arguments: [pcwcBuffer] -- Returns the # of WCHARs returned
  408. // [awcBuffer] -- Where text is written
  409. //
  410. //--------------------------------------------------------------------------
  411. SCODE STDMETHODCALLTYPE HtmlPropIFilter::GetText(
  412. ULONG * pcwcBuffer,
  413. WCHAR * awcBuffer )
  414. {
  415. return _pHtmlFilter->GetText( pcwcBuffer, awcBuffer );
  416. } //GetText
  417. //+-------------------------------------------------------------------------
  418. //
  419. // Method: HtmlPropIFilter::BindRegion
  420. //
  421. //--------------------------------------------------------------------------
  422. SCODE STDMETHODCALLTYPE HtmlPropIFilter::BindRegion(
  423. FILTERREGION origPos,
  424. REFIID riid,
  425. void ** ppunk )
  426. {
  427. return _pHtmlFilter->BindRegion( origPos, riid, ppunk );
  428. } //BindRegion
  429. //+-------------------------------------------------------------------------
  430. //
  431. // Method: HtmlPropIFilter::GetClassID
  432. //
  433. //--------------------------------------------------------------------------
  434. SCODE STDMETHODCALLTYPE HtmlPropIFilter::GetClassID( CLSID * pClassID )
  435. {
  436. *pClassID = CLSID_HtmlPropIFilter;
  437. return S_OK;
  438. } //GetClassID
  439. //+-------------------------------------------------------------------------
  440. //
  441. // Method: HtmlPropIFilter::IsDirty
  442. //
  443. //--------------------------------------------------------------------------
  444. SCODE STDMETHODCALLTYPE HtmlPropIFilter::IsDirty()
  445. {
  446. return S_FALSE;
  447. } //IsDirty
  448. //+-------------------------------------------------------------------------
  449. //
  450. // Method: HtmlPropIFilter::Load
  451. //
  452. // Synopsis: Loads the file for the filter
  453. //
  454. // Arguments: [pszFileName] -- Name of the file
  455. // [dwMode] -- Mode of the load
  456. //
  457. //--------------------------------------------------------------------------
  458. SCODE STDMETHODCALLTYPE HtmlPropIFilter::Load(
  459. LPCWSTR pszFileName,
  460. DWORD dwMode)
  461. {
  462. //
  463. // Get html filter class object and class factory
  464. //
  465. IClassFactory * pcf;
  466. SCODE sc = E_FAIL;
  467. if ( 0 != g_hHtmlDll )
  468. {
  469. LPFNGETCLASSOBJECT pfn = (LPFNGETCLASSOBJECT)GetProcAddress(
  470. g_hHtmlDll,
  471. "DllGetClassObject" );
  472. if ( 0 != pfn )
  473. sc = (pfn)( CLSID_HtmlIFilter, IID_IClassFactory, (void **)&pcf );
  474. }
  475. if ( SUCCEEDED(sc) )
  476. {
  477. // Get an html filter
  478. sc = pcf->CreateInstance( 0, IID_IFilter, (void **)&_pHtmlFilter );
  479. pcf->Release();
  480. if ( SUCCEEDED(sc) )
  481. {
  482. // Load the file
  483. sc = _pHtmlFilter->QueryInterface( IID_IPersistFile,
  484. (void **) &_pPersistFile );
  485. if ( SUCCEEDED(sc) )
  486. {
  487. sc = _pPersistFile->Load( pszFileName, dwMode );
  488. }
  489. else
  490. {
  491. _pHtmlFilter->Release();
  492. _pHtmlFilter = 0;
  493. }
  494. }
  495. }
  496. return sc;
  497. } //Load
  498. //+-------------------------------------------------------------------------
  499. //
  500. // Method: HtmlPropIFilter::Save
  501. //
  502. //--------------------------------------------------------------------------
  503. SCODE STDMETHODCALLTYPE HtmlPropIFilter::Save(
  504. LPCWSTR pszFileName,
  505. BOOL fRemember )
  506. {
  507. return E_FAIL;
  508. } //Save
  509. //+-------------------------------------------------------------------------
  510. //
  511. // Method: HtmlPropIFilter::SaveCompleted
  512. //
  513. //--------------------------------------------------------------------------
  514. SCODE STDMETHODCALLTYPE HtmlPropIFilter::SaveCompleted(
  515. LPCWSTR pszFileName )
  516. {
  517. return E_FAIL;
  518. } //SaveCompleted
  519. //+-------------------------------------------------------------------------
  520. //
  521. // Method: HtmlPropIFilter::GetcurFile
  522. //
  523. //--------------------------------------------------------------------------
  524. SCODE STDMETHODCALLTYPE HtmlPropIFilter::GetCurFile(
  525. LPWSTR * ppszFileName )
  526. {
  527. return _pPersistFile->GetCurFile( ppszFileName );
  528. } //GetCurFile
  529. //+-------------------------------------------------------------------------
  530. //
  531. // Function: ParsePropertyFile
  532. //
  533. // Synopsis: Parses a property file and stores datatypes for html meta
  534. // properties. Property files are in .idq format, with a
  535. // [Names] section.
  536. //
  537. //--------------------------------------------------------------------------
  538. void ParsePropertyFile()
  539. {
  540. // already parsed the file?
  541. if ( g_cEntries > 0 )
  542. return;
  543. // open the property file in the system32 directory
  544. WCHAR awcFile[ MAX_PATH ];
  545. GetSystemDirectory( awcFile, sizeof awcFile / sizeof WCHAR );
  546. wcscat( awcFile, L"\\" );
  547. wcscat( awcFile, pwcHTMLPropertyFile );
  548. FILE *file = _wfopen( awcFile, L"r" );
  549. if ( 0 != file )
  550. {
  551. WCHAR awc[ 500 ];
  552. BOOL fNames = FALSE;
  553. // for each line of the file
  554. while ( fgetws( awc, sizeof awc, file ) )
  555. {
  556. int cwc = wcslen( awc );
  557. if ( 0 == cwc )
  558. continue;
  559. // trim off trailing newline
  560. if ( awc[ cwc - 1 ] == '\n' )
  561. {
  562. cwc--;
  563. awc[cwc] = 0;
  564. }
  565. // is this a section line?
  566. if ( '[' == awc[0] )
  567. {
  568. fNames = !_wcsicmp( L"[names]", awc );
  569. }
  570. else if ( ( '#' != awc[0] ) && fNames )
  571. {
  572. // parse the data type
  573. WCHAR *pwcType = wcschr( awc, L'(' );
  574. if ( 0 != pwcType )
  575. {
  576. pwcType++;
  577. while ( ' ' == *pwcType )
  578. pwcType++;
  579. WCHAR *pwcX = wcstok( pwcType, L", )" );
  580. if ( 0 != pwcType )
  581. {
  582. // lookup the type in the list of types
  583. for ( ULONG i = 0; i < cTypeEntries; i++ )
  584. {
  585. if ( !_wcsicmp( aTypeEntries[i].awcName,
  586. pwcType ) )
  587. break;
  588. }
  589. // got the type, so find the guid
  590. if ( i < cTypeEntries )
  591. {
  592. // find the property guid
  593. pwcType += 1 + wcslen( pwcType );
  594. WCHAR *pwcName = wcschr( pwcType, '=' );
  595. if ( pwcName )
  596. {
  597. pwcName++;
  598. while ( ' ' == *pwcName )
  599. pwcName++;
  600. // is this the html guid?
  601. if ( !_wcsnicmp( pwcName,
  602. pwcMetaProperty,
  603. wcslen( pwcMetaProperty ) ) )
  604. {
  605. // find the property name
  606. pwcName = wcschr( pwcName, ' ' );
  607. if ( pwcName )
  608. {
  609. // skip white space
  610. while ( ' ' == *pwcName )
  611. pwcName++;
  612. // got it -- save it away if it fits
  613. if ( ( wcslen( pwcName ) < cwcMaxName ) &&
  614. ( g_cEntries < maxEntries ) )
  615. {
  616. wcscpy( g_aEntries[g_cEntries].awcName,
  617. pwcName );
  618. g_aEntries[g_cEntries++].dbType =
  619. aTypeEntries[i].dbType;
  620. }
  621. }
  622. }
  623. }
  624. }
  625. }
  626. }
  627. }
  628. }
  629. fclose( file );
  630. }
  631. } //ParsePropertyFile
  632. //+-------------------------------------------------------------------------
  633. //
  634. // Method: HtmlPropIFilterCF::HtmlPropIFilterCF
  635. //
  636. // Synopsis: HTML Property IFilter class factory constructor
  637. //
  638. //--------------------------------------------------------------------------
  639. HtmlPropIFilterCF::HtmlPropIFilterCF()
  640. {
  641. _lRefs = 1;
  642. long c = InterlockedIncrement( &g_cInstances );
  643. if ( 0 == g_hHtmlDll && 1 == c )
  644. {
  645. // load the html filter dll
  646. g_hHtmlDll = LoadLibrary( pwcHTMLFilter );
  647. // load the property information
  648. ParsePropertyFile();
  649. }
  650. } //HtmlPropIFilterCF
  651. //+-------------------------------------------------------------------------
  652. //
  653. // Method: HtmlPropIFilterCF::~HtmlPropIFilterCF
  654. //
  655. // Synopsis: HTML IFilter class factory constructor
  656. //
  657. //--------------------------------------------------------------------------
  658. HtmlPropIFilterCF::~HtmlPropIFilterCF()
  659. {
  660. long c = InterlockedDecrement( &g_cInstances );
  661. if ( 0 != g_hHtmlDll && 0 == c )
  662. {
  663. FreeLibrary( g_hHtmlDll );
  664. g_hHtmlDll = 0;
  665. }
  666. } //~HtmlPropIFilterCF
  667. //+-------------------------------------------------------------------------
  668. //
  669. // Method: HtmlPropIFilterCF::QueryInterface
  670. //
  671. // Synopsis: Rebind to other interface
  672. //
  673. // Arguments: [riid] -- IID of new interface
  674. // [ppvObject] -- New interface * returned here
  675. //
  676. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  677. //
  678. //--------------------------------------------------------------------------
  679. SCODE STDMETHODCALLTYPE HtmlPropIFilterCF::QueryInterface(
  680. REFIID riid,
  681. void ** ppvObject )
  682. {
  683. if ( IID_IClassFactory == riid )
  684. *ppvObject = (IUnknown *) (IClassFactory *) this;
  685. else if ( IID_IUnknown == riid )
  686. *ppvObject = (IUnknown *) (IPersist *) this;
  687. else
  688. {
  689. *ppvObject = 0;
  690. return E_NOINTERFACE;
  691. }
  692. AddRef();
  693. return S_OK;
  694. } //QueryInterface
  695. //+-------------------------------------------------------------------------
  696. //
  697. // Method: HtmlPropIFilterCF::AddRef
  698. //
  699. // Synopsis: Increments refcount
  700. //
  701. //--------------------------------------------------------------------------
  702. ULONG STDMETHODCALLTYPE HtmlPropIFilterCF::AddRef()
  703. {
  704. return InterlockedIncrement( &_lRefs );
  705. } //AddRef
  706. //+-------------------------------------------------------------------------
  707. //
  708. // Method: HtmlPropIFilterCF::Release
  709. //
  710. // Synopsis: Decrement refcount. Delete if necessary.
  711. //
  712. //--------------------------------------------------------------------------
  713. ULONG STDMETHODCALLTYPE HtmlPropIFilterCF::Release()
  714. {
  715. long lTmp = InterlockedDecrement( &_lRefs );
  716. if ( 0 == lTmp )
  717. delete this;
  718. return lTmp;
  719. } //Release
  720. //+-------------------------------------------------------------------------
  721. //
  722. // Method: HtmlPropIFilterCF::CreateInstance
  723. //
  724. // Synopsis: Creates new HtmlPropIFilter object
  725. //
  726. // Arguments: [pUnkOuter] -- 'Outer' IUnknown
  727. // [riid] -- Interface to bind
  728. // [ppvObject] -- Interface returned here
  729. //
  730. //--------------------------------------------------------------------------
  731. SCODE STDMETHODCALLTYPE HtmlPropIFilterCF::CreateInstance(
  732. IUnknown * pUnkOuter,
  733. REFIID riid,
  734. void * * ppvObject )
  735. {
  736. *ppvObject = 0;
  737. HtmlPropIFilter * pFilter = new HtmlPropIFilter;
  738. if ( 0 == pFilter )
  739. return E_OUTOFMEMORY;
  740. SCODE sc = pFilter->QueryInterface( riid , ppvObject );
  741. pFilter->Release();
  742. return sc;
  743. } //CreateInstance
  744. //+-------------------------------------------------------------------------
  745. //
  746. // Method: HtmlPropIFilterCF::LockServer
  747. //
  748. // Synopsis: Force class factory to remain loaded
  749. //
  750. // Arguments: [fLock] -- TRUE if locking, FALSE if unlocking
  751. //
  752. // Returns: S_OK
  753. //
  754. //--------------------------------------------------------------------------
  755. SCODE STDMETHODCALLTYPE HtmlPropIFilterCF::LockServer(BOOL fLock)
  756. {
  757. if(fLock)
  758. InterlockedIncrement( &g_cInstances );
  759. else
  760. InterlockedDecrement( &g_cInstances );
  761. return S_OK;
  762. } //LockServer
  763. //+-------------------------------------------------------------------------
  764. //
  765. // Function: DllGetClassObject
  766. //
  767. // Synopsis: Ole DLL load class routine
  768. //
  769. // Arguments: [cid] -- Class to load
  770. // [iid] -- Interface to bind to on class object
  771. // [ppvObj] -- Interface pointer returned here
  772. //
  773. // Returns: HTML Property filter class factory
  774. //
  775. //--------------------------------------------------------------------------
  776. extern "C" SCODE STDMETHODCALLTYPE DllGetClassObject(
  777. REFCLSID cid,
  778. REFIID iid,
  779. void ** ppvObj )
  780. {
  781. IUnknown * pUnk = 0;
  782. if ( CLSID_HtmlPropIFilter == cid ||
  783. CLSID_HtmlPropClass == cid )
  784. {
  785. pUnk = new HtmlPropIFilterCF;
  786. if ( 0 == pUnk )
  787. return E_OUTOFMEMORY;
  788. }
  789. else
  790. {
  791. *ppvObj = 0;
  792. return E_NOINTERFACE;
  793. }
  794. SCODE sc = pUnk->QueryInterface( iid, ppvObj );
  795. pUnk->Release();
  796. return sc;
  797. } //DllGetClassObject
  798. //+-------------------------------------------------------------------------
  799. //
  800. // Method: DllCanUnloadNow
  801. //
  802. // Synopsis: Notifies DLL to unload (cleanup global resources)
  803. //
  804. // Returns: S_OK if it is acceptable for caller to unload DLL.
  805. //
  806. //--------------------------------------------------------------------------
  807. extern "C" SCODE STDMETHODCALLTYPE DllCanUnloadNow( void )
  808. {
  809. if ( 0 == g_cInstances )
  810. return S_OK;
  811. else
  812. return S_FALSE;
  813. } //DllCanUnloadNow
  814. SClassEntry const aHtmlPropClasses[] =
  815. {
  816. { L".hhc", L"hhcfile", L"HHC file", L"{7f73b8f6-c19c-11d0-aa66-00c04fc2eddc}", L"HHC file" },
  817. { L".htm", L"htmlfile", L"HTML file", L"{25336920-03f9-11cf-8fd0-00aa00686f13}", L"HTML file" },
  818. { L".html", L"htmlfile", L"HTML file", L"{25336920-03f9-11cf-8fd0-00aa00686f13}", L"HTML file" },
  819. { L".htx", L"htmlfile", L"HTML file", L"{25336920-03f9-11cf-8fd0-00aa00686f13}", L"HTML file" },
  820. { L".stm", L"htmlfile", L"HTML file", L"{25336920-03f9-11cf-8fd0-00aa00686f13}", L"HTML file" },
  821. { L".htw", L"htmlfile", L"HTML file", L"{25336920-03f9-11cf-8fd0-00aa00686f13}", L"HTML file" },
  822. { L".asp", L"asp_auto_file", L"ASP auto file", L"{bd70c020-2d24-11d0-9110-00004c752752}", L"ASP auto file" },
  823. };
  824. SHandlerEntry const HtmlPropHandler =
  825. {
  826. L"{c694d910-a439-11d1-a903-00e098006ed3}",
  827. L"html property persistent handler",
  828. L"{f4309e80-a1db-11d1-a8fb-00e098006ed3}",
  829. };
  830. SFilterEntry const HtmlPropFilter =
  831. {
  832. L"{f4309e80-a1db-11d1-a8fb-00e098006ed3}",
  833. L"html property filter",
  834. L"HtmlProp.dll",
  835. L"Both"
  836. };
  837. DEFINE_DLLREGISTERFILTER( HtmlPropHandler, HtmlPropFilter, aHtmlPropClasses )