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.

725 lines
20 KiB

  1. /*****************************************************************************
  2. *
  3. * map.h - Main private header file
  4. *
  5. *****************************************************************************/
  6. /*****************************************************************************
  7. *
  8. * Coding conventions:
  9. *
  10. * + Follow standard shell coding conventions.
  11. *
  12. * + Standard K&R brace placement and indentation style.
  13. *
  14. * + Indent by 4 spaces.
  15. *
  16. * + Fully-brace all dependent clauses. Never write "if (c) foo();"
  17. *
  18. * + Do not return in the middle of a function. If forced,
  19. * use a "goto exit". This way, you can stick entry/exit stuff
  20. * later without getting caught out. (I learned this rule the
  21. * hard way.)
  22. *
  23. * + Declare variables with narrowest possible scope.
  24. *
  25. * + Always test for success, not failure! The compiler will
  26. * thank you.
  27. *
  28. *****************************************************************************/
  29. /*****************************************************************************
  30. *
  31. * NOTE! This code was written for readability, not efficiency.
  32. *
  33. * I'm trusting the compiler to do optimizations like these:
  34. *
  35. * "Parameter alias":
  36. *
  37. * Function(LPFOO pfoo)
  38. * {
  39. * LPBAR pbar = (LPBAR)pfoo;
  40. * ... use pbar and never mention pfoo again ...
  41. * }
  42. *
  43. * --> becomes
  44. *
  45. * Function(LPFOO pfoo)
  46. * {
  47. * #define pbar ((LPBAR)pfoo)
  48. * ... use pbar and never mention pfoo again ...
  49. * #undef pbar
  50. * }
  51. *
  52. * "Speculative Execution":
  53. *
  54. * Function(PFOO pfoo)
  55. * {
  56. * BOOL fRc;
  57. * if (... condition 1 ...) {
  58. * ... complicated stuff ...
  59. * *pfoo = result;
  60. * fRc = 1;
  61. * } else { // condition 1 failed
  62. * *pfoo = 0;
  63. * fRc = 0;
  64. * }
  65. * return fRc;
  66. * }
  67. *
  68. * --> becomes
  69. *
  70. * Function(PFOO pfoo)
  71. * {
  72. * BOOL fRc = 0;
  73. * *pfoo = 0;
  74. * if (... condition 1 ...) {
  75. * ... complicated stuff ...
  76. * *pfoo = result;
  77. * fRc = 1;
  78. * }
  79. * return fRc;
  80. * }
  81. *
  82. * "Single Exit":
  83. *
  84. * Function(...)
  85. * {
  86. * BOOL fRc;
  87. * if (... condition 1 ...) {
  88. * ...
  89. * if (... condition 2 ...) {
  90. * ...
  91. * fRc = 1;
  92. * } else { // condition 2 failed
  93. * ... clean up ...
  94. * fRc = 0;
  95. * }
  96. * } else { // condition 1 failed
  97. * ... clean up ...
  98. * fRc = 0;
  99. * }
  100. * return fRc;
  101. * }
  102. *
  103. * --> becomes
  104. *
  105. * Function(...)
  106. * {
  107. * if (... condition 1 ...) {
  108. * ...
  109. * if (... condition 2 ...) {
  110. * ...
  111. * return 1;
  112. * } else { // condition 2 failed
  113. * ... clean up ...
  114. * return 0;
  115. * }
  116. * } else { // condition 1 failed
  117. * ... clean up ...
  118. * return 0;
  119. * }
  120. * NOTREACHED;
  121. * }
  122. *
  123. *
  124. *
  125. *****************************************************************************/
  126. #define STRICT
  127. #undef WIN32_LEAN_AND_MEAN
  128. #define WIN32_LEAN_AND_MEAN
  129. #define NOIME
  130. #define NOSERVICE
  131. #undef WINVER
  132. #undef _WIN32_WINDOWS
  133. #define WINVER 0x0400 /* Windows 4.0 compatible */
  134. #define _WIN32_WINDOWS 0x0400 /* Windows 4.0 compatible */
  135. #include <windows.h>
  136. #ifdef RC_INVOKED /* Define some tags to speed up rc.exe */
  137. #define __RPCNDR_H__ /* Don't need RPC network data representation */
  138. #define __RPC_H__ /* Don't need RPC */
  139. #include <oleidl.h> /* Get the DROPEFFECT stuff */
  140. #define _OLE2_H_ /* But none of the rest */
  141. #define _WINDEF_
  142. #define _WINBASE_
  143. #define _WINGDI_
  144. #define NONLS
  145. #define _WINCON_
  146. #define _WINREG_
  147. #define _WINNETWK_
  148. #define _INC_COMMCTRL
  149. #define _INC_SHELLAPI
  150. #else
  151. #include <windowsx.h>
  152. #include <regstr.h>
  153. #endif
  154. #include <shlobj.h>
  155. #include <shellapi.h>
  156. #ifdef DBG /* NT build process uses DBG */
  157. #define DEBUG
  158. #endif
  159. /*****************************************************************************
  160. *
  161. * Int64 goo.
  162. *
  163. *****************************************************************************/
  164. #define SetWindowPointer(hwnd, i, p) SetWindowLongPtr(hwnd, i, (LRESULT)(p))
  165. #define GetWindowPointer(hwnd, i) (void *)GetWindowLongPtr(hwnd, i)
  166. /*****************************************************************************
  167. *
  168. * Stuff
  169. *
  170. *****************************************************************************/
  171. #define IToClass(T, f, p) CONTAINING_RECORD(p, T, f)
  172. #define _IOffset(T, f) FIELD_OFFSET(T, f)
  173. /*****************************************************************************
  174. *
  175. * Resource identifiers
  176. *
  177. *****************************************************************************/
  178. /*****************************************************************************
  179. *
  180. * Dialogs
  181. *
  182. *****************************************************************************/
  183. #define IDC_STATIC -1
  184. #define IDD_MAIN 1
  185. #define IDC_FROM 16
  186. #define IDC_TO 17
  187. /*****************************************************************************
  188. *
  189. * Strings
  190. *
  191. *****************************************************************************/
  192. #define IDS_KEYFIRST 32
  193. #define IDS_CAPSLOCK 32
  194. #define IDS_LCTRL 33
  195. #define IDS_RCTRL 34
  196. #define IDS_LALT 35
  197. #define IDS_RALT 36
  198. #define IDS_LSHIFT 37
  199. #define IDS_RSHIFT 38
  200. #define IDS_LWIN 39
  201. #define IDS_RWIN 40
  202. #define IDS_APPS 41
  203. #define IDS_KEYLAST 41
  204. #define IDS_NUMKEYS (IDS_KEYLAST - IDS_KEYFIRST + 1)
  205. #ifndef RC_INVOKED
  206. /*****************************************************************************
  207. *
  208. * Stuff I'm tired of typing over and over.
  209. *
  210. *****************************************************************************/
  211. typedef LPITEMIDLIST PIDL, *PPIDL;
  212. typedef LPCITEMIDLIST PCIDL;
  213. typedef LPSHELLFOLDER PSF;
  214. typedef LPVOID PV;
  215. typedef LPVOID *PPV;
  216. typedef LPCVOID PCV;
  217. typedef REFIID RIID;
  218. typedef LPUNKNOWN PUNK;
  219. /*****************************************************************************
  220. *
  221. * Baggage - Stuff I carry everywhere
  222. *
  223. *****************************************************************************/
  224. #define INTERNAL NTAPI /* Called only within a translation unit */
  225. #define EXTERNAL NTAPI /* Called from other translation units */
  226. #define INLINE static __inline
  227. #define BEGIN_CONST_DATA data_seg(".text", "CODE")
  228. #define END_CONST_DATA data_seg(".data", "DATA")
  229. #define OBJAT(T, v) (*(T *)(v)) /* Pointer punning */
  230. #define PUN(T, v) OBJAT(T, &(v)) /* General-purpose type-punning */
  231. /*
  232. * Convert a count of TCHAR's to a count of bytes.
  233. */
  234. #define cbCtch(ctch) ((ctch) * sizeof(TCHAR))
  235. /*
  236. * Convert an object (X) to a count of bytes (cb).
  237. */
  238. #define cbX(X) sizeof(X)
  239. /*
  240. * Convert an array name (A) to a generic count (c).
  241. */
  242. #define cA(a) (cbX(a)/cbX(a[0]))
  243. /*
  244. * Convert an array name (A) to a pointer to its Max.
  245. * (I.e., one past the last element.)
  246. */
  247. #define pvMaxA(a) (&a[cA(a)])
  248. #define pvSubPvCb(pv, cb) ((PV)((PBYTE)pv - (cb)))
  249. #define pvAddPvCb(pv, cb) ((PV)((PBYTE)pv + (cb)))
  250. #define cbSubPvPv(p1, p2) ((PBYTE)(p1) - (PBYTE)(p2))
  251. /*
  252. * Round cb up to the nearest multiple of cbAlign. cbAlign must be
  253. * a power of 2 whose evaluation entails no side-effects.
  254. */
  255. #define ROUNDUP(cb, cbAlign) ((((cb) + (cbAlign) - 1) / (cbAlign)) * (cbAlign))
  256. /*
  257. * lfNeVV
  258. *
  259. * Given two values, return zero if they are equal and nonzero if they
  260. * are different. This is the same as (v1) != (v2), except that the
  261. * return value on unequal is a random nonzero value instead of 1.
  262. * (lf = logical flag)
  263. *
  264. * lfNePvPv
  265. *
  266. * The same as lfNeVV, but for pointers.
  267. *
  268. * lfPv
  269. *
  270. * Nonzero if pv is not null.
  271. *
  272. */
  273. #define lfNeVV(v1, v2) ((v1) - (v2))
  274. #define lfNePvPv(v1, v2) lfNeVV((DWORD)(PV)(v1), (DWORD)(PV)(v2))
  275. #define lfPv(pv) ((BOOL)(PV)(pv))
  276. /*
  277. * land -- Logical and. Evaluate the first. If the first is zero,
  278. * then return zero. Otherwise, return the second.
  279. */
  280. #define fLandFF(f1, f2) ((f1) ? (f2) : 0)
  281. /*
  282. * lor -- Logical or. Evaluate the first. If the first is nonzero,
  283. * return it. Otherwise, return the second.
  284. *
  285. * Unfortunately, due to the stupidity of the C language, this can
  286. * be implemented only with a GNU extension. In the non-GNU case,
  287. * we return 1 if the first is nonzero.
  288. */
  289. #if defined(__GNUC__)
  290. #define fLorFF(f1, f2) ({ typeof (f1) _f = f1; if (!_f) _f = f2; _f; })
  291. #else
  292. #define fLorFF(f1, f2) ((f1) ? 1 : (f2))
  293. #endif
  294. /*
  295. * limp - logical implication. True unless the first is nonzero and
  296. * the second is zero.
  297. */
  298. #define fLimpFF(f1, f2) (!(f1) || (f2))
  299. /*
  300. * leqv - logical equivalence. True if both are zero or both are nonzero.
  301. */
  302. #define fLeqvFF(f1, f2) (!(f1) == !(f2))
  303. /*
  304. * InOrder - checks that i1 <= i2 < i3.
  305. */
  306. #define fInOrder(i1, i2, i3) ((unsigned)((i2)-(i1)) < (unsigned)((i3)-(i1)))
  307. /*****************************************************************************
  308. *
  309. * Wrappers and other quickies
  310. *
  311. *****************************************************************************/
  312. #define pvExchangePpvPv(ppv, pv) \
  313. InterlockedExchangePointer(ppv, pv)
  314. /*****************************************************************************
  315. *
  316. * Static globals: Initialized at PROCESS_ATTACH and never modified.
  317. *
  318. *****************************************************************************/
  319. HINSTANCE g_hinst; /* My instance handle */
  320. DEFINE_GUID(CLSID_KeyRemap, 0x176AA2C0, 0x9E15, 0x11cf,
  321. 0xbf,0xc7,0x44,0x45,0x53,0x54,0,0);
  322. /*****************************************************************************
  323. *
  324. * Dynamic Globals. There should be as few of these as possible.
  325. *
  326. * All access to dynamic globals must be thread-safe.
  327. *
  328. *****************************************************************************/
  329. ULONG g_cRef; /* Global reference count */
  330. /*****************************************************************************
  331. *
  332. * mapcf.c - Class Factory
  333. *
  334. *****************************************************************************/
  335. STDMETHODIMP CMapFactory_New(RIID riid, PPV ppvObj);
  336. /*****************************************************************************
  337. *
  338. * mappsx.c - IPropSheetExt, IShellExtInit
  339. *
  340. *****************************************************************************/
  341. STDMETHODIMP CMapPsx_New(RIID riid, PPV ppvObj);
  342. /*****************************************************************************
  343. *
  344. * mapps.c - Property sheet
  345. *
  346. *****************************************************************************/
  347. INT_PTR CALLBACK MapPs_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam);
  348. /*****************************************************************************
  349. *
  350. * Common object managers.
  351. *
  352. *****************************************************************************/
  353. typedef struct PREVTBL0 { /* Simple (non-OLE) object */
  354. void (NTAPI *FinalizeProc)(PV pv); /* Finalization procedure */
  355. } PREVTBL0, *PPREVTBL0;
  356. typedef struct PREVTBL { /* Primary interface */
  357. REFIID riid; /* Type of this object */
  358. void (NTAPI *FinalizeProc)(PV pv); /* Finalization procedure */
  359. } PREVTBL, *PPREVTBL;
  360. typedef struct PREVTBL2 { /* Secondary interface */
  361. ULONG lib; /* offset from start of object */
  362. } PREVTBL2, *PPREVTBL2;
  363. #ifdef DEBUG
  364. #define Simple_Interface(C) Primary_Interface(C, IUnknown); \
  365. Default_QueryInterface(C) \
  366. Default_AddRef(C) \
  367. Default_Release(C)
  368. #define Simple_Vtbl(C) Primary_Vtbl(C)
  369. #define Simple_Interface_Begin(C) Primary_Interface_Begin(C, IUnknown)
  370. #define Simple_Interface_End(C) Primary_Interface_End(C, IUnknown)
  371. #else
  372. #define Simple_Interface(C) Primary_Interface(C, IUnknown)
  373. #define Simple_Vtbl(C) Primary_Vtbl(C)
  374. #define Simple_Interface_Begin(C) \
  375. struct S_##C##Vtbl c_####C##VI = { { \
  376. &IID_##IUnknown, \
  377. C##_Finalize, \
  378. }, { \
  379. Common##_QueryInterface, \
  380. Common##_AddRef, \
  381. Common##_Release, \
  382. #define Simple_Interface_End(C) Primary_Interface_End(C, IUnknown)
  383. #endif
  384. #define Primary_Interface(C, I) \
  385. extern struct S_##C##Vtbl { \
  386. PREVTBL prevtbl; \
  387. I##Vtbl vtbl; \
  388. } c_##C##VI \
  389. #define Primary_Vtbl(C) &c_##C##VI.vtbl
  390. #define Primary_Interface_Begin(C, I) \
  391. struct S_##C##Vtbl c_####C##VI = { { \
  392. &IID_##I, \
  393. C##_Finalize, \
  394. }, { \
  395. C##_QueryInterface, \
  396. C##_AddRef, \
  397. C##_Release, \
  398. #define Primary_Interface_End(C, I) \
  399. } }; \
  400. #define Secondary_Interface(C, I) \
  401. extern struct S_##I##_##C##Vtbl { \
  402. PREVTBL2 prevtbl; \
  403. I##Vtbl vtbl; \
  404. } c_##I##_##C##VI \
  405. #define Secondary_Vtbl(C, I) &c_##I##_##C##VI.vtbl
  406. #define Secondary_Interface_Begin(C, I, nm) \
  407. struct S_##I##_##C##Vtbl c_##I##_##C##VI = { { \
  408. _IOffset(C, nm), \
  409. }, { \
  410. Forward_QueryInterface, \
  411. Forward_AddRef, \
  412. Forward_Release, \
  413. #define Secondary_Interface_End(C, I, nm) \
  414. } }; \
  415. STDMETHODIMP Common_QueryInterface(PV, REFIID, PPV);
  416. STDMETHODIMP_(ULONG) _Common_AddRef(PV pv);
  417. STDMETHODIMP_(ULONG) _Common_Release(PV pv);
  418. /*
  419. * In DEBUG, go through the vtbl for additional squirties.
  420. */
  421. #ifdef DEBUG
  422. #define Common_AddRef(punk) \
  423. ((IUnknown *)(punk))->lpVtbl->AddRef((IUnknown *)(punk))
  424. #define Common_Release(punk) \
  425. ((IUnknown *)(punk))->lpVtbl->Release((IUnknown *)(punk))
  426. #else
  427. #define Common_AddRef _Common_AddRef
  428. #define Common_Release _Common_Release
  429. #endif
  430. void EXTERNAL Common_Finalize(PV);
  431. STDMETHODIMP _Common_New(ULONG cb, PV vtbl, PPV ppvObj);
  432. #define Common_NewCb(cb, C, ppvObj) _Common_New(cb, Primary_Vtbl(C), ppvObj)
  433. #define Common_New(C, ppvObj) Common_NewCb(cbX(C), C, ppvObj)
  434. STDMETHODIMP Forward_QueryInterface(PV pv, REFIID riid, PPV ppvObj);
  435. STDMETHODIMP_(ULONG) Forward_AddRef(PV pv);
  436. STDMETHODIMP_(ULONG) Forward_Release(PV pv);
  437. /*****************************************************************************
  438. *
  439. * Common_CopyAddRef
  440. *
  441. * Copy a pointer and increment its reference count.
  442. *
  443. * Cannot be a macro because Common_AddRef evaluates its argument
  444. * twice.
  445. *
  446. *****************************************************************************/
  447. INLINE void Common_CopyAddRef(PV pvDst, PV pvSrc)
  448. {
  449. PPV ppvDst = pvDst;
  450. *ppvDst = pvSrc;
  451. Common_AddRef(pvSrc);
  452. }
  453. /*****************************************************************************
  454. *
  455. * Invoking OLE methods.
  456. *
  457. * Invoke_Release is called with a pointer to the object, not with
  458. * the object itself. It zeros out the variable on the release.
  459. *
  460. *****************************************************************************/
  461. void EXTERNAL Invoke_AddRef(PV pv);
  462. void EXTERNAL Invoke_Release(PV pv);
  463. /*****************************************************************************
  464. *
  465. * assert.c - Assertion stuff
  466. *
  467. *****************************************************************************/
  468. #define AssertNow(c) switch(0) case 0: case c:
  469. #define CAssertNowPP(c,l) INLINE void Assert##l(void) { AssertNow(c); }
  470. #define CAssertNowP(c,l) CAssertNowPP(c,l)
  471. #define CAssertNow(c) CAssertNowP(c,__LINE__)
  472. typedef enum {
  473. sqflAlways = 0x00000000, /* Unconditional */
  474. sqflDll = 0x00000001, /* Dll bookkeeping */
  475. sqflFactory = 0x00000002, /* IClassFactory */
  476. sqflPsx = 0x00000004, /* IPropSheetExt */
  477. sqflPs = 0x00000008, /* Property sheet */
  478. sqflCommon = 0x00000000, /* common.c */
  479. sqflError = 0x80000000, /* Errors */
  480. } SQFL; /* squiffle */
  481. void EXTERNAL SquirtSqflPtszV(SQFL sqfl, LPCTSTR ptsz, ...);
  482. int EXTERNAL AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine);
  483. #ifndef DEBUG
  484. #define SquirtSqflPtszV sizeof
  485. #endif
  486. /*****************************************************************************
  487. *
  488. * Procedure enter/exit tracking.
  489. *
  490. * Start a procedure with
  491. *
  492. * EnterProc(ProcedureName, (_ "format", arg, arg, arg, ...));
  493. *
  494. * The format string is documented in EmitPal.
  495. *
  496. * End a procedure with one of the following:
  497. *
  498. * ExitProc();
  499. *
  500. * Procedure returns no value.
  501. *
  502. * ExitProcX();
  503. *
  504. * Procedure returns an arbitrary DWORD.
  505. *
  506. * ExitOleProc();
  507. *
  508. * Procedure returns an HRESULT (named "hres").
  509. *
  510. * ExitOleProcPpv(ppvOut);
  511. *
  512. * Procedure returns an HRESULT (named "hres") and, on success,
  513. * puts a new object in ppvOut.
  514. *
  515. *****************************************************************************/
  516. #define cpvArgMax 10 /* Max of 10 args per procedure */
  517. typedef struct ARGLIST {
  518. LPCSTR pszProc;
  519. LPCSTR pszFormat;
  520. PV rgpv[cpvArgMax];
  521. } ARGLIST, *PARGLIST;
  522. void EXTERNAL ArgsPalPszV(PARGLIST pal, LPCSTR psz, ...);
  523. void EXTERNAL EnterSqflPszPal(SQFL sqfl, LPCTSTR psz, PARGLIST pal);
  524. void EXTERNAL ExitSqflPalHresPpv(SQFL, PARGLIST, HRESULT, PPV);
  525. #ifdef DEBUG
  526. SQFL sqflCur;
  527. #define AssertFPtsz(c, ptsz) \
  528. ((c) ? 0 : AssertPtszPtszLn(ptsz, TEXT(__FILE__), __LINE__))
  529. #define ValidateF(c) \
  530. ((c) ? 0 : AssertPtszPtszLn(TEXT(#c), TEXT(__FILE__), __LINE__))
  531. #define D(x) x
  532. #define SetupEnterProc(nm) \
  533. static CHAR s_szProc[] = #nm; \
  534. ARGLIST _al[1] \
  535. #define _ _al,
  536. #define ppvBool ((PPV)1)
  537. #define ppvVoid ((PPV)2)
  538. #define DoEnterProc(v) \
  539. ArgsPalPszV v; \
  540. EnterSqflPszPal(sqfl, s_szProc, _al) \
  541. #define EnterProc(nm, v) \
  542. SetupEnterProc(nm); \
  543. DoEnterProc(v) \
  544. #define ExitOleProcPpv(ppv) \
  545. ExitSqflPalHresPpv(sqfl, _al, hres, (PPV)(ppv)) \
  546. #define ExitOleProc() \
  547. ExitOleProcPpv(0) \
  548. #define ExitProc() \
  549. ExitSqflPalHresPpv(sqfl, _al, 0, ppvVoid) \
  550. #define ExitProcX(x) \
  551. ExitSqflPalHresPpv(sqfl, _al, (HRESULT)(x), ppvBool) \
  552. #else
  553. #define AssertFPtsz(c, ptsz)
  554. #define ValidateF(c) (c)
  555. #define D(x)
  556. #define SetupEnterProc(nm)
  557. #define DoEnterProc(v)
  558. #define EnterProc(nm, v)
  559. #define ExitOleProcPpv(ppv)
  560. #define ExitOleProc()
  561. #define ExitProc()
  562. #endif
  563. #define AssertF(c) AssertFPtsz(c, TEXT(#c))
  564. /*****************************************************************************
  565. *
  566. * Macros that forward to the common handlers after squirting.
  567. * Use these only in DEBUG.
  568. *
  569. * It is assumed that sqfl has been #define'd to the appropriate sqfl.
  570. *
  571. *****************************************************************************/
  572. #ifdef DEBUG
  573. #define Default_QueryInterface(Class) \
  574. STDMETHODIMP \
  575. Class##_QueryInterface(PV pv, RIID riid, PPV ppvObj) \
  576. { \
  577. SquirtSqflPtszV(sqfl, TEXT(#Class) TEXT("_QueryInterface()")); \
  578. return Common_QueryInterface(pv, riid, ppvObj); \
  579. } \
  580. #define Default_AddRef(Class) \
  581. STDMETHODIMP_(ULONG) \
  582. Class##_AddRef(PV pv) \
  583. { \
  584. ULONG ulRc = _Common_AddRef(pv); \
  585. SquirtSqflPtszV(sqfl, TEXT(#Class) \
  586. TEXT("_AddRef(%08x) -> %d"), pv, ulRc); \
  587. return ulRc; \
  588. } \
  589. #define Default_Release(Class) \
  590. STDMETHODIMP_(ULONG) \
  591. Class##_Release(PV pv) \
  592. { \
  593. ULONG ulRc = _Common_Release(pv); \
  594. SquirtSqflPtszV(sqfl, TEXT(#Class) \
  595. TEXT("_Release(%08x) -> %d"), pv, ulRc); \
  596. return ulRc; \
  597. } \
  598. #endif
  599. /*****************************************************************************
  600. *
  601. * mem.c
  602. *
  603. * Be extremely careful with FreePv, because it doesn't work if
  604. * the pointer is null.
  605. *
  606. *****************************************************************************/
  607. STDMETHODIMP EXTERNAL ReallocCbPpv(UINT cb, PV ppvObj);
  608. STDMETHODIMP EXTERNAL AllocCbPpv(UINT cb, PV ppvObj);
  609. #define FreePpv(ppv) ReallocCbPpv(0, ppv)
  610. #define FreePv(pv) LocalFree((HLOCAL)(pv))
  611. #endif /* !RC_INVOKED */