/*++ 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" #include LONG g_lLinkOnDesktop = 0; //the path of the desktop folder. TCHAR g_lpszDesktopFolder[MAX_PATH]; //the path to the send to folder; TCHAR g_lpszSendToFolder[MAX_PATH]; BOOL GetShortcutInfo ( LPTSTR lpszShortcutName, ULONG ShortCutNameLength, LPTSTR lpszFullExeName, ULONG ExeNameLength ); BOOL GetSendToInfo ( LPTSTR lpszSendToName, ULONG SendToNameLength, LPTSTR lpszFullExeName, ULONG FullExeNameLength ); #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; \ } \ } // // 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) { // // start with the path // StringCchCopy(pszTemp, iSize ,pszPath); // // add on the file name // StringCchCat(pszTemp, iSize, pszFilesList); // // move the next files name // iLen = lstrlen(pszFilesList); pszFilesList += iLen + 1; // // move past the current path and file name // iLen = lstrlen(pszTemp); pszTemp += iLen + 1; iSize-=iLen; } *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]; StringCchCopy(pszFullFileName, iFileLen + 2, 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]; StringCchCopy(pszFullFileName + 2, iCharCount-2, pszFilesList); pszFullFileName[iCharCount - 1] = '\0'; //we need to have 2 terminating nulls } else //ordinary file name { iCharCount = iPathLen + iFileLen + 2; //2 terminating nulls // // sometimes the path does not have a \ at the end, so we need to add these ourselves // iCharCount += ('\\' == pszPath[iPathLen - 1])?0:1; pszFullFileName = new TCHAR [iCharCount]; // // put in the path // StringCchCopy(pszFullFileName,iCharCount, pszPath); if ('\\' != pszPath[iPathLen - 1]) { // // we need to add the \ ourselves // StringCchCat(pszFullFileName,iCharCount,TEXT("\\")); } // // add on the file name // StringCchCat(pszFullFileName,iCharCount,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; } /////////////////////////////////////////////////////////////////////////////////////// // 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, int Location, error_status_t * pStatus ) { VALIDATE_SEND_COOKIE (Cookie) struct SEND_FAILURE_DATA Data; COPYDATASTRUCT cStruct; CWnd* progressDlg = (CWnd*)Cookie; StringCbCopy(Data.FileName,sizeof(Data.FileName), FileName); Data.Location = (FAILURE_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); LONG NewLinkCount = InterlockedIncrement(&g_lLinkOnDesktop); BOOL Result; if (NewLinkCount == 1) { // // the link count went from zero to 1, create the links now // Result=CreateLinks(); if (!Result) { // // could not create the links // InterlockedExchange(&g_lLinkOnDesktop,0); } } g_deviceList= device; *pStatus = 0; } void _NoDeviceInRange( handle_t RpcBinding, error_status_t* pStatus ) { InterlockedExchange(&g_lLinkOnDesktop,0); RemoveLinks(); g_deviceList = NULL; if (0 == g_lUIComponentCount) { // // nothing displayed, start timer to shutdown app if no device comeback some. // appController->PostMessage (WM_APP_START_TIMER); } *pStatus = 0; } VOID CloseDownUI( VOID ) { if (0 == g_lUIComponentCount) { if (appController != NULL) { appController->PostMessage (WM_CLOSE); } } else { if (appController != NULL) { appController->SessionOver(); } } return; } 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 BOOL CreateLinks( VOID ) { AFX_MANAGE_STATE (AfxGetStaticModuleState()); HRESULT Result=E_FAIL; LONG i; TCHAR lpszFullExeName [2*MAX_PATH]; TCHAR lpszShortcutName[2*MAX_PATH]; CString szDesc; szDesc.LoadString (IDS_SHTCUT_DESC); // // create the desktop link // if (GetShortcutInfo(lpszShortcutName,sizeof(lpszShortcutName)/sizeof(TCHAR), lpszFullExeName,sizeof(lpszFullExeName)/sizeof(TCHAR))) { #if 0 OutputDebugString(lpszShortcutName); OutputDebugStringA("\n"); #endif Result=CreateShortcut (lpszFullExeName, lpszShortcutName, (LPCTSTR) szDesc); if (SUCCEEDED(Result)) { } else { #if DB OutputDebugStringA("Could not create desktop link\n"); #endif } } else { #if DBG OutputDebugStringA("Could not get desktop path\n"); #endif } if (!SUCCEEDED(Result)) { return FALSE; } // // create the send to link // if (GetSendToInfo(lpszShortcutName,sizeof(lpszShortcutName)/sizeof(TCHAR) ,lpszFullExeName,sizeof(lpszFullExeName)/sizeof(TCHAR))) { Result=CreateShortcut (lpszFullExeName, lpszShortcutName, (LPCTSTR) szDesc); if (SUCCEEDED(Result)) { } else { #if DBG OutputDebugStringA("Could not create desktop link\n"); #endif } } else { #if DBG OutputDebugStringA("Could get sendto path\n"); #endif } return SUCCEEDED(Result); } ////////////////////////////////////////////////////////////////////////////// // 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,sizeof(lpszShortcutName)/sizeof(TCHAR), lpszFullExeName,sizeof(lpszFullExeName)/sizeof(TCHAR))) { DeleteFile (lpszShortcutName); } //delete the send to shortcut // if (GetSendToInfo (lpszShortcutName,sizeof(lpszShortcutName)/sizeof(TCHAR), lpszFullExeName,sizeof(lpszFullExeName)/sizeof(TCHAR))) { DeleteFile (lpszShortcutName); } } BOOL GetShortcutInfo ( LPTSTR lpszShortcutName, ULONG ShortCutNameLength, LPTSTR lpszFullExeName, ULONG ExeNameLength ) { 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, ExeNameLength); if (0 == len) { return FALSE; } StringCchCat(lpszFullExeName,ExeNameLength,LPCTSTR (szExe)); if('\0' == g_lpszDesktopFolder[0]) //try once again if we had failed before, or maybe this is the first time { if (!SHGetSpecialFolderPath(NULL, g_lpszDesktopFolder, CSIDL_DESKTOPDIRECTORY, 0)) { g_lpszDesktopFolder[0] = '\0'; //we failed so give up. return FALSE; } } StringCchCopy(lpszShortcutName,ShortCutNameLength, g_lpszDesktopFolder); StringCchCat(lpszShortcutName,ShortCutNameLength, (LPCTSTR) szShtCut); return TRUE; } BOOL GetSendToInfo ( LPTSTR lpszSendToName, ULONG SendToNameLength, LPTSTR lpszFullExeName, ULONG FullExeNameLength ) { AFX_MANAGE_STATE (AfxGetStaticModuleState()); *lpszSendToName = TEXT('\0'); //precautionary measures *lpszFullExeName = TEXT('\0'); CString szExe; CString szSendTo; int len; szExe.LoadString (IDS_EXE); szSendTo.LoadString (IDS_SENDTO_SHTCUT); len = GetSystemDirectory (lpszFullExeName, FullExeNameLength); if (0 == len) { return FALSE; } StringCchCat(lpszFullExeName,FullExeNameLength, (LPCTSTR) szExe); if ('\0' == g_lpszSendToFolder[0]) //try once again if we had failed before, or maybe this is the first time { if (!SHGetSpecialFolderPath(NULL, g_lpszSendToFolder, CSIDL_SENDTO, 0)) { g_lpszSendToFolder[0] = TEXT('\0'); return FALSE; } } StringCchCopy(lpszSendToName,SendToNameLength, g_lpszSendToFolder); StringCchCat(lpszSendToName, SendToNameLength,(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); StringCbVPrintf(lpszMessage, sizeof(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); }