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.

884 lines
24 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: init.c
  6. //
  7. // This file contains the library entry points
  8. //
  9. // Usage and assumptions used in this DLL.
  10. //
  11. // 1) Message crackers are used. See windowsx.h and windowsx.txt.
  12. //
  13. // 2) Many functions are considered "member functions" of a
  14. // particular class. Because this is not C++, the function
  15. // names follow a special naming convention: "Class_Name".
  16. // In addition, it is common practice that the first
  17. // argument for these type of functions is a "this" pointer
  18. // to the particular object.
  19. //
  20. // History:
  21. // 08-06-93 ScottH Transferred from twin code
  22. //
  23. //---------------------------------------------------------------------------
  24. ///////////////////////////////////////////////////// INCLUDES
  25. #include "brfprv.h" // common headers
  26. #include <brfcasep.h>
  27. #define INITGUID // Initialize GUIDs
  28. #include <initguid.h>
  29. #include <oleguid.h>
  30. #include <coguid.h>
  31. #include <shlguid.h>
  32. #include <shguidp.h> // Contains CLSID_Briefcase
  33. #include "res.h"
  34. #include "recact.h"
  35. #ifdef DEBUG
  36. #include <debugstr.h>
  37. #endif
  38. //---------------------------------------------------------------------------
  39. // Per instance data
  40. //---------------------------------------------------------------------------
  41. HINSTANCE g_hinst = 0;
  42. TWINRESULT g_tr = TR_SUCCESS;
  43. // Debugging variables
  44. UINT g_uBreakFlags = 0; // Controls when to int 3
  45. UINT g_uTraceFlags = 0; // Controls what trace messages are spewed
  46. UINT g_uDumpFlags = 0; // Controls what structs get dumped
  47. // The delay mutex and the cs that protects the cRef is per-instance
  48. HANDLE g_hMutexDelay = NULL;
  49. static UINT g_cRefMutex = 0;
  50. static CRITICAL_SECTION s_csDelay = { 0 };
  51. //---------------------------------------------------------------------------
  52. // Global data
  53. //---------------------------------------------------------------------------
  54. CRITICAL_SECTION g_csSyncUI = { 0 };
  55. DEBUG_CODE( UINT g_cRefSyncUI = 0; )
  56. UINT g_cfBriefObj = 0;
  57. BOOL g_bMirroredOS = FALSE;
  58. // Use the helper macros in brfprv.h
  59. UINT g_cBusyRef = 0; // Semaphore
  60. UINT g_cBriefRef = 0; // Semaphore
  61. // Metrics
  62. int g_cxIconSpacing = 0;
  63. int g_cyIconSpacing = 0;
  64. int g_cxBorder = 0;
  65. int g_cyBorder = 0;
  66. int g_cxIcon = 0;
  67. int g_cyIcon = 0;
  68. int g_cxIconMargin = 0;
  69. int g_cyIconMargin = 0;
  70. int g_cxLabelMargin = 0;
  71. int g_cyLabelSpace = 0;
  72. int g_cxMargin = 0;
  73. // System colors
  74. COLORREF g_clrHighlightText = 0;
  75. COLORREF g_clrHighlight = 0;
  76. COLORREF g_clrWindowText = 0;
  77. COLORREF g_clrWindow = 0;
  78. HBRUSH g_hbrHighlight = 0;
  79. HBRUSH g_hbrWindow = 0;
  80. // Strings
  81. TCHAR g_szDBName[MAXPATHLEN];
  82. TCHAR g_szDBNameShort[MAXPATHLEN];
  83. // Get the system metrics we need
  84. void PRIVATE GetMetrics(WPARAM wParam) // wParam from WM_WININICHANGE
  85. {
  86. if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
  87. {
  88. g_cxIconSpacing = GetSystemMetrics( SM_CXICONSPACING );
  89. g_cyIconSpacing = GetSystemMetrics( SM_CYICONSPACING );
  90. g_cxBorder = GetSystemMetrics(SM_CXBORDER);
  91. g_cyBorder = GetSystemMetrics(SM_CYBORDER);
  92. g_cxIcon = GetSystemMetrics(SM_CXICON);
  93. g_cyIcon = GetSystemMetrics(SM_CYICON);
  94. g_cxIconMargin = g_cxBorder * 8;
  95. g_cyIconMargin = g_cyBorder * 2;
  96. g_cyLabelSpace = g_cyIconMargin + (g_cyBorder * 2);
  97. g_cxLabelMargin = (g_cxBorder * 2);
  98. g_cxMargin = g_cxBorder * 5;
  99. }
  100. }
  101. // Initializes colors
  102. void PRIVATE InitGlobalColors()
  103. {
  104. g_clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
  105. g_clrWindow = GetSysColor(COLOR_WINDOW);
  106. g_clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  107. g_clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
  108. g_hbrWindow = GetSysColorBrush(COLOR_WINDOW);
  109. g_hbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
  110. }
  111. // Initialize global strings
  112. void PRIVATE InitGlobalStrings()
  113. {
  114. SzFromIDS(IDS_BC_DATABASE, g_szDBName, ARRAYSIZE(g_szDBName));
  115. SzFromIDS(IDS_BC_DATABASE_SHORT, g_szDBNameShort, ARRAYSIZE(g_szDBNameShort));
  116. }
  117. // Initialize the DLL on the first PROCESS_ATTACH
  118. BOOL PRIVATE InitializeFirstTime(void)
  119. {
  120. BOOL bRet = FALSE;
  121. InitCommonControls();
  122. GetMetrics(0);
  123. CPATH_InitCS();
  124. CBS_InitCS();
  125. CRL_InitCS();
  126. if (!Atom_Init())
  127. goto Init_Cleanup;
  128. if (!CPATH_Init())
  129. goto Init_Cleanup;
  130. // We do not load the engine DLL until we really need it.
  131. // Initialize our global imagelist
  132. //
  133. g_cfBriefObj = RegisterClipboardFormat(CFSTR_BRIEFOBJECT);
  134. if (g_cfBriefObj == 0)
  135. goto Init_Cleanup;
  136. bRet = TRUE;
  137. Init_Cleanup:
  138. if (bRet == FALSE)
  139. {
  140. Atom_Term();
  141. }
  142. return bRet;
  143. }
  144. // Register window classes per process
  145. BOOL PRIVATE InitWindowClasses(HINSTANCE hinst)
  146. {
  147. return RecAct_Init(hinst);
  148. }
  149. // Terminate DLL on the last PROCESS_DETACH
  150. void PRIVATE FinalTerminate(HINSTANCE hinst)
  151. {
  152. CPATH_Term();
  153. Atom_Term();
  154. CRL_DeleteCS();
  155. CBS_DeleteCS();
  156. CPATH_DeleteCS();
  157. Mem_Terminate();
  158. }
  159. // Unregister window classes per process
  160. void PRIVATE TermWindowClasses(HINSTANCE hinst)
  161. {
  162. RecAct_Term(hinst);
  163. }
  164. // Purpose: Obtain ownership of the delay-calculation mutex
  165. // Returns: reference count
  166. UINT PUBLIC Delay_Own(void)
  167. {
  168. UINT cRef;
  169. EnterCriticalSection(&s_csDelay);
  170. {
  171. if (0 == g_cRefMutex++)
  172. {
  173. // Obtain ownership of the mutex. This will get released
  174. // when Delay_Release is called.
  175. LeaveCriticalSection(&s_csDelay);
  176. {
  177. MsgWaitObjectsSendMessage(1, &g_hMutexDelay, INFINITE);
  178. }
  179. EnterCriticalSection(&s_csDelay);
  180. TRACE_MSG(TF_GENERAL, TEXT("Set delay mutex"));
  181. }
  182. cRef = g_cRefMutex;
  183. }
  184. LeaveCriticalSection(&s_csDelay);
  185. return cRef;
  186. }
  187. /*----------------------------------------------------------
  188. Purpose: Release ownership of the delay-calculation mutex
  189. Returns: reference count
  190. Cond: --
  191. */
  192. UINT PUBLIC Delay_Release(void)
  193. {
  194. UINT cRef;
  195. EnterCriticalSection(&s_csDelay);
  196. {
  197. ASSERT(0 < g_cRefMutex);
  198. if (0 < g_cRefMutex)
  199. {
  200. if (0 == --g_cRefMutex)
  201. {
  202. ReleaseMutex(g_hMutexDelay);
  203. TRACE_MSG(TF_GENERAL, TEXT("Release delay mutex"));
  204. }
  205. }
  206. cRef = g_cRefMutex;
  207. }
  208. LeaveCriticalSection(&s_csDelay);
  209. return cRef;
  210. }
  211. void PUBLIC Brief_EnterExclusive(void)
  212. {
  213. EnterCriticalSection(&g_csSyncUI);
  214. #ifdef DEBUG
  215. g_cRefSyncUI++;
  216. #endif
  217. }
  218. void PUBLIC Brief_LeaveExclusive(void)
  219. {
  220. #ifdef DEBUG
  221. g_cRefSyncUI--;
  222. #endif
  223. LeaveCriticalSection(&g_csSyncUI);
  224. }
  225. BOOL ProcessAttach(HINSTANCE hDll)
  226. {
  227. DWORD dwLayout = 0;
  228. BOOL bSuccess = TRUE;
  229. SHFusionInitializeFromModule(hDll);
  230. bSuccess = InitializeCriticalSectionAndSpinCount(&g_csSyncUI, 0);
  231. if (bSuccess)
  232. {
  233. bSuccess = InitializeCriticalSectionAndSpinCount(&s_csDelay, 0);
  234. if (bSuccess)
  235. {
  236. g_hinst = hDll;
  237. #ifdef DEBUG
  238. // We do this simply to load the debug .ini flags
  239. ProcessIniFile();
  240. DEBUG_BREAK(BF_ONPROCESSATT);
  241. #endif
  242. // Under NT, we need to initialize on every process attach, not just the first
  243. bSuccess = InitializeFirstTime();
  244. if (bSuccess)
  245. {
  246. // security: Changing to unnamed mutex to avoid any possible
  247. // squatting issues. Handle is global and accessible
  248. // across process.
  249. g_hMutexDelay = CreateMutex(NULL, FALSE, NULL);
  250. bSuccess = (NULL != g_hMutexDelay);
  251. }
  252. if (bSuccess)
  253. {
  254. // (Only do this if we succeeded above)
  255. //
  256. // Do the following for every process
  257. bSuccess = InitWindowClasses(hDll);
  258. }
  259. InitGlobalColors();
  260. InitGlobalStrings();
  261. //Bug 199701, 199647, 199699
  262. //Apparently this is either broke or never worked: g_bMirroredOS = IS_MIRRORING_ENABLED();
  263. GetProcessDefaultLayout(&dwLayout);
  264. if (dwLayout == LAYOUT_RTL)
  265. {
  266. g_bMirroredOS = TRUE;
  267. }
  268. //End bug 199701, 199647, 199699
  269. }
  270. }
  271. return bSuccess;
  272. }
  273. BOOL ProcessDetach(HINSTANCE hDll)
  274. {
  275. BOOL bSuccess = TRUE;
  276. ASSERT(hDll == g_hinst);
  277. DEBUG_CODE( DEBUG_BREAK(BF_ONPROCESSDET); )
  278. ASSERT(0 == g_cRefMutex);
  279. if (g_hMutexDelay)
  280. {
  281. CloseHandle(g_hMutexDelay);
  282. g_hMutexDelay = NULL;
  283. }
  284. FinalTerminate(g_hinst);
  285. Sync_ReleaseVTable();
  286. DeleteCriticalSection(&g_csSyncUI);
  287. DeleteCriticalSection(&s_csDelay);
  288. TermWindowClasses(hDll);
  289. SHFusionUninitialize();
  290. return bSuccess;
  291. }
  292. BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, void *lpReserved)
  293. {
  294. switch(dwReason)
  295. {
  296. case DLL_PROCESS_ATTACH:
  297. ProcessAttach(hDll);
  298. #ifndef DEBUG
  299. DisableThreadLibraryCalls(hDll);
  300. #endif
  301. break;
  302. case DLL_PROCESS_DETACH:
  303. ProcessDetach(hDll);
  304. break;
  305. case DLL_THREAD_ATTACH:
  306. #ifdef DEBUG
  307. // We do this simply to load the debug .ini flags
  308. ProcessIniFile();
  309. #endif
  310. break;
  311. case DLL_THREAD_DETACH:
  312. #ifdef DEBUG
  313. DEBUG_BREAK(BF_ONTHREADDET);
  314. #endif
  315. break;
  316. default:
  317. break;
  318. }
  319. return TRUE;
  320. }
  321. /*----------------------------------------------------------
  322. Purpose: Registers property sheet and context menu extensions
  323. for the briefcase.
  324. Returns: TRUE on success
  325. Cond: --
  326. */
  327. BOOL PRIVATE RegisterShellExtension(void)
  328. {
  329. const static TCHAR c_szPage[] = STRREG_SHEX_PROPSHEET TEXT("\\BriefcasePage");
  330. const static TCHAR c_szCM[] = STRREG_SHEX_MENUHANDLER TEXT("\\BriefcaseMenu");
  331. const static TCHAR c_szFolder[] = TEXT("Folder");
  332. const static TCHAR c_szStar[] = TEXT("*");
  333. const static TCHAR c_szFmt[] = TEXT("SOFTWARE\\Classes\\%s\\%s");
  334. // This must be per instance, else it will cause a fixup in
  335. // shared data segment.
  336. const static LPCTSTR rgpsz[2] = { c_szFolder, c_szStar };
  337. TCHAR sz[MAXBUFLEN];
  338. int i;
  339. for (i = 0; i < ARRAYSIZE(rgpsz); i++)
  340. {
  341. // Add briefcase page extension
  342. wnsprintf(sz, ARRAYSIZE(sz), c_szFmt, (LPCTSTR)rgpsz[i], (LPCTSTR)c_szPage);
  343. RegSetValue(HKEY_LOCAL_MACHINE, sz, REG_SZ, c_szCLSID, lstrlen(c_szCLSID));
  344. // Add briefcase context menu extension
  345. wnsprintf(sz, ARRAYSIZE(sz), c_szFmt, (LPCTSTR)rgpsz[i], (LPCTSTR)c_szCM);
  346. RegSetValue(HKEY_LOCAL_MACHINE, sz, REG_SZ, c_szCLSID, lstrlen(c_szCLSID));
  347. }
  348. return TRUE;
  349. }
  350. /*----------------------------------------------------------
  351. Purpose: Create a briefcase at the specified location.
  352. Returns: TRUE on success
  353. Cond: --
  354. */
  355. BOOL PRIVATE CreateTheBriefcase(HWND hwnd, LPCTSTR pszNewPath)
  356. {
  357. BOOL bRet = FALSE;
  358. TCHAR szParent[MAX_PATH];
  359. TCHAR szTmp[MAX_PATH];
  360. DEBUG_CODE( TRACE_MSG(TF_ALWAYS, TEXT("Creating %s"), (LPCTSTR)pszNewPath); )
  361. // We do not allow briefcases to be created inside other briefcases.
  362. lstrcpyn(szParent, pszNewPath, ARRAYSIZE(szParent));
  363. PathRemoveFileSpec(szParent);
  364. // Is this inside another briefcase?
  365. if (PL_FALSE != PathGetLocality(szParent, szTmp, ARRAYSIZE(szTmp)))
  366. {
  367. // Yes; don't do it!
  368. MsgBox(hwnd,
  369. MAKEINTRESOURCE(IDS_ERR_CREATE_INANOTHER),
  370. MAKEINTRESOURCE(IDS_CAP_CREATE),
  371. NULL,
  372. MB_WARNING);
  373. }
  374. else if (CreateDirectory(pszNewPath, NULL))
  375. {
  376. // Mark the briefcase as a system directory
  377. //
  378. if (!SetFileAttributes(pszNewPath, FILE_ATTRIBUTE_READONLY))
  379. {
  380. TRACE_MSG(TF_ALWAYS, TEXT("Cannot make %s a system directory"), (LPCTSTR)pszNewPath);
  381. RemoveDirectory(pszNewPath);
  382. MsgBox(hwnd,
  383. MAKEINTRESOURCE(IDS_ERR_CANTCREATEBC),
  384. MAKEINTRESOURCE(IDS_CAP_CREATE),
  385. NULL,
  386. MB_ERROR,
  387. pszNewPath);
  388. }
  389. else
  390. {
  391. const static TCHAR c_szConfirmFileOp[] = TEXT("ConfirmFileOp");
  392. HBRFCASE hbrf;
  393. TWINRESULT tr;
  394. LPCTSTR pszDBName;
  395. DECLAREHOURGLASS;
  396. if (PathsTooLong(pszNewPath, c_szDesktopIni) ||
  397. PathsTooLong(pszNewPath, g_szDBName) ||
  398. PathsTooLong(pszNewPath, g_szDBNameShort))
  399. {
  400. MsgBox(hwnd,
  401. MAKEINTRESOURCE(IDS_ERR_CREATE_TOOLONG),
  402. MAKEINTRESOURCE(IDS_CAP_CREATE),
  403. NULL,
  404. MB_ERROR);
  405. }
  406. else
  407. {
  408. // Write in the desktop.ini the briefcase class ID
  409. PathCombine(szTmp, pszNewPath, c_szDesktopIni);
  410. // (First, flush the cache to make sure the desktop.ini
  411. // file is really created.)
  412. WritePrivateProfileString(NULL, NULL, NULL, szTmp);
  413. WritePrivateProfileString(STRINI_CLASSINFO, c_szIniKeyCLSID, c_szCLSID, szTmp);
  414. WritePrivateProfileString(STRINI_CLASSINFO, c_szConfirmFileOp, TEXT("0"), szTmp);
  415. // Make wizard run the first time it is opened.
  416. WritePrivateProfileString(STRINI_CLASSINFO, c_szRunWizard, TEXT("1"), szTmp);
  417. // Hide the desktop.ini since the shell does not selectively hide it.
  418. // Also make it readonly so that the user can't customize the briefcase.
  419. if (!SetFileAttributes(szTmp, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
  420. {
  421. TRACE_MSG(TF_ALWAYS, TEXT("Cannot hide and/or make read-only %s"), (LPCTSTR)szTmp);
  422. }
  423. RegisterShellExtension();
  424. PathNotifyShell(pszNewPath, NSE_MKDIR, TRUE);
  425. // Create the database file
  426. SetHourglass();
  427. if (IsLFNDrive(pszNewPath))
  428. pszDBName = g_szDBName;
  429. else
  430. pszDBName = g_szDBNameShort;
  431. PathCombine(szTmp, pszNewPath, pszDBName);
  432. if (Sync_QueryVTable())
  433. {
  434. tr = Sync_OpenBriefcase(szTmp,
  435. OB_FL_OPEN_DATABASE | OB_FL_TRANSLATE_DB_FOLDER | OB_FL_ALLOW_UI,
  436. hwnd,
  437. &hbrf);
  438. if (TR_SUCCESS == tr)
  439. {
  440. // (Don't really care about errors here)
  441. Sync_SaveBriefcase(hbrf);
  442. Sync_CloseBriefcase(hbrf);
  443. }
  444. }
  445. ResetHourglass();
  446. bRet = TRUE;
  447. }
  448. }
  449. }
  450. else
  451. {
  452. // Could not create the directory. Is it because a briefcase
  453. // already exists at this location?
  454. if (PathExists(pszNewPath))
  455. {
  456. // Yes
  457. TRACE_MSG(TF_ALWAYS, TEXT("Briefcase already exists at this location: %s"), (LPCTSTR)pszNewPath);
  458. }
  459. else
  460. {
  461. // No
  462. MsgBox(hwnd,
  463. MAKEINTRESOURCE(IDS_ERR_CANTCREATEBC),
  464. MAKEINTRESOURCE(IDS_CAP_CREATE),
  465. NULL,
  466. MB_ERROR,
  467. pszNewPath);
  468. }
  469. }
  470. return bRet;
  471. }
  472. /*----------------------------------------------------------
  473. Purpose: Adds the briefcase at pszPath to the SendTo folder
  474. Returns: standard result
  475. Cond: --
  476. */
  477. HRESULT PRIVATE AddBriefcaseToSendToFolder(HWND hwnd, LPCTSTR pszPath)
  478. {
  479. HRESULT hres = E_OUTOFMEMORY;
  480. TCHAR szSendTo[MAX_PATH];
  481. Shell_GetImageLists( NULL, NULL ); // make sure icon cache is around
  482. if (SHGetSpecialFolderPath(hwnd, szSendTo, CSIDL_SENDTO, FALSE))
  483. {
  484. LPITEMIDLIST pidl = ILCreateFromPath(pszPath);
  485. if (pidl)
  486. {
  487. LPITEMIDLIST pidlParent = ILClone(pidl);
  488. if (pidlParent)
  489. {
  490. IShellFolder * psf;
  491. IShellFolder * psfDesktop;
  492. ILRemoveLastID(pidlParent);
  493. hres = SHGetDesktopFolder(&psfDesktop);
  494. if (SUCCEEDED(hres))
  495. {
  496. hres = psfDesktop->lpVtbl->BindToObject(psfDesktop, pidlParent,
  497. NULL, &IID_IShellFolder, &psf);
  498. if (SUCCEEDED(hres))
  499. {
  500. IDataObject *pdtobj;
  501. LPCITEMIDLIST pidlName = ILFindLastID(pidl);
  502. hres = psf->lpVtbl->GetUIObjectOf(psf, hwnd, 1, &pidlName, &IID_IDataObject, NULL, &pdtobj);
  503. if (SUCCEEDED(hres))
  504. {
  505. SHCreateLinks(hwnd, szSendTo, pdtobj, 0, NULL);
  506. pdtobj->lpVtbl->Release(pdtobj);
  507. }
  508. psf->lpVtbl->Release(psf);
  509. }
  510. psfDesktop->lpVtbl->Release(psfDesktop);
  511. }
  512. ILFree(pidlParent);
  513. }
  514. ILFree(pidl);
  515. }
  516. }
  517. return hres;
  518. }
  519. /*----------------------------------------------------------
  520. Purpose: Creates a briefcase in the specified directory.
  521. Returns: --
  522. Cond: --
  523. */
  524. void WINAPI Briefcase_CreateInDirectory(HWND hwnd, HWND hwndCabinet, LPCTSTR pszPath)
  525. {
  526. if (CreateTheBriefcase(hwnd, pszPath))
  527. {
  528. // Select the newly created item to edit it
  529. LPITEMIDLIST pidl = ILCreateFromPath(pszPath);
  530. if (pidl)
  531. {
  532. SelectItemInCabinet(hwndCabinet, ILFindLastID(pidl), TRUE);
  533. ILFree(pidl);
  534. }
  535. }
  536. }
  537. /*----------------------------------------------------------
  538. Purpose: Creates a briefcase on the desktop.
  539. Returns: --
  540. Cond: --
  541. */
  542. void WINAPI Briefcase_CreateOnDesktop(HWND hwnd)
  543. {
  544. // Place it on the desktop
  545. TCHAR szPath[MAX_PATH];
  546. if (SHGetSpecialFolderPath(hwnd, szPath, CSIDL_DESKTOPDIRECTORY, FALSE))
  547. {
  548. int cch;
  549. UINT ids;
  550. if (IsLFNDrive(szPath))
  551. ids = IDS_BC_NAME;
  552. else
  553. ids = IDS_BC_NAME_SHORT;
  554. StrCatBuff(szPath, TEXT("\\"), ARRAYSIZE(szPath));
  555. cch = lstrlen(szPath);
  556. LoadString(g_hinst, ids, &szPath[cch], ARRAYSIZE(szPath)-cch);
  557. if (CreateTheBriefcase(hwnd, szPath))
  558. {
  559. // Add a shortcut of this briefcase to the SendTo folder
  560. AddBriefcaseToSendToFolder(hwnd, szPath);
  561. }
  562. }
  563. }
  564. /*----------------------------------------------------------
  565. Purpose: Create a briefcase folder in the specified
  566. directory or on the desktop.
  567. Returns: --
  568. Cond: --
  569. */
  570. void WINAPI _export Briefcase_Create_Common(HWND hwnd, HINSTANCE hAppInstance, LPTSTR pszCmdLine, int nCmdShow)
  571. {
  572. DEBUG_CODE( DEBUG_BREAK(BF_ONRUNONCE); )
  573. // Command line should be of format "xxxx path" where <path>
  574. // is the fully qualified pathname of the briefcase to create,
  575. // and <xxxx> is the explorer hwnd.
  576. if (pszCmdLine && *pszCmdLine)
  577. {
  578. LPTSTR psz;
  579. HWND hwndCabinet;
  580. // Get hwnd
  581. hwndCabinet = IntToPtr(AnsiToInt(pszCmdLine));
  582. psz = StrChr(pszCmdLine, TEXT(' '));
  583. if (NULL != hwndCabinet && NULL != psz)
  584. {
  585. Briefcase_CreateInDirectory(hwnd, hwndCabinet, CharNext(psz));
  586. return;
  587. }
  588. }
  589. Briefcase_CreateOnDesktop(hwnd);
  590. }
  591. void WINAPI _export Briefcase_Create(HWND hwnd, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
  592. {
  593. UINT iLength = lstrlenA(pszCmdLine)+1;
  594. LPWSTR lpwszCmdLine;
  595. lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR, iLength *SIZEOF(TCHAR));
  596. if (lpwszCmdLine)
  597. {
  598. MultiByteToWideChar(CP_ACP, 0, pszCmdLine, -1,
  599. lpwszCmdLine, iLength);
  600. Briefcase_Create_Common(hwnd, hAppInstance, lpwszCmdLine, nCmdShow);
  601. LocalFree((HANDLE)lpwszCmdLine);
  602. }
  603. }
  604. void WINAPI _export Briefcase_CreateW(HWND hwnd, HINSTANCE hAppInstance, LPWSTR pwszCmdLine, int nCmdShow)
  605. {
  606. Briefcase_Create_Common(hwnd, hAppInstance, pwszCmdLine, nCmdShow);
  607. }
  608. /*----------------------------------------------------------
  609. Purpose: Display the introduction "wizard". (It's really not
  610. a wizard since it is not making anything for us.)
  611. NOTE: This function serves double duty for both the ansi and unicode
  612. versions. It never uses the command line.
  613. Returns: --
  614. Cond: --
  615. */
  616. void WINAPI _export Briefcase_Intro(
  617. HWND hwnd,
  618. HINSTANCE hAppInstance,
  619. LPTSTR lpszCmdLine,
  620. int nCmdShow)
  621. {
  622. Intro_DoModal(hwnd);
  623. }
  624. //---------------------------------------------------------------------------
  625. // DLL entry-points
  626. //---------------------------------------------------------------------------
  627. /*----------------------------------------------------------
  628. Purpose: This function is called back from within
  629. IClassFactory::CreateInstance() of the default class
  630. factory object, which is created by SHCreateClassObject.
  631. Returns: standard
  632. Cond: --
  633. */
  634. HRESULT CALLBACK DllFactoryCallback(IUnknown *punkOuter, REFIID riid, void **ppvOut)
  635. {
  636. HRESULT hres;
  637. if (IsEqualIID(riid, &IID_IShellExtInit))
  638. {
  639. hres = BriefExt_CreateInstance(punkOuter, riid, ppvOut);
  640. }
  641. else if (IsEqualIID(riid, &IID_IBriefcaseStg))
  642. {
  643. hres = BriefStg_CreateInstance(punkOuter, riid, ppvOut);
  644. }
  645. else
  646. {
  647. hres = E_NOINTERFACE;
  648. *ppvOut = NULL;
  649. }
  650. return hres;
  651. }
  652. /*----------------------------------------------------------
  653. Purpose: Standard OLE 2.0 entry-point
  654. Returns: standard
  655. Cond: --
  656. */
  657. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppvOut)
  658. {
  659. HRESULT hres;
  660. if (IsEqualIID(rclsid, &CLSID_Briefcase))
  661. {
  662. // We are supposed return the class object for this class. Instead
  663. // of fully implementing it in this DLL, we just call a helper
  664. // function in the shell DLL which creates a default class factory
  665. // object for us. When its CreateInstance member is called, it
  666. // will call back our create instance function.
  667. hres = SHCreateDefClassObject(
  668. riid, // Interface ID
  669. ppvOut, // Non-null to aggregate
  670. DllFactoryCallback, // callback function
  671. &g_cBusyRef, // reference count of this DLL
  672. NULL); // init interface
  673. }
  674. else
  675. {
  676. hres = REGDB_E_CLASSNOTREG;
  677. *ppvOut = NULL;
  678. }
  679. return hres;
  680. }
  681. /*----------------------------------------------------------
  682. Purpose: "Can Unload Now" entry point. Called by the shell DLL
  683. task handler list.
  684. Returns: S_OK to unload
  685. Cond: --
  686. */
  687. STDAPI DllCanUnloadNow(void)
  688. {
  689. HRESULT hr;
  690. // We only unload when:
  691. // 2) We are not busy processing anything else *and*
  692. // 3) No briefcases are currently open
  693. //
  694. ENTEREXCLUSIVE();
  695. {
  696. if (!IsBusySemaphore() &&
  697. !IsOpenBriefSemaphore())
  698. {
  699. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("DllCanUnloadNow says OK (Busy=%d, Brief=%d)"),
  700. g_cBusyRef, g_cBriefRef); )
  701. hr = S_OK;
  702. }
  703. else
  704. {
  705. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("DllCanUnloadNow says FALSE (Busy=%d, Brief=%d)"),
  706. g_cBusyRef, g_cBriefRef); )
  707. hr = S_FALSE;
  708. }
  709. }
  710. LEAVEEXCLUSIVE();
  711. return hr;
  712. }