1106 lines
29 KiB
C
1106 lines
29 KiB
C
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1993-1994
|
|
//
|
|
// File: init.c
|
|
//
|
|
// This file contains the library entry points
|
|
//
|
|
// Usage and assumptions used in this DLL.
|
|
//
|
|
// 1) Message crackers are used. See windowsx.h and windowsx.txt.
|
|
//
|
|
// 2) Many functions are considered "member functions" of a
|
|
// particular class. Because this is not C++, the function
|
|
// names follow a special naming convention: "Class_Name".
|
|
// In addition, it is common practice that the first
|
|
// argument for these type of functions is a "this" pointer
|
|
// to the particular object.
|
|
//
|
|
// History:
|
|
// 08-06-93 ScottH Transferred from twin code
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
///////////////////////////////////////////////////// INCLUDES
|
|
|
|
#include "brfprv.h" // common headers
|
|
#include <oleguid.h>
|
|
#include <coguid.h>
|
|
#include <shlguid.h>
|
|
|
|
#include <initguid.h>
|
|
#define INITGUID // Initialize GUIDs
|
|
#include "syncmgr.h"
|
|
#include <shguidp.h> // Contains CLSID_Briefcase
|
|
#include <brfcasep.h>
|
|
|
|
DEFINE_GUID(IID_IBriefcaseStg2, 0x8BCE1FA1L, 0x1921, 0x101B, 0xB1, 0xFF, 0x00, 0xDD, 0x01, 0x0C, 0xCC, 0x48);
|
|
|
|
|
|
DEFINE_GUID(CLSID_SyncMgr,0x6295df27, 0x35ee, 0x11d1, 0x87, 0x7, 0x0, 0xc0, 0x4f, 0xd9, 0x33, 0x27);
|
|
DEFINE_GUID(IID_ISyncMgrSynchronizeInvoke,0x6295df2c, 0x35ee, 0x11d1, 0x87, 0x7, 0x0, 0xc0, 0x4f, 0xd9, 0x33, 0x27);
|
|
DEFINE_GUID(CLSID_BriefCase,0x85BBD920,0x42A0,0x1069,0xA2,0xE4,0x08,0x00,0x2B,0x30,0x30,0x9D);
|
|
DEFINE_GUID(CLSID_OneStopHandler,0x97484ba2, 0x26c7, 0x11d1, 0x9a, 0x39, 0x0, 0x20, 0xaf, 0xda, 0x97, 0xb0);
|
|
|
|
#include "res.h"
|
|
#include "recact.h"
|
|
|
|
#ifdef DEBUG
|
|
#include <debugstr.h>
|
|
#endif
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Per instance data
|
|
//---------------------------------------------------------------------------
|
|
|
|
#pragma data_seg(DATASEG_PERINSTANCE)
|
|
|
|
HINSTANCE g_hinst = 0;
|
|
TWINRESULT g_tr = TR_SUCCESS;
|
|
|
|
IShellFolder * g_psfDesktop = NULL;
|
|
|
|
// Debugging variables
|
|
UINT g_uBreakFlags = 0; // Controls when to int 3
|
|
UINT g_uTraceFlags = 0; // Controls what trace messages are spewed
|
|
UINT g_uDumpFlags = 0; // Controls what structs get dumped
|
|
|
|
// The delay mutex and the cs that protects the cRef is per-instance
|
|
HANDLE g_hMutexDelay = NULL;
|
|
static UINT g_cRefMutex = 0;
|
|
static CRITICAL_SECTION s_csDelay = { 0 };
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Global data
|
|
//---------------------------------------------------------------------------
|
|
|
|
int g_cProcesses = 0;
|
|
CRITICAL_SECTION g_csSyncUI = { 0 };
|
|
DEBUG_CODE( UINT g_cRefSyncUI = 0; )
|
|
UINT g_cfBriefObj = 0;
|
|
|
|
// Use the helper macros in brfprv.h
|
|
UINT g_cBusyRef = 0; // Semaphore
|
|
UINT g_cBriefRef = 0; // Semaphore
|
|
|
|
// Metrics
|
|
int g_cxIconSpacing = 0;
|
|
int g_cyIconSpacing = 0;
|
|
int g_cxBorder = 0;
|
|
int g_cyBorder = 0;
|
|
int g_cxIcon = 0;
|
|
int g_cyIcon = 0;
|
|
int g_cxIconMargin = 0;
|
|
int g_cyIconMargin = 0;
|
|
int g_cxLabelMargin = 0;
|
|
int g_cyLabelSpace = 0;
|
|
int g_cxMargin = 0;
|
|
|
|
// System colors
|
|
COLORREF g_clrHighlightText = 0;
|
|
COLORREF g_clrHighlight = 0;
|
|
COLORREF g_clrWindowText = 0;
|
|
COLORREF g_clrWindow = 0;
|
|
|
|
HBRUSH g_hbrHighlight = 0;
|
|
HBRUSH g_hbrWindow = 0;
|
|
|
|
// Strings
|
|
TCHAR g_szDBName[MAXPATHLEN];
|
|
TCHAR g_szDBNameShort[MAXPATHLEN];
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns an IShellFolder interface to the shell's desktop.
|
|
The interface is cached in g_psfDesktop for speed.
|
|
|
|
The shell is guaranteed to have a desktop IShellFolder.
|
|
|
|
Returns: psfDesktop
|
|
Cond: --
|
|
*/
|
|
LPSHELLFOLDER PUBLIC GetDesktopShellFolder(void)
|
|
{
|
|
ENTEREXCLUSIVE()
|
|
{
|
|
if (NULL == g_psfDesktop)
|
|
{
|
|
IShellFolder * psfDesktop;
|
|
|
|
LEAVEEXCLUSIVE();
|
|
SHCoCreateInstance(NULL, &CLSID_ShellDesktop, NULL, &IID_IShellFolder, &psfDesktop);
|
|
ENTEREXCLUSIVE();
|
|
|
|
g_psfDesktop = psfDesktop;
|
|
}
|
|
}
|
|
LEAVEEXCLUSIVE()
|
|
|
|
return g_psfDesktop;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Releases the cached desktop IShellFolder interface.
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE ReleaseDesktopShellFolder(void)
|
|
{
|
|
ENTEREXCLUSIVE()
|
|
{
|
|
if (NULL != g_psfDesktop)
|
|
{
|
|
g_psfDesktop->lpVtbl->Release(g_psfDesktop);
|
|
g_psfDesktop = NULL;
|
|
}
|
|
}
|
|
LEAVEEXCLUSIVE()
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Get the system metrics we need
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE GetMetrics(
|
|
WPARAM wParam) // wParam from WM_WININICHANGE
|
|
{
|
|
if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
|
|
{
|
|
g_cxIconSpacing = GetSystemMetrics( SM_CXICONSPACING );
|
|
g_cyIconSpacing = GetSystemMetrics( SM_CYICONSPACING );
|
|
|
|
g_cxBorder = GetSystemMetrics(SM_CXBORDER);
|
|
g_cyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
|
|
g_cxIcon = GetSystemMetrics(SM_CXICON);
|
|
g_cyIcon = GetSystemMetrics(SM_CYICON);
|
|
|
|
g_cxIconMargin = g_cxBorder * 8;
|
|
g_cyIconMargin = g_cyBorder * 2;
|
|
g_cyLabelSpace = g_cyIconMargin + (g_cyBorder * 2);
|
|
g_cxLabelMargin = (g_cxBorder * 2);
|
|
g_cxMargin = g_cxBorder * 5;
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Initializes colors
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE InitGlobalColors()
|
|
{
|
|
g_clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
|
|
g_clrWindow = GetSysColor(COLOR_WINDOW);
|
|
g_clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
|
|
g_clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
|
|
|
|
g_hbrWindow = GetSysColorBrush(COLOR_WINDOW);
|
|
g_hbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Initialize global strings
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE InitGlobalStrings()
|
|
{
|
|
SzFromIDS(IDS_BC_DATABASE, g_szDBName, ARRAYSIZE(g_szDBName));
|
|
SzFromIDS(IDS_BC_DATABASE_SHORT, g_szDBNameShort, ARRAYSIZE(g_szDBNameShort));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Initialize the DLL on the first PROCESS_ATTACH
|
|
|
|
Returns: TRUE on success
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE InitializeFirstTime(void)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
InitCommonControls();
|
|
|
|
GetMetrics(0);
|
|
|
|
CPATH_InitCS();
|
|
CBS_InitCS();
|
|
CRL_InitCS();
|
|
|
|
if (!Atom_Init())
|
|
goto Init_Cleanup;
|
|
|
|
if (!CPATH_Init())
|
|
goto Init_Cleanup;
|
|
|
|
// We do not load the engine DLL until we really need it.
|
|
|
|
// Initialize our global imagelist
|
|
//
|
|
g_cfBriefObj = RegisterClipboardFormat(CFSTR_BRIEFOBJECT);
|
|
if (g_cfBriefObj == 0)
|
|
goto Init_Cleanup;
|
|
|
|
bRet = TRUE;
|
|
|
|
Init_Cleanup:
|
|
if (bRet == FALSE)
|
|
{
|
|
Atom_Term();
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Register window classes per process
|
|
|
|
Returns: TRUE on success
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE InitWindowClasses(
|
|
HINSTANCE hinst)
|
|
{
|
|
if (!RecAct_Init(hinst))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Terminate DLL on the last PROCESS_DETACH
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE FinalTerminate(
|
|
HINSTANCE hinst)
|
|
{
|
|
CPATH_Term();
|
|
Atom_Term();
|
|
|
|
CRL_DeleteCS();
|
|
CBS_DeleteCS();
|
|
CPATH_DeleteCS();
|
|
|
|
Mem_Terminate();
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Unregister window classes per process
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE TermWindowClasses(
|
|
HINSTANCE hinst)
|
|
{
|
|
RecAct_Term(hinst);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Obtain ownership of the delay-calculation mutex
|
|
|
|
Returns: reference count
|
|
Cond: --
|
|
*/
|
|
UINT PUBLIC Delay_Own(void)
|
|
{
|
|
UINT cRef;
|
|
|
|
EnterCriticalSection(&s_csDelay);
|
|
{
|
|
if (0 == g_cRefMutex++)
|
|
{
|
|
// Obtain ownership of the mutex. This will get released
|
|
// when Delay_Release is called.
|
|
LeaveCriticalSection(&s_csDelay);
|
|
{
|
|
MsgWaitObjectsSendMessage(1, &g_hMutexDelay, INFINITE);
|
|
}
|
|
EnterCriticalSection(&s_csDelay);
|
|
|
|
TRACE_MSG(TF_GENERAL, TEXT("Set delay mutex"));
|
|
}
|
|
cRef = g_cRefMutex;
|
|
}
|
|
LeaveCriticalSection(&s_csDelay);
|
|
|
|
return cRef;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Release ownership of the delay-calculation mutex
|
|
|
|
Returns: reference count
|
|
Cond: --
|
|
*/
|
|
UINT PUBLIC Delay_Release(void)
|
|
{
|
|
UINT cRef;
|
|
|
|
EnterCriticalSection(&s_csDelay);
|
|
{
|
|
ASSERT(0 < g_cRefMutex);
|
|
|
|
if (0 < g_cRefMutex)
|
|
{
|
|
if (0 == --g_cRefMutex)
|
|
{
|
|
ReleaseMutex(g_hMutexDelay);
|
|
|
|
TRACE_MSG(TF_GENERAL, TEXT("Release delay mutex"));
|
|
}
|
|
}
|
|
cRef = g_cRefMutex;
|
|
}
|
|
LeaveCriticalSection(&s_csDelay);
|
|
|
|
return cRef;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Enter a critical section
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC Brief_EnterExclusive(void)
|
|
{
|
|
EnterCriticalSection(&g_csSyncUI);
|
|
#ifdef DEBUG
|
|
g_cRefSyncUI++;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Leave a critical section
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC Brief_LeaveExclusive(void)
|
|
{
|
|
#ifdef DEBUG
|
|
g_cRefSyncUI--;
|
|
#endif
|
|
LeaveCriticalSection(&g_csSyncUI);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Attach a process to this DLL
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
BOOL ProcessAttach(HINSTANCE hDll)
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
|
|
// It's okay to use a critical section in Chicago because (unlike
|
|
// NT) they work across processes. (See NT case below)
|
|
|
|
if (0) // rogerg ReInitialize is undefined.
|
|
{
|
|
|
|
#ifdef WINNT
|
|
// InitializeCriticalSection(&g_csSyncUI);
|
|
#else
|
|
// ReinitializeCriticalSection(&g_csSyncUI);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
InitializeCriticalSection(&g_csSyncUI);
|
|
}
|
|
|
|
|
|
ASSERT(0 != *((LPDWORD)&g_csSyncUI));
|
|
|
|
InitializeCriticalSection(&s_csDelay);
|
|
ASSERT(0 != *((LPDWORD)&s_csDelay));
|
|
|
|
ENTEREXCLUSIVE()
|
|
{
|
|
g_hinst = hDll;
|
|
|
|
#ifdef DEBUG
|
|
|
|
// We do this simply to load the debug .ini flags
|
|
//
|
|
ProcessIniFile();
|
|
|
|
TRACE_MSG(TF_GENERAL, TEXT("Process Attach [%d] (hDll = %lx)"), g_cProcesses, hDll);
|
|
DEBUG_BREAK(BF_ONPROCESSATT);
|
|
|
|
#endif
|
|
|
|
// Under NT, we need to initialize on every process attach, not just the first
|
|
|
|
#ifdef WINNT
|
|
g_cProcesses++;
|
|
bSuccess = InitializeFirstTime();
|
|
#else
|
|
if (0 == g_cProcesses++)
|
|
{
|
|
bSuccess = InitializeFirstTime();
|
|
}
|
|
#endif
|
|
|
|
if (bSuccess)
|
|
{
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
const static TCHAR c_szSyncUI[] = TEXT("SYNCUI");
|
|
#pragma data_seg()
|
|
|
|
g_hMutexDelay = CreateMutex(NULL, FALSE, c_szSyncUI);
|
|
bSuccess = (NULL != g_hMutexDelay);
|
|
}
|
|
}
|
|
LEAVEEXCLUSIVE()
|
|
|
|
if (bSuccess)
|
|
{
|
|
// (Only do this if we succeeded above)
|
|
//
|
|
// Do the following for every process
|
|
bSuccess = InitWindowClasses(hDll);
|
|
}
|
|
|
|
InitGlobalColors();
|
|
InitGlobalStrings();
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Detach a process from the DLL
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
BOOL ProcessDetach(HINSTANCE hDll)
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
|
|
ENTEREXCLUSIVE()
|
|
{
|
|
ASSERT(hDll == g_hinst);
|
|
|
|
DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Process Detach [%d] (hDll = %lx)"),
|
|
g_cProcesses, hDll-1); )
|
|
|
|
DEBUG_CODE( DEBUG_BREAK(BF_ONPROCESSDET); )
|
|
|
|
ASSERT(0 == g_cRefMutex);
|
|
|
|
if (g_hMutexDelay)
|
|
{
|
|
CloseHandle(g_hMutexDelay);
|
|
g_hMutexDelay = NULL;
|
|
}
|
|
|
|
if (0 == --g_cProcesses)
|
|
{
|
|
FinalTerminate(g_hinst);
|
|
}
|
|
|
|
ReleaseDesktopShellFolder();
|
|
|
|
Sync_ReleaseVTable();
|
|
}
|
|
LEAVEEXCLUSIVE()
|
|
|
|
if (g_cProcesses == 0)
|
|
{
|
|
DeleteCriticalSection(&g_csSyncUI);
|
|
}
|
|
|
|
DeleteCriticalSection(&s_csDelay);
|
|
|
|
TermWindowClasses(hDll);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Win32 Libmain
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
BOOL APIENTRY LibMain(
|
|
HANDLE hDll,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved)
|
|
{
|
|
|
|
|
|
switch(dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
ProcessAttach(hDll);
|
|
#ifndef DEBUG
|
|
DisableThreadLibraryCalls(hDll);
|
|
#endif
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
ProcessDetach(hDll);
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
|
|
#ifdef DEBUG
|
|
|
|
ENTEREXCLUSIVE()
|
|
{
|
|
// We do this simply to load the debug .ini flags
|
|
//
|
|
ProcessIniFile();
|
|
|
|
TRACE_MSG(TF_GENERAL, TEXT("Thread Attach [%d] (hDll = %lx)"),
|
|
g_cProcesses, hDll);
|
|
}
|
|
LEAVEEXCLUSIVE()
|
|
|
|
DEBUG_BREAK(BF_ONTHREADATT);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
|
|
#ifdef DEBUG
|
|
|
|
ENTEREXCLUSIVE()
|
|
{
|
|
TRACE_MSG(TF_GENERAL, TEXT("Thread Detach [%d] (hDll = %lx)"),
|
|
g_cProcesses, hDll);
|
|
}
|
|
LEAVEEXCLUSIVE()
|
|
|
|
DEBUG_BREAK(BF_ONTHREADDET);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Registers property sheet and context menu extensions
|
|
for the briefcase.
|
|
|
|
Returns: TRUE on success
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE RegisterShellExtension(void)
|
|
{
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
const static TCHAR c_szPage[] = STRREG_SHEX_PROPSHEET TEXT("\\BriefcasePage");
|
|
const static TCHAR c_szCM[] = STRREG_SHEX_MENUHANDLER TEXT("\\BriefcaseMenu");
|
|
const static TCHAR c_szFolder[] = TEXT("Folder");
|
|
const static TCHAR c_szStar[] = TEXT("*");
|
|
const static TCHAR c_szFmt[] = TEXT("SOFTWARE\\Classes\\%s\\%s");
|
|
#pragma data_seg(DATASEG_PERINSTANCE)
|
|
// This must be per instance, else it will cause a fixup in
|
|
// shared data segment.
|
|
const static LPCTSTR rgpsz[2] = { c_szFolder, c_szStar };
|
|
#pragma data_seg()
|
|
TCHAR sz[MAXBUFLEN];
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(rgpsz); i++)
|
|
{
|
|
// Add briefcase page extension
|
|
wsprintf(sz, c_szFmt, (LPCTSTR)rgpsz[i], (LPCTSTR)c_szPage);
|
|
RegSetValue(HKEY_LOCAL_MACHINE, sz, REG_SZ, c_szCLSID, lstrlen(c_szCLSID));
|
|
|
|
// Add briefcase context menu extension
|
|
wsprintf(sz, c_szFmt, (LPCTSTR)rgpsz[i], (LPCTSTR)c_szCM);
|
|
RegSetValue(HKEY_LOCAL_MACHINE, sz, REG_SZ, c_szCLSID, lstrlen(c_szCLSID));
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Create a briefcase at the specified location.
|
|
|
|
Returns: TRUE on success
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE CreateTheBriefcase(
|
|
HWND hwnd,
|
|
LPCTSTR pszNewPath)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
TCHAR szParent[MAX_PATH];
|
|
TCHAR szTmp[MAX_PATH];
|
|
|
|
DEBUG_CODE( TRACE_MSG(TF_ALWAYS, TEXT("Creating %s"), (LPCTSTR)pszNewPath); )
|
|
|
|
// We do not allow briefcases to be created inside other briefcases.
|
|
|
|
lstrcpy(szParent, pszNewPath);
|
|
PathRemoveFileSpec(szParent);
|
|
|
|
// Is this inside another briefcase?
|
|
if (PL_FALSE != PathGetLocality(szParent, szTmp))
|
|
{
|
|
// Yes; don't do it!
|
|
MsgBox(hwnd,
|
|
MAKEINTRESOURCE(IDS_ERR_CREATE_INANOTHER),
|
|
MAKEINTRESOURCE(IDS_CAP_CREATE),
|
|
NULL,GUID_NULL,NULL,
|
|
MB_WARNING);
|
|
}
|
|
else if (CreateDirectory(pszNewPath, NULL))
|
|
{
|
|
// Mark the briefcase as a system directory
|
|
//
|
|
if (!SetFileAttributes(pszNewPath, FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, TEXT("Cannot make %s a system directory"), (LPCTSTR)pszNewPath);
|
|
RemoveDirectory(pszNewPath);
|
|
|
|
MsgBox(hwnd,
|
|
MAKEINTRESOURCE(IDS_ERR_CANTCREATEBC),
|
|
MAKEINTRESOURCE(IDS_CAP_CREATE),
|
|
NULL,GUID_NULL,NULL,
|
|
MB_ERROR,
|
|
pszNewPath);
|
|
}
|
|
else
|
|
{
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
const static TCHAR c_szConfirmFileOp[] = TEXT("ConfirmFileOp");
|
|
#pragma data_seg()
|
|
HBRFCASE hbrf;
|
|
TWINRESULT tr;
|
|
LPCTSTR pszDBName;
|
|
DECLAREHOURGLASS;
|
|
|
|
if (PathsTooLong(pszNewPath, c_szDesktopIni) ||
|
|
PathsTooLong(pszNewPath, g_szDBName) ||
|
|
PathsTooLong(pszNewPath, g_szDBNameShort))
|
|
{
|
|
MsgBox(hwnd,
|
|
MAKEINTRESOURCE(IDS_ERR_CREATE_TOOLONG),
|
|
MAKEINTRESOURCE(IDS_CAP_CREATE),
|
|
NULL,GUID_NULL,NULL,
|
|
MB_ERROR);
|
|
}
|
|
else
|
|
{
|
|
// Write in the desktop.ini the briefcase class ID
|
|
PathCombine(szTmp, pszNewPath, c_szDesktopIni);
|
|
// (First, flush the cache to make sure the desktop.ini
|
|
// file is really created.)
|
|
WritePrivateProfileString(NULL, NULL, NULL, szTmp);
|
|
WritePrivateProfileString(STRINI_CLASSINFO, c_szIniKeyCLSID, c_szCLSID, szTmp);
|
|
WritePrivateProfileString(STRINI_CLASSINFO, c_szConfirmFileOp, TEXT("0"), szTmp);
|
|
|
|
// Make wizard run the first time it is opened.
|
|
WritePrivateProfileString(STRINI_CLASSINFO, c_szRunWizard, TEXT("1"), szTmp);
|
|
|
|
// Hide the desktop.ini since the shell does not selectively
|
|
// hide it.
|
|
if (!SetFileAttributes(szTmp, FILE_ATTRIBUTE_HIDDEN))
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, TEXT("Cannot hide %s"), (LPCTSTR)szTmp);
|
|
}
|
|
|
|
RegisterShellExtension();
|
|
|
|
PathNotifyShell(pszNewPath, NSE_MKDIR, TRUE);
|
|
|
|
// Create the database file
|
|
SetHourglass();
|
|
|
|
if (IsLFNDrive(pszNewPath))
|
|
pszDBName = g_szDBName;
|
|
else
|
|
pszDBName = g_szDBNameShort;
|
|
|
|
PathCombine(szTmp, pszNewPath, pszDBName);
|
|
if (Sync_QueryVTable())
|
|
{
|
|
tr = Sync_OpenBriefcase(szTmp,
|
|
OB_FL_OPEN_DATABASE | OB_FL_TRANSLATE_DB_FOLDER | OB_FL_ALLOW_UI,
|
|
hwnd,
|
|
&hbrf);
|
|
if (TR_SUCCESS == tr)
|
|
{
|
|
// (Don't really care about errors here)
|
|
Sync_SaveBriefcase(hbrf);
|
|
Sync_CloseBriefcase(hbrf);
|
|
}
|
|
}
|
|
ResetHourglass();
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Could not create the directory. Is it because a briefcase
|
|
// already exists at this location?
|
|
if (PathExists(pszNewPath))
|
|
{
|
|
// Yes
|
|
TRACE_MSG(TF_ALWAYS, TEXT("Briefcase already exists at this location: %s"), (LPCTSTR)pszNewPath);
|
|
}
|
|
else
|
|
{
|
|
// No
|
|
MsgBox(hwnd,
|
|
MAKEINTRESOURCE(IDS_ERR_CANTCREATEBC),
|
|
MAKEINTRESOURCE(IDS_CAP_CREATE),
|
|
NULL,GUID_NULL,NULL,
|
|
MB_ERROR,
|
|
pszNewPath);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Adds the briefcase at pszPath to the SendTo folder
|
|
|
|
Returns: standard result
|
|
Cond: --
|
|
*/
|
|
HRESULT PRIVATE AddBriefcaseToSendToFolder(
|
|
HWND hwnd,
|
|
LPCTSTR pszPath)
|
|
{
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
LPDATAOBJECT pdtobj;
|
|
LPITEMIDLIST pidl;
|
|
TCHAR szSendTo[MAX_PATH];
|
|
|
|
Shell_GetImageLists( NULL, NULL ); // make sure icon cache is around
|
|
|
|
if (SHGetSpecialFolderPath(hwnd, szSendTo, CSIDL_SENDTO, FALSE))
|
|
{
|
|
pidl = ILCreateFromPath(pszPath);
|
|
if (pidl)
|
|
{
|
|
LPITEMIDLIST pidlParent = ILClone(pidl);
|
|
if (pidlParent)
|
|
{
|
|
IShellFolder * psf;
|
|
IShellFolder * psfDesktop;
|
|
|
|
ILRemoveLastID(pidlParent);
|
|
|
|
psfDesktop = GetDesktopShellFolder();
|
|
hres = psfDesktop->lpVtbl->BindToObject(psfDesktop, pidlParent,
|
|
NULL, &IID_IShellFolder, &psf);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPCITEMIDLIST pidlName = ILFindLastID(pidl);
|
|
|
|
hres = psf->lpVtbl->GetUIObjectOf(psf, hwnd, 1,
|
|
&pidlName, &IID_IDataObject, NULL, &pdtobj);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
SHCreateLinks(hwnd, szSendTo, pdtobj, 0, NULL);
|
|
pdtobj->lpVtbl->Release(pdtobj);
|
|
}
|
|
psf->lpVtbl->Release(psf);
|
|
}
|
|
ILFree(pidlParent);
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Create a briefcase folder on the desktop.
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void WINAPI _export Briefcase_Create_Common(
|
|
HWND hwnd,
|
|
HINSTANCE hAppInstance,
|
|
LPTSTR pszCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
DEBUG_CODE( DEBUG_BREAK(BF_ONRUNONCE); )
|
|
|
|
// Command line should be of format "xxxx path" where <path>
|
|
// is the fully qualified pathname of the briefcase to create,
|
|
// and <xxxx> is the explorer hwnd.
|
|
|
|
if (pszCmdLine && *pszCmdLine)
|
|
{
|
|
LPTSTR psz;
|
|
HWND hwndCabinet;
|
|
|
|
// Get hwnd
|
|
hwndCabinet = (HWND)AnsiToInt(pszCmdLine);
|
|
psz = StrChr(pszCmdLine, TEXT(' '));
|
|
psz = CharNext(psz); // skip over space token
|
|
|
|
if (CreateTheBriefcase(hwnd, psz))
|
|
{
|
|
// Select the newly created item to edit it
|
|
LPITEMIDLIST pidl;
|
|
|
|
pidl = ILCreateFromPath(psz);
|
|
if (pidl)
|
|
{
|
|
SelectItemInCabinet(hwndCabinet, ILFindLastID(pidl), TRUE);
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Place it on the desktop
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
if (SHGetSpecialFolderPath(hwnd, szPath, CSIDL_DESKTOPDIRECTORY, FALSE))
|
|
{
|
|
int cch;
|
|
UINT ids;
|
|
|
|
if (IsLFNDrive(szPath))
|
|
ids = IDS_BC_NAME;
|
|
else
|
|
ids = IDS_BC_NAME_SHORT;
|
|
|
|
lstrcat(szPath, TEXT("\\"));
|
|
cch = lstrlen(szPath);
|
|
LoadString(g_hinst, ids, &szPath[cch], ARRAYSIZE(szPath)-cch);
|
|
if (CreateTheBriefcase(hwnd, szPath))
|
|
{
|
|
// Add a shortcut of this briefcase to the SendTo folder
|
|
AddBriefcaseToSendToFolder(hwnd, szPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WINAPI _export Briefcase_Create(
|
|
HWND hwnd,
|
|
HINSTANCE hAppInstance,
|
|
LPSTR pszCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
#ifdef UNICODE
|
|
UINT iLength = lstrlenA(pszCmdLine)+1;
|
|
LPWSTR lpwszCmdLine;
|
|
|
|
lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR, iLength *SIZEOF(TCHAR));
|
|
if (lpwszCmdLine)
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
pszCmdLine, -1,
|
|
lpwszCmdLine, iLength);
|
|
|
|
Briefcase_Create_Common(hwnd, hAppInstance, lpwszCmdLine, nCmdShow);
|
|
LocalFree((HANDLE)lpwszCmdLine);
|
|
}
|
|
#else
|
|
Briefcase_Create_Common(hwnd, hAppInstance, pszCmdLine, nCmdShow);
|
|
#endif
|
|
}
|
|
|
|
void WINAPI _export Briefcase_CreateW(
|
|
HWND hwnd,
|
|
HINSTANCE hAppInstance,
|
|
LPWSTR pwszCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
#ifdef UNICODE
|
|
Briefcase_Create_Common(hwnd, hAppInstance, pwszCmdLine, nCmdShow);
|
|
#else
|
|
UINT iLength = WideCharToMultiByte(CP_ACP, 0,
|
|
pwszCmdLine, -1,
|
|
NULL, 0, 0, 0)+1;
|
|
LPSTR lpszCmdLine;
|
|
|
|
lpszCmdLine = (LPSTR)LocalAlloc(LPTR, iLength);
|
|
if (lpszCmdLine)
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
pwszCmdLine, -1,
|
|
lpszCmdLine, iLength);
|
|
|
|
Briefcase_Create_Common(hwnd, hAppInstance, lpszCmdLine, nCmdShow);
|
|
LocalFree((HANDLE)lpszCmdLine);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Display the introduction "wizard". (It's really not
|
|
a wizard since it is not making anything for us.)
|
|
|
|
NOTE: This function serves double duty for both the ansi and unicode
|
|
versions. It never uses the command line.
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void WINAPI _export Briefcase_Intro(
|
|
HWND hwnd,
|
|
HINSTANCE hAppInstance,
|
|
LPTSTR lpszCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
Intro_DoModal(hwnd);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DLL entry-points
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: This function is called back from within
|
|
IClassFactory::CreateInstance() of the default class
|
|
factory object, which is created by SHCreateClassObject.
|
|
|
|
Returns: standard
|
|
Cond: --
|
|
*/
|
|
HRESULT CALLBACK DllFactoryCallback(
|
|
LPUNKNOWN punkOuter, // Should be NULL for us
|
|
REFIID riid,
|
|
LPVOID * ppvOut)
|
|
{
|
|
HRESULT hres;
|
|
|
|
if (IsEqualIID(riid, &IID_IShellExtInit))
|
|
{
|
|
hres = BriefExt_CreateInstance(punkOuter, riid, ppvOut);
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IBriefcaseStg) ||
|
|
IsEqualIID(riid, &IID_IBriefcaseStg2))
|
|
{
|
|
hres = BriefStg_CreateInstance(punkOuter, riid, ppvOut);
|
|
}
|
|
else
|
|
{
|
|
hres = ResultFromScode(E_NOINTERFACE);
|
|
*ppvOut = NULL;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Standard OLE 2.0 entry-point
|
|
|
|
Returns: standard
|
|
Cond: --
|
|
*/
|
|
STDAPI DllGetClassObject(
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
LPVOID * ppvOut)
|
|
{
|
|
HRESULT hres;
|
|
|
|
if (IsEqualIID(rclsid, &CLSID_Briefcase))
|
|
{
|
|
// We are supposed return the class object for this class. Instead
|
|
// of fully implementing it in this DLL, we just call a helper
|
|
// function in the shell DLL which creates a default class factory
|
|
// object for us. When its CreateInstance member is called, it
|
|
// will call back our create instance function.
|
|
hres = SHCreateDefClassObject(
|
|
riid, // Interface ID
|
|
ppvOut, // Non-null to aggregate
|
|
DllFactoryCallback, // callback function
|
|
&g_cBusyRef, // reference count of this DLL
|
|
NULL); // init interface
|
|
}
|
|
else
|
|
{
|
|
hres = ResultFromScode(REGDB_E_CLASSNOTREG);
|
|
*ppvOut = NULL;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: "Can Unload Now" entry point. Called by the shell DLL
|
|
task handler list.
|
|
Returns: S_OK to unload
|
|
Cond: --
|
|
*/
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// We only unload when:
|
|
// 2) We are not busy processing anything else *and*
|
|
// 3) No briefcases are currently open
|
|
//
|
|
ENTEREXCLUSIVE()
|
|
{
|
|
if (!IsBusySemaphore() &&
|
|
!IsOpenBriefSemaphore())
|
|
{
|
|
DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("DllCanUnloadNow says OK (Busy=%d, Brief=%d)"),
|
|
g_cBusyRef, g_cBriefRef); )
|
|
|
|
hr = ResultFromScode(S_OK);
|
|
}
|
|
else
|
|
{
|
|
DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("DllCanUnloadNow says FALSE (Busy=%d, Brief=%d)"),
|
|
g_cBusyRef, g_cBriefRef); )
|
|
|
|
hr = ResultFromScode(S_FALSE);
|
|
}
|
|
}
|
|
LEAVEEXCLUSIVE()
|
|
|
|
return hr;
|
|
}
|