529 lines
15 KiB
C++
529 lines
15 KiB
C++
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998-2001
|
|
*
|
|
* TITLE: STIEVENT.CPP
|
|
*
|
|
* VERSION: 1.0
|
|
*
|
|
* AUTHOR: ShaunIv
|
|
*
|
|
* DATE: 4-6-2001
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*******************************************************************************/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <wiaregst.h>
|
|
#include "simcrack.h"
|
|
#include "resource.h"
|
|
#include "stievent.h"
|
|
#include "evntparm.h"
|
|
#include "shmemsec.h"
|
|
|
|
//
|
|
// This dialog displays the sti application list and lets the user choose one.
|
|
//
|
|
class CStiEventHandlerDialog
|
|
{
|
|
public:
|
|
struct CData
|
|
{
|
|
//
|
|
// This will contain the event information, including the application list,
|
|
// which is really what we are interested in.
|
|
//
|
|
CStiEventData *pStiEventData;
|
|
|
|
//
|
|
// The OUT member is intended to contain the selected handler, which will
|
|
// be copied from the list contained in the CStiEventData class
|
|
//
|
|
CStiEventData::CStiEventHandler EventHandler;
|
|
|
|
//
|
|
// We will set the window handle in this shared memory section,
|
|
// so we can activate ourselves.
|
|
//
|
|
CSharedMemorySection<HWND> *pStiEventHandlerSharedMemory;
|
|
};
|
|
|
|
private:
|
|
//
|
|
// Not implemented
|
|
//
|
|
CStiEventHandlerDialog();
|
|
CStiEventHandlerDialog( const CStiEventHandlerDialog & );
|
|
CStiEventHandlerDialog &operator=( const CStiEventHandlerDialog & );
|
|
|
|
private:
|
|
HWND m_hWnd;
|
|
CData *m_pData;
|
|
|
|
private:
|
|
//
|
|
// Sole constructor
|
|
//
|
|
explicit CStiEventHandlerDialog( HWND hWnd )
|
|
: m_hWnd(hWnd),
|
|
m_pData(NULL)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Destructor
|
|
//
|
|
~CStiEventHandlerDialog()
|
|
{
|
|
m_hWnd = NULL;
|
|
m_pData = NULL;
|
|
}
|
|
|
|
//
|
|
// WM_INITDIALOG handler.
|
|
//
|
|
LRESULT OnInitDialog( WPARAM, LPARAM lParam )
|
|
{
|
|
//
|
|
// Get the dialog's data
|
|
//
|
|
m_pData = reinterpret_cast<CData*>(lParam);
|
|
|
|
//
|
|
// Make sure we have valid data
|
|
//
|
|
if (!m_pData || !m_pData->pStiEventData)
|
|
{
|
|
EndDialog( m_hWnd, -1 );
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Make sure we were supplied with a memory section
|
|
//
|
|
if (m_pData->pStiEventHandlerSharedMemory)
|
|
{
|
|
//
|
|
// Get a pointer to the shared memory
|
|
//
|
|
HWND *phWnd = m_pData->pStiEventHandlerSharedMemory->Lock();
|
|
if (phWnd)
|
|
{
|
|
//
|
|
// Store our window handle
|
|
//
|
|
*phWnd = m_hWnd;
|
|
|
|
//
|
|
// Release the mutex
|
|
//
|
|
m_pData->pStiEventHandlerSharedMemory->Release();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the handlers to the list
|
|
//
|
|
for (int i=0;i<m_pData->pStiEventData->EventHandlers().Size();++i)
|
|
{
|
|
//
|
|
// Get the program name and make sure it is valid
|
|
//
|
|
CSimpleString strAppName = CSimpleStringConvert::NaturalString(m_pData->pStiEventData->EventHandlers()[i].ApplicationName());
|
|
if (strAppName.Length())
|
|
{
|
|
//
|
|
// Add the string and save the item id
|
|
//
|
|
LRESULT nIndex = SendDlgItemMessage( m_hWnd, IDC_STI_APPS_LIST, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(strAppName.String()) );
|
|
if (LB_ERR != nIndex)
|
|
{
|
|
//
|
|
// Set the item data to the index in our handler array
|
|
//
|
|
SendDlgItemMessage( m_hWnd, IDC_STI_APPS_LIST, LB_SETITEMDATA, nIndex, i );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select the first item
|
|
//
|
|
SendDlgItemMessage( m_hWnd, IDC_STI_APPS_LIST, LB_SETCURSEL, 0, 0 );
|
|
|
|
//
|
|
// Enable the OK button if we have a valid selected item
|
|
//
|
|
EnableWindow( GetDlgItem( m_hWnd, IDOK ), GetHandlerIndexOfCurrentSelection() != -1 );
|
|
|
|
return 0;
|
|
}
|
|
|
|
void OnCancel( WPARAM, LPARAM )
|
|
{
|
|
//
|
|
// Just close the dialog on cancel
|
|
//
|
|
EndDialog( m_hWnd, IDCANCEL );
|
|
}
|
|
|
|
int GetHandlerIndexOfCurrentSelection()
|
|
{
|
|
//
|
|
// Assume failure
|
|
//
|
|
int nResult = -1;
|
|
|
|
//
|
|
// Make sure we have valid pointers still
|
|
//
|
|
if (m_pData && m_pData->pStiEventData)
|
|
{
|
|
//
|
|
// Get the current selection index and make sure it is valid
|
|
//
|
|
LRESULT nCurIndex = SendDlgItemMessage( m_hWnd, IDC_STI_APPS_LIST, LB_GETCURSEL, 0, 0 );
|
|
if (LB_ERR != nCurIndex)
|
|
{
|
|
//
|
|
// Get the index into our event handler array from the item data for the current item
|
|
//
|
|
LRESULT nEventItemIndex = SendDlgItemMessage( m_hWnd, IDC_STI_APPS_LIST, LB_GETITEMDATA, nCurIndex, 0 );
|
|
|
|
//
|
|
// Make sure the index is valid
|
|
//
|
|
if (nEventItemIndex >= 0 && nEventItemIndex < m_pData->pStiEventData->EventHandlers().Size())
|
|
{
|
|
nResult = static_cast<int>(nEventItemIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
void OnOK( WPARAM, LPARAM )
|
|
{
|
|
//
|
|
// Make sure we have valid parameters
|
|
//
|
|
int nEventItemIndex = GetHandlerIndexOfCurrentSelection();
|
|
if (-1 != nEventItemIndex)
|
|
{
|
|
//
|
|
// Copy the event handler to our OUT parameter
|
|
//
|
|
m_pData->EventHandler = m_pData->pStiEventData->EventHandlers()[nEventItemIndex];
|
|
|
|
//
|
|
// Close the dialog
|
|
//
|
|
EndDialog( m_hWnd, IDOK );
|
|
}
|
|
}
|
|
|
|
void OnAppsListDblClk( WPARAM, LPARAM )
|
|
{
|
|
//
|
|
// Simulate the user pressing the OK button
|
|
//
|
|
SendMessage( m_hWnd, WM_COMMAND, MAKEWPARAM(IDOK,0), 0 );
|
|
}
|
|
|
|
void OnAppsListSelChange( WPARAM, LPARAM )
|
|
{
|
|
//
|
|
// Enable the OK button if we have a valid selected item
|
|
//
|
|
EnableWindow( GetDlgItem( m_hWnd, IDOK ), GetHandlerIndexOfCurrentSelection() != -1 );
|
|
}
|
|
|
|
LRESULT OnCommand( WPARAM wParam, LPARAM lParam )
|
|
{
|
|
SC_BEGIN_COMMAND_HANDLERS()
|
|
{
|
|
SC_HANDLE_COMMAND(IDCANCEL,OnCancel);
|
|
SC_HANDLE_COMMAND(IDOK,OnOK);
|
|
SC_HANDLE_COMMAND_NOTIFY(LBN_DBLCLK,IDC_STI_APPS_LIST,OnAppsListDblClk);
|
|
SC_HANDLE_COMMAND_NOTIFY(LBN_SELCHANGE,IDC_STI_APPS_LIST,OnAppsListSelChange);
|
|
}
|
|
SC_END_COMMAND_HANDLERS();
|
|
}
|
|
|
|
public:
|
|
static INT_PTR __stdcall DlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
SC_BEGIN_DIALOG_MESSAGE_HANDLERS(CStiEventHandlerDialog)
|
|
{
|
|
SC_HANDLE_DIALOG_MESSAGE( WM_INITDIALOG, OnInitDialog );
|
|
SC_HANDLE_DIALOG_MESSAGE( WM_COMMAND, OnCommand );
|
|
}
|
|
SC_END_DIALOG_MESSAGE_HANDLERS();
|
|
}
|
|
};
|
|
|
|
|
|
HRESULT StiEventHandler( CStiEventData &StiEventData )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
#if defined(DBG)
|
|
//
|
|
// Dump the parameters
|
|
//
|
|
WIA_PUSH_FUNCTION((TEXT("StiEventHandler")));
|
|
WIA_PRINTGUID((StiEventData.Event(),TEXT(" Event")));
|
|
WIA_TRACE((TEXT(" EventDescription: %ws"), StiEventData.EventDescription().String()));
|
|
WIA_TRACE((TEXT(" DeviceDescription: %ws"), StiEventData.DeviceDescription().String()));
|
|
WIA_TRACE((TEXT(" DeviceId: %ws"), StiEventData.DeviceId().String()));
|
|
WIA_TRACE((TEXT(" EventType: %08X"), StiEventData.EventType()));
|
|
WIA_TRACE((TEXT(" Reserved: %08X"), StiEventData.Reserved()));
|
|
for (int i=0;i<StiEventData.EventHandlers().Size();++i)
|
|
{
|
|
WIA_TRACE((TEXT(" Handler %d: [%ws] CommandLine: [%ws]"), i, StiEventData.EventHandlers()[i].ApplicationName().String(), StiEventData.EventHandlers()[i].CommandLine().String()));
|
|
}
|
|
#endif // defined(DBG)
|
|
|
|
//
|
|
// Make sure we have some handlers
|
|
//
|
|
if (0 == StiEventData.EventHandlers().Size())
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Create the mutex name
|
|
//
|
|
CSimpleStringWide strMutexName = StiEventData.DeviceId();
|
|
|
|
//
|
|
// Append the event ID
|
|
//
|
|
LPOLESTR pwszEventGuid = NULL;
|
|
if (SUCCEEDED(StringFromIID( StiEventData.Event(), &pwszEventGuid )) && pwszEventGuid)
|
|
{
|
|
strMutexName += CSimpleStringWide(pwszEventGuid);
|
|
CoTaskMemFree( pwszEventGuid );
|
|
}
|
|
|
|
WIA_TRACE((TEXT("strMutexName: %ws"), strMutexName.String() ));
|
|
|
|
//
|
|
// Create the shared memory section for excluding multiple instances
|
|
//
|
|
CSharedMemorySection<HWND> StiEventHandlerSharedMemory;
|
|
|
|
//
|
|
// If we were able to open the memory section
|
|
//
|
|
if (CSharedMemorySection<HWND>::SmsOpened == StiEventHandlerSharedMemory.Open( CSimpleStringConvert::NaturalString(CSimpleStringWide(strMutexName)), true ))
|
|
{
|
|
HWND *phWnd = StiEventHandlerSharedMemory.Lock();
|
|
if (phWnd)
|
|
{
|
|
//
|
|
// Make sure we have a valid window handle
|
|
//
|
|
if (*phWnd && IsWindow(*phWnd))
|
|
{
|
|
//
|
|
// If it is a valid window, bring it to the foreground.
|
|
//
|
|
SetForegroundWindow(*phWnd);
|
|
}
|
|
|
|
//
|
|
// Release the mutex
|
|
//
|
|
StiEventHandlerSharedMemory.Release();
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// We will execute this handler below, after we decide which one to use
|
|
//
|
|
CStiEventData::CStiEventHandler EventHandler;
|
|
|
|
//
|
|
// If there is only one handler, save that handler
|
|
//
|
|
if (1 == StiEventData.EventHandlers().Size())
|
|
{
|
|
EventHandler = StiEventData.EventHandlers()[0];
|
|
}
|
|
|
|
//
|
|
// Otherwise, if there is more than one handler, display the handler prompt dialog
|
|
//
|
|
else
|
|
{
|
|
//
|
|
// Prepare the dialog data
|
|
//
|
|
CStiEventHandlerDialog::CData DialogData;
|
|
DialogData.pStiEventData = &StiEventData;
|
|
DialogData.pStiEventHandlerSharedMemory = &StiEventHandlerSharedMemory;
|
|
|
|
//
|
|
// Display the dialog
|
|
//
|
|
INT_PTR nDialogResult = DialogBoxParam( g_hInstance, MAKEINTRESOURCE(IDD_CHOOSE_STI_APPLICATION), NULL, CStiEventHandlerDialog::DlgProc, reinterpret_cast<LPARAM>(&DialogData) );
|
|
|
|
//
|
|
// If the user selected a program and hit OK, save the handler
|
|
//
|
|
if (IDOK == nDialogResult)
|
|
{
|
|
EventHandler = DialogData.EventHandler;
|
|
}
|
|
|
|
//
|
|
// If the user cancelled, just return S_FALSE immediately (premature return)
|
|
//
|
|
else if (IDCANCEL == nDialogResult)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// If there was an internal error, save the correct error
|
|
//
|
|
else if (-1 == nDialogResult)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
//
|
|
// For all other return values, save a generic error
|
|
//
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Make sure we have a valid handler
|
|
//
|
|
if (EventHandler.IsValid())
|
|
{
|
|
//
|
|
// Prepare the process information
|
|
//
|
|
STARTUPINFO StartupInfo = {0};
|
|
StartupInfo.cb = sizeof(StartupInfo);
|
|
|
|
//
|
|
// Convert the command line to a TCHAR string
|
|
//
|
|
CSimpleString CommandLine = CSimpleStringConvert::NaturalString(EventHandler.CommandLine());
|
|
|
|
//
|
|
// Make sure we actually have a command line
|
|
//
|
|
if (CommandLine.Length())
|
|
{
|
|
//
|
|
// Execute the program
|
|
//
|
|
PROCESS_INFORMATION ProcessInformation = {0};
|
|
if (CreateProcess( NULL, const_cast<LPTSTR>(CommandLine.String()), NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInformation ))
|
|
{
|
|
//
|
|
// If the program succeeded, close the handles to prevent leaks
|
|
//
|
|
CloseHandle( ProcessInformation.hProcess );
|
|
CloseHandle( ProcessInformation.hThread );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Save the error from CreateProcess
|
|
//
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Assume out of memory error if we couldn't create the string
|
|
//
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Who knows what went wrong?
|
|
//
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we've failed, display an error message
|
|
//
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// We will display this string, after we've constructed it
|
|
//
|
|
CSimpleString strMessage;
|
|
|
|
//
|
|
// Get the error text
|
|
//
|
|
CSimpleString strError = WiaUiUtil::GetErrorTextFromHResult(hr);
|
|
|
|
//
|
|
// Get the application name
|
|
//
|
|
CSimpleString strApplication = CSimpleStringConvert::NaturalString(EventHandler.ApplicationName());
|
|
|
|
//
|
|
// If we don't have an application name, use some default
|
|
//
|
|
if (!strApplication.Length())
|
|
{
|
|
strApplication.LoadString( IDS_STI_EVENT_ERROR_APP_NAME, g_hInstance );
|
|
}
|
|
|
|
//
|
|
// If we have a specific error message, use it.
|
|
//
|
|
if (strError.Length())
|
|
{
|
|
strMessage.Format( IDS_STI_EVENT_ERROR_WITH_EXPLANATION, g_hInstance, strApplication.String(), strError.String() );
|
|
}
|
|
|
|
//
|
|
// Otherwise, use a generic error message.
|
|
//
|
|
else
|
|
{
|
|
strMessage.Format( IDS_STI_EVENT_ERROR_NO_EXPLANATION, g_hInstance, strApplication.String() );
|
|
}
|
|
|
|
//
|
|
// Display the error message.
|
|
//
|
|
MessageBox( NULL, strMessage, CSimpleString( IDS_STI_EVENT_ERROR_TITLE, g_hInstance ), MB_ICONHAND );
|
|
}
|
|
}
|
|
|
|
//
|
|
// We're done here
|
|
//
|
|
return hr;
|
|
}
|
|
|