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.

894 lines
25 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. ftpmcpl.cxx
  7. This is the main module for the FTP Server Control Panel Applet.
  8. It contains the "CplApplet" function.
  9. FILE HISTORY:
  10. YiHsinS 22-Mar-1993 Templated from Keithmo's srvmcpl.cxx.
  11. JonN 26-Jun-2000 CPlApplet takes HWND, UINT, LPARAM, LPARAM
  12. */
  13. #define INCL_NET
  14. #define INCL_NETLIB
  15. #define INCL_NETSERVICE
  16. #define INCL_WINDOWS
  17. #define INCL_WINDOWS_GDI
  18. #define INCL_NETERRORS
  19. #define INCL_DOSERRORS
  20. #include <lmui.hxx>
  21. #if defined(DEBUG)
  22. static const CHAR szFileName[] = __FILE__;
  23. #define _FILENAME_DEFINED_ONCE szFileName
  24. #endif
  25. #include <uiassert.hxx>
  26. #include <uitrace.hxx>
  27. #define INCL_BLT_WINDOW
  28. #define INCL_BLT_DIALOG
  29. #define INCL_BLT_CONTROL
  30. #define INCL_BLT_CLIENT
  31. #define INCL_BLT_MSGPOPUP
  32. #define INCL_BLT_EVENT
  33. #define INCL_BLT_MISC
  34. #define INCL_BLT_TIMER
  35. #define INCL_BLT_CC
  36. #include <blt.hxx>
  37. #include <dbgstr.hxx>
  38. #include <uatom.hxx>
  39. #include <regkey.hxx>
  40. #include <lmoloc.hxx>
  41. #include <srvsvc.hxx>
  42. extern "C"
  43. {
  44. #include <cpl.h> // Multimedia CPL defs
  45. #include <ftpmgr.h>
  46. #include <ftpd.h>
  47. }
  48. extern "C"
  49. {
  50. //
  51. // Control Panel Applet entry point.
  52. //
  53. LONG FAR PASCAL CPlApplet( HWND hwndCPl,
  54. UINT nMsg,
  55. LPARAM lParam1,
  56. LPARAM lparam2 );
  57. //
  58. // DLL load/unload entry point.
  59. //
  60. BOOL FAR PASCAL FtpMgrDllInitialize( HINSTANCE hInstance,
  61. DWORD nReason,
  62. LPVOID pReserved );
  63. //
  64. // Globals.
  65. //
  66. HINSTANCE _hCplInstance = NULL;
  67. } // extern "C"
  68. #include <ftpmgr.hxx>
  69. //
  70. // This is the "type" for an applet startup function.
  71. //
  72. typedef APIERR (* PCPL_APPLET_FUNC)( HWND hWnd );
  73. //
  74. // We'll keep one of these structures for each applet in this DLL.
  75. //
  76. typedef struct _CPL_APPLET
  77. {
  78. int idIcon;
  79. int idName;
  80. int idInfo;
  81. int idHelpFile;
  82. DWORD dwHelpContext;
  83. LONG lData;
  84. PCPL_APPLET_FUNC pfnApplet;
  85. } CPL_APPLET;
  86. //
  87. // Forward reference prototypes.
  88. //
  89. APIERR RunFtpSvcMgr( HWND hWnd );
  90. //
  91. // Our applet descriptors.
  92. //
  93. CPL_APPLET CplApplets[] = {
  94. { // FTP Server applet
  95. IDI_FTPCPA_ICON,
  96. IDS_FTPCPA_NAME_STRING,
  97. IDS_FTPCPA_INFO_STRING,
  98. IDS_CPL_HELPFILENAME,
  99. HC_FTPSVCMGR_DIALOG,
  100. 0L,
  101. &RunFtpSvcMgr
  102. }
  103. };
  104. #define NUM_APPLETS ( sizeof(CplApplets) / sizeof(CplApplets[0]) )
  105. /*******************************************************************
  106. NAME: InitializeDll
  107. SYNOPSIS: Perform DLL initialiazation functions on a
  108. once-per-process basis.
  109. ENTRY: hInstance - Program instance of the caller.
  110. EXIT: If this is the first initialization request for this
  111. process, then all necessary BLT initializers have
  112. been invoked.
  113. RETURNS: BOOL - TRUE = Initialization OK.
  114. FALSE = Initialization failed.
  115. HISTORY:
  116. YiHsinS 22-Mar-1993 Templated from Keithmo's srvmcpl.cxx.
  117. ********************************************************************/
  118. BOOL InitializeDll( HINSTANCE hInstance )
  119. {
  120. //
  121. // Save the instance handle.
  122. //
  123. _hCplInstance = hInstance;
  124. return TRUE;
  125. } // InitializeDll
  126. /*******************************************************************
  127. NAME: TerminateDll
  128. SYNOPSIS: Perform DLL termination functions on a
  129. once-per-process basis.
  130. EXIT: All necessary BLT terminators have been invoked.
  131. HISTORY:
  132. YiHsinS 22-Mar-1993 Templated from Keithmo's srvmcpl.cxx.
  133. ********************************************************************/
  134. VOID TerminateDll( VOID )
  135. {
  136. //
  137. // Just in case we try to do anything goofy.
  138. //
  139. _hCplInstance = NULL;
  140. } // TerminateDll
  141. /*******************************************************************
  142. NAME: IsFtpServerInstalled
  143. SYNOPSIS: Determines if the FTP Server service is installed.
  144. This doesn't necessarily mean the service is actually
  145. running, just that it is installed on the system.
  146. RETURNS: BOOL - TRUE = FTP Server service is installed.
  147. FALSE = FTP Server service isn't installed.
  148. NOTES: We could perform this check by trying to open the
  149. service via the Service Controller, but this would
  150. cause a lot of extraneous code to get paged in.
  151. Instead, we'll check for the presence of the registry
  152. key that controls the service.
  153. HISTORY:
  154. KeithMo 09-Apr-1993 Created.
  155. ********************************************************************/
  156. BOOL IsFtpServerInstalled( VOID )
  157. {
  158. BOOL fInstalled = FALSE; // until proven otherwise...
  159. //
  160. // Open the registry root.
  161. //
  162. REG_KEY RootKey( HKEY_LOCAL_MACHINE );
  163. APIERR err = RootKey.QueryError();
  164. if( err == NERR_Success )
  165. {
  166. //
  167. // Open the FTPSVC registry key.
  168. //
  169. ALIAS_STR nlsKeyName( (TCHAR *)FTPD_PARAMETERS_KEY );
  170. UIASSERT( !!nlsKeyName );
  171. REG_KEY RegKey( RootKey, nlsKeyName );
  172. err = RegKey.QueryError();
  173. if( err == NERR_Success )
  174. {
  175. //
  176. // Since we successfully opened the FTP Server's
  177. // parameters key, we'll assume that the service
  178. // is indeed installed.
  179. //
  180. fInstalled = TRUE;
  181. }
  182. }
  183. return fInstalled;
  184. } // IsFtpServerInstalled
  185. /*******************************************************************
  186. NAME: InitializeAllApplets
  187. SYNOPSIS: Called before applet proper is run.
  188. ENTRY: hWnd - Window handle of parent window.
  189. RETURNS: BOOL - TRUE = Applet should be installed.
  190. FALSE = Applet cannot be installed.
  191. HISTORY:
  192. YiHsinS 22-Mar-1993 Templated from Keithmo's srvmcpl.cxx.
  193. KeithMo 09-Apr-1993 Don't init if service not installed.
  194. JonN 05-Oct-1994 Added lParam parameters to CPL_INIT, CPL_TERM
  195. JonN 22-Sep-1995 Only called when applet is run
  196. ********************************************************************/
  197. BOOL InitializeAllApplets( HWND hWnd, LPARAM lParam1, LPARAM lParam2 )
  198. {
  199. TRACEEOL( "FTPMGR.CPL: InitializeAllApplets enter" );
  200. //
  201. // Before we do anything, check to see if the FTP Server service
  202. // is installed. If it isn't there's not much point in running
  203. // this applet.
  204. //
  205. if( !IsFtpServerInstalled() )
  206. {
  207. return FALSE;
  208. }
  209. //
  210. // Initialize all of the NetUI goodies.
  211. //
  212. APIERR err = BLT::Init( _hCplInstance,
  213. IDRSRC_FTPMGR_BASE, IDRSRC_FTPMGR_LAST,
  214. IDS_UI_FTPMGR_BASE, IDS_UI_FTPMGR_LAST );
  215. TRACEEOL( "FTPMGR.CPL: InitializeAllApplets BLT::Init returns " << err );
  216. if( err == NERR_Success )
  217. {
  218. TRACEEOL( "FTPMGR.CPL: InitializeAllApplets BLT::_MASTER_TIMER::Init next" );
  219. err = BLT_MASTER_TIMER::Init();
  220. TRACEEOL( "FTPMGR.CPL: InitializeAllApplets BLT::_MASTER_TIMER::Init returns " << err );
  221. if( err != NERR_Success )
  222. {
  223. //
  224. // BLT initialized OK, but BLT_MASTER_TIMER
  225. // failed. So, before we bag-out, we must
  226. // deinitialize BLT.
  227. //
  228. BLT::Term( _hCplInstance );
  229. }
  230. }
  231. if( err == NERR_Success )
  232. {
  233. err = BLT::RegisterHelpFile( _hCplInstance,
  234. IDS_CPL_HELPFILENAME,
  235. HC_UI_FTPMGR_BASE,
  236. HC_UI_FTPMGR_LAST );
  237. if( err != NERR_Success )
  238. {
  239. //
  240. // This is the only place where we can safely
  241. // invoke MsgPopup, since we *know* that all of
  242. // the BLT goodies were initialized properly.
  243. //
  244. ::MsgPopup( hWnd, err );
  245. BLT::Term( _hCplInstance );
  246. }
  247. }
  248. TRACEEOL( "FTPMGR.CPL: InitializeAllApplets exit" );
  249. return err == NERR_Success;
  250. } // InitializeAllApplets
  251. /*******************************************************************
  252. NAME: TerminateAllApplets
  253. SYNOPSIS: Called after applet is run.
  254. ENTRY: hWnd - Window handle of parent window.
  255. HISTORY:
  256. YiHsinS 22-Mar-1993 Templated from Keithmo's srvmcpl.cxx.
  257. JonN 04-Oct-1994 Added lParam parameters to CPL_INIT, CPL_TERM
  258. JonN 22-Sep-1995 Only called when applet is run
  259. ********************************************************************/
  260. VOID TerminateAllApplets( HWND hWnd, LPARAM lParam1, LPARAM lParam2 )
  261. {
  262. UNREFERENCED( hWnd );
  263. TRACEEOL( "FTPMGR.CPL: TerminateAllApplets enter" );
  264. //
  265. // Kill the NetUI goodies.
  266. //
  267. BLT::DeregisterHelpFile( _hCplInstance, 0 );
  268. TRACEEOL( "FTPMGR.CPL: TerminateAllApplets BLT::_MASTER_TIMER::Term next" );
  269. BLT_MASTER_TIMER::Term();
  270. TRACEEOL( "FTPMGR.CPL: TerminateAllApplets BLT::_MASTER_TIMER::Term complete" );
  271. BLT::Term( _hCplInstance );
  272. TRACEEOL( "FTPMGR.CPL: TerminateAllApplets exit" );
  273. } // TerminateAllApplets
  274. /*******************************************************************
  275. NAME: AutoStartFtpServer
  276. SYNOPSIS: Check the state of the FTP Server service. If it
  277. isn't started, ask the user if it should be started.
  278. If the user wants us to start the service, start it.
  279. ENTRY: hWnd - Window handle of parent window.
  280. RETURNS: BOOL - TRUE == FTP Server service is running.
  281. FALSE == FTP Server service isn't running.
  282. This may indicate either an error
  283. or the user didn't want the service
  284. started. If an error occurs, this
  285. routine is responsible for displaying
  286. it to the user.
  287. HISTORY:
  288. KeithMo 09-Apr-1993 Created.
  289. ********************************************************************/
  290. BOOL AutoStartFtpServer( HWND hWnd )
  291. {
  292. BOOL fStarted = FALSE; // until proven otherwise...
  293. //
  294. // Get the "display name" for the local machine.
  295. //
  296. LOCATION loc( LOC_TYPE_LOCAL );
  297. NLS_STR nlsDisplayName;
  298. APIERR err = loc.QueryError();
  299. err = err ? err : nlsDisplayName.QueryError();
  300. err = err ? err : loc.QueryDisplayName( &nlsDisplayName );
  301. if( err == NERR_Success )
  302. {
  303. //
  304. // Determine the state of the service.
  305. //
  306. GENERIC_SERVICE * psvc = new GENERIC_SERVICE( hWnd,
  307. NULL,
  308. nlsDisplayName,
  309. (TCHAR *)FTPD_SERVICE_NAME );
  310. err = ( psvc == NULL ) ? ERROR_NOT_ENOUGH_MEMORY
  311. : psvc->QueryError();
  312. if( err == NERR_Success )
  313. {
  314. fStarted = psvc->IsInstalled( &err );
  315. if( !fStarted && ( err == NERR_Success ) )
  316. {
  317. //
  318. // Service isn't started. See if the user wants us
  319. // to start it.
  320. //
  321. if( ::MsgPopup( hWnd,
  322. IDS_START_FTPSVC_NOW,
  323. MPSEV_WARNING,
  324. MP_YESNO,
  325. MP_YES ) == IDYES )
  326. {
  327. err = psvc->Start();
  328. if( err == NERR_ServiceInstalled )
  329. {
  330. //
  331. // Somebody must have started the service
  332. // behind our backs...
  333. //
  334. err = NERR_Success;
  335. }
  336. if( err == NERR_Success )
  337. {
  338. //
  339. // Whew!
  340. //
  341. fStarted = TRUE;
  342. }
  343. }
  344. }
  345. }
  346. delete psvc;
  347. }
  348. //
  349. // If anything tragic occurred, tell the user.
  350. //
  351. if( err != NERR_Success )
  352. {
  353. ::MsgPopup( hWnd, err );
  354. }
  355. return fStarted;
  356. } // AutoStartFtpServer
  357. /*******************************************************************
  358. NAME: RunFtpSvcMgr
  359. SYNOPSIS: Invoke the main dialog of the FTP Server Control
  360. Panel Applet.
  361. ENTRY: hWnd - Window handle of parent window.
  362. RETURNS: APIERR
  363. HISTORY:
  364. YiHsinS 18-Mar-1993 Created
  365. KeithMo 09-Apr-1993 Autostart FTP service.
  366. ********************************************************************/
  367. APIERR RunFtpSvcMgr( HWND hWnd )
  368. {
  369. //
  370. // If the service isn't started, ask the user if
  371. // it should be started.
  372. //
  373. if( !AutoStartFtpServer( hWnd ) )
  374. {
  375. //
  376. // The user doesn't want to play right now.
  377. //
  378. return NERR_Success;
  379. }
  380. AUTO_CURSOR autocur;
  381. // In the control panel applet, we will only be focusing on
  382. // the local machine.
  383. POPUP::SetCaption( IDS_FTPCPA_CAPTION );
  384. FTP_SVCMGR_DIALOG * pDlg = new FTP_SVCMGR_DIALOG( hWnd,
  385. NULL ); // local computer
  386. APIERR err = ( pDlg == NULL ) ? ERROR_NOT_ENOUGH_MEMORY
  387. : pDlg->QueryError();
  388. if ( err == NERR_Success )
  389. err = pDlg->Process();
  390. delete pDlg;
  391. pDlg = NULL;
  392. if( err != NERR_Success )
  393. {
  394. if ( err == RPC_S_SERVER_UNAVAILABLE )
  395. err = IERR_FTP_SERVICE_UNAVAILABLE;
  396. ::MsgPopup( hWnd, err );
  397. }
  398. POPUP::ResetCaption();
  399. return err;
  400. } // RunFtpSvcMgr
  401. BOOL strLoad( INT idString, WCHAR * pszBuffer, INT cchBuffer )
  402. {
  403. int result = ::LoadString( ::_hCplInstance,
  404. idString,
  405. pszBuffer,
  406. cchBuffer );
  407. return ( result > 0 ) && ( result < cchBuffer );
  408. } // strLoad
  409. /*******************************************************************
  410. NAME: CPlApplet
  411. SYNOPSIS: Exported function to start the FTP Server Control
  412. Panel Applet.
  413. ENTRY: hwndCPl - Window handle of parent.
  414. nMsg - CPL user message (see CPL.H
  415. in WINDOWS\SHELL\CONTROL\H).
  416. lParam1 - Message-specific pointer.
  417. lParam2 - Message-specific pointer.
  418. RETURNS: LONG
  419. HISTORY:
  420. YiHsinS 22-Mar-1993 Templated from Keithmo's srvmcpl.cxx.
  421. JonN 04-Oct-1994 Added lParam parameters to CPL_INIT, CPL_TERM
  422. JonN 22-Sep-1995 BLT::Init only called when applet is run
  423. JonN 26-Jun-2000 CPlApplet takes HWND, UINT, LPARAM, LPARAM
  424. ********************************************************************/
  425. LONG FAR PASCAL CPlApplet( HWND hwndCPl,
  426. UINT nMsg,
  427. LPARAM lParam1,
  428. LPARAM lParam2 )
  429. {
  430. LPCPLINFO pCplInfo;
  431. LPNEWCPLINFO pNewInfo;
  432. LONG nResult = 0;
  433. switch( nMsg )
  434. {
  435. case CPL_INIT:
  436. //
  437. // This message is sent to indicate that CPlApplet() was found.
  438. //
  439. // lParam1 is not used, but we pass it anyway.
  440. //
  441. // lParam2 is -1 iff the DLL will be used only to confirm the
  442. // number of applets.
  443. //
  444. // Return TRUE if applet should be installed, FALSE otherwise.
  445. //
  446. // Before we do anything, check to see if the FTP Server service
  447. // is installed. If it isn't there's not much point in running
  448. // this applet.
  449. //
  450. return IsFtpServerInstalled();
  451. case CPL_GETCOUNT:
  452. //
  453. // This message is set to determine the number of applets contained
  454. // in this DLL.
  455. //
  456. // lParam1 and lParam2 are not used.
  457. //
  458. // Return the number of applets contained in this DLL.
  459. //
  460. return NUM_APPLETS;
  461. case CPL_INQUIRE:
  462. //
  463. // This message is sent once per applet to retrieve information
  464. // about each applet.
  465. //
  466. // lParam1 is the applet number to register.
  467. //
  468. // lParam2 is a pointer to a CPLINFO structure. The CPLINFO
  469. // structure's idIcon, idName, idInfo, and lData fields should
  470. // be initialized as appropriate for the applet.
  471. //
  472. // There is no return value.
  473. //
  474. pCplInfo = (LPCPLINFO)lParam2;
  475. if( lParam1 < NUM_APPLETS )
  476. {
  477. CPL_APPLET * pApplet = &CplApplets[lParam1];
  478. pCplInfo->idIcon = pApplet->idIcon;
  479. pCplInfo->idName = pApplet->idName;
  480. pCplInfo->idInfo = pApplet->idInfo;
  481. pCplInfo->lData = pApplet->lData;
  482. }
  483. break;
  484. case CPL_SELECT:
  485. //
  486. // This message is sent when the applet's icon has been
  487. // selected.
  488. //
  489. // lParam1 is the applet number that was selected.
  490. //
  491. // lParam2 is the applet's lData value.
  492. //
  493. // There is no return value.
  494. //
  495. break;
  496. case CPL_DBLCLK:
  497. //
  498. // This message is sent when the applet's icon has been
  499. // double-clicked. This message should initiate the
  500. // applet's dialog box.
  501. //
  502. // lParam1 is the applet number that was selected.
  503. //
  504. // lParam2 is the applet's lData value.
  505. //
  506. // There is no return value.
  507. //
  508. if( lParam1 < NUM_APPLETS )
  509. {
  510. if ((LONG)InitializeAllApplets( hwndCPl, lParam1, lParam2 ))
  511. {
  512. (CplApplets[lParam1].pfnApplet)( hwndCPl );
  513. TerminateAllApplets( hwndCPl, lParam1, lParam2 );
  514. }
  515. else
  516. {
  517. ASSERT( FALSE );
  518. }
  519. }
  520. break;
  521. case CPL_STOP:
  522. //
  523. // This message is sent once for each applet when the
  524. // control panel is shutting down. This message should
  525. // initiate applet specific cleanup.
  526. //
  527. // lParam1 is the applet number being stopped.
  528. //
  529. // lParam2 is the applet's lData value.
  530. //
  531. // There is no return value.
  532. //
  533. break;
  534. case CPL_EXIT:
  535. //
  536. // This message is sent just before the control panel calls
  537. // FreeLibrary. This message should initiate non applet
  538. // specific cleanup.
  539. //
  540. // lParam1 is not used, but we pass it anyway.
  541. //
  542. // lParam2 is -1 iff the DLL was used only to confirm the
  543. // number of applets.
  544. //
  545. // There is no return value.
  546. //
  547. break;
  548. case CPL_NEWINQUIRE:
  549. //
  550. // This message is basically the same as CPL_INQUIRE, except
  551. // lParam2 points to a NEWCPLINFO structure. This message will
  552. // be sent *before* CPL_INQUIRE. If the applet returns a non
  553. // zero value, then CPL_INQUIRE will not be sent.
  554. //
  555. // lParam1 is the applet number to register.
  556. //
  557. // lParam2 is a pointer to a NEWCPLINFO structure.
  558. //
  559. // Return TRUE this message was handled, otherwise return FALSE.
  560. //
  561. pNewInfo = (LPNEWCPLINFO)lParam2;
  562. if( lParam1 < NUM_APPLETS )
  563. {
  564. CPL_APPLET * pApplet = &CplApplets[lParam1];
  565. pNewInfo->dwSize = sizeof(*pNewInfo);
  566. pNewInfo->dwFlags = 0;
  567. pNewInfo->dwHelpContext = pApplet->dwHelpContext;
  568. pNewInfo->lData = pApplet->lData;
  569. pNewInfo->hIcon = ::LoadIcon( ::_hCplInstance,
  570. MAKEINTRESOURCE( pApplet->idIcon ) );
  571. if( ( pNewInfo->hIcon != NULL ) &&
  572. strLoad( pApplet->idName,
  573. pNewInfo->szName,
  574. sizeof(pNewInfo->szName) ) &&
  575. strLoad( pApplet->idInfo,
  576. pNewInfo->szInfo,
  577. sizeof(pNewInfo->szInfo) ) &&
  578. strLoad( pApplet->idHelpFile,
  579. pNewInfo->szHelpFile,
  580. sizeof(pNewInfo->szHelpFile) ) )
  581. {
  582. nResult = TRUE;
  583. }
  584. }
  585. break;
  586. default:
  587. //
  588. // Who knows. Ignore it.
  589. //
  590. break;
  591. }
  592. return nResult;
  593. } // CPlApplet
  594. /*******************************************************************
  595. NAME: FtpMgrDllInitialize
  596. SYNOPSIS: This DLL entry point is called when processes & threads
  597. are initialized and terminated, or upon calls to
  598. LoadLibrary() and FreeLibrary().
  599. ENTRY: hInstance - A handle to the DLL.
  600. nReason - Indicates why the DLL entry
  601. point is being called.
  602. pReserved - Reserved.
  603. RETURNS: BOOL - TRUE = DLL init was successful.
  604. FALSE = DLL init failed.
  605. NOTES: The return value is only relevant during processing of
  606. DLL_PROCESS_ATTACH notifications.
  607. HISTORY:
  608. YiHsinS 22-Mar-1993 Templated from Keithmo's srvmcpl.cxx.
  609. ********************************************************************/
  610. BOOL FAR PASCAL FtpMgrDllInitialize( HINSTANCE hInstance,
  611. DWORD nReason,
  612. LPVOID pReserved )
  613. {
  614. UNREFERENCED( pReserved );
  615. BOOL fResult = TRUE;
  616. switch( nReason )
  617. {
  618. case DLL_PROCESS_ATTACH:
  619. //
  620. // This notification indicates that the DLL is attaching to
  621. // the address space of the current process. This is either
  622. // the result of the process starting up, or after a call to
  623. // LoadLibrary(). The DLL should us this as a hook to
  624. // initialize any instance data or to allocate a TLS index.
  625. //
  626. // This call is made in the context of the thread that
  627. // caused the process address space to change.
  628. //
  629. fResult = InitializeDll( hInstance );
  630. break;
  631. case DLL_PROCESS_DETACH:
  632. //
  633. // This notification indicates that the calling process is
  634. // detaching the DLL from its address space. This is either
  635. // due to a clean process exit or from a FreeLibrary() call.
  636. // The DLL should use this opportunity to return any TLS
  637. // indexes allocated and to free any thread local data.
  638. //
  639. // Note that this notification is posted only once per
  640. // process. Individual threads do not invoke the
  641. // DLL_THREAD_DETACH notification.
  642. //
  643. TerminateDll();
  644. break;
  645. case DLL_THREAD_ATTACH:
  646. //
  647. // This notfication indicates that a new thread is being
  648. // created in the current process. All DLLs attached to
  649. // the process at the time the thread starts will be
  650. // notified. The DLL should use this opportunity to
  651. // initialize a TLS slot for the thread.
  652. //
  653. // Note that the thread that posts the DLL_PROCESS_ATTACH
  654. // notification will not post a DLL_THREAD_ATTACH.
  655. //
  656. // Note also that after a DLL is loaded with LoadLibrary,
  657. // only threads created after the DLL is loaded will
  658. // post this notification.
  659. //
  660. break;
  661. case DLL_THREAD_DETACH:
  662. //
  663. // This notification indicates that a thread is exiting
  664. // cleanly. The DLL should use this opportunity to
  665. // free any data stored in TLS indices.
  666. //
  667. break;
  668. default:
  669. //
  670. // Who knows? Just ignore it.
  671. //
  672. break;
  673. }
  674. return fResult;
  675. } // FtpMgrDllInitialize