488 lines
14 KiB
C++
488 lines
14 KiB
C++
|
/*++
|
||
|
|
||
|
Microsoft Windows
|
||
|
Copyright (C) Microsoft Corporation, 1981 - 1999
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
sendprogress.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Rahul Thombre (RahulTh) 4/30/1998
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
4/30/1998 RahulTh
|
||
|
|
||
|
Created this module.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
// SendProgress.cpp : implementation file
|
||
|
//
|
||
|
|
||
|
#include "precomp.hxx"
|
||
|
#include "winsock.h"
|
||
|
|
||
|
#define MAX_FILENAME_DISPLAY 35
|
||
|
|
||
|
#define DIALOG_DISPLAY_DURATION 800 //the minimum amount of time a dialog
|
||
|
//should be displayed (in milliseconds)
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CSendProgress dialog
|
||
|
|
||
|
|
||
|
CSendProgress::CSendProgress(LPTSTR lpszFileList /*=NULL*/, int iCharCount /*=0*/, CWnd* pParent /*=NULL*/)
|
||
|
{
|
||
|
m_dwMagicID = MAGIC_ID; //an id used to validate CSendProgress pointers
|
||
|
//received over an RPC interface.
|
||
|
m_lpszFileList = lpszFileList;
|
||
|
m_iCharCount = iCharCount;
|
||
|
m_lSelectedDeviceID = errIRFTP_SELECTIONCANCELLED;
|
||
|
m_lpszSelectedDeviceName[0] = '\0';
|
||
|
m_fSendDone = FALSE;
|
||
|
m_fTimerExpired = FALSE;
|
||
|
m_ptl = NULL;
|
||
|
m_fCancelled = FALSE;
|
||
|
appController->PostMessage (WM_APP_KILL_TIMER);
|
||
|
InterlockedIncrement (&g_lUIComponentCount);
|
||
|
Create(IDD, appController);
|
||
|
//{{AFX_DATA_INIT(CSendProgress)
|
||
|
// NOTE: the ClassWizard will add member initialization here
|
||
|
//}}AFX_DATA_INIT
|
||
|
}
|
||
|
|
||
|
|
||
|
void CSendProgress::DoDataExchange(CDataExchange* pDX)
|
||
|
{
|
||
|
CDialog::DoDataExchange(pDX);
|
||
|
//{{AFX_DATA_MAP(CSendProgress)
|
||
|
DDX_Control(pDX, IDC_XFER_PERCENTAGE, m_xferPercentage);
|
||
|
DDX_Control(pDX, IDC_CONNECTIONTEXT, m_connectedTo);
|
||
|
DDX_Control(pDX, IDC_FILESEND_PROGRESS, m_transferProgress);
|
||
|
DDX_Control(pDX, IDC_FILESEND_ANIM, m_transferAnim);
|
||
|
DDX_Control(pDX, IDC_FILE_NAME, m_fileName);
|
||
|
DDX_Control(pDX, IDC_SENDING_TITLE, m_sndTitle);
|
||
|
DDX_Control(pDX, IDCANCEL, m_btnCancel);
|
||
|
//}}AFX_DATA_MAP
|
||
|
}
|
||
|
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CSendProgress, CDialog)
|
||
|
//{{AFX_MSG_MAP(CSendProgress)
|
||
|
ON_WM_COPYDATA()
|
||
|
ON_WM_TIMER()
|
||
|
ON_MESSAGE(WM_APP_UPDATE_PROGRESS, OnUpdateProgress)
|
||
|
ON_MESSAGE(WM_APP_SEND_COMPLETE, OnSendComplete)
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CSendProgress message handlers
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
GetLocationDescription(
|
||
|
FAILURE_LOCATION Location
|
||
|
)
|
||
|
{
|
||
|
switch (Location)
|
||
|
{
|
||
|
case locStartup:
|
||
|
return IDS_LOC_STARTUP;
|
||
|
case locConnect:
|
||
|
return IDS_LOC_CONNECT;
|
||
|
case locFileOpen:
|
||
|
return IDS_LOC_FILEOPEN;
|
||
|
case locFileRead:
|
||
|
return IDS_LOC_FILEREAD;
|
||
|
case locFileSend:
|
||
|
return IDS_LOC_FILESEND;
|
||
|
case locFileRecv:
|
||
|
return IDS_LOC_FILERECV;
|
||
|
case locFileWrite:
|
||
|
return IDS_LOC_FILEWRITE;
|
||
|
case locUnknown:
|
||
|
default:
|
||
|
return IDS_LOC_UNKNOWN;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL CSendProgress::OnInitDialog()
|
||
|
{
|
||
|
TCHAR lpszConnectionInfo[100];
|
||
|
TCHAR lpszDeviceName[50];
|
||
|
TCHAR lpszConnecting[50];
|
||
|
error_status_t err;
|
||
|
error_status_t sendError;
|
||
|
LONG lDeviceID;
|
||
|
FAILURE_LOCATION location=locUnknown;
|
||
|
CError error;
|
||
|
CError xferError (this);
|
||
|
CString szConnect;
|
||
|
CString szErrorDesc;
|
||
|
CString szLocDesc;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
OBEX_DEVICE_TYPE DeviceType;
|
||
|
|
||
|
CDialog::OnInitDialog();
|
||
|
|
||
|
::LoadString (g_hInstance, IDS_CONNECTEDTO, lpszConnectionInfo, 100);
|
||
|
::LoadString (g_hInstance, IDS_CONNECTING, lpszConnecting, 50);
|
||
|
szConnect = lpszConnecting;
|
||
|
|
||
|
m_transferProgress.SetPos(0);
|
||
|
m_transferAnim.Open (IDR_TRANSFER_AVI);
|
||
|
m_transferAnim.Play(0, -1, -1);
|
||
|
m_fileName.SetWindowText (L"");
|
||
|
m_connectedTo.SetWindowText ((LPCTSTR) szConnect);
|
||
|
m_xferPercentage.SetWindowText(TEXT("0%"));
|
||
|
|
||
|
if (!g_deviceList.GetDeviceCount())
|
||
|
{
|
||
|
error.ShowMessage (IDS_NODEVICES_ERROR);
|
||
|
DestroyWindow();
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
lDeviceID = g_deviceList.SelectDevice(this, lpszDeviceName);
|
||
|
|
||
|
switch(lDeviceID)
|
||
|
{
|
||
|
case errIRFTP_NODEVICE:
|
||
|
error.ShowMessage (IDS_MISSING_RECIPIENT);
|
||
|
|
||
|
case errIRFTP_SELECTIONCANCELLED:
|
||
|
DestroyWindow();
|
||
|
return TRUE;
|
||
|
|
||
|
case errIRFTP_MULTDEVICES: //there were multiple devices in range, one of which was selected
|
||
|
|
||
|
if (g_deviceList.GetDeviceType(m_lSelectedDeviceID,&DeviceType)) {
|
||
|
|
||
|
SendFiles (g_hIrRpcHandle, (COOKIE)this, TEXT(""), m_lpszFileList, m_iCharCount, m_lSelectedDeviceID, DeviceType, &sendError, &location);
|
||
|
lstrcat (lpszConnectionInfo, m_lpszSelectedDeviceName);
|
||
|
m_connectedTo.SetWindowText(lpszConnectionInfo);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
error.ShowMessage (IDS_MISSING_RECIPIENT);
|
||
|
DestroyWindow();
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default: //there was only one device in range
|
||
|
|
||
|
if (g_deviceList.GetDeviceType(lDeviceID,&DeviceType)) {
|
||
|
|
||
|
SendFiles (g_hIrRpcHandle, (COOKIE)this, TEXT(""), m_lpszFileList, m_iCharCount, lDeviceID, DeviceType, &sendError, &location);
|
||
|
lstrcat (lpszConnectionInfo, lpszDeviceName);
|
||
|
m_connectedTo.SetWindowText(lpszConnectionInfo);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
error.ShowMessage (IDS_MISSING_RECIPIENT);
|
||
|
DestroyWindow();
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (sendError)
|
||
|
{
|
||
|
LPVOID lpMessageBuffer;
|
||
|
TCHAR ErrDesc [ERROR_DESCRIPTION_LENGTH];
|
||
|
CString ErrorDescription;
|
||
|
|
||
|
if (!FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL, // ignored
|
||
|
sendError,
|
||
|
0, // try default language ids
|
||
|
(LPTSTR) &lpMessageBuffer,
|
||
|
0,
|
||
|
NULL // ignored
|
||
|
))
|
||
|
{
|
||
|
wsprintf(ErrDesc, g_Strings.ErrorNoDescription, sendError);
|
||
|
//using the overloaded CString assignment operator. It is
|
||
|
//essentially a string copy, but MFC takes care of allocating
|
||
|
//and freeing the destination buffer.
|
||
|
ErrorDescription = ErrDesc;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//Note: this is not a pointer assignment. We are using the
|
||
|
//overloaded CString assignment operator which essentially
|
||
|
//does a string copy. (see comments above)
|
||
|
ErrorDescription = (TCHAR *) lpMessageBuffer;
|
||
|
LocalFree (lpMessageBuffer);
|
||
|
}
|
||
|
|
||
|
szLocDesc.LoadString (GetLocationDescription(location));
|
||
|
xferError.ShowMessage (IDS_XFER_ERROR, (LPCTSTR) szLocDesc,
|
||
|
(LPCTSTR) ErrorDescription);
|
||
|
DestroyWindow();
|
||
|
}
|
||
|
|
||
|
//there were no errors.
|
||
|
//first put up a taskbar button for the dialog
|
||
|
//Initialize the taskbar list interface
|
||
|
hr = CoInitialize(NULL);
|
||
|
if (SUCCEEDED (hr))
|
||
|
hr = CoCreateInstance(CLSID_TaskbarList,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_ITaskbarList,
|
||
|
(LPVOID*)&m_ptl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = m_ptl->HrInit();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_ptl = NULL;
|
||
|
}
|
||
|
|
||
|
if (m_ptl)
|
||
|
{
|
||
|
if (SUCCEEDED(hr))
|
||
|
m_ptl->AddTab(m_hWnd);
|
||
|
else
|
||
|
{
|
||
|
m_ptl->Release();
|
||
|
m_ptl = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Also set a timer to go off in half a second
|
||
|
//this timer is used to ensure that this dialog is displayed for
|
||
|
//at least half a second so that users can see that the file has been
|
||
|
//sent
|
||
|
//if we fail to get a timer, we simply treat this condition as if the
|
||
|
//timer has expired
|
||
|
m_fTimerExpired = SetTimer (1, DIALOG_DISPLAY_DURATION, NULL)?FALSE:TRUE;
|
||
|
return TRUE; // return TRUE unless you set the focus to a control
|
||
|
// EXCEPTION: OCX Property Pages should return FALSE
|
||
|
}
|
||
|
|
||
|
void CSendProgress::PostNcDestroy()
|
||
|
{
|
||
|
//do some cleanup
|
||
|
if (m_lpszFileList)
|
||
|
delete [] m_lpszFileList;
|
||
|
|
||
|
BOOL fNoUIComponents = (0 == InterlockedDecrement (&g_lUIComponentCount));
|
||
|
if (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);
|
||
|
}
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
//removes the taskbar button if one had been put up
|
||
|
BOOL CSendProgress::DestroyWindow()
|
||
|
{
|
||
|
//stop the animation and close the file.
|
||
|
m_transferAnim.Stop();
|
||
|
m_transferAnim.Close();
|
||
|
|
||
|
//if a taskbar button had been put up, remove that first
|
||
|
if (m_ptl)
|
||
|
{
|
||
|
m_ptl->DeleteTab(m_hWnd);
|
||
|
m_ptl->Release();
|
||
|
m_ptl = NULL;
|
||
|
}
|
||
|
|
||
|
//then destroy the window
|
||
|
return CWnd::DestroyWindow();
|
||
|
}
|
||
|
|
||
|
void CSendProgress::OnCancel()
|
||
|
{
|
||
|
TCHAR lpszCancel[MAX_PATH];
|
||
|
|
||
|
CancelSend(g_hIrRpcHandle, (COOKIE)this);
|
||
|
//important: do not destroy the window here.
|
||
|
//must wait until confirmation of the cancel
|
||
|
//is received from the other machine. after that
|
||
|
//irxfer will call sendcomplete. That is when the
|
||
|
//window should get destroyed. otherwise, CWnd pointer
|
||
|
//for this window might get reused and messages from
|
||
|
//irxfer meant for this window will go to another window
|
||
|
//which could cause it to get destroyed without the transmission
|
||
|
//getting interrupted.
|
||
|
//
|
||
|
//but make the user aware that an attempt to cancel the send is being made
|
||
|
m_fCancelled = TRUE;
|
||
|
m_btnCancel.EnableWindow(FALSE);
|
||
|
m_sndTitle.SetWindowText (TEXT(""));
|
||
|
m_fileName.SetWindowText (TEXT(""));
|
||
|
lpszCancel[0] = '\0';
|
||
|
::LoadString (g_hInstance, IDS_SENDCANCEL, lpszCancel, MAX_PATH);
|
||
|
m_fileName.SetWindowText (lpszCancel);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CSendProgress::OnTimer (UINT nTimerID)
|
||
|
{
|
||
|
m_fTimerExpired = TRUE;
|
||
|
//we don't need the timer any more. it needs to go off only once
|
||
|
KillTimer(1);
|
||
|
//half a second has elapsed since we started
|
||
|
//if the send is already complete, then it is this routine's
|
||
|
//responsibility to destroy the window since the SEND_COMPLETE
|
||
|
//notification has already been received
|
||
|
if (m_fSendDone)
|
||
|
DestroyWindow();
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CSendProgress::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
|
||
|
{
|
||
|
AFX_MANAGE_STATE (AfxGetStaticModuleState());
|
||
|
|
||
|
SEND_FAILURE_DATA * pData = (SEND_FAILURE_DATA *) (pCopyDataStruct->lpData);
|
||
|
|
||
|
LPVOID lpMessageBuffer;
|
||
|
TCHAR ErrDesc [ERROR_DESCRIPTION_LENGTH];
|
||
|
CString ErrorDescription;
|
||
|
CString szErrorDesc;
|
||
|
CString szLocDesc;
|
||
|
CError error (this);
|
||
|
|
||
|
if (m_fCancelled)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (!FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
||
|
NULL, // ignored
|
||
|
pData->Error,
|
||
|
0, // try default language ids
|
||
|
(LPTSTR) &lpMessageBuffer,
|
||
|
0,
|
||
|
NULL // ignored
|
||
|
))
|
||
|
{
|
||
|
wsprintf(ErrDesc, g_Strings.ErrorNoDescription, pData->Error);
|
||
|
//using the overloaded CString assignment operator. It is
|
||
|
//essentially a string copy, but MFC takes care of allocating
|
||
|
//and freeing the destination buffer.
|
||
|
ErrorDescription = ErrDesc;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//Note: this is not a pointer assignment. We are using the
|
||
|
//overloaded CString assignment operator which essentially
|
||
|
//does a string copy. (see comments above)
|
||
|
ErrorDescription = (TCHAR *) lpMessageBuffer;
|
||
|
LocalFree (lpMessageBuffer);
|
||
|
}
|
||
|
|
||
|
szLocDesc.LoadString (GetLocationDescription(pData->Location));
|
||
|
error.ShowMessage (IDS_SEND_FAILURE, pData->FileName, (LPCTSTR) szLocDesc,
|
||
|
(LPCTSTR) ErrorDescription);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void CSendProgress::OnUpdateProgress (WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
TCHAR lpszXferPercentage [50];
|
||
|
wsprintf(lpszXferPercentage, TEXT("%d%%"), (int)lParam);
|
||
|
m_xferPercentage.SetWindowText (lpszXferPercentage);
|
||
|
m_transferProgress.SetPos((int)lParam);
|
||
|
}
|
||
|
|
||
|
void CSendProgress::OnSendComplete (WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
m_fSendDone = TRUE;
|
||
|
//make sure that the dialog is displayed for at least half a second
|
||
|
if (m_fTimerExpired)
|
||
|
DestroyWindow();
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: SetCurrentFileName
|
||
|
//
|
||
|
// Synopsis: displays on the progress dialog the name of the file that is
|
||
|
// currently being transmitted
|
||
|
//
|
||
|
// Arguments: [in] pwszCurrFile : name of the file being transmitted
|
||
|
//
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
// History: 12/14/1998 RahulTh created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
void CSendProgress::SetCurrentFileName (wchar_t * pwszCurrFile)
|
||
|
{
|
||
|
WCHAR * pwszSource;
|
||
|
WCHAR * pwszDest;
|
||
|
WCHAR * pwszTemp;
|
||
|
int len;
|
||
|
int cbStart;
|
||
|
int cbEnd;
|
||
|
int i;
|
||
|
const int cbCenter = 5;
|
||
|
|
||
|
if (m_fCancelled)
|
||
|
{
|
||
|
//the user has already hit cancel on this dialog and we are just
|
||
|
//waiting for confirmation from irxfer. Hence we do not change
|
||
|
//the file name as that control is now being used to indicate
|
||
|
//that we are trying to abort the file transfer
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!pwszCurrFile)
|
||
|
{
|
||
|
m_fileName.SetWindowText (L"");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
len = wcslen (pwszCurrFile);
|
||
|
|
||
|
if (len > MAX_FILENAME_DISPLAY)
|
||
|
{
|
||
|
cbStart = MAX_FILENAME_DISPLAY/2 - cbCenter;
|
||
|
cbEnd = MAX_FILENAME_DISPLAY - cbStart - cbCenter;
|
||
|
pwszTemp = pwszCurrFile + cbStart;
|
||
|
pwszTemp [0] = L' ';
|
||
|
pwszTemp[1] = pwszTemp[2] = pwszTemp[3] = L'.';
|
||
|
pwszTemp[4] = L' ';
|
||
|
for (i = 0, pwszSource = pwszCurrFile + len - cbEnd, pwszDest = pwszTemp + cbCenter;
|
||
|
i <= cbEnd; /*account for the terminating NULL too*/
|
||
|
i++, pwszSource++, pwszDest++)
|
||
|
*pwszDest = *pwszSource;
|
||
|
}
|
||
|
|
||
|
m_fileName.SetWindowText (pwszCurrFile);
|
||
|
return;
|
||
|
}
|