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.

116 lines
3.4 KiB

  1. // this file builds a "lib" (really just an .obj) for people who want to
  2. // use the kernel32.dll delay-load exception handler.
  3. #define DELAYLOAD_VERSION 0x0200
  4. #include <windows.h>
  5. #include <delayimp.h>
  6. // kernel32's base hmodule
  7. extern HANDLE BaseDllHandle;
  8. // prototype (implemented in kernl32p.lib)
  9. FARPROC
  10. DelayLoadFailureHook (
  11. LPCSTR pszDllName,
  12. LPCSTR pszProcName
  13. );
  14. // people who care about being notified of dll loadlibray will override this
  15. PfnDliHook __pfnDliNotifyHook2;
  16. // Instead of implementing a "notify hook" (__pfnDliNotifyHook2) or a
  17. // "failure hook" (__pfnDliFailureHook2) we are just going to up and implement
  18. // __delayLoadHelper2 which is the stub who's fn. pointer is filled in all
  19. // of the import tables for delayloaded entries.
  20. //
  21. // This will effectively bypass the linker's LoadLibrary/GetProcAddress thunk code
  22. // as we simply duplicate it here (most of this fn. was stolen from \vc7\delayhlp.cpp)
  23. FARPROC
  24. WINAPI
  25. __delayLoadHelper2(
  26. PCImgDelayDescr pidd,
  27. FARPROC * ppfnIATEntry
  28. )
  29. {
  30. UINT iINT;
  31. PCImgThunkData pitd;
  32. LPCSTR pszProcName;
  33. LPCSTR pszDllName = (LPCSTR)PFromRva(pidd->rvaDLLName, NULL);
  34. HMODULE* phmod = (HMODULE*)PFromRva(pidd->rvaHmod, NULL);
  35. PCImgThunkData pIAT = (PCImgThunkData)PFromRva(pidd->rvaIAT, NULL);
  36. PCImgThunkData pINT = (PCImgThunkData)PFromRva(pidd->rvaINT, NULL);
  37. FARPROC pfnRet = 0;
  38. HMODULE hmod = *phmod;
  39. // Calculate the index for the name in the import name table.
  40. // N.B. it is ordered the same as the IAT entries so the calculation
  41. // comes from the IAT side.
  42. //
  43. iINT = IndexFromPImgThunkData((PCImgThunkData)ppfnIATEntry, pIAT);
  44. pitd = &(pINT[iINT]);
  45. if (!IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal))
  46. {
  47. PIMAGE_IMPORT_BY_NAME pibn = (PIMAGE_IMPORT_BY_NAME)PFromRva((RVA)pitd->u1.AddressOfData, NULL);
  48. pszProcName = pibn->Name;
  49. }
  50. else
  51. {
  52. pszProcName = MAKEINTRESOURCEA(IMAGE_ORDINAL(pitd->u1.Ordinal));
  53. }
  54. if (hmod == 0)
  55. {
  56. hmod = LoadLibraryA(pszDllName);
  57. if (hmod != 0)
  58. {
  59. // Store the library handle. If it is already there, we infer
  60. // that another thread got there first, and we need to do a
  61. // FreeLibrary() to reduce the refcount
  62. //
  63. HMODULE hmodT = (HMODULE)InterlockedCompareExchangePointer((void**)phmod, (void*)hmod, NULL);
  64. if (hmodT == NULL)
  65. {
  66. DelayLoadInfo dli = {0};
  67. dli.cb = sizeof(dli);
  68. dli.szDll = pszDllName;
  69. dli.hmodCur = hmod;
  70. // call the notify hook to inform them that we have successfully LoadLibrary'ed a dll.
  71. // (we do this in case they want to free it when they unload)
  72. if (__pfnDliNotifyHook2 != NULL)
  73. {
  74. __pfnDliNotifyHook2(dliNoteEndProcessing, &dli);
  75. }
  76. }
  77. else
  78. {
  79. // some other thread beat us to loading this module, use the existing hmod
  80. FreeLibrary(hmod);
  81. hmod = hmodT;
  82. }
  83. }
  84. }
  85. if (hmod)
  86. {
  87. // Go for the procedure now.
  88. pfnRet = GetProcAddress(hmod, pszProcName);
  89. }
  90. if (pfnRet == 0)
  91. {
  92. pfnRet = DelayLoadFailureHook(pszDllName, pszProcName);
  93. }
  94. *ppfnIATEntry = pfnRet;
  95. return pfnRet;
  96. }