windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/autorun/dataitem.cpp
2020-09-26 16:20:57 +08:00

170 lines
5.6 KiB
C++

#include <windows.h>
#include <shlwapi.h>
#include <commctrl.h>
#include "dataitem.h"
#include "resource.h"
#include "autorun.h"
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
CDataItem::CDataItem()
{
m_pszTitle = m_pszMenuName = m_pszDescription = m_pszCmdLine = m_pszArgs = NULL;
m_dwFlags = 0;
m_chAccel = NULL;
}
CDataItem::~CDataItem()
{
if ( m_pszTitle )
delete [] m_pszTitle;
if ( m_pszMenuName )
delete [] m_pszMenuName;
if ( m_pszDescription )
delete [] m_pszDescription;
if ( m_pszCmdLine )
delete [] m_pszCmdLine;
if ( m_pszArgs )
delete [] m_pszArgs;
}
BOOL CDataItem::SetData( LPTSTR szTitle, LPTSTR szMenu, LPTSTR szDesc, LPTSTR szCmd, LPTSTR szArgs, DWORD dwFlags, int iImgIndex )
{
TCHAR * psz;
// This function should only be called once or else we will leak like a, like a, a thing that leaks a lot.
ASSERT( NULL==m_pszTitle && NULL==m_pszMenuName && NULL==m_pszDescription && NULL==m_pszCmdLine && NULL==m_pszArgs );
m_pszTitle = new TCHAR[lstrlen(szTitle)+1];
if ( m_pszTitle )
lstrcpy( m_pszTitle, szTitle );
if ( szMenu )
{
// menuname is allowed to remain NULL. This is only used if you want the
// text on the menu item to be different than the description. This could
// be useful for localization where a shortened name might be required.
m_pszMenuName = new TCHAR[lstrlen(szMenu)+1];
if ( m_pszMenuName )
lstrcpy( m_pszMenuName, szMenu );
psz = StrChr(szMenu, TEXT('&'));
if ( psz )
m_chAccel = *(CharNext(psz));
}
m_pszDescription = new TCHAR[lstrlen(szDesc)+1];
if ( m_pszDescription )
lstrcpy( m_pszDescription, szDesc );
m_pszCmdLine = new TCHAR[lstrlen(szCmd)+1];
if ( m_pszCmdLine )
lstrcpy( m_pszCmdLine, szCmd );
if ( szArgs )
{
// Some commands don't have any args so this can remain NULL. This is only used
// if the executable requires arguments.
m_pszArgs = new TCHAR[lstrlen(szArgs)+1];
if ( m_pszArgs )
lstrcpy( m_pszArgs, szArgs );
}
m_dwFlags = dwFlags;
m_iImage = iImgIndex;
return TRUE;
}
BOOL CDataItem::Invoke(HWND hwnd)
{
BOOL fResult;
TCHAR szCmdLine[MAX_PATH*2];
PROCESS_INFORMATION ei;
STARTUPINFO si = {0};
si.cb = sizeof(si);
lstrcpy( szCmdLine, m_pszCmdLine );
if ( m_pszArgs )
{
strcat( szCmdLine, TEXT(" ") );
strcat( szCmdLine, m_pszArgs );
}
fResult = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &ei);
if (fResult)
{
if (NULL != ei.hProcess)
{
DWORD dwObject;
// passing in a NULL HWND is used as a signal not to wait in this inner loop.
while (hwnd)
{
dwObject = MsgWaitForMultipleObjects(1, &ei.hProcess, FALSE, INFINITE, QS_ALLINPUT);
if (WAIT_OBJECT_0 == dwObject)
{
break;
}
else if (WAIT_OBJECT_0+1 == dwObject)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if ( WM_QUIT == msg.message )
{
CloseHandle(ei.hProcess);
return fResult;
}
else
{
GetMessage(&msg, NULL, 0, 0);
// IsDialogMessage cannot understand the concept of ownerdraw default pushbuttons. It treats
// these attributes as mutually exclusive. As a result, we handle this ourselves. We want
// whatever control has focus to act as the default pushbutton.
if ( (WM_KEYDOWN == msg.message) && (VK_RETURN == msg.wParam) )
{
HWND hwndFocus = GetFocus();
if ( hwndFocus )
{
SendMessage(hwnd, WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndFocus), BN_CLICKED), (LPARAM)hwndFocus);
}
continue;
}
if ( IsDialogMessage(hwnd, &msg) )
continue;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
if ( !hwnd )
{
// A NULL hwnd means we were called in the mode by which we execute the item and then immediately
// exit. If our process exits before the other process is ready it'll end up in the wrong place
// in the z-order. To prevent this, when we're in "exit when done" mode we need to wait for the
// process we created to be ready. The way to do this is to call WaitForInputIdle. This is really
// only needed on NT5 and above due to the new "rude window activation" stuff, but since this API
// is available all the way back to NT 3.1 we simply call it blindly.
WaitForInputIdle(ei.hProcess, 20*1000); // we wait a maximum of 20 seconds
}
CloseHandle(ei.hProcess);
}
}
else
{
// do something if we fail to create a process?
}
return fResult;
}