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

534 lines
15 KiB
C++

/*++
Microsoft Windows
Copyright (C) Microsoft Corporation, 1981 - 1999
Module Name:
controller.cpp
Abstract:
Author:
Rahul Thombre (RahulTh) 4/30/1998
Revision History:
4/30/1998 RahulTh
Created this module.
--*/
// Controller.cpp : implementation file
//
#include "precomp.hxx"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DEFAULT_TIMEOUT 30000 //30 seconds.
#define TIMER_ID 7 //randomly chosen id for the timer
///////////////////
// Module wide structure.
//
FLASHWINFO fwinfo = {
sizeof (FLASHWINFO),
NULL, // Window handle initialized later.
FLASHW_ALL,
3,
0
};
/////////////////////////////////////////////////////////////////////////////
//type for loading CPlApplet function declaration: declared in irprops.cpl
typedef LONG (*LPROCCPLAPPLET) (HWND , UINT , LPARAM, LPARAM);
inline CIrRecvProgress *
ValidateRecvCookie( COOKIE cookie)
{
CIrRecvProgress * window = (CIrRecvProgress *) cookie;
__try
{
if (RECV_MAGIC_ID != window->m_dwMagicID)
{
window = 0;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
window = 0;
}
return window;
}
/////////////////////////////////////////////////////////////////////////////
// CController dialog
//bNoForeground specifies whether the dialog should give focus back to the
//app. which had the focus before irftp started. If set to true, the focus
//is given back. This is necessary because an irftp is usually started with
//the /h option by the irmon service and it is a bad user experience if the
//an app. which the user is running suddenly loses focus to a window which
//is not even visible.
CController::CController(BOOL bNoForeground, CController* pParent /*=NULL*/) : m_pParent(pParent), m_lAppIsDisplayed(-1)
#if 0
, m_pDlgRecvProgress(NULL)
#endif
{
m_hLibApplet = NULL;
m_fHaveTimer = FALSE;
m_lTimeout = DEFAULT_TIMEOUT;
HWND hwnd = NULL;
InterlockedIncrement (&g_lUIComponentCount);
if (appController)
{
appController->PostMessage (WM_APP_KILL_TIMER);
}
else
{
InitTimeout(); //initializes the timeout period
//the app kills itself if there are no devices in range and no UI has
// been put up for a period specified by the timeout period
//note: we only need to initialize the timeout period for the main
//app window. The other windows will never even have a timer.
}
//hack. the call to create steals the focus from the current
//foreground window. This is bad if we are not going to put up any
//UI. Therefore, in this case, we get the foreground window just before the
//call to create and give it back its focus immediately after the call.
//the whole operation takes only about 35 milliseconds, so the loss of
//focus in the other app. is almost imperceptible.
hwnd = ::GetForegroundWindow ();
Create(IDD);
if (bNoForeground && hwnd)
::SetForegroundWindow (hwnd);
//{{AFX_DATA_INIT(CController)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CController::InitTimeout (void)
{
m_fHaveTimer = FALSE; //we have not obtained a timer yet.
m_lTimeout = DEFAULT_TIMEOUT; //set it to the default
//then see if a different value has been set in the registry
HKEY hftKey = NULL;
DWORD iSize = sizeof(DWORD);
DWORD data = 0;
RegOpenKeyEx (HKEY_CURRENT_USER,
TEXT("Control Panel\\Infrared\\File Transfer"),
0, KEY_READ, &hftKey);
if (!hftKey)
return; //we did not find a value in the registry, so use defaults
if (hftKey && ERROR_SUCCESS ==
RegQueryValueEx (hftKey, TEXT("AppTimeout"), NULL, NULL,
(LPBYTE)&data, &iSize))
{
m_lTimeout = (LONG)data;
if (m_lTimeout < 10000)
m_lTimeout = 10000;
}
if (hftKey)
RegCloseKey(hftKey);
}
void CController::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CController)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CController, CDialog)
//{{AFX_MSG_MAP(CController)
ON_WM_CLOSE()
ON_WM_ENDSESSION()
ON_MESSAGE(WM_APP_TRIGGER_UI, OnTriggerUI)
ON_MESSAGE(WM_APP_DISPLAY_UI, OnDisplayUI)
ON_MESSAGE(WM_APP_TRIGGER_SETTINGS, OnTriggerSettings)
ON_MESSAGE(WM_APP_DISPLAY_SETTINGS, OnDisplaySettings)
ON_MESSAGE(WM_APP_RECV_IN_PROGRESS, OnRecvInProgress)
ON_MESSAGE(WM_APP_GET_PERMISSION, OnGetPermission)
ON_MESSAGE(WM_APP_RECV_FINISHED, OnRecvFinished)
ON_MESSAGE(WM_APP_START_TIMER, OnStartTimer)
ON_MESSAGE(WM_APP_KILL_TIMER, OnKillTimer)
ON_WM_COPYDATA()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CController message handlers
void CController::PostNcDestroy()
{
if (m_hLibApplet)
{
FreeLibrary (m_hLibApplet);
m_hLibApplet = NULL;
}
if (this != appController)
{
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;
}
void CController::OnEndSession(BOOL Ending)
{
// OutputDebugStringA("OnEndSession\n");
RemoveLinks();
}
void CController::OnClose()
{
//if the WM_CLOSE message was posted from the RPC thread's ShutdownUi
//routine, then it might be a good idea to wait for a couple of seconds
//before killing the app. so that the RPC stack can unwind. 3 seconds seems
//like a reasonable amount of time. - 6/22/1998 : rahulth & jroberts
// OutputDebugStringA("OnClose\n");
RemoveLinks();
Sleep (3000);
if (AppUI.m_pParentWnd)
AppUI.m_pParentWnd->PostMessage(WM_QUIT);
CWnd::OnClose();
}
void CController::OnCancel()
{
DestroyWindow(); //For modeless boxes
}
void CController::OnDisplayUI(WPARAM wParam, LPARAM lParam)
{
ASSERT (m_pParent);
AppUI.m_ofn.hInstance = g_hInstance;
AppUI.DoModal();
AppUI.m_pParentWnd = NULL;
InterlockedDecrement(&m_lAppIsDisplayed);
InterlockedDecrement(&(m_pParent->m_lAppIsDisplayed));
DestroyWindow();
}
void CController::OnTriggerUI (WPARAM wParam, LPARAM lParam)
{
CWnd * pWnd = NULL;
BOOL fAppIsDisplayed = (0 != InterlockedIncrement(&m_lAppIsDisplayed));
if (fAppIsDisplayed)
{
InterlockedDecrement(&m_lAppIsDisplayed); //decrement the count before leaving.
if (NULL != (pWnd = AppUI.m_pParentWnd))
{
//this will usually be true except in the case where the displayed
//window is just getting destroyed at the same time. In that case,
//we must go ahead and create it again.
pWnd->SetActiveWindow();
return;
}
}
//the app is not displayed
CController* dlgSubController = new CController(FALSE, this);
InterlockedIncrement(&(dlgSubController->m_lAppIsDisplayed));
dlgSubController->ShowWindow (SW_HIDE);
dlgSubController->PostMessage(WM_APP_DISPLAY_UI);
}
void CController::OnTriggerSettings(WPARAM wParam, LPARAM lParam)
{
CController* dlgSettingsController = new CController(FALSE, this);
dlgSettingsController->ShowWindow(SW_HIDE);
dlgSettingsController->PostMessage(WM_APP_DISPLAY_SETTINGS);
}
void CController::OnDisplaySettings(WPARAM wParam, LPARAM lParam)
{
LPROCCPLAPPLET pProcApplet = NULL;
CString szApplet;
CError error (this);
#if 0
szApplet = TEXT("irprops.cpl");
if(NULL == (m_hLibApplet = LoadLibrary((LPCTSTR) szApplet)))
{
error.ShowMessage (IDS_APPLET_ERROR);
}
else
{
if (NULL != (pProcApplet = (LPROCCPLAPPLET)GetProcAddress (m_hLibApplet, "CPlApplet")))
{
if((*pProcApplet)(m_hWnd, CPL_INIT, NULL, NULL))
(*pProcApplet)(m_hWnd, CPL_DBLCLK, NULL, NULL);
else
{
error.ShowMessage (IDS_MISSING_PROTOCOL);
}
}
else
{
error.ShowMessage (IDS_APPLET_ERROR);
}
}
#else
{
PROCESS_INFORMATION ProcessInformation;
STARTUPINFO StartupInfo;
BOOL bResult;
TCHAR Path[MAX_PATH];
ZeroMemory(&StartupInfo,sizeof(StartupInfo));
StartupInfo.cb=sizeof(StartupInfo);
GetSystemDirectory(
Path,
sizeof(Path)/sizeof(TCHAR)
);
lstrcat(Path,TEXT("\\rundll32.exe"));
bResult=CreateProcess(
Path,
TEXT("rundll32.exe shell32.dll,Control_RunDLL irprops.cpl "),
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&StartupInfo,
&ProcessInformation
);
if (bResult) {
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
} else {
error.ShowMessage (IDS_APPLET_ERROR);
}
}
#endif
DestroyWindow();
}
void CController::OnRecvInProgress (WPARAM wParam, LPARAM lParam)
{
DWORD dwShowRecv;
struct MSG_RECEIVE_IN_PROGRESS * msg = (struct MSG_RECEIVE_IN_PROGRESS *) wParam;
dwShowRecv = GetIRRegVal (TEXT("ShowRecvStatus"), 1);
if (!dwShowRecv)
{
msg->status = 0;
return;
}
if (wcslen(msg->MachineName) > IRDA_DEVICE_NAME_LENGTH)
{
msg->status = ERROR_INVALID_PARAMETER;
return;
}
CIrRecvProgress * pDlgRecvProgress = new CIrRecvProgress(msg->MachineName,
msg->bSuppressRecvConf);
if (!pDlgRecvProgress)
{
msg->status = ERROR_NOT_ENOUGH_MEMORY;
return;
}
SetForegroundWindow();
pDlgRecvProgress->SetActiveWindow();
pDlgRecvProgress->SetWindowPos(&appController->wndTop, -1, -1, -1, -1, SWP_NOSIZE | SWP_NOMOVE);
fwinfo.hwnd = pDlgRecvProgress->m_hWnd;
FlashWindowEx (&fwinfo);
*(msg->pCookie) = (COOKIE) pDlgRecvProgress;
msg->status = 0;
}
void CController::OnGetPermission( WPARAM wParam, LPARAM lParam )
{
DWORD dwShowRecv;
struct MSG_GET_PERMISSION * msg = (MSG_GET_PERMISSION *) wParam;
dwShowRecv = GetIRRegVal (TEXT("ShowRecvStatus"), 1);
if (!dwShowRecv)
{
msg->status = 0;
return;
}
SetForegroundWindow();
CIrRecvProgress * pDlgRecvProgress = ValidateRecvCookie(msg->Cookie);
if (!pDlgRecvProgress)
{
msg->status = ERROR_INVALID_PARAMETER;
return;
}
msg->status = pDlgRecvProgress->GetPermission( msg->Name, msg->fDirectory );
}
void CController::OnRecvFinished (WPARAM wParam, LPARAM lParam)
{
DWORD dwShowRecv;
struct MSG_RECEIVE_FINISHED * msg = (struct MSG_RECEIVE_FINISHED *) wParam;
dwShowRecv = GetIRRegVal (TEXT("ShowRecvStatus"), 1);
if (!dwShowRecv)
{
msg->status = 0;
return;
}
CIrRecvProgress * pDlgRecvProgress = ValidateRecvCookie(msg->Cookie);
if (!pDlgRecvProgress)
{
msg->status = ERROR_INVALID_PARAMETER;
return;
}
//
// Preset the error code to ERROR_SUCCESS -- no error popup
//
DWORD Win32Error = ERROR_SUCCESS;
//
// first, filter out unwarranted errors. These error codes
// are treated as ERROR_SUCCESS.
// We have three so far:
// ERROR_SCEP_UNSPECIFIED_DISCONNECT,
// ERROR_SCEP_USER_DISCONNECT and
// ERROR_SCEP_PROVIDER_DISCONNECT.
//
// ERROR_SCEP_UNSPECIFIED_DISCONNECT is the error code
// we encounter most of the time because users usually do
// (1) move the device within IR range
// (2) do image transfer
// (3) move the device out of IR range.
//
if (ERROR_SCEP_UNSPECIFIED_DISCONNECT != (DWORD)msg->ReceiveStatus &&
ERROR_SCEP_USER_DISCONNECT != (DWORD)msg->ReceiveStatus &&
ERROR_SCEP_PROVIDER_DISCONNECT != (DWORD)msg->ReceiveStatus)
{
Win32Error = (DWORD)msg->ReceiveStatus;
}
pDlgRecvProgress->DestroyAndCleanup(Win32Error);
pDlgRecvProgress = NULL;
msg->status = 0;
}
BOOL CController::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
int iCharCount;
TCHAR* lpszFileNames = new TCHAR [iCharCount = (int)pCopyDataStruct->dwData];
CSendProgress* dlgProgress;
memcpy ((LPVOID)lpszFileNames, pCopyDataStruct->lpData, pCopyDataStruct->cbData);
dlgProgress = new CSendProgress(lpszFileNames, iCharCount);
dlgProgress->ShowWindow(SW_SHOW);
dlgProgress->SetFocus();
dlgProgress->SetWindowPos (&wndTop, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE);
fwinfo.hwnd = dlgProgress->m_hWnd;
::FlashWindowEx (&fwinfo);
return TRUE;
}
void CController::OnStartTimer (WPARAM wParam, LPARAM lParam)
{
//update the state of the help window
if (g_hwndHelp && ! ::IsWindow (g_hwndHelp))
g_hwndHelp = NULL;
if (!m_fHaveTimer)
{
m_fHaveTimer = SetTimer (TIMER_ID,
m_lTimeout,
NULL //want WM_TIMER messages
)?TRUE:FALSE;
}
}
void CController::OnKillTimer (WPARAM wParam, LPARAM lParam)
{
//update the state of the help window
if (g_hwndHelp && ! ::IsWindow (g_hwndHelp))
g_hwndHelp = NULL;
if (m_fHaveTimer)
{
KillTimer(TIMER_ID);
m_fHaveTimer = FALSE;
}
}
void CController::OnTimer (UINT nTimerID)
{
//there is only one timer, so we don't have to check for it.
//the timer has expired, so kill self
//however, first make sure that the help window (if it was put up)
//is gone.
if (g_hwndHelp && ::IsWindow (g_hwndHelp))
{
//the help window is around. restart the timer.
//this is the only way we can kill ourselves when the window
//is finally destroyed.
m_fHaveTimer = FALSE;
this->OnStartTimer (NULL, NULL);
}
else
{
g_hwndHelp = NULL;
this->PostMessage(WM_CLOSE);
}
}