windows-nt/Source/XPSP1/NT/net/irda/irftp/utils.cpp
2020-09-26 16:20:57 +08:00

848 lines
23 KiB
C++

/*++
Microsoft Windows
Copyright (C) Microsoft Corporation, 1981 - 1999
Module Name:
utils.cpp
Abstract:
Author:
Rahul Thombre (RahulTh) 4/30/1998
Revision History:
4/30/1998 RahulTh
Created this module.
10/12/98 RahulTh
Better error handling capabilities added : CError etc.
--*/
#include "precomp.hxx"
#define VALIDATE_SEND_COOKIE(cookie) \
{ \
__try \
{ \
*pStatus = ERROR_INVALID_DATA; \
if (MAGIC_ID != ((CSendProgress *)cookie)->m_dwMagicID) \
return; \
*pStatus = ERROR_SUCCESS; \
} \
__except (EXCEPTION_EXECUTE_HANDLER) \
{ \
return; \
} \
}
////////////////////////////////////////////////////////////////////////
//
//RPC Functions
//
///////////////////////////////////////////////////////////////////////
void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t Size)
{
return new char[Size];
}
void __RPC_USER MIDL_user_free( void __RPC_FAR * buf)
{
delete [] buf;
}
//
// wireless link specific errors
//
ERROR_TO_STRING_ID g_ErrorToStringId[] =
{
{ERROR_IRTRANP_OUT_OF_MEMORY, IDS_ERROR_NO_MEMORY},
{ERROR_IRTRANP_DISK_FULL, IDS_ERROR_DISK_FULL},
{ERROR_SCEP_CANT_CREATE_FILE, IDS_ERROR_DISK_FULL},
{ERROR_SCEP_ABORT, IDS_ERROR_ABORTED},
{ERROR_SCEP_INVALID_PROTOCOL, IDS_ERROR_PROTOCOL},
{ERROR_SCEP_PDU_TOO_LARGE, IDS_ERROR_PROTOCOL},
{ERROR_BFTP_INVALID_PROTOCOL, IDS_ERROR_PROTOCOL},
{ERROR_BFTP_NO_MORE_FRAGMENTS, IDS_ERROR_PROTOCOL},
{ERROR_SUCCESS, -1}
};
////////////////////////////////////////////////////////////////////
//
//Miscellaneous useful functions
//
///////////////////////////////////////////////////////////////////
int ParseFileNames (TCHAR* pszInString, TCHAR* pszFilesList, int& iCharCount)
{
ASSERT(pszFilesList != NULL);
ASSERT(pszInString != NULL);
BOOL fInQuotes = FALSE;
BOOL fIgnoreSpaces = FALSE;
TCHAR* pszSource = pszInString;
TCHAR* pszTarget = pszFilesList;
int iFileCount = 0;
TCHAR curr;
//ignore leading whitespaces
while(' ' == *pszSource || '\t' == *pszSource)
pszSource++;
iCharCount = 0;
*pszTarget = '\0'; //precautionary measures
if ('\0' == *pszSource) //special case : if this was an empty string, return 0
return iFileCount;
//parse the string to get filenames
while(curr = *pszSource)
{
if('\"' == curr)
{
fInQuotes = fInQuotes?FALSE:TRUE;
}
else if(' ' == curr && !fInQuotes)
{
if(!fIgnoreSpaces)
{
*pszTarget++ = 0;
iFileCount++;
iCharCount++;
fIgnoreSpaces = TRUE;
}
}
else
{
*pszTarget++ = curr;
iCharCount++;
fIgnoreSpaces = FALSE;
}
pszSource++;
}
if(' ' != *(pszSource-1)) //if there was no trailing space
{
*pszTarget++ = '\0'; //then the last file was not accounted for.
iCharCount++; //so we do it here
iFileCount++;
}
*pszTarget++ = '\0'; //should have 2 terminating nulls
iCharCount++;
return iFileCount;
}
//+--------------------------------------------------------------------------
//
// Function: GetIRRegVal
//
// Synopsis: gets the specified registry value from the IR subtree in HKCU
//
// Arguments: [in] szValName : the name of the value.
// [in] dwDefVal : the default value to be returned if the read
// from the registry fails or if the value is
// missing.
//
// Returns: the actual value stored in the registry or the default value
// if the read fails.
//
// History: 10/27/1999 RahulTh created
//
// Notes:
//
//---------------------------------------------------------------------------
DWORD GetIRRegVal (LPCTSTR szValName, DWORD dwDefVal)
{
HKEY hftKey = NULL;
DWORD iSize = sizeof(DWORD);
DWORD data = 0;
DWORD Status;
RegOpenKeyEx (HKEY_CURRENT_USER, TEXT("Control Panel\\Infrared\\File Transfer"),
0, KEY_READ, &hftKey);
if (!hftKey)
return dwDefVal;
Status = RegQueryValueEx (hftKey, szValName, NULL, NULL,
(LPBYTE)&data, &iSize);
if (ERROR_SUCCESS != Status)
data = dwDefVal;
RegCloseKey (hftKey);
return data;
}
TCHAR* GetFullPathnames (TCHAR* pszPath, //directory in which the files are located
const TCHAR* pszFilesList, //NULL separated list of filenames
int iFileCount, //number of files in pszFilesList
int& iCharCount //number of characters in pszFilesList. also returns the number of chars in the return string
)
{
int iChars;
int iPathLen = lstrlen(pszPath);
if (pszPath[iPathLen - 1] != '\\') //append a '\' character to the path if not already present
{
pszPath[iPathLen++] = '\\';
pszPath[iPathLen] = '\0';
}
int iSize = (iChars = iFileCount*iPathLen + iCharCount);
TCHAR* pszFilePathList = new TCHAR[iSize];
TCHAR* pszTemp = pszFilePathList;
int iLen;
while(*pszFilesList)
{
lstrcpy(pszTemp, pszPath);
pszTemp += iPathLen;
lstrcpy(pszTemp, pszFilesList);
iLen = lstrlen(pszFilesList);
pszFilesList += iLen + 1;
pszTemp += iLen + 1;
}
*pszTemp = '\0'; //should be terminated by 2 null characters
iCharCount = (int)(pszTemp - pszFilePathList) + 1; //return the actual char count of this string
return pszFilePathList;
}
TCHAR* ProcessOneFile (TCHAR* pszPath, //directory in which the files are located
const TCHAR* pszFilesList, //NULL separated list of filenames
int iFileCount, //number of files in pszFilesList
int& iCharCount //number of characters in pszFilesList. also returns the number of characters in the return string
)
{
int iFileLen, iPathLen;
TCHAR* pszFullFileName;
iFileLen = lstrlen (pszFilesList);
iPathLen = lstrlen (pszPath);
ASSERT (iFileLen);
ASSERT (iPathLen);
if(':' == pszFilesList[1] //this is an absolute path starting with the drive letter;
|| ('\\' == pszFilesList[0] && '\\' == pszFilesList[1]) //UNC path
)
{
pszFullFileName = new TCHAR [iFileLen + 2];
lstrcpy (pszFullFileName, pszFilesList);
pszFullFileName[iFileLen + 1] = '\0'; //we need to have 2 terminating nulls
iCharCount = iFileLen + 2;
}
else if('\\' == pszFilesList[0]) //path relative to the root
{
iCharCount = iFileLen + 2 /*drive letter and colon*/ + 2 /*terminating nulls*/;
pszFullFileName = new TCHAR [iCharCount];
pszFullFileName[0] = pszPath[0];
pszFullFileName[1] = pszPath[1];
lstrcpy (pszFullFileName + 2, pszFilesList);
pszFullFileName[iCharCount - 1] = '\0'; //we need to have 2 terminating nulls
}
else //ordinary file name
{
iCharCount = iPathLen + iFileLen + 2; //2 terminating nulls
iCharCount += ('\\' == pszPath[iPathLen - 1])?0:1; //sometimes the path does not have a \ at the end, so we need to add these ourselves
pszFullFileName = new TCHAR [iCharCount];
lstrcpy (pszFullFileName, pszPath);
if('\\' != pszPath[iPathLen - 1]) //we need to add the \ ourselves
{
pszFullFileName[iPathLen] = '\\';
lstrcpy(pszFullFileName + iPathLen + 1, pszFilesList);
}
else
lstrcpy (pszFullFileName + iPathLen, pszFilesList);
pszFullFileName[iCharCount - 1] = '\0'; //2 terminating nulls
}
return pszFullFileName;
}
//+--------------------------------------------------------------------------
//
// Function: GetPrimaryAppWindow
//
// Synopsis: gets the handle to the main window of an existing instance of
// irftp
//
// Arguments: none.
//
// Returns: handle to the window if it finds one. otherwise NULL.
//
// History: 6/30/1999 RahulTh created
//
// Notes:
//
//---------------------------------------------------------------------------
HWND GetPrimaryAppWindow (void)
{
HWND hwnd = NULL;
int i = 1;
//try to find the window for 5 seconds.
do
{
hwnd = FindWindow (L"#32770", //the dialog class
MAIN_WINDOW_TITLE);
if (hwnd)
break;
Sleep (500);
} while ( i++ <= 10 );
return hwnd;
}
/////////////////////////////////////////////////////////////////////////
// Initialize the RPC server
////////////////////////////////////////////////////////////////////////
BOOL InitRPCServer (void)
{
DWORD Status;
Status = RpcServerRegisterIf( _IrNotifications_v1_0_s_ifspec, 0, 0);
if (Status)
{
return FALSE;
}
Status = RpcServerUseAllProtseqsIf( RPC_C_PROTSEQ_MAX_REQS_DEFAULT, _IrNotifications_v1_0_s_ifspec, 0);
if (Status)
{
return FALSE;
}
Status = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
if (Status)
{
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////
//Connect to the RPC server running on the first instance of the app
//this function is called only if this is not the first instance of the app
//////////////////////////////////////////////////////////////////////////////////
RPC_BINDING_HANDLE GetRpcHandle (void)
{
DWORD Status;
RPC_BINDING_HANDLE Binding;
Status = RpcBindingFromStringBinding(L"ncalrpc:", &Binding);
if (Status)
return NULL;
else
return Binding;
}
///////////////////////////////////////////////////////////////////////////////////////
// RPC Server functions
//////////////////////////////////////////////////////////////////////////////////////
void _PopupUI (handle_t Binding)
{
int nResponse;
appController->PostMessage(WM_APP_TRIGGER_UI);
return;
}
void _InitiateFileTransfer (handle_t Binding, ULONG lSize, wchar_t __RPC_FAR lpszFilesList[])
{
COPYDATASTRUCT cStruct;
cStruct.dwData = lSize;
cStruct.cbData = lSize * sizeof(wchar_t);
cStruct.lpData = (LPVOID)(lpszFilesList);
appController->SendMessage(WM_COPYDATA, (WPARAM)NULL, (LPARAM)(&cStruct));
}
void _DisplaySettings (handle_t Binding)
{
appController->PostMessage(WM_APP_TRIGGER_SETTINGS);
}
void _UpdateSendProgress (
handle_t RpcBinding,
COOKIE Cookie,
wchar_t CurrentFile[],
__int64 BytesInTransfer,
__int64 BytesTransferred,
error_status_t* pStatus
)
{
VALIDATE_SEND_COOKIE (Cookie)
CSendProgress* progressDlg = (CSendProgress*)Cookie;
int percentComplete;
if (BytesInTransfer)
{
percentComplete = (int)((BytesTransferred*100.0)/BytesInTransfer);
}
else
{
percentComplete = 100;
}
progressDlg->PostMessage(WM_APP_UPDATE_PROGRESS, (WPARAM) 0, (LPARAM) percentComplete);
if (100 > percentComplete)
{
progressDlg->SetCurrentFileName (CurrentFile);
}
*pStatus = 0;
}
void _OneSendFileFailed(
handle_t RpcBinding,
COOKIE Cookie,
wchar_t FileName[],
error_status_t ErrorCode,
FAILURE_LOCATION Location,
error_status_t * pStatus
)
{
VALIDATE_SEND_COOKIE (Cookie)
struct SEND_FAILURE_DATA Data;
COPYDATASTRUCT cStruct;
CWnd* progressDlg = (CWnd*)Cookie;
lstrcpy(Data.FileName, FileName);
Data.Location = Location;
Data.Error = ErrorCode;
cStruct.cbData = sizeof(SEND_FAILURE_DATA);
cStruct.lpData = &Data;
progressDlg->SendMessage(WM_COPYDATA, (WPARAM) 0, (LPARAM)(&cStruct));
*pStatus = 0;
}
void _SendComplete(
handle_t RpcBinding,
COOKIE Cookie,
__int64 BytesTransferred,
error_status_t* pStatus
)
{
VALIDATE_SEND_COOKIE (Cookie)
CWnd* progressDlg = (CWnd*)Cookie;
progressDlg->PostMessage(WM_APP_SEND_COMPLETE);
*pStatus = 0;
}
error_status_t
_ReceiveInProgress(
handle_t RpcBinding,
wchar_t MachineName[],
COOKIE * pCookie,
boolean bSuppressRecvConf
)
{
struct MSG_RECEIVE_IN_PROGRESS msg;
msg.MachineName = MachineName;
msg.pCookie = pCookie;
msg.bSuppressRecvConf = bSuppressRecvConf;
msg.status = ~0UL;
appController->SendMessage( WM_APP_RECV_IN_PROGRESS, (WPARAM) &msg );
return msg.status;
}
error_status_t
_GetPermission(
handle_t RpcBinding,
COOKIE Cookie,
wchar_t Name[],
boolean fDirectory
)
{
struct MSG_GET_PERMISSION msg;
msg.Cookie = Cookie;
msg.Name = Name;
msg.fDirectory = fDirectory;
msg.status = ~0UL;
appController->SendMessage( WM_APP_GET_PERMISSION, (WPARAM) &msg );
return msg.status;
}
error_status_t
_ReceiveFinished(
handle_t RpcBinding,
COOKIE Cookie,
error_status_t Status
)
{
struct MSG_RECEIVE_FINISHED msg;
msg.Cookie = Cookie;
msg.ReceiveStatus = Status;
msg.status = ~0UL;
appController->SendMessage( WM_APP_RECV_FINISHED, (WPARAM) &msg );
return msg.status;
}
void _DeviceInRange(
handle_t RpcBinding,
POBEX_DEVICE_LIST device,
error_status_t* pStatus
)
{
appController->PostMessage (WM_APP_KILL_TIMER);
BOOL fLinkOnDesktop = (0 != InterlockedIncrement(&g_lLinkOnDesktop));
if(!fLinkOnDesktop)
CreateLinks();
else
InterlockedDecrement(&g_lLinkOnDesktop); //don't allow the value to exceed 0
g_deviceList = device;
*pStatus = 0;
}
void _NoDeviceInRange(
handle_t RpcBinding,
error_status_t* pStatus
)
{
RemoveLinks();
InterlockedDecrement(&g_lLinkOnDesktop);
g_deviceList = NULL;
if (0 == g_lUIComponentCount)
appController->PostMessage (WM_APP_START_TIMER);
*pStatus = 0;
}
void _Message(
handle_t RpcBinding,
wchar_t String[]
)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState());
CString szTitle;
szTitle.LoadString (IDS_CAPTION);
InterlockedIncrement (&g_lUIComponentCount);
::MessageBox (NULL, String, (LPCTSTR) szTitle, MB_OK);
BOOL fNoUIComponents = (0 == InterlockedDecrement (&g_lUIComponentCount));
if (appController && fNoUIComponents && ! g_deviceList.GetDeviceCount())
{
//there are no UI components displayed and there are no devices in
//range. Start the timer. If the timer expires, the app. will quit.
appController->PostMessage (WM_APP_START_TIMER);
}
}
error_status_t
_ShutdownUi(handle_t RpcBinding)
{
appController->PostMessage( WM_CLOSE );
return 0;
}
error_status_t
_ShutdownRequested(
handle_t RpcBinding,
boolean * pAnswer
)
{
WCHAR pwszCaption [50];
WCHAR pwszMessage [MAX_PATH];
*pAnswer = TRUE;
if (appController)
{
appController->PostMessage (WM_APP_KILL_TIMER);
}
if (! ::LoadString ( g_hInstance, IDS_CAPTION, pwszCaption, 50))
{
return ERROR_NOT_ENOUGH_MEMORY;
}
if (! ::LoadString ( g_hInstance, IDS_SHUTDOWN_MESSAGE, pwszMessage, MAX_PATH))
{
return ERROR_NOT_ENOUGH_MEMORY;
}
//display a message box with YES / NO buttons
if (IDYES == ::MessageBox (appController->m_hWnd, pwszMessage, pwszCaption,
MB_ICONEXCLAMATION | MB_YESNO | MB_SYSTEMMODAL | MB_SETFOREGROUND))
{
*pAnswer = TRUE;
}
else
{
*pAnswer = FALSE;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////
//Create links on the desktop and in the Send To menu to this executable file
void CreateLinks(void)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState());
TCHAR lpszFullExeName [MAX_PATH];
TCHAR lpszShortcutName[MAX_PATH];
CString szDesc;
szDesc.LoadString (IDS_SHTCUT_DESC);
//create the desktop link
if (GetShortcutInfo(lpszShortcutName, lpszFullExeName))
CreateShortcut (lpszFullExeName, lpszShortcutName, (LPCTSTR) szDesc);
//create the send to link
if (GetSendToInfo(lpszShortcutName, lpszFullExeName))
CreateShortcut (lpszFullExeName, lpszShortcutName, (LPCTSTR) szDesc);
}
//////////////////////////////////////////////////////////////////////////////
// CreateShortcut - uses the shell's IShellLink and IPersistFile interfaces
// to create and store a shortcut to the specified object.
HRESULT CreateShortcut (LPCTSTR lpszExe, LPCTSTR lpszLink, LPCTSTR lpszDesc)
{
HRESULT hres;
IShellLink* psl;
hres = CoInitialize(NULL);
if (FAILED(hres))
return hres;
// Get a pointer to the IShellLink interface.
hres = CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres)) {
IPersistFile* ppf;
// Set the path to the shortcut target and add the
// description.
psl->SetPath(lpszExe);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres)) {
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(lpszLink, TRUE);
ppf->Release();
}
psl->Release();
}
return SUCCEEDED(hres)?S_OK:E_FAIL;
}
void RemoveLinks (void)
{
TCHAR lpszShortcutName[2 * MAX_PATH];
TCHAR lpszFullExeName[2 * MAX_PATH];
//delete the desktop shortcut
if(GetShortcutInfo (lpszShortcutName, lpszFullExeName))
DeleteFile (lpszShortcutName);
//delete the send to shortcut
if (GetSendToInfo (lpszShortcutName, lpszFullExeName))
DeleteFile (lpszShortcutName);
}
BOOL GetShortcutInfo (LPTSTR lpszShortcutName, LPTSTR lpszFullExeName)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState());
*lpszShortcutName = '\0'; //precautionary measures
*lpszFullExeName = '\0';
CString szExe;
CString szShtCut;
int len;
szExe.LoadString (IDS_EXE);
szShtCut.LoadString (IDS_DESKTOP_SHTCUT);
len = GetSystemDirectory (lpszFullExeName, MAX_PATH);
if(0 == len)
return FALSE;
lstrcat(lpszFullExeName, LPCTSTR (szExe));
if('\0' == g_lpszDesktopFolder[0]) //try once again if we had failed before, or maybe this is the first time
{
if (FAILED(SHGetSpecialFolderPath(NULL, g_lpszDesktopFolder,
CSIDL_DESKTOPDIRECTORY, 0)))
{
g_lpszDesktopFolder[0] = '\0'; //we failed so give up.
return FALSE;
}
}
lstrcpy (lpszShortcutName, g_lpszDesktopFolder);
lstrcat (lpszShortcutName, (LPCTSTR) szShtCut);
return TRUE;
}
BOOL GetSendToInfo (LPTSTR lpszSendToName, LPTSTR lpszFullExeName)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState());
*lpszSendToName = '\0'; //precautionary measures
*lpszFullExeName = '\0';
CString szExe;
CString szSendTo;
int len;
szExe.LoadString (IDS_EXE);
szSendTo.LoadString (IDS_SENDTO_SHTCUT);
len = GetSystemDirectory (lpszFullExeName, MAX_PATH);
if (0 == len)
return FALSE;
lstrcat (lpszFullExeName, (LPCTSTR) szExe);
if ('\0' == g_lpszSendToFolder[0]) //try once again if we had failed before, or maybe this is the first time
{
if (FAILED(SHGetSpecialFolderPath(NULL, g_lpszSendToFolder,
CSIDL_SENDTO, 0)))
{
g_lpszSendToFolder[0] = '\0';
return FALSE;
}
}
lstrcpy (lpszSendToName, g_lpszSendToFolder);
lstrcat (lpszSendToName, (LPCTSTR) szSendTo);
return TRUE;
}
//+--------------------------------------------------------------------------
//
// Member: CError::ConstructMessage
//
// Synopsis: this is an internal helper function that constructs a message
// from the available error codes it is called by both ShowMessage
//
// Arguments: [in] argList : the va_list of arguments
// [out] szErrMsg : the formatted error message
//
// Returns: nothing
//
// History: 10/2/1998 RahulTh created
//
// Notes:
//
//---------------------------------------------------------------------------
void CError::ConstructMessage (va_list argList, CString& szErrMsg)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState());
TCHAR lpszMessage[2048];
szErrMsg.LoadString (m_msgID);
wvsprintf (lpszMessage, (LPCTSTR) szErrMsg, argList);
szErrMsg = lpszMessage;
if (ERROR_SUCCESS != m_winErr)
{
LPVOID lpMsgBuf;
DWORD dwRet;
dwRet = ::FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
m_winErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
if (dwRet)
{
szErrMsg += TEXT("\n\n");
szErrMsg += (LPCTSTR) lpMsgBuf;
LocalFree (lpMsgBuf);
}
}
}
//+--------------------------------------------------------------------------
//
// Member: CError::ShowMessage
//
// Synopsis: displays an error message in a message box based on the
// members of the object
//
// Arguments: message id for the error + more
//
// Returns: the return value of the message box
//
// History: 10/1/1998 RahulTh created
//
// Notes: if the resultant message is longer than 2048 characters
// then result is unpredictable and may also cause AVs.
// but this is a limitation of wvsprintf. However, this is not
// so bad since we can make sure that we do not have any error
// message that exceed this self imposed limit
//
//---------------------------------------------------------------------------
int CError::ShowMessage (UINT errID, ...)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState());
va_list argList;
CString szErrMsg;
CString szTitle;
m_msgID = errID; //update the message ID with the new one
szTitle.LoadString (m_titleID);
va_start (argList, errID);
ConstructMessage (argList, szErrMsg);
va_end (argList);
return ::MessageBox (m_hWndParent, (LPCTSTR)szErrMsg,
(LPCTSTR) szTitle, m_nStyle);
}