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.

879 lines
23 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. InitializeCriticalSection(&g_csSyncUI);
  231. InitializeCriticalSection(&s_csDelay);
  232. g_hinst = hDll;
  233. #ifdef DEBUG
  234. // We do this simply to load the debug .ini flags
  235. ProcessIniFile();
  236. DEBUG_BREAK(BF_ONPROCESSATT);
  237. #endif
  238. // Under NT, we need to initialize on every process attach, not just the first
  239. bSuccess = InitializeFirstTime();
  240. if (bSuccess)
  241. {
  242. g_hMutexDelay = CreateMutex(NULL, FALSE, TEXT("SYNCUI"));
  243. bSuccess = (NULL != g_hMutexDelay);
  244. }
  245. if (bSuccess)
  246. {
  247. // (Only do this if we succeeded above)
  248. //
  249. // Do the following for every process
  250. bSuccess = InitWindowClasses(hDll);
  251. }
  252. InitGlobalColors();
  253. InitGlobalStrings();
  254. //Bug 199701, 199647, 199699
  255. //Apparently this is either broke or never worked: g_bMirroredOS = IS_MIRRORING_ENABLED();
  256. GetProcessDefaultLayout(&dwLayout);
  257. if (dwLayout == LAYOUT_RTL)
  258. {
  259. g_bMirroredOS = TRUE;
  260. }
  261. //End bug 199701, 199647, 199699
  262. return bSuccess;
  263. }
  264. BOOL ProcessDetach(HINSTANCE hDll)
  265. {
  266. BOOL bSuccess = TRUE;
  267. ASSERT(hDll == g_hinst);
  268. DEBUG_CODE( DEBUG_BREAK(BF_ONPROCESSDET); )
  269. ASSERT(0 == g_cRefMutex);
  270. if (g_hMutexDelay)
  271. {
  272. CloseHandle(g_hMutexDelay);
  273. g_hMutexDelay = NULL;
  274. }
  275. FinalTerminate(g_hinst);
  276. Sync_ReleaseVTable();
  277. DeleteCriticalSection(&g_csSyncUI);
  278. DeleteCriticalSection(&s_csDelay);
  279. TermWindowClasses(hDll);
  280. SHFusionUninitialize();
  281. return bSuccess;
  282. }
  283. BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, void *lpReserved)
  284. {
  285. switch(dwReason)
  286. {
  287. case DLL_PROCESS_ATTACH:
  288. ProcessAttach(hDll);
  289. #ifndef DEBUG
  290. DisableThreadLibraryCalls(hDll);
  291. #endif
  292. break;
  293. case DLL_PROCESS_DETACH:
  294. ProcessDetach(hDll);
  295. break;
  296. case DLL_THREAD_ATTACH:
  297. #ifdef DEBUG
  298. // We do this simply to load the debug .ini flags
  299. ProcessIniFile();
  300. #endif
  301. break;
  302. case DLL_THREAD_DETACH:
  303. #ifdef DEBUG
  304. DEBUG_BREAK(BF_ONTHREADDET);
  305. #endif
  306. break;
  307. default:
  308. break;
  309. }
  310. return TRUE;
  311. }
  312. /*----------------------------------------------------------
  313. Purpose: Registers property sheet and context menu extensions
  314. for the briefcase.
  315. Returns: TRUE on success
  316. Cond: --
  317. */
  318. BOOL PRIVATE RegisterShellExtension(void)
  319. {
  320. const static TCHAR c_szPage[] = STRREG_SHEX_PROPSHEET TEXT("\\BriefcasePage");
  321. const static TCHAR c_szCM[] = STRREG_SHEX_MENUHANDLER TEXT("\\BriefcaseMenu");
  322. const static TCHAR c_szFolder[] = TEXT("Folder");
  323. const static TCHAR c_szStar[] = TEXT("*");
  324. const static TCHAR c_szFmt[] = TEXT("SOFTWARE\\Classes\\%s\\%s");
  325. // This must be per instance, else it will cause a fixup in
  326. // shared data segment.
  327. const static LPCTSTR rgpsz[2] = { c_szFolder, c_szStar };
  328. TCHAR sz[MAXBUFLEN];
  329. int i;
  330. for (i = 0; i < ARRAYSIZE(rgpsz); i++)
  331. {
  332. // Add briefcase page extension
  333. wsprintf(sz, c_szFmt, (LPCTSTR)rgpsz[i], (LPCTSTR)c_szPage);
  334. RegSetValue(HKEY_LOCAL_MACHINE, sz, REG_SZ, c_szCLSID, lstrlen(c_szCLSID));
  335. // Add briefcase context menu extension
  336. wsprintf(sz, c_szFmt, (LPCTSTR)rgpsz[i], (LPCTSTR)c_szCM);
  337. RegSetValue(HKEY_LOCAL_MACHINE, sz, REG_SZ, c_szCLSID, lstrlen(c_szCLSID));
  338. }
  339. return TRUE;
  340. }
  341. /*----------------------------------------------------------
  342. Purpose: Create a briefcase at the specified location.
  343. Returns: TRUE on success
  344. Cond: --
  345. */
  346. BOOL PRIVATE CreateTheBriefcase(HWND hwnd, LPCTSTR pszNewPath)
  347. {
  348. BOOL bRet = FALSE;
  349. TCHAR szParent[MAX_PATH];
  350. TCHAR szTmp[MAX_PATH];
  351. DEBUG_CODE( TRACE_MSG(TF_ALWAYS, TEXT("Creating %s"), (LPCTSTR)pszNewPath); )
  352. // We do not allow briefcases to be created inside other briefcases.
  353. lstrcpy(szParent, pszNewPath);
  354. PathRemoveFileSpec(szParent);
  355. // Is this inside another briefcase?
  356. if (PL_FALSE != PathGetLocality(szParent, szTmp))
  357. {
  358. // Yes; don't do it!
  359. MsgBox(hwnd,
  360. MAKEINTRESOURCE(IDS_ERR_CREATE_INANOTHER),
  361. MAKEINTRESOURCE(IDS_CAP_CREATE),
  362. NULL,
  363. MB_WARNING);
  364. }
  365. else if (CreateDirectory(pszNewPath, NULL))
  366. {
  367. // Mark the briefcase as a system directory
  368. //
  369. if (!SetFileAttributes(pszNewPath, FILE_ATTRIBUTE_READONLY))
  370. {
  371. TRACE_MSG(TF_ALWAYS, TEXT("Cannot make %s a system directory"), (LPCTSTR)pszNewPath);
  372. RemoveDirectory(pszNewPath);
  373. MsgBox(hwnd,
  374. MAKEINTRESOURCE(IDS_ERR_CANTCREATEBC),
  375. MAKEINTRESOURCE(IDS_CAP_CREATE),
  376. NULL,
  377. MB_ERROR,
  378. pszNewPath);
  379. }
  380. else
  381. {
  382. const static TCHAR c_szConfirmFileOp[] = TEXT("ConfirmFileOp");
  383. HBRFCASE hbrf;
  384. TWINRESULT tr;
  385. LPCTSTR pszDBName;
  386. DECLAREHOURGLASS;
  387. if (PathsTooLong(pszNewPath, c_szDesktopIni) ||
  388. PathsTooLong(pszNewPath, g_szDBName) ||
  389. PathsTooLong(pszNewPath, g_szDBNameShort))
  390. {
  391. MsgBox(hwnd,
  392. MAKEINTRESOURCE(IDS_ERR_CREATE_TOOLONG),
  393. MAKEINTRESOURCE(IDS_CAP_CREATE),
  394. NULL,
  395. MB_ERROR);
  396. }
  397. else
  398. {
  399. // Write in the desktop.ini the briefcase class ID
  400. PathCombine(szTmp, pszNewPath, c_szDesktopIni);
  401. // (First, flush the cache to make sure the desktop.ini
  402. // file is really created.)
  403. WritePrivateProfileString(NULL, NULL, NULL, szTmp);
  404. WritePrivateProfileString(STRINI_CLASSINFO, c_szIniKeyCLSID, c_szCLSID, szTmp);
  405. WritePrivateProfileString(STRINI_CLASSINFO, c_szConfirmFileOp, TEXT("0"), szTmp);
  406. // Make wizard run the first time it is opened.
  407. WritePrivateProfileString(STRINI_CLASSINFO, c_szRunWizard, TEXT("1"), szTmp);
  408. // Hide the desktop.ini since the shell does not selectively hide it.
  409. // Also make it readonly so that the user can't customize the briefcase.
  410. if (!SetFileAttributes(szTmp, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
  411. {
  412. TRACE_MSG(TF_ALWAYS, TEXT("Cannot hide and/or make read-only %s"), (LPCTSTR)szTmp);
  413. }
  414. RegisterShellExtension();
  415. PathNotifyShell(pszNewPath, NSE_MKDIR, TRUE);
  416. // Create the database file
  417. SetHourglass();
  418. if (IsLFNDrive(pszNewPath))
  419. pszDBName = g_szDBName;
  420. else
  421. pszDBName = g_szDBNameShort;
  422. PathCombine(szTmp, pszNewPath, pszDBName);
  423. if (Sync_QueryVTable())
  424. {
  425. tr = Sync_OpenBriefcase(szTmp,
  426. OB_FL_OPEN_DATABASE | OB_FL_TRANSLATE_DB_FOLDER | OB_FL_ALLOW_UI,
  427. hwnd,
  428. &hbrf);
  429. if (TR_SUCCESS == tr)
  430. {
  431. // (Don't really care about errors here)
  432. Sync_SaveBriefcase(hbrf);
  433. Sync_CloseBriefcase(hbrf);
  434. }
  435. }
  436. ResetHourglass();
  437. bRet = TRUE;
  438. }
  439. }
  440. }
  441. else
  442. {
  443. // Could not create the directory. Is it because a briefcase
  444. // already exists at this location?
  445. if (PathExists(pszNewPath))
  446. {
  447. // Yes
  448. TRACE_MSG(TF_ALWAYS, TEXT("Briefcase already exists at this location: %s"), (LPCTSTR)pszNewPath);
  449. }
  450. else
  451. {
  452. // No
  453. MsgBox(hwnd,
  454. MAKEINTRESOURCE(IDS_ERR_CANTCREATEBC),
  455. MAKEINTRESOURCE(IDS_CAP_CREATE),
  456. NULL,
  457. MB_ERROR,
  458. pszNewPath);
  459. }
  460. }
  461. return bRet;
  462. }
  463. /*----------------------------------------------------------
  464. Purpose: Adds the briefcase at pszPath to the SendTo folder
  465. Returns: standard result
  466. Cond: --
  467. */
  468. HRESULT PRIVATE AddBriefcaseToSendToFolder(HWND hwnd, LPCTSTR pszPath)
  469. {
  470. HRESULT hres = E_OUTOFMEMORY;
  471. TCHAR szSendTo[MAX_PATH];
  472. Shell_GetImageLists( NULL, NULL ); // make sure icon cache is around
  473. if (SHGetSpecialFolderPath(hwnd, szSendTo, CSIDL_SENDTO, FALSE))
  474. {
  475. LPITEMIDLIST pidl = ILCreateFromPath(pszPath);
  476. if (pidl)
  477. {
  478. LPITEMIDLIST pidlParent = ILClone(pidl);
  479. if (pidlParent)
  480. {
  481. IShellFolder * psf;
  482. IShellFolder * psfDesktop;
  483. ILRemoveLastID(pidlParent);
  484. hres = SHGetDesktopFolder(&psfDesktop);
  485. if (SUCCEEDED(hres))
  486. {
  487. hres = psfDesktop->lpVtbl->BindToObject(psfDesktop, pidlParent,
  488. NULL, &IID_IShellFolder, &psf);
  489. if (SUCCEEDED(hres))
  490. {
  491. IDataObject *pdtobj;
  492. LPCITEMIDLIST pidlName = ILFindLastID(pidl);
  493. hres = psf->lpVtbl->GetUIObjectOf(psf, hwnd, 1, &pidlName, &IID_IDataObject, NULL, &pdtobj);
  494. if (SUCCEEDED(hres))
  495. {
  496. SHCreateLinks(hwnd, szSendTo, pdtobj, 0, NULL);
  497. pdtobj->lpVtbl->Release(pdtobj);
  498. }
  499. psf->lpVtbl->Release(psf);
  500. }
  501. psfDesktop->lpVtbl->Release(psfDesktop);
  502. }
  503. ILFree(pidlParent);
  504. }
  505. ILFree(pidl);
  506. }
  507. }
  508. return hres;
  509. }
  510. /*----------------------------------------------------------
  511. Purpose: Creates a briefcase in the specified directory.
  512. Returns: --
  513. Cond: --
  514. */
  515. void WINAPI Briefcase_CreateInDirectory(HWND hwnd, HWND hwndCabinet, LPCTSTR pszPath)
  516. {
  517. if (CreateTheBriefcase(hwnd, pszPath))
  518. {
  519. // Select the newly created item to edit it
  520. LPITEMIDLIST pidl = ILCreateFromPath(pszPath);
  521. if (pidl)
  522. {
  523. SelectItemInCabinet(hwndCabinet, ILFindLastID(pidl), TRUE);
  524. ILFree(pidl);
  525. }
  526. }
  527. }
  528. /*----------------------------------------------------------
  529. Purpose: Creates a briefcase on the desktop.
  530. Returns: --
  531. Cond: --
  532. */
  533. void WINAPI Briefcase_CreateOnDesktop(HWND hwnd)
  534. {
  535. // Place it on the desktop
  536. TCHAR szPath[MAX_PATH];
  537. if (SHGetSpecialFolderPath(hwnd, szPath, CSIDL_DESKTOPDIRECTORY, FALSE))
  538. {
  539. int cch;
  540. UINT ids;
  541. if (IsLFNDrive(szPath))
  542. ids = IDS_BC_NAME;
  543. else
  544. ids = IDS_BC_NAME_SHORT;
  545. lstrcat(szPath, TEXT("\\"));
  546. cch = lstrlen(szPath);
  547. LoadString(g_hinst, ids, &szPath[cch], ARRAYSIZE(szPath)-cch);
  548. if (CreateTheBriefcase(hwnd, szPath))
  549. {
  550. // Add a shortcut of this briefcase to the SendTo folder
  551. AddBriefcaseToSendToFolder(hwnd, szPath);
  552. }
  553. }
  554. }
  555. /*----------------------------------------------------------
  556. Purpose: Create a briefcase folder in the specified
  557. directory or on the desktop.
  558. Returns: --
  559. Cond: --
  560. */
  561. void WINAPI _export Briefcase_Create_Common(HWND hwnd, HINSTANCE hAppInstance, LPTSTR pszCmdLine, int nCmdShow)
  562. {
  563. DEBUG_CODE( DEBUG_BREAK(BF_ONRUNONCE); )
  564. // Command line should be of format "xxxx path" where <path>
  565. // is the fully qualified pathname of the briefcase to create,
  566. // and <xxxx> is the explorer hwnd.
  567. if (pszCmdLine && *pszCmdLine)
  568. {
  569. LPTSTR psz;
  570. HWND hwndCabinet;
  571. // Get hwnd
  572. hwndCabinet = IntToPtr(AnsiToInt(pszCmdLine));
  573. psz = StrChr(pszCmdLine, TEXT(' '));
  574. if (NULL != hwndCabinet && NULL != psz)
  575. {
  576. Briefcase_CreateInDirectory(hwnd, hwndCabinet, CharNext(psz));
  577. return;
  578. }
  579. }
  580. Briefcase_CreateOnDesktop(hwnd);
  581. }
  582. void WINAPI _export Briefcase_Create(HWND hwnd, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
  583. {
  584. UINT iLength = lstrlenA(pszCmdLine)+1;
  585. LPWSTR lpwszCmdLine;
  586. lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR, iLength *SIZEOF(TCHAR));
  587. if (lpwszCmdLine)
  588. {
  589. MultiByteToWideChar(CP_ACP, 0,
  590. pszCmdLine, -1,
  591. lpwszCmdLine, iLength);
  592. Briefcase_Create_Common(hwnd, hAppInstance, lpwszCmdLine, nCmdShow);
  593. LocalFree((HANDLE)lpwszCmdLine);
  594. }
  595. }
  596. void WINAPI _export Briefcase_CreateW(HWND hwnd, HINSTANCE hAppInstance, LPWSTR pwszCmdLine, int nCmdShow)
  597. {
  598. Briefcase_Create_Common(hwnd, hAppInstance, pwszCmdLine, nCmdShow);
  599. }
  600. /*----------------------------------------------------------
  601. Purpose: Display the introduction "wizard". (It's really not
  602. a wizard since it is not making anything for us.)
  603. NOTE: This function serves double duty for both the ansi and unicode
  604. versions. It never uses the command line.
  605. Returns: --
  606. Cond: --
  607. */
  608. void WINAPI _export Briefcase_Intro(
  609. HWND hwnd,
  610. HINSTANCE hAppInstance,
  611. LPTSTR lpszCmdLine,
  612. int nCmdShow)
  613. {
  614. Intro_DoModal(hwnd);
  615. }
  616. //---------------------------------------------------------------------------
  617. // DLL entry-points
  618. //---------------------------------------------------------------------------
  619. /*----------------------------------------------------------
  620. Purpose: This function is called back from within
  621. IClassFactory::CreateInstance() of the default class
  622. factory object, which is created by SHCreateClassObject.
  623. Returns: standard
  624. Cond: --
  625. */
  626. HRESULT CALLBACK DllFactoryCallback(IUnknown *punkOuter, REFIID riid, void **ppvOut)
  627. {
  628. HRESULT hres;
  629. if (IsEqualIID(riid, &IID_IShellExtInit))
  630. {
  631. hres = BriefExt_CreateInstance(punkOuter, riid, ppvOut);
  632. }
  633. else if (IsEqualIID(riid, &IID_IBriefcaseStg))
  634. {
  635. hres = BriefStg_CreateInstance(punkOuter, riid, ppvOut);
  636. }
  637. else
  638. {
  639. hres = E_NOINTERFACE;
  640. *ppvOut = NULL;
  641. }
  642. return hres;
  643. }
  644. /*----------------------------------------------------------
  645. Purpose: Standard OLE 2.0 entry-point
  646. Returns: standard
  647. Cond: --
  648. */
  649. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppvOut)
  650. {
  651. HRESULT hres;
  652. if (IsEqualIID(rclsid, &CLSID_Briefcase))
  653. {
  654. // We are supposed return the class object for this class. Instead
  655. // of fully implementing it in this DLL, we just call a helper
  656. // function in the shell DLL which creates a default class factory
  657. // object for us. When its CreateInstance member is called, it
  658. // will call back our create instance function.
  659. hres = SHCreateDefClassObject(
  660. riid, // Interface ID
  661. ppvOut, // Non-null to aggregate
  662. DllFactoryCallback, // callback function
  663. &g_cBusyRef, // reference count of this DLL
  664. NULL); // init interface
  665. }
  666. else
  667. {
  668. hres = REGDB_E_CLASSNOTREG;
  669. *ppvOut = NULL;
  670. }
  671. return hres;
  672. }
  673. /*----------------------------------------------------------
  674. Purpose: "Can Unload Now" entry point. Called by the shell DLL
  675. task handler list.
  676. Returns: S_OK to unload
  677. Cond: --
  678. */
  679. STDAPI DllCanUnloadNow(void)
  680. {
  681. HRESULT hr;
  682. // We only unload when:
  683. // 2) We are not busy processing anything else *and*
  684. // 3) No briefcases are currently open
  685. //
  686. ENTEREXCLUSIVE();
  687. {
  688. if (!IsBusySemaphore() &&
  689. !IsOpenBriefSemaphore())
  690. {
  691. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("DllCanUnloadNow says OK (Busy=%d, Brief=%d)"),
  692. g_cBusyRef, g_cBriefRef); )
  693. hr = S_OK;
  694. }
  695. else
  696. {
  697. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("DllCanUnloadNow says FALSE (Busy=%d, Brief=%d)"),
  698. g_cBusyRef, g_cBriefRef); )
  699. hr = S_FALSE;
  700. }
  701. }
  702. LEAVEEXCLUSIVE();
  703. return hr;
  704. }