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.

477 lines
20 KiB

  1. // You are expected to #include this file from your private dllload.c.
  2. // WARNING! Failure to observe these rules will result in really subtle
  3. // (and horrible) runtime/build problems.
  4. //
  5. // WARNING! If you choose to delay-load a DLL, you **must** disable
  6. // import thunks for that DLL when you include its header file. For example,
  7. // you must #define _OLE32_ before you #include <ole32.h>. Otherwise,
  8. // what happens is that the linker ends up exporting your delayload thunk
  9. // (because it thinks it's an exported function because the header file
  10. // said so) and then everybody who links to your DLL will accidentally
  11. // use the delayload thunk instead of the original function. This is
  12. // particularly gruesome because this problem hoses every DLL in the system
  13. // **except for you**.
  14. //
  15. // WARNING! But if you are delay-loading an optional function and
  16. // you are statically linking to the target DLL for required functions
  17. // (e.g., you are delayloading an NT5-only function), then you should not
  18. // disable import thunks since you really do want import thunks for the
  19. // regular functions. The way do handle this is to delayload the function
  20. // with an alternate name (e.g., prepend an underscore) and use the MAP
  21. // version of the delay-load macros. Then in your global header file,
  22. // #define the function to its mapped name.
  23. //
  24. // End of warnings.
  25. // Delay loading mechanism. This allows you to write code as if you are
  26. // calling implicitly linked APIs, and yet have these APIs really be
  27. // explicitly linked. You can reduce the initial number of DLLs that
  28. // are loaded (load on demand) using this technique.
  29. //
  30. // Use the following macros to indicate which APIs/DLLs are delay-linked
  31. // and -loaded.
  32. //
  33. // DELAY_LOAD
  34. // DELAY_LOAD_HRESULT
  35. // DELAY_LOAD_SAFEARRAY
  36. // DELAY_LOAD_UINT
  37. // DELAY_LOAD_INT
  38. // DELAY_LOAD_VOID
  39. //
  40. // Use these macros for APIs that are exported by ordinal only.
  41. //
  42. // DELAY_LOAD_ORD
  43. // DELAY_LOAD_VOID_ORD
  44. //
  45. // Use these macros for APIs that only exist on the integrated-shell
  46. // installations (i.e., a new shell32 is on the system).
  47. //
  48. // DELAY_LOAD_SHELL
  49. // DELAY_LOAD_SHELL_HRESULT
  50. // DELAY_LOAD_SHELL_VOID
  51. //
  52. //
  53. // Use DELAY_LOAD_IE_* for APIs that come from BrowseUI. This used
  54. // to be important when BrowseUI was in the IEXPLORE directory, but
  55. // now it's in the System directory so the difference is pretty
  56. // meaningless.
  57. //
  58. // Use DELAY_LOAD_OCX_* for APIs that come from OCXs and not DLLs.
  59. //
  60. /**********************************************************************/
  61. #ifdef DEBUG
  62. void _DumpLoading(LPTSTR pszDLL, LPTSTR pszFunc)
  63. {
  64. #ifdef DF_DELAYLOADDLL
  65. if (g_dwDumpFlags & DF_DELAYLOADDLL)
  66. {
  67. TraceMsg(TF_ALWAYS, "DLLLOAD: Loading %s for the first time for %s",
  68. pszDLL, pszFunc);
  69. }
  70. #endif
  71. }
  72. #define ENSURE_LOADED(_hmod, _dll, _ext, pszfn) \
  73. (_hmod ? (_hmod) : (_DumpLoading(TEXT(#_dll) TEXT(".") TEXT(#_ext), pszfn), \
  74. _hmod = LoadLibraryA(#_dll "." #_ext)))
  75. #else
  76. #define ENSURE_LOADED(_hmod, _dll, _ext, pszfn) \
  77. (_hmod ? (_hmod) : (_hmod = LoadLibraryA(#_dll "." #_ext)))
  78. #endif // DEBUG
  79. /**********************************************************************/
  80. void _GetProcFromDLL(HMODULE* phmod, LPCSTR pszDLL, FARPROC* ppfn, LPCSTR pszProc)
  81. {
  82. #ifdef DEBUG
  83. CHAR szProcD[MAX_PATH];
  84. if (!IS_INTRESOURCE(pszProc)) {
  85. lstrcpynA(szProcD, pszProc, ARRAYSIZE(szProcD));
  86. } else {
  87. wsprintfA(szProcD, "(ordinal %d)", LOWORD((DWORD_PTR)pszProc));
  88. }
  89. #endif
  90. // If it's already loaded, return.
  91. if (*ppfn) {
  92. return;
  93. }
  94. if (*phmod == NULL) {
  95. #ifdef DEBUG
  96. #ifdef DF_DELAYLOADDLL
  97. if (g_dwDumpFlags & DF_DELAYLOADDLL)
  98. {
  99. TraceMsg(TF_ALWAYS, "DLLLOAD: Loading %s for the first time for %s",
  100. pszDLL, szProcD);
  101. }
  102. #endif
  103. if (g_dwBreakFlags & 0x00000080)
  104. {
  105. DebugBreak();
  106. }
  107. #endif
  108. *phmod = LoadLibraryA(pszDLL);
  109. #ifdef UNIX
  110. if (*phmod == NULL) {
  111. if (lstrcmpiA(pszDLL, "inetcpl.dll") == 0) {
  112. *phmod = LoadLibraryA("inetcpl.cpl");
  113. }
  114. }
  115. #endif
  116. if (*phmod == NULL) {
  117. return;
  118. }
  119. }
  120. #if defined(DEBUG) && defined(DF_DELAYLOADDLL)
  121. if (g_dwDumpFlags & DF_DELAYLOADDLL) {
  122. TraceMsg(TF_ALWAYS, "DLLLOAD: GetProc'ing %s from %s for the first time",
  123. pszDLL, szProcD);
  124. }
  125. #endif
  126. *ppfn = GetProcAddress(*phmod, pszProc);
  127. }
  128. #if defined(DEBUG) && defined(BROWSEUI_IN_IEXPLORE_DIRECTORY)
  129. void _GetProcFromSystemDLL(HMODULE* phmod, LPCSTR pszDLL, FARPROC* ppfn, LPCSTR pszProc)
  130. {
  131. #ifdef UNIX
  132. if (lstrcmpiA(pszDLL, "inetcpl.dll") == 0) {
  133. _GetProcFromDLL(phmod, "inetcpl.cpl", ppfn, pszProc);
  134. return;
  135. }
  136. #endif
  137. // You must use DELAY_LOAD_IE for BROWSEUI since BROWSEUI lives in the
  138. // IE directory, not the System directory.
  139. if (lstrcmpiA(pszDLL, "BROWSEUI.DLL") == 0) {
  140. ASSERT(!"Somebody used DELAY_LOAD instead of DELAY_LOAD_IE on BROWSEUI");
  141. }
  142. _GetProcFromDLL(phmod, pszDLL, ppfn, pszProc);
  143. }
  144. #else
  145. #define _GetProcFromSystemDLL _GetProcFromDLL
  146. #endif
  147. // NOTE: this takes two parameters that are the function name. the First (_fn) is the name that
  148. // NOTE: the function will be called in this DLL and the other (_fni) is the
  149. // NOTE: name of the function we will GetProcAddress. This helps get around functions that
  150. // NOTE: are defined in the header files with _declspec...
  151. //
  152. // HMODULE _hmod - where we cache the HMODULE (aka HINSTANCE)
  153. // _dll - Basename of the target DLL, not quoted
  154. // _ext - Extension of the target DLL, not quoted (usually DLL)
  155. // _ret - Data type of return value
  156. // _fnpriv - Local name for the function
  157. // _fn - Exported name for the function
  158. // _args - Argument list in the form (TYPE1 arg1, TYPE2 arg2, ...)
  159. // _nargs - Argument list in the form (arg1, arg2, ...)
  160. // _err - Return value if we can't call the actual function
  161. //
  162. #define DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll, _ext, _ret, _fnpriv, _fn, _args, _nargs, _err) \
  163. _ret __stdcall _fnpriv _args \
  164. { \
  165. static _ret (__stdcall *_pfn##_fn) _args = NULL; \
  166. _GetProcFromSystemDLL(&_hmod, #_dll "." #_ext, (FARPROC*)&_pfn##_fn, #_fn); \
  167. if (_pfn##_fn) \
  168. return _pfn##_fn _nargs; \
  169. return (_ret)_err; \
  170. }
  171. #define DELAY_LOAD_NAME_ERR(_hmod, _dll, _ret, _fnpriv, _fn, _args, _nargs, _err) \
  172. DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll, DLL, _ret, _fnpriv, _fn, _args, _nargs, _err)
  173. #define DELAY_LOAD_ERR(_hmod, _dll, _ret, _fn, _args, _nargs, _err) \
  174. DELAY_LOAD_NAME_ERR(_hmod, _dll, _ret, _fn, _fn, _args, _nargs, _err)
  175. #define DELAY_LOAD(_hmod, _dll, _ret, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, _ret, _fn, _args, _nargs, 0)
  176. #define DELAY_LOAD_HRESULT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, HRESULT, _fn, _args, _nargs, E_FAIL)
  177. #define DELAY_LOAD_SAFEARRAY(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, SAFEARRAY *, _fn, _args, _nargs, NULL)
  178. #define DELAY_LOAD_UINT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, UINT, _fn, _args, _nargs, 0)
  179. #define DELAY_LOAD_INT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, INT, _fn, _args, _nargs, 0)
  180. #define DELAY_LOAD_BOOL(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, BOOL, _fn, _args, _nargs, FALSE)
  181. #define DELAY_LOAD_BOOLEAN(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, BOOLEAN, _fn, _args, _nargs, FALSE)
  182. #define DELAY_LOAD_DWORD(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, DWORD, _fn, _args, _nargs, FALSE)
  183. #define DELAY_LOAD_LRESULT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, LRESULT, _fn, _args, _nargs, FALSE)
  184. #define DELAY_LOAD_WNET(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, DWORD, _fn, _args, _nargs, WN_NOT_SUPPORTED)
  185. #define DELAY_LOAD_LPVOID(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, LPVOID, _fn, _args, _nargs, 0)
  186. // the NAME variants allow the local function to be called something different from the imported
  187. // function to avoid dll linkage problems.
  188. #define DELAY_LOAD_NAME(_hmod, _dll, _ret, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, _ret, _fn, _fni, _args, _nargs, 0)
  189. #define DELAY_LOAD_NAME_HRESULT(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, HRESULT, _fn, _fni, _args, _nargs, E_FAIL)
  190. #define DELAY_LOAD_NAME_SAFEARRAY(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, SAFEARRAY *, _fn, _fni, _args, _nargs, NULL)
  191. #define DELAY_LOAD_NAME_UINT(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, UINT, _fn, _fni, _args, _nargs, 0)
  192. #define DELAY_LOAD_NAME_BOOL(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, BOOL, _fn, _fni, _args, _nargs, FALSE)
  193. #define DELAY_LOAD_NAME_DWORD(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, DWORD, _fn, _fni, _args, _nargs, 0)
  194. #define DELAY_LOAD_NAME_VOID(_hmod, _dll, _fn, _fni, _args, _nargs) \
  195. void __stdcall _fn _args \
  196. { \
  197. static void (__stdcall *_pfn##_fni) _args = NULL; \
  198. if (!ENSURE_LOADED(_hmod, _dll, DLL, TEXT(#_fni))) \
  199. { \
  200. AssertMsg(BOOLFROMPTR(_hmod), TEXT("LoadLibrary failed on ") ## TEXT(#_dll)); \
  201. return; \
  202. } \
  203. if (_pfn##_fni == NULL) \
  204. { \
  205. *(FARPROC*)&(_pfn##_fni) = GetProcAddress(_hmod, #_fni); \
  206. AssertMsg(BOOLFROMPTR(_pfn##_fni), TEXT("GetProcAddress failed on ") ## TEXT(#_fni)); \
  207. if (_pfn##_fni == NULL) \
  208. return; \
  209. } \
  210. _pfn##_fni _nargs; \
  211. }
  212. #define DELAY_LOAD_VOID(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_NAME_VOID(_hmod, _dll, _fn, _fn, _args, _nargs)
  213. // For private entrypoints exported by ordinal.
  214. #define DELAY_LOAD_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
  215. _ret __stdcall _fn _args \
  216. { \
  217. static _ret (__stdcall *_pfn##_fn) _args = NULL; \
  218. _GetProcFromSystemDLL(&_hmod, #_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  219. if (_pfn##_fn) \
  220. return _pfn##_fn _nargs; \
  221. return (_ret)_err; \
  222. }
  223. #define DELAY_LOAD_ORD(_hmod, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, 0)
  224. #define DELAY_LOAD_EXT_ORD(_hmod, _dll, _ext, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_ORD_ERR(_hmod, #_dll "." #_ext, _ret, _fn, _ord, _args, _nargs, 0)
  225. #define DELAY_LOAD_ORD_VOID(_hmod, _dll, _fn, _ord, _args, _nargs) \
  226. void __stdcall _fn _args \
  227. { \
  228. static void (__stdcall *_pfn##_fn) _args = NULL; \
  229. _GetProcFromSystemDLL(&_hmod, #_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  230. if (_pfn##_fn) \
  231. _pfn##_fn _nargs; \
  232. return; \
  233. }
  234. #define DELAY_LOAD_VOID_ORD DELAY_LOAD_ORD_VOID // cuz people mess this up all the time
  235. #define DELAY_LOAD_ORD_BOOL(_hmod, _dll, _fn, _ord, _args, _nargs) \
  236. DELAY_LOAD_ORD_ERR(_hmod, _dll, BOOL, _fn, _ord, _args, _nargs, 0)
  237. #define DELAY_LOAD_EXT(_hmod, _dll, _ext, _ret, _fn, _args, _nargs) \
  238. DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll, _ext, _ret, _fn, _fn, _args, _nargs, 0)
  239. #define DELAY_LOAD_EXT_WRAP(_hmod, _dll, _ext, _ret, _fnWrap, _fnOrig, _args, _nargs) \
  240. DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll, _ext, _ret, _fnWrap, _fnOrig, _args, _nargs, 0)
  241. #if defined(BROWSEUI_IN_IEXPLORE_DIRECTORY) || defined(UNIX)
  242. /*----------------------------------------------------------
  243. Purpose: Loads the DLL via a CLSID it is known to be registered for
  244. */
  245. void _GetProcFromCLSID(HMODULE* phmod, const CLSID *pclsid, FARPROC* ppfn, LPCSTR pszProc)
  246. {
  247. if (*phmod == NULL) {
  248. //
  249. // SHPinDLLOfCLSID does all the annoying work of opening the
  250. // appropriate registry key, doing REG_EXPAND_SZ, etc.
  251. // It also loads the DLL with exactly the same name that OLE does,
  252. // which is important because NT4 SP3 didn't like it when you loaded
  253. // a DLL sometimes via SFN and sometimes via LFN. (It would
  254. // think they were different DLLs, and two copies of it got loaded
  255. // into memory. Aigh!)
  256. //
  257. *phmod = (HMODULE)SHPinDllOfCLSID(pclsid);
  258. if (!*phmod)
  259. return;
  260. }
  261. // We don't know the name of the DLL, but fortunately _GetProcFromDLL
  262. // doesn't need it if *phmod is already filled in.
  263. ASSERT(*phmod);
  264. _GetProcFromDLL(phmod, "", ppfn, pszProc);
  265. }
  266. //
  267. // Private exports by ordinal for browseui. loads from the browseui in apppath dir
  268. //
  269. #ifndef UNIX
  270. #define DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
  271. _ret __stdcall _fn _args \
  272. { \
  273. static _ret (__stdcall *_pfn##_fn) _args = NULL; \
  274. _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  275. if (_pfn##_fn) \
  276. return _pfn##_fn _nargs; \
  277. return (_ret)_err; \
  278. }
  279. #else
  280. #define DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
  281. _ret __stdcall _fn _args \
  282. { \
  283. static _ret (__stdcall *_pfn##_fn) _args = NULL; \
  284. _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)#_fn); \
  285. if (_pfn##_fn) \
  286. return _pfn##_fn _nargs; \
  287. return (_ret)_err; \
  288. }
  289. #endif
  290. #ifndef UNIX
  291. #define DELAY_LOAD_IE_ORD_VOID(_hmod, _dll, _fn, _ord, _args, _nargs) \
  292. void __stdcall _fn _args \
  293. { \
  294. static void (__stdcall *_pfn##_fn) _args = NULL; \
  295. _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  296. if (_pfn##_fn) \
  297. _pfn##_fn _nargs; \
  298. return; \
  299. }
  300. #else
  301. #define DELAY_LOAD_IE_ORD_VOID(_hmod, _dll, _fn, _ord, _args, _nargs) \
  302. void __stdcall _fn _args \
  303. { \
  304. static void (__stdcall *_pfn##_fn) _args = NULL; \
  305. _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)#_fn); \
  306. if (_pfn##_fn) \
  307. _pfn##_fn _nargs; \
  308. return; \
  309. }
  310. #endif
  311. #else // BrowseUI is in the System directory
  312. #define DELAY_LOAD_IE_ORD_ERR DELAY_LOAD_ORD_ERR
  313. #define DELAY_LOAD_IE_ORD_VOID DELAY_LOAD_ORD_VOID
  314. #endif
  315. #define DELAY_LOAD_IE(_hmod, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, 0)
  316. #define DELAY_LOAD_IE_HRESULT(_hmod, _dll, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, HRESULT, _fn, _ord, _args, _nargs, E_FAIL)
  317. #define DELAY_LOAD_IE_BOOL(_hmod, _dll, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, BOOL, _fn, _ord, _args, _nargs, FALSE)
  318. #define DELAY_LOAD_IE_ORD(_hmod, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, 0)
  319. #ifndef NO_LOADING_OF_SHDOCVW_ONLY_FOR_WHICHPLATFORM
  320. /*----------------------------------------------------------
  321. Purpose: Performs a loadlibrary on the DLL only if the machine
  322. has the integrated shell installation.
  323. */
  324. void _SHGetProcFromDLL(HINSTANCE* phinst, LPCSTR pszDLL, FARPROC* ppfn, LPCSTR pszProc)
  325. {
  326. if (PLATFORM_INTEGRATED == WhichPlatform())
  327. _GetProcFromSystemDLL(phinst, pszDLL, ppfn, pszProc);
  328. else
  329. TraceMsg(TF_ERROR, "Could not load integrated shell version of %s for %d", pszDLL, pszProc);
  330. }
  331. #endif // NO_LOADING_OF_SHDOCVW_ONLY_FOR_WHICHPLATFORM
  332. //
  333. // Private exports by ordinal for integrated-shell installs
  334. //
  335. #define DELAY_LOAD_SHELL_ERR(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
  336. _ret __stdcall _fn _args \
  337. { \
  338. static _ret (__stdcall *_pfn##_fn) _args = NULL; \
  339. _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  340. if (_pfn##_fn) \
  341. return _pfn##_fn _nargs; \
  342. return (_ret)_err; \
  343. }
  344. #define DELAY_LOAD_SHELL(_hinst, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_SHELL_ERR(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, 0)
  345. #define DELAY_LOAD_SHELL_HRESULT(_hinst, _dll, _fn, _ord, _args, _nargs ) DELAY_LOAD_SHELL_ERR(_hinst, _dll, HRESULT, _fn, _ord, _args, _nargs, E_FAIL )
  346. #define DELAY_LOAD_SHELL_VOID(_hinst, _dll, _fn, _ord, _args, _nargs) \
  347. void __stdcall _fn _args \
  348. { \
  349. static void (__stdcall *_pfn##_fn) _args = NULL; \
  350. _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  351. if (_pfn##_fn) \
  352. _pfn##_fn _nargs; \
  353. return; \
  354. }
  355. // Following Macros are functionally same as above only that they are
  356. // using function name on UNIX rather than ordinals. The above macros
  357. // are left untouched because other dlls like shdocvw/shdoc401 still use
  358. // them.
  359. #ifndef UNIX
  360. #define DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _err, _realfn) \
  361. _ret __stdcall _fn _args \
  362. { \
  363. static _ret (__stdcall *_pfn##_fn) _args = NULL; \
  364. _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  365. if (_pfn##_fn) \
  366. return _pfn##_fn _nargs; \
  367. return (_ret)_err; \
  368. }
  369. #else
  370. #define DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _err, _realfn) \
  371. _ret __stdcall _fn _args \
  372. { \
  373. static _ret (__stdcall *_pfn##_fn) _args = NULL; \
  374. _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)#_realfn); \
  375. if (_pfn##_fn) \
  376. return _pfn##_fn _nargs; \
  377. return (_ret)_err; \
  378. }
  379. #endif
  380. #define DELAY_LOAD_SHELL_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _realfn) DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, 0, _realfn)
  381. #define DELAY_LOAD_SHELL_HRESULT_FN(_hinst, _dll, _fn, _ord, _args, _nargs, realfn) DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, HRESULT, _fn, _ord, _args, _nargs, E_FAIL, _realfn)
  382. #ifndef UNIX
  383. #define DELAY_LOAD_SHELL_VOID_FN(_hinst, _dll, _fn, _ord, _args, _nargs, _realfn) \
  384. void __stdcall _fn _args \
  385. { \
  386. static void (__stdcall *_pfn##_fn) _args = NULL; \
  387. _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
  388. if (_pfn##_fn) \
  389. _pfn##_fn _nargs; \
  390. return; \
  391. }
  392. #else
  393. #define DELAY_LOAD_SHELL_VOID_FN(_hinst, _dll, _fn, _ord, _args, _nargs, _realfn) \
  394. void __stdcall _fn _args \
  395. { \
  396. static void (__stdcall *_pfn##_fn) _args = NULL; \
  397. _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)#_realfn); \
  398. if (_pfn##_fn) \
  399. _pfn##_fn _nargs; \
  400. return; \
  401. }
  402. #endif