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.

915 lines
19 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. globals.cxx
  5. Abstract:
  6. Contains global data items for WININET.DLL and initialization function
  7. Contents:
  8. GlobalDllInitialize
  9. GlobalDllTerminate
  10. GlobalDataInitialize
  11. GlobalDataTerminate
  12. IsHttp1_1
  13. SetOfflineUserState
  14. GetWininetUserName
  15. ChangeGlobalSettings
  16. Author:
  17. Richard L Firth (rfirth) 15-Jul-1995
  18. Revision History:
  19. 15-Jul-1995 rfirth
  20. Created
  21. 07-Oct-1998 joshco
  22. updated minor version number 1->2
  23. --*/
  24. #include <wininetp.h>
  25. #include <ntverp.h>
  26. #include <schnlsp.h>
  27. #include <persist.h>
  28. #include "autodial.h"
  29. #ifdef INCLUDE_CACHE
  30. #include "..\urlcache\cache.hxx"
  31. #endif
  32. //
  33. // WinHttpX major & minor versions - allow to be defined externally
  34. //
  35. #if !defined(WINHTTPX_MAJOR_VERSION)
  36. #define WINHTTPX_MAJOR_VERSION 5
  37. #endif
  38. #if !defined(WINHTTPX_MINOR_VERSION)
  39. #define WINHTTPX_MINOR_VERSION 1
  40. #endif
  41. //
  42. // external functions
  43. //
  44. #if INET_DEBUG
  45. VOID
  46. InitDebugSock(
  47. VOID
  48. );
  49. #endif
  50. //
  51. // global DLL state data
  52. //
  53. GLOBAL HINSTANCE GlobalDllHandle = NULL;
  54. GLOBAL DWORD GlobalPlatformType;
  55. GLOBAL DWORD GlobalPlatformVersion5;
  56. GLOBAL DWORD GlobalPlatformMillennium = FALSE;
  57. GLOBAL DWORD GlobalPlatformWhistler = FALSE;
  58. GLOBAL DWORD GlobalPlatformDotNet = FALSE;
  59. GLOBAL BOOL GlobalDataInitialized = FALSE;
  60. GLOBAL BOOL GlobalIsProcessNtService = FALSE;
  61. GLOBAL HANDLE g_hCompletionPort = NULL;
  62. GLOBAL LPOVERLAPPED g_lpCustomOverlapped = NULL;
  63. GLOBAL DWORD g_cNumIOCPThreads = 0;
  64. #if INET_DEBUG
  65. LONG g_cWSACompletions = 0;
  66. LONG g_cCustomCompletions = 0;
  67. #endif
  68. #if defined (INCLUDE_CACHE)
  69. GLOBAL LPOVERLAPPED g_lpCustomUserOverlapped = NULL;
  70. #if INET_DEBUG
  71. LONG g_cCustomUserCompletions = 0;
  72. LONG g_cCacheFileCompletions = 0;
  73. #endif
  74. #endif
  75. //
  76. // WinInet DLL version information (mainly for diagnostics)
  77. //
  78. #if !defined(VER_PRODUCTBUILD)
  79. #define VER_PRODUCTBUILD 0
  80. #endif
  81. GLOBAL DWORD InternetBuildNumber = VER_PRODUCTBUILD;
  82. //
  83. // transport-based time-outs, etc.
  84. //
  85. #ifndef unix
  86. GLOBAL const DWORD GlobalConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
  87. #else
  88. GLOBAL const DWORD GlobalConnectTimeout = 1 * 60 * 1000;
  89. #endif /* unix */
  90. GLOBAL const DWORD GlobalResolveTimeout = DEFAULT_RESOLVE_TIMEOUT;
  91. GLOBAL const DWORD GlobalConnectRetries = DEFAULT_CONNECT_RETRIES;
  92. GLOBAL const DWORD GlobalSendTimeout = DEFAULT_SEND_TIMEOUT;
  93. GLOBAL const DWORD GlobalReceiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
  94. GLOBAL const DWORD GlobalReceiveResponseTimeout = DEFAULT_RECEIVE_RESPONSE_TIMEOUT;
  95. GLOBAL const DWORD GlobalTransportPacketLength = DEFAULT_TRANSPORT_PACKET_LENGTH;
  96. GLOBAL const DWORD GlobalKeepAliveSocketTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
  97. GLOBAL const DWORD GlobalSocketSendBufferLength = DEFAULT_SOCKET_SEND_BUFFER_LENGTH;
  98. GLOBAL const DWORD GlobalSocketReceiveBufferLength = DEFAULT_SOCKET_RECEIVE_BUFFER_LENGTH;
  99. GLOBAL const DWORD GlobalMaxHttpRedirects = DEFAULT_MAX_HTTP_REDIRECTS;
  100. GLOBAL const DWORD GlobalMaxHttpStatusContinues = 10;
  101. GLOBAL const DWORD GlobalConnectionInactiveTimeout = DEFAULT_CONNECTION_INACTIVE_TIMEOUT;
  102. GLOBAL const DWORD GlobalServerInfoTimeout = DEFAULT_SERVER_INFO_TIMEOUT;
  103. GLOBAL const DWORD GlobalMaxSizeStatusLineResultText = 1024;
  104. GLOBAL const DWORD GlobalMaxHeaderSize = (64 * 1024);
  105. GLOBAL const DWORD GlobalMaxDrainSize = (1000 * 1024);
  106. //
  107. // switches
  108. //
  109. GLOBAL BOOL InDllCleanup = FALSE;
  110. GLOBAL BOOL GlobalDynaUnload = FALSE;
  111. //
  112. // AutoDetect Proxy Globals
  113. //
  114. GLOBAL LONG GlobalInternetOpenHandleCount = -1;
  115. GLOBAL DWORD GlobalProxyVersionCount = 0;
  116. GLOBAL BOOL GlobalAutoProxyInInit = FALSE;
  117. GLOBAL BOOL GlobalAutoProxyCacheEnable = TRUE;
  118. GLOBAL BOOL GlobalDisplayScriptDownloadFailureUI = FALSE;
  119. //
  120. // Workaround for Novell's Client32
  121. //
  122. GLOBAL const BOOL fDontUseDNSLoadBalancing = FALSE;
  123. //
  124. // lists
  125. //
  126. #if INET_DEBUG
  127. GLOBAL SERIALIZED_LIST GlobalObjectList;
  128. #endif
  129. GLOBAL BOOL GlobalDisableNTLMPreAuth = FALSE;
  130. //
  131. // critical sections
  132. //
  133. GLOBAL CCritSec MlangCritSec;
  134. GLOBAL CCritSec GlobalDataInitCritSec;
  135. // Mlang related data and functions.
  136. PRIVATE HINSTANCE hInstMlang;
  137. PRIVATE PFNINETMULTIBYTETOUNICODE pfnInetMultiByteToUnicode;
  138. PRIVATE BOOL bFailedMlangLoad; // So we don't try repeatedly if we fail once.
  139. BOOL LoadMlang( );
  140. BOOL UnloadMlang( );
  141. #define MLANGDLLNAME "mlang.dll"
  142. //
  143. // novell client32 (hack) "support"
  144. //
  145. GLOBAL BOOL GlobalRunningNovellClient32 = FALSE;
  146. GLOBAL const BOOL GlobalNonBlockingClient32 = FALSE;
  147. //
  148. // proxy info
  149. //
  150. GLOBAL PROXY_INFO_GLOBAL * g_pGlobalProxyInfo;
  151. //
  152. // DLL version info
  153. //
  154. GLOBAL INTERNET_VERSION_INFO InternetVersionInfo = {
  155. WINHTTPX_MAJOR_VERSION,
  156. WINHTTPX_MINOR_VERSION
  157. };
  158. //
  159. // HTTP version info - default 1.1
  160. //
  161. GLOBAL HTTP_VERSION_INFO HttpVersionInfo = {1, 1};
  162. GLOBAL BOOL fCdromDialogActive = FALSE; // this needs to go
  163. //
  164. // The following globals are literal strings passed to winsock.
  165. // Do NOT make them const, otherwise they end up in .text section,
  166. // and web release of winsock2 has a bug where it locks and dirties
  167. // send buffers, confusing the win95 vmm and resulting in code
  168. // getting corrupted when it is paged back in. -RajeevD
  169. //
  170. GLOBAL char gszAt[] = "@";
  171. GLOBAL char gszBang[] = "!";
  172. GLOBAL char gszCRLF[] = "\r\n";
  173. GLOBAL LONG g_cSessionCount=0;
  174. GLOBAL CAsyncCount* g_pAsyncCount = NULL;
  175. // implemented in ihttprequest\httprequest.cxx:
  176. extern void CleanupWinHttpRequestGlobals();
  177. //
  178. // functions
  179. //
  180. #if 0
  181. /*
  182. BOOL AddEventSource(void)
  183. {
  184. HKEY hKey;
  185. DWORD dwData;
  186. CHAR szBuf[80];
  187. DWORD dwDispo;
  188. // Add your source name as a subkey under the Application
  189. // key in the EventLog registry key.
  190. if (RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  191. "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\WinHttp",
  192. 0,
  193. NULL,
  194. REG_OPTION_NON_VOLATILE,
  195. KEY_READ | KEY_WRITE,
  196. NULL,
  197. &hKey,
  198. &dwDispo) != ERROR_SUCCESS)
  199. {
  200. return FALSE;
  201. }
  202. if (dwDispo == REG_OPENED_EXISTING_KEY)
  203. {
  204. RegCloseKey(hKey);
  205. return TRUE;
  206. }
  207. // Set the name of the message file.
  208. strcpy(szBuf, "%SystemRoot%\\System32\\WinHttp.dll");
  209. // Add the name to the EventMessageFile subkey.
  210. if (RegSetValueEx(hKey, // subkey handle
  211. "EventMessageFile", // value name
  212. 0, // must be zero
  213. REG_EXPAND_SZ, // value type
  214. (LPBYTE) szBuf, // pointer to value data
  215. strlen(szBuf) + 1) != ERROR_SUCCESS) // length of value data
  216. {
  217. RegCloseKey(hKey);
  218. return FALSE;
  219. }
  220. // Set the supported event types in the TypesSupported subkey.
  221. dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
  222. EVENTLOG_INFORMATION_TYPE;
  223. if (RegSetValueEx(hKey, // subkey handle
  224. "TypesSupported", // value name
  225. 0, // must be zero
  226. REG_DWORD, // value type
  227. (LPBYTE) &dwData, // pointer to value data
  228. sizeof(DWORD)) != ERROR_SUCCESS) // length of value data
  229. {
  230. RegCloseKey(hKey);
  231. return FALSE;
  232. }
  233. RegCloseKey(hKey);
  234. return TRUE;
  235. }
  236. HANDLE g_hEventLog = 0;
  237. BOOL InitializeEventLog(void)
  238. {
  239. if (AddEventSource() == FALSE)
  240. {
  241. return FALSE;
  242. }
  243. g_hEventLog = ::RegisterEventSourceA(NULL, "WinHttp");
  244. return g_hEventLog != NULL;
  245. }
  246. void TerminateEventLog(void)
  247. {
  248. if (g_hEventLog)
  249. {
  250. ::DeregisterEventSource(g_hEventLog);
  251. g_hEventLog = NULL;
  252. }
  253. }
  254. */
  255. #endif
  256. #ifdef UNIX
  257. extern "C"
  258. #endif /* UNIX */
  259. BOOL
  260. GlobalDllInitialize(
  261. VOID
  262. )
  263. /*++
  264. Routine Description:
  265. The set of initializations - critical sections, etc. - that must be done at
  266. DLL_PROCESS_ATTACH
  267. Arguments:
  268. None.
  269. Return Value:
  270. TRUE, only FALSE when not enough memory to initialize globals
  271. --*/
  272. {
  273. BOOL fResult = FALSE;
  274. DEBUG_ENTER((DBG_GLOBAL,
  275. Bool,
  276. "GlobalDllInitialize",
  277. NULL
  278. ));
  279. CLEAR_DEBUG_CRIT(szDebugBlankBuffer);
  280. if (MlangCritSec.Init() &&
  281. #if INET_DEBUG
  282. InitializeSerializedList(&GlobalObjectList) &&
  283. #endif
  284. AuthOpen() &&
  285. IwinsockInitialize() &&
  286. SecurityInitialize() &&
  287. GlobalDataInitCritSec.Init() &&
  288. DIGEST_CTX::s_CritSection.Init()
  289. #ifdef INCLUDE_CACHE
  290. &&
  291. DLLUrlCacheEntry(DLL_PROCESS_ATTACH)
  292. #endif
  293. )
  294. {
  295. fResult = TRUE;
  296. }
  297. DEBUG_LEAVE(fResult);
  298. return fResult;
  299. }
  300. #ifdef UNIX
  301. extern "C"
  302. #endif /* UNIX */
  303. VOID
  304. GlobalDllTerminate(
  305. VOID
  306. )
  307. /*++
  308. Routine Description:
  309. Undoes the initializations of GlobalDllInitialize
  310. Arguments:
  311. None.
  312. Return Value:
  313. None.
  314. --*/
  315. {
  316. DEBUG_ENTER((DBG_GLOBAL,
  317. None,
  318. "GlobalDllTerminate",
  319. NULL
  320. ));
  321. //
  322. // only perform resource clean-up if this DLL is being unloaded due to a
  323. // FreeLibrary() call. Otherwise, we take the lazy way out and let the
  324. // system clean up after us
  325. //
  326. if (GlobalDynaUnload) {
  327. TerminateAsyncSupport(TRUE);
  328. IwinsockTerminate();
  329. HandleTerminate();
  330. }
  331. CHECK_SOCKETS();
  332. AuthClose();
  333. CTracer::s_CritSectionTraceInit.FreeLock();
  334. #if INET_DEBUG
  335. //
  336. //BUGBUG: we can't Terminate the list here because
  337. // of a race condition from IE3
  338. // (someone still holds the handle)
  339. // but we don't want to leak the CritSec
  340. // TerminateSerlizedList == DeleteCritSec + some Asserts
  341. //
  342. //TerminateSerializedList(&GlobalObjectList);
  343. GlobalObjectList.Lock.FreeLock();
  344. #endif
  345. MlangCritSec.FreeLock();
  346. GlobalDataInitCritSec.FreeLock();
  347. DIGEST_CTX::s_CritSection.FreeLock();
  348. SecurityTerminate();
  349. DLOleTerminate();
  350. #ifdef INCLUDE_CACHE
  351. DLLUrlCacheEntry(DLL_PROCESS_DETACH);
  352. #endif
  353. //Close this here because keepalive sync sockets may depend on it.
  354. if (g_hCompletionPort)
  355. {
  356. CloseHandle(g_hCompletionPort);
  357. g_hCompletionPort = NULL;
  358. }
  359. if (g_lpCustomOverlapped)
  360. {
  361. delete g_lpCustomOverlapped;
  362. g_lpCustomOverlapped = NULL;
  363. }
  364. #if defined (INCLUDE_CACHE)
  365. if (g_lpCustomUserOverlapped)
  366. {
  367. delete g_lpCustomUserOverlapped;
  368. g_lpCustomUserOverlapped = NULL;
  369. }
  370. #endif
  371. DEBUG_LEAVE(0);
  372. }
  373. DWORD
  374. GlobalDataInitialize(
  375. VOID
  376. )
  377. /*++
  378. Routine Description:
  379. Loads any global data items from the registry
  380. Arguments:
  381. None.
  382. Return Value:
  383. DWORD
  384. Success - ERROR_SUCCESS
  385. Failure - ERROR_NOT_ENOUGH_MEMORY
  386. --*/
  387. {
  388. DEBUG_ENTER((DBG_GLOBAL,
  389. Dword,
  390. "GlobalDataInitialize",
  391. NULL
  392. ));
  393. static BOOL Initializing = FALSE;
  394. static BOOL Initialized = FALSE;
  395. static DWORD error = ERROR_SUCCESS;
  396. //
  397. // only one thread initializes
  398. //
  399. if (!GlobalDataInitCritSec.Lock())
  400. {
  401. error = ERROR_NOT_ENOUGH_MEMORY;
  402. goto done;
  403. }
  404. if (Initializing)
  405. {
  406. //if re-entered on same thread, fail.
  407. error = ERROR_WINHTTP_NOT_INITIALIZED;
  408. goto leave;
  409. }
  410. else if (GlobalDataInitialized)
  411. {
  412. //else some other thread succeeded, and we can fall out.
  413. error = ERROR_SUCCESS;
  414. goto leave;
  415. }
  416. else if (Initialized)
  417. {
  418. //else if we've failed initialization for non-entrancy reasons, don't reattempt
  419. error = ERROR_WINHTTP_INTERNAL_ERROR;
  420. goto leave;
  421. }
  422. Initializing = TRUE;
  423. //Ensure that the GlobalDataInitCritSec function is never abandoned.
  424. __try
  425. {
  426. //
  427. // create the global proxy lists
  428. //
  429. INET_ASSERT(g_pGlobalProxyInfo==NULL);
  430. g_pGlobalProxyInfo = New PROXY_INFO_GLOBAL();
  431. if (!g_pGlobalProxyInfo)
  432. {
  433. error = ERROR_NOT_ENOUGH_MEMORY;
  434. goto quit;
  435. }
  436. g_pGlobalProxyInfo->InitializeProxySettings();
  437. //
  438. // Load proxy config settings from registry...
  439. //
  440. error = LoadProxySettings();
  441. if (error != ERROR_SUCCESS)
  442. goto quit;
  443. //
  444. // perform module/package-specific initialization
  445. //
  446. error = HandleInitialize();
  447. if (error != ERROR_SUCCESS) {
  448. goto quit;
  449. }
  450. g_pGlobalServerInfoPool = New CGlobalServerInfoPool();
  451. if (!g_pGlobalServerInfoPool
  452. || !g_pGlobalServerInfoPool->Initialize())
  453. {
  454. error = ERROR_NOT_ENOUGH_MEMORY;
  455. }
  456. char buf[MAX_PATH + 1];
  457. if (GetModuleFileName(NULL, buf, sizeof(buf)-1)) // leave room for null char
  458. {
  459. buf[sizeof(buf)-1] = '\0'; // guarantee null-termination
  460. LPSTR p = strrchr(buf, DIR_SEPARATOR_CHAR);
  461. p = p ? ++p : buf;
  462. DEBUG_PRINT(GLOBAL, INFO, ("process is %q\n", p));
  463. if (!lstrcmpi(p, "SVCHOST.EXE") || !lstrcmpi(p, "SERVICES.EXE"))
  464. {
  465. GlobalIsProcessNtService = TRUE;
  466. }
  467. }
  468. else
  469. {
  470. DEBUG_PRINT(GLOBAL,
  471. INFO,
  472. ("GetModuleFileName() returns %d\n",
  473. GetLastError()
  474. ));
  475. }
  476. XStringInitialize();
  477. }
  478. __except(EXCEPTION_EXECUTE_HANDLER)
  479. {
  480. error = ERROR_NOT_ENOUGH_MEMORY;
  481. goto leave_change_state;
  482. }
  483. ENDEXCEPT
  484. quit:
  485. if (error == ERROR_SUCCESS) {
  486. GlobalDataInitialized = TRUE;
  487. }
  488. leave_change_state:
  489. //
  490. // irrespective of success or failure, we have attempted global data
  491. // initialization. If we failed then we assume its something fundamental
  492. // and fatal: we don't try again
  493. //
  494. Initialized = TRUE;
  495. Initializing = FALSE;
  496. //jump here if you grabbed GlobalDataInitCritSec but don't want to affect Init*
  497. leave:
  498. GlobalDataInitCritSec.Unlock();
  499. //jump here IFF you didn't grab GlobalDataInitCritSec
  500. done:
  501. DEBUG_LEAVE(error);
  502. return error;
  503. }
  504. VOID
  505. GlobalDataTerminate(
  506. VOID
  507. )
  508. /*++
  509. Routine Description:
  510. Undoes work of GlobalDataInitialize()
  511. Arguments:
  512. None.
  513. Return Value:
  514. None.
  515. --*/
  516. {
  517. DEBUG_ENTER((DBG_GLOBAL,
  518. None,
  519. "GlobalDataTerminate",
  520. NULL
  521. ));
  522. RIP(g_cSessionCount == 0);
  523. #ifndef WININET_SERVER_CORE
  524. //
  525. // Release background task manager
  526. //
  527. UnloadBackgroundTaskMgr();
  528. #endif
  529. AuthUnload();
  530. //
  531. // terminate the global proxy lists
  532. //
  533. if (g_pGlobalProxyInfo)
  534. {
  535. g_pGlobalProxyInfo->TerminateProxySettings();
  536. delete g_pGlobalProxyInfo;
  537. g_pGlobalProxyInfo = NULL;
  538. }
  539. if (g_pGlobalServerInfoPool)
  540. {
  541. g_pGlobalServerInfoPool->Terminate();
  542. delete g_pGlobalServerInfoPool;
  543. g_pGlobalServerInfoPool = NULL;
  544. }
  545. UnloadMlang();
  546. UnloadSecurity();
  547. UnloadAutoProxy();
  548. ExitAutodialModule();
  549. CleanupWinHttpRequestGlobals();
  550. XStringUninitialize();
  551. UnloadWinsock(TRUE);
  552. GlobalDataInitialized = FALSE;
  553. DEBUG_LEAVE(0);
  554. }
  555. BOOL
  556. IsHttp1_1(
  557. VOID
  558. )
  559. /*++
  560. Routine Description:
  561. Determine if we are using HTTP 1.1 or greater
  562. Arguments:
  563. None.
  564. Return Value:
  565. BOOL
  566. --*/
  567. {
  568. return (HttpVersionInfo.dwMajorVersion > 1)
  569. ? TRUE
  570. : (((HttpVersionInfo.dwMajorVersion == 1)
  571. && (HttpVersionInfo.dwMajorVersion >= 1))
  572. ? TRUE
  573. : FALSE);
  574. }
  575. VOID
  576. ChangeGlobalSettings(
  577. VOID
  578. )
  579. /*++
  580. Routine Description:
  581. Changes global settings
  582. Arguments:
  583. None.
  584. Return Value:
  585. None.
  586. --*/
  587. {
  588. DEBUG_ENTER((DBG_GLOBAL,
  589. None,
  590. "ChangeGlobalSettings",
  591. NULL
  592. ));
  593. DEBUG_LEAVE(0);
  594. }
  595. // Loads Mlang.dll and get the entry point we are interested in.
  596. BOOL LoadMlang( )
  597. {
  598. if (!MlangCritSec.Lock())
  599. goto quit;
  600. if (hInstMlang == NULL && !bFailedMlangLoad)
  601. {
  602. INET_ASSERT(pfnInetMultiByteToUnicode == NULL);
  603. hInstMlang = LoadLibrary(MLANGDLLNAME);
  604. if (hInstMlang != NULL)
  605. {
  606. pfnInetMultiByteToUnicode = (PFNINETMULTIBYTETOUNICODE)GetProcAddress
  607. (hInstMlang,"ConvertINetMultiByteToUnicode");
  608. if (pfnInetMultiByteToUnicode == NULL)
  609. {
  610. INET_ASSERT(FALSE);
  611. FreeLibrary(hInstMlang);
  612. hInstMlang = NULL;
  613. }
  614. }
  615. else
  616. {
  617. INET_ASSERT(FALSE); // bad news if we can't load mlang.dll
  618. }
  619. if (pfnInetMultiByteToUnicode == NULL)
  620. bFailedMlangLoad = TRUE;
  621. }
  622. MlangCritSec.Unlock();
  623. quit:
  624. return (pfnInetMultiByteToUnicode != NULL);
  625. }
  626. BOOL UnloadMlang( )
  627. {
  628. if (!MlangCritSec.Lock())
  629. return FALSE;
  630. if (hInstMlang)
  631. FreeLibrary(hInstMlang);
  632. hInstMlang = NULL;
  633. pfnInetMultiByteToUnicode = NULL;
  634. bFailedMlangLoad = FALSE;
  635. MlangCritSec.Unlock();
  636. return TRUE;
  637. }
  638. PFNINETMULTIBYTETOUNICODE GetInetMultiByteToUnicode( )
  639. {
  640. // We are checking for pfnInetMultiByteToUnicode without getting a crit section.
  641. // This works only because UnloadMlang is called at the Dll unload time.
  642. if (pfnInetMultiByteToUnicode == NULL)
  643. {
  644. LoadMlang( );
  645. }
  646. return pfnInetMultiByteToUnicode;
  647. }
  648. #if 0
  649. /*
  650. int cdecl _sprintf(char* buffer, char* format, va_list args);
  651. void LOG_EVENT(DWORD dwEventType, char* format, ...)
  652. {
  653. if (g_hEventLog == NULL)
  654. {
  655. return;
  656. }
  657. va_list args;
  658. int n;
  659. char *pBuffer = (char *) ALLOCATE_FIXED_MEMORY(1024);
  660. if (pBuffer == NULL)
  661. return;
  662. va_start(args, format);
  663. n = _sprintf(pBuffer, format, args);
  664. va_end(args);
  665. LPCSTR pszMessages[1];
  666. pszMessages[0] = &pBuffer[0];
  667. ::ReportEvent(g_hEventLog,
  668. (WORD)dwEventType,
  669. 0,
  670. dwEventType,
  671. NULL,
  672. 1,
  673. 0,
  674. &pszMessages[0],
  675. NULL);
  676. FREE_MEMORY(pBuffer);
  677. }
  678. */
  679. #endif