mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
643 lines
21 KiB
643 lines
21 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999
|
|
//
|
|
// File: eventprompt.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
#include "eventprompt.h"
|
|
#include "resource.h"
|
|
#include "wiacsh.h"
|
|
#include "psutil.h"
|
|
//
|
|
|
|
|
|
#define COL_NAME 0
|
|
#define COL_DESCRIPTION 1
|
|
|
|
const UINT c_auTileColumns[] = {COL_NAME, COL_DESCRIPTION};
|
|
const UINT c_auTileSubItems[] = {COL_DESCRIPTION};
|
|
|
|
static const DWORD HelpIds [] =
|
|
{
|
|
IDC_EVENTNAME, IDH_WIA_EVENT_OCCURRED,
|
|
IDC_HANDLERLIST, IDH_WIA_PROGRAM_LIST,
|
|
IDC_NOPROMPT, IDH_WIA_ALWAYS_USE,
|
|
IDOK, IDH_OK,
|
|
IDCANCEL, IDH_CANCEL,
|
|
0,0
|
|
};
|
|
|
|
INT_PTR CALLBACK
|
|
CEventPromptDlg::DlgProc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
{
|
|
CEventPromptDlg *pThis;
|
|
pThis = reinterpret_cast<CEventPromptDlg*>(GetWindowLongPtr(hwnd,DWLP_USER));
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
SetWindowLongPtr (hwnd, DWLP_USER, lp);
|
|
pThis = reinterpret_cast<CEventPromptDlg*>(lp);
|
|
pThis->m_hwnd = hwnd;
|
|
pThis->OnInit ();
|
|
|
|
//
|
|
// Initially disable the OK button, unless there is something selected
|
|
//
|
|
EnableWindow(GetDlgItem(hwnd,IDOK),(0!=ListView_GetSelectedCount(GetDlgItem(hwnd,IDC_HANDLERLIST))));
|
|
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
if (pThis)
|
|
{
|
|
return pThis->OnCommand(HIWORD(wp), LOWORD(wp));
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
//
|
|
// Delete the listview's image list
|
|
//
|
|
HIMAGELIST hImageList = ListView_SetImageList(GetDlgItem(hwnd,IDC_HANDLERLIST), NULL, LVSIL_NORMAL);
|
|
if (hImageList)
|
|
{
|
|
ImageList_Destroy(hImageList);
|
|
}
|
|
|
|
if (pThis)
|
|
{
|
|
pThis->m_PromptData->Close();
|
|
}
|
|
|
|
SetWindowLongPtr(hwnd, DWLP_USER, NULL);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_HELP:
|
|
WiaHelp::HandleWmHelp( wp, lp, HelpIds );
|
|
return TRUE;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WiaHelp::HandleWmContextMenu( wp, lp, HelpIds );
|
|
return TRUE;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
//
|
|
// Get the notification struct
|
|
//
|
|
NMHDR *pNmHdr = reinterpret_cast<NMHDR*>(lp);
|
|
if (pNmHdr)
|
|
{
|
|
//
|
|
// Is this the handler listview?
|
|
//
|
|
if (IDC_HANDLERLIST == pNmHdr->idFrom)
|
|
{
|
|
//
|
|
// Get the listview notification stuff
|
|
//
|
|
NMLISTVIEW *pNmListView = reinterpret_cast<NMLISTVIEW*>(lp);
|
|
|
|
//
|
|
// If this is an item changed notification message
|
|
//
|
|
if (LVN_ITEMCHANGED == pNmHdr->code)
|
|
{
|
|
//
|
|
// If the state changed
|
|
//
|
|
if (pNmListView->uChanged & LVIF_STATE)
|
|
{
|
|
//
|
|
// Enable the OK button iff there is a selected item
|
|
//
|
|
EnableWindow(GetDlgItem(hwnd,IDOK),(0!=ListView_GetSelectedCount(GetDlgItem(hwnd,IDC_HANDLERLIST))));
|
|
return TRUE;
|
|
}
|
|
}
|
|
//
|
|
// Double click?
|
|
//
|
|
else if (NM_DBLCLK == pNmHdr->code)
|
|
{
|
|
//
|
|
// Check to make sure something is selected
|
|
//
|
|
if (ListView_GetSelectedCount(GetDlgItem(hwnd,IDC_HANDLERLIST)))
|
|
{
|
|
//
|
|
// Simulate an OK message
|
|
//
|
|
SendMessage( hwnd, WM_COMMAND, MAKEWPARAM(IDOK,BN_CLICKED), 0 );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Deleting an item
|
|
//
|
|
else if (LVN_DELETEITEM == pNmHdr->code)
|
|
{
|
|
//
|
|
// Get the event data
|
|
//
|
|
WIA_EVENT_HANDLER *peh = reinterpret_cast<WIA_EVENT_HANDLER*>(pNmListView->lParam);
|
|
if (peh)
|
|
{
|
|
//
|
|
// Free the bstrings
|
|
//
|
|
if (peh->bstrDescription)
|
|
{
|
|
SysFreeString (peh->bstrDescription);
|
|
}
|
|
if (peh->bstrIcon)
|
|
{
|
|
SysFreeString (peh->bstrIcon);
|
|
}
|
|
if (peh->bstrName)
|
|
{
|
|
SysFreeString (peh->bstrName);
|
|
}
|
|
|
|
//
|
|
// Free the structure
|
|
//
|
|
delete peh;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
CEventPromptDlg::OnInit ()
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CEventPromptDlg::OnInit"));
|
|
// update the shared memory section indicating we exist
|
|
// use a unique name for the shared memory
|
|
LPWSTR wszGuid;
|
|
StringFromCLSID (m_pEventParameters->EventGUID, &wszGuid);
|
|
CSimpleStringWide strSection(wszGuid);
|
|
strSection.Concat (m_pEventParameters->strDeviceID);
|
|
CoTaskMemFree (wszGuid);
|
|
m_PromptData = new CSharedMemorySection<HWND>(CSimpleStringConvert::NaturalString(strSection), true);
|
|
if (m_PromptData)
|
|
{
|
|
HWND *pData = m_PromptData->Lock();
|
|
if (pData)
|
|
{
|
|
*pData = m_hwnd;
|
|
m_PromptData->Release();
|
|
}
|
|
}
|
|
// fill in the list of handlers
|
|
m_pList = new CHandlerList (GetDlgItem(m_hwnd, IDC_HANDLERLIST));
|
|
if (m_pList)
|
|
{
|
|
m_pList->FillList (m_pEventParameters->strDeviceID,
|
|
m_pEventParameters->EventGUID);
|
|
|
|
}
|
|
// Set the dialog's caption to be the name of the device
|
|
SetWindowText (m_hwnd, CSimpleStringConvert::NaturalString(m_pEventParameters->strDeviceDescription));
|
|
|
|
// Set the event description text
|
|
SetDlgItemText (m_hwnd, IDC_EVENTNAME, CSimpleStringConvert::NaturalString(m_pEventParameters->strEventDescription));
|
|
|
|
//
|
|
// Disable the "always make this the handler" checkbox for low privilege users
|
|
SC_HANDLE hSCM = ::OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (!hSCM)
|
|
{
|
|
EnableWindow(GetDlgItem(m_hwnd, IDC_NOPROMPT), FALSE);
|
|
}
|
|
else
|
|
{
|
|
CloseServiceHandle(hSCM);
|
|
}
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
CEventPromptDlg::OnCommand (WORD wCode, WORD widItem)
|
|
{
|
|
INT_PTR iRet = TRUE;
|
|
// we only care about IDOK or IDCANCEL
|
|
|
|
switch (widItem)
|
|
{
|
|
case IDOK:
|
|
iRet = OnOK ();
|
|
if (!iRet)
|
|
{
|
|
break;;
|
|
}
|
|
// fall through
|
|
case IDCANCEL:
|
|
EndDialog (m_hwnd, 1);
|
|
break;
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
|
|
// When the user presses OK, invoke the selected application and make it
|
|
// the default if requested
|
|
INT_PTR
|
|
CEventPromptDlg::OnOK ()
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CEventPromptDlg::OnOK"));
|
|
WIA_EVENT_HANDLER *pSelHandler = NULL;
|
|
if (m_pList)
|
|
{
|
|
pSelHandler = m_pList->GetSelectedHandler ();
|
|
}
|
|
if (pSelHandler)
|
|
{
|
|
if (IsDlgButtonChecked (m_hwnd, IDC_NOPROMPT))
|
|
{
|
|
// Set this handler as the default
|
|
SetDefaultHandler (pSelHandler);
|
|
}
|
|
if (!InvokeHandler(pSelHandler))
|
|
{
|
|
WIA_ERROR((TEXT("InvokeHandler failed")));
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
CEventPromptDlg::SetDefaultHandler (WIA_EVENT_HANDLER *pHandler)
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CEventPromptDlg::SetDefaultHandler"));
|
|
CComPtr<IWiaDevMgr> pDevMgr;
|
|
|
|
|
|
if (SUCCEEDED(CoCreateInstance (CLSID_WiaDevMgr,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IWiaDevMgr,
|
|
reinterpret_cast<LPVOID*>(&pDevMgr))))
|
|
{
|
|
|
|
|
|
pDevMgr->RegisterEventCallbackCLSID (WIA_SET_DEFAULT_HANDLER,
|
|
CComBSTR(m_pEventParameters->strDeviceID),
|
|
&m_pEventParameters->EventGUID,
|
|
&pHandler->guid,
|
|
pHandler->bstrName,
|
|
pHandler->bstrDescription,
|
|
pHandler->bstrIcon);
|
|
|
|
|
|
}
|
|
}
|
|
|
|
bool
|
|
CEventPromptDlg::InvokeHandler(WIA_EVENT_HANDLER *pHandler)
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CEventPromptDlg::InvokeHandler"));
|
|
CComPtr<IWiaEventCallback> pCallback;
|
|
|
|
if (pHandler->bstrCommandline) {
|
|
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si;
|
|
|
|
TCHAR szCommand[MAX_PATH*2];
|
|
ZeroMemory (&si, sizeof(si));
|
|
ZeroMemory (&pi, sizeof(pi));
|
|
si.cb = sizeof(si);
|
|
si.wShowWindow = SW_SHOW;
|
|
|
|
#ifdef UNICODE
|
|
wcscpy (szCommand, pHandler->bstrCommandline);
|
|
#else
|
|
WideCharToMultiByte (CP_ACP, 0,
|
|
pHandler->bstrCommandline, -1,
|
|
szCommand, ARRAYSIZE(szCommand),
|
|
NULL, NULL);
|
|
#endif
|
|
|
|
// Trace(TEXT("Command line for STI app is %s"), szCommand);
|
|
if (CreateProcess (NULL,
|
|
szCommand,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi))
|
|
{
|
|
CloseHandle (pi.hProcess);
|
|
CloseHandle (pi.hThread);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((HRESULT_FROM_WIN32(GetLastError()),TEXT("Execution of pHandler->bstrCommandline [%ws] FAILED"),pHandler->bstrCommandline));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
HRESULT hr = CoCreateInstance(pHandler->guid,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IWiaEventCallback,
|
|
reinterpret_cast<LPVOID*>(&pCallback));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pCallback->ImageEventCallback (&m_pEventParameters->EventGUID,
|
|
CComBSTR(m_pEventParameters->strEventDescription),
|
|
CComBSTR(m_pEventParameters->strDeviceID),
|
|
CComBSTR(m_pEventParameters->strDeviceDescription),
|
|
m_pEventParameters->dwDeviceType,
|
|
CComBSTR(m_pEventParameters->strFullItemName),
|
|
&m_pEventParameters->ulEventType,
|
|
m_pEventParameters->ulReserved);
|
|
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
// inform the user something went wrong
|
|
UIErrors::ReportMessage(m_hwnd,g_hInstance,
|
|
NULL,
|
|
MAKEINTRESOURCE(IDS_HANDLERERR_CAPTION),
|
|
MAKEINTRESOURCE(IDS_HANDLERERR),
|
|
MB_OK);
|
|
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
// Parse the bstrIconPath to get the image name and resource id
|
|
// Note that -1 is not a valid id for ExtractIconEx
|
|
int
|
|
AddIconToImageList (HIMAGELIST himl, BSTR strIconPath)
|
|
{
|
|
int iRet = 0;
|
|
|
|
|
|
TCHAR szPath[MAX_PATH];
|
|
LONG nIcon;
|
|
INT nComma=0;
|
|
HICON hIcon = NULL;
|
|
HRESULT hr;
|
|
|
|
if (!strIconPath)
|
|
{
|
|
return 0;
|
|
}
|
|
while (strIconPath[nComma] && strIconPath[nComma] != L',')
|
|
{
|
|
nComma++;
|
|
}
|
|
if (strIconPath[nComma])
|
|
{
|
|
ZeroMemory (szPath, sizeof(szPath));
|
|
nIcon = wcstol (strIconPath+nComma+1, NULL, 10);
|
|
#ifdef UNICODE
|
|
wcsncpy (szPath, strIconPath, nComma);
|
|
*(szPath+nComma)=L'\0';
|
|
#else
|
|
WideCharToMultiByte (CP_ACP,
|
|
0,
|
|
strIconPath, nComma,
|
|
szPath, MAX_PATH,
|
|
NULL,NULL);
|
|
#endif
|
|
|
|
ExtractIconEx (szPath, nIcon, &hIcon, NULL, 1);
|
|
|
|
|
|
if (hIcon)
|
|
{
|
|
iRet = ImageList_AddIcon (himl, hIcon);
|
|
DestroyIcon (hIcon);
|
|
}
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
static int CALLBACK HandlerListCompareFunction( LPARAM lParam1, LPARAM lParam2, LPARAM )
|
|
{
|
|
int nResult = 0;
|
|
LVITEM *pItem1 = reinterpret_cast<LVITEM*>(lParam1);
|
|
LVITEM *pItem2 = reinterpret_cast<LVITEM*>(lParam2);
|
|
if (pItem1 && pItem2 && pItem1->pszText && pItem2->pszText)
|
|
{
|
|
int nCompareResult = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE, pItem1->pszText, -1, pItem2->pszText, -1 );
|
|
switch (nCompareResult)
|
|
{
|
|
case CSTR_LESS_THAN:
|
|
nResult = -1;
|
|
break;
|
|
case CSTR_GREATER_THAN:
|
|
nResult = 1;
|
|
break;
|
|
}
|
|
}
|
|
return nResult;
|
|
}
|
|
|
|
// Enumerate the installed handlers for the event and add them to the listview
|
|
// return the number of handlers we added
|
|
UINT
|
|
CHandlerList::FillList (const CSimpleStringWide &strDeviceId, GUID &guidEvent)
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CHandlerList::FillList"));
|
|
CComPtr<IWiaDevMgr> pDevMgr;
|
|
CComPtr<IWiaItem> pItem;
|
|
UINT uRet = 0;
|
|
//
|
|
// Remove all existing items
|
|
//
|
|
ListView_DeleteAllItems(m_hwnd);
|
|
if (SUCCEEDED(CoCreateInstance( CLSID_WiaDevMgr,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IWiaDevMgr,
|
|
reinterpret_cast<LPVOID*>(&pDevMgr))))
|
|
{
|
|
if (SUCCEEDED(pDevMgr->CreateDevice(CComBSTR(strDeviceId.String()),
|
|
&pItem)))
|
|
{
|
|
RECT rc = {0};
|
|
LVTILEVIEWINFO lvtvi = {0};
|
|
// set up the listview style
|
|
ListView_SetView(m_hwnd, LV_VIEW_TILE);
|
|
for (int i = 0; i < ARRAYSIZE(c_auTileColumns); ++i)
|
|
{
|
|
LVCOLUMN lvcolumn = {0};
|
|
|
|
lvcolumn.mask = LVCF_SUBITEM;
|
|
lvcolumn.iSubItem = c_auTileColumns[i];
|
|
ListView_InsertColumn(m_hwnd, i, &lvcolumn);
|
|
}
|
|
|
|
GetClientRect(m_hwnd, &rc);
|
|
|
|
lvtvi.cbSize = sizeof(lvtvi);
|
|
lvtvi.dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS;
|
|
lvtvi.dwFlags = LVTVIF_FIXEDWIDTH;
|
|
|
|
// Leave room for the scroll bar when setting tile sizes or listview gets screwed up.
|
|
lvtvi.sizeTile.cx = ((rc.right - rc.left) - GetSystemMetrics(SM_CXVSCROLL));
|
|
lvtvi.cLines = ARRAYSIZE(c_auTileSubItems);
|
|
ListView_SetTileViewInfo(m_hwnd, &lvtvi);
|
|
|
|
CComPtr<IEnumWIA_DEV_CAPS> pEnum;
|
|
if (SUCCEEDED(pItem->EnumRegisterEventInfo(0,
|
|
&guidEvent,
|
|
&pEnum)) )
|
|
{
|
|
|
|
WIA_EVENT_HANDLER *pHandler;
|
|
ULONG ul;
|
|
LVITEM lvi = {0};
|
|
HICON hicon;
|
|
HRESULT hr = NOERROR;
|
|
CSimpleString strText;
|
|
// Create a new imagelist
|
|
HIMAGELIST hImageList = ImageList_Create (GetSystemMetrics(SM_CXICON),
|
|
GetSystemMetrics(SM_CYICON),
|
|
PrintScanUtil::CalculateImageListColorDepth() | ILC_MASK,
|
|
2,
|
|
2);
|
|
// Add the "default" icon
|
|
hicon =reinterpret_cast<HICON>(LoadImage (g_hInstance,
|
|
MAKEINTRESOURCE(IDI_SCANCAM),
|
|
IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXICON),
|
|
GetSystemMetrics(SM_CYICON),
|
|
LR_SHARED | LR_DEFAULTCOLOR));
|
|
ImageList_AddIcon (hImageList, hicon);
|
|
SendMessage (m_hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL,
|
|
reinterpret_cast<LPARAM>(hImageList));
|
|
// enum the items and add them to the listview
|
|
|
|
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
|
|
|
|
while (S_OK == hr)
|
|
{
|
|
pHandler = new WIA_EVENT_HANDLER;
|
|
if (!pHandler)
|
|
{
|
|
break;
|
|
}
|
|
hr = pEnum->Next (1, pHandler, &ul);
|
|
|
|
if (IsEqualCLSID(pHandler->guid, CLSID_EventPrompter) ||
|
|
IsEqualCLSID(pHandler->guid, WIA_EVENT_HANDLER_NO_ACTION) ||
|
|
IsEqualCLSID(pHandler->guid, WIA_EVENT_HANDLER_PROMPT) ||
|
|
!lstrcmpiW(pHandler->bstrName, L"Internal"))
|
|
{
|
|
delete pHandler;
|
|
continue;
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// get the string
|
|
strText = CSimpleStringConvert::NaturalString (CSimpleStringWide(pHandler->bstrName));
|
|
lvi.pszText = const_cast<LPTSTR>(strText.String());
|
|
lvi.lParam = reinterpret_cast<LPARAM>(pHandler);
|
|
// get the icon
|
|
lvi.iImage = AddIconToImageList (hImageList, pHandler->bstrIcon);
|
|
// get the index
|
|
lvi.iItem = ListView_GetItemCount(m_hwnd);
|
|
// add the item
|
|
int nIndex = ListView_InsertItem(m_hwnd, &lvi);
|
|
if (-1 != nIndex)
|
|
{
|
|
// add the description subitem
|
|
strText = CSimpleStringConvert::NaturalString (CSimpleStringWide(pHandler->bstrDescription));
|
|
LVTILEINFO lvti = {0};
|
|
lvti.cbSize = sizeof(LVTILEINFO);
|
|
lvti.iItem = nIndex;
|
|
lvti.cColumns = 1;
|
|
lvti.puColumns = (UINT*)c_auTileSubItems;
|
|
ListView_SetTileInfo(m_hwnd, &lvti);
|
|
ListView_SetItemText(m_hwnd, nIndex, 1, (LPTSTR)strText.String());
|
|
uRet++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pHandler)
|
|
{
|
|
delete pHandler;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort the list
|
|
ListView_SortItems( m_hwnd, HandlerListCompareFunction, 0 );
|
|
|
|
// set the default to the first item
|
|
lvi.iItem = 0;
|
|
lvi.mask = LVIF_STATE;
|
|
lvi.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
|
|
lvi.state = LVIS_FOCUSED|LVIS_SELECTED;
|
|
ListView_SetItem(m_hwnd, &lvi);
|
|
ListView_EnsureVisible(m_hwnd, lvi.iItem, FALSE);
|
|
}
|
|
}
|
|
}
|
|
return uRet;
|
|
}
|
|
|
|
WIA_EVENT_HANDLER *
|
|
CHandlerList::GetSelectedHandler ()
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CHandlerList::GetSelectedHandler"));
|
|
WIA_EVENT_HANDLER *pRet = NULL;
|
|
|
|
int nIndex = ListView_GetNextItem( m_hwnd, -1, LVNI_SELECTED );
|
|
if (-1 != nIndex)
|
|
{
|
|
LVITEM lvi = {0};
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = nIndex;
|
|
if (ListView_GetItem(m_hwnd, &lvi))
|
|
{
|
|
pRet = reinterpret_cast<WIA_EVENT_HANDLER*>(lvi.lParam);
|
|
}
|
|
}
|
|
return pRet;
|
|
}
|
|
|