windows-nt/Source/XPSP1/NT/windows/winstate/cobra/app/migwiz/migoobe.cpp
2020-09-26 16:20:57 +08:00

648 lines
17 KiB
C++

//
// dll.cpp
//
#include <iostream.h>
#include <objbase.h>
#include <shlwapi.h>
#include <shlwapip.h>
#include <shlobj.h>
#include "cowsite.h"
#include "Iface.h" // Interface declarations
#include "Registry.h" // Registry helper functions
#include "migutil.h"
#include "migeng.h"
#include "migtask.h"
#include "migoobe.h"
// DLL functions, declared in dll.cpp
STDAPI DllAddRef();
STDAPI DllRelease();
extern HMODULE g_hModule;
///////////////////////////////////////////////////////////
//
// Global variables
//
///////////////////////////////////////////////////////////
//
// Component
//
//
// Constructor
//
CMigWizEngine::CMigWizEngine() : m_cRef(1), m_fCancelled(TRUE), m_fUserApplying(FALSE), m_fInBackgroundThread(FALSE)
{
DllAddRef();
}
//
// Destructor
//
CMigWizEngine::~CMigWizEngine()
{
DllRelease();
}
//
// IUnknown implementation
//
STDMETHODIMP CMigWizEngine::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CMigWizEngine, IObjectWithSite),
QITABENT(CMigWizEngine, IMigrationWizardAuto),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) CMigWizEngine::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CMigWizEngine::Release()
{
if (InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
///////////////////////////////////////////////////////////
STDMETHODIMP CMigWizEngine::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** ppITypeInfo)
{
return E_NOTIMPL;
}
STDMETHODIMP CMigWizEngine::GetIDsOfNames(REFIID /*riid */, LPOLESTR* rgszNames,
UINT cNames, LCID lcid, DISPID* rgdispid)
{
return E_NOTIMPL;
}
STDMETHODIMP CMigWizEngine::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams,
VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
{
return E_NOTIMPL;
}
STDMETHODIMP CMigWizEngine::GetTypeInfoCount(UINT* pctinfo)
{
return E_NOTIMPL;
}
///////////////////////////////////////////////////////////
HRESULT CMigWizEngine::_FireEvent (LPVOID lpParam, int iDISPID, DISPPARAMS* pdisp)
{
HRESULT hr = E_FAIL;
IDispatch* pDispatch = (IDispatch*)lpParam;
if (pDispatch)
{
VARIANT varResult;
DISPPARAMS disp = { NULL, NULL, 0, 0};
if (pdisp == NULL)
{
pdisp = &disp;
}
hr = pDispatch->Invoke(iDISPID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, pdisp, &varResult, NULL, NULL);
}
return hr;
}
HRESULT CMigWizEngine::_GetIDispatchStream(IStream** ppStream)
{
HRESULT hr = E_FAIL;
BOOL fDone = FALSE;
if (_punkSite)
{
IConnectionPointContainer* pCPC;
hr = _punkSite->QueryInterface(IID_PPV_ARG(IConnectionPointContainer, &pCPC)); // get the connect point container
if (SUCCEEDED(hr))
{
IEnumConnectionPoints* pEnum;
hr = pCPC->EnumConnectionPoints(&pEnum); // get all the connection points
if (SUCCEEDED(hr))
{
IConnectionPoint* pcp;
while (!fDone)
{
ULONG cpcp = 1;
if (FAILED(pEnum->Next(1, &pcp, &cpcp)) || 0 == cpcp)
{
break;
}
else
{
IID iidInterface;
if (SUCCEEDED ( pcp->GetConnectionInterface(&iidInterface) && // get only the connection point for DMigrationWizardAutoEvents
(DIID_DMigrationWizardAutoEvents == iidInterface)))
{
// now fire the event for all listeners on this connection point
IEnumConnections* pEnumConnections;
if (SUCCEEDED(pcp->EnumConnections(&pEnumConnections)))
{
CONNECTDATA rgcd[1];
ULONG ccd;
while (!fDone)
{
if (FAILED(pEnumConnections->Next(ARRAYSIZE(rgcd), rgcd, &ccd)) || ccd == 0)
{
break;
}
else if (rgcd[0].pUnk)
{
IDispatch* pDispatch;
if (SUCCEEDED(rgcd[0].pUnk->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch))))
{
if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(IID_IDispatch, pDispatch, ppStream)))
{
fDone = TRUE;
hr = S_OK;
}
pDispatch->Release();
}
rgcd[0].pUnk->Release();
}
}
pEnumConnections->Release();
}
}
pcp->Release();
}
}
pEnum->Release();
}
pCPC->Release();
}
}
return hr;
}
HRESULT CMigWizEngine::_FireProgress(LPVOID lpParam, BSTR pszMsg, int iDone, int iTotal)
{
VARIANTARG rgvarg[3];
VARIANT varResult;
VariantClear(&varResult);
HRESULT hr = E_OUTOFMEMORY;
DISPPARAMS disp = { rgvarg, NULL, ARRAYSIZE(rgvarg), 0};
rgvarg[0].vt = VT_BSTR;
rgvarg[0].bstrVal = SysAllocString(pszMsg);
if (rgvarg[0].bstrVal)
{
rgvarg[1].vt = VT_I4;
rgvarg[1].lVal = iDone;
rgvarg[2].vt = VT_I4;
rgvarg[2].lVal = iTotal;
hr = _FireEvent(lpParam, 1, &disp);
SysFreeString(rgvarg[0].bstrVal);
}
return hr;
}
HRESULT CMigWizEngine::_FireComplete(LPVOID lpParam, BSTR pszMsg)
{
VARIANTARG rgvarg[1];
DISPPARAMS disp = { rgvarg, NULL, ARRAYSIZE(rgvarg), 0};
rgvarg[0].vt = VT_BSTR;
rgvarg[0].bstrVal = SysAllocString(pszMsg);
if (rgvarg[0].bstrVal)
{
_FireEvent(lpParam, 2, &disp);
SysFreeString(rgvarg[0].bstrVal);
}
return S_OK;
}
typedef struct {
IDispatch* pDispatch;
CMigWizEngine* pengine;
} PROGRESSCALLBACKSTRUCT;
UINT ProgressCallback (LPVOID lpParam, UINT ui1, UINT ui2)
{
PROGRESSCALLBACKSTRUCT* ppcs = (PROGRESSCALLBACKSTRUCT*)lpParam;
ppcs->pengine->_FireProgress((LPVOID)(ppcs->pDispatch), SZ_MIGWIZPROGRESS_OK, ui1, ui2);
return 0;
}
#define SZ_OOBEMODE TEXT("OOBEMODE")
HRESULT CMigWizEngine::_CreateToolDiskThreadWorker ()
{
HRESULT hr = E_FAIL;
BOOL fNoDisk = FALSE;
IDispatch* pDispatch;
hr = CoGetInterfaceAndReleaseStream(m_pDispatchStream, IID_PPV_ARG(IDispatch, &pDispatch));
if (SUCCEEDED(hr))
{
// copy the INF
CHAR szDrivePathA[MAX_PATH];
if (SUCCEEDED(_SHUnicodeToAnsi(m_pszDrivePath, szDrivePathA, ARRAYSIZE(szDrivePathA))))
{
CHAR szFilesPathA[MAX_PATH];
if (SUCCEEDED(_SHUnicodeToAnsi(m_pszFilesPath, szFilesPathA, ARRAYSIZE(szFilesPathA))))
{
CHAR szManifestPathA[MAX_PATH];
if (SUCCEEDED(_SHUnicodeToAnsi(m_pszManifestPath, szManifestPathA, ARRAYSIZE(szManifestPathA))))
{
PROGRESSCALLBACKSTRUCT pcs;
pcs.pDispatch = pDispatch;
pDispatch->AddRef();
pcs.pengine = this;
this->AddRef();
if (SUCCEEDED(_CopyInfToDisk(szDrivePathA, szFilesPathA, szManifestPathA,
ProgressCallback, (LPVOID)&pcs, NULL, NULL, g_hModule, &m_fCancelled, &fNoDisk)))
{
if (!m_fCancelled)
{
hr = S_OK;
IStream* pStream = NULL;
TCHAR szPath[MAX_PATH];
lstrcpy(szPath, szDrivePathA);
PathAppend(szPath, TEXT("oobemode.dat"));
if (SUCCEEDED(SHCreateStreamOnFile(szPath, STGM_WRITE | STGM_CREATE, &pStream)))
{
pStream->Write(SZ_OOBEMODE, sizeof(TCHAR) * (ARRAYSIZE(SZ_OOBEMODE) - 1), NULL);
pStream->Release();
}
}
}
pDispatch->Release();
this->Release();
}
}
}
m_fInBackgroundThread = FALSE;
if (m_fCancelled)
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_CANCEL);
}
else if (fNoDisk)
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_NODISK);
}
else if (SUCCEEDED(hr))
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_OK);
}
else
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_FAIL);
}
}
m_fCancelled = TRUE;
SysFreeString(m_pszDrivePath);
SysFreeString(m_pszFilesPath);
SysFreeString(m_pszManifestPath);
if (pDispatch)
{
pDispatch->Release();
}
Release();
return 0;
}
DWORD WINAPI CMigWizEngine::_CreateToolDiskThread (LPVOID lpParam)
{
if (lpParam)
{
((CMigWizEngine*)lpParam)->_CreateToolDiskThreadWorker();
}
return 0;
}
STDMETHODIMP CMigWizEngine::CreateToolDisk(BSTR pszDrivePath, BSTR pszFilesPath, BSTR pszManifestPath)
{
HRESULT hr = S_OK; // we always want to return S_OK
if (!m_fInBackgroundThread)
{
m_fInBackgroundThread = TRUE;
hr = S_OK;
IStream* pDispatchStream;
hr = _GetIDispatchStream(&pDispatchStream);
if (SUCCEEDED(hr))
{
m_pszDrivePath = SysAllocString(pszDrivePath);
m_pszFilesPath = SysAllocString(pszFilesPath);
m_pszManifestPath = SysAllocString(pszManifestPath);
if (m_pszDrivePath && m_pszFilesPath && m_pszManifestPath)
{
m_fCancelled = FALSE;
m_pDispatchStream = pDispatchStream;
m_pDispatchStream->AddRef();
AddRef();
if (!SHCreateThread(_CreateToolDiskThread, this, (CTF_COINIT | CTF_PROCESS_REF | CTF_FREELIBANDEXIT), NULL))
{
Release();
}
}
else
{
hr = E_OUTOFMEMORY;
SysFreeString(pszDrivePath); // SysFreeString doesn't mind being passed NULL
SysFreeString(pszFilesPath);
SysFreeString(pszManifestPath);
}
pDispatchStream->Release();
}
}
return hr;
}
BOOL g_fApplyDiskNotFound;
ULONG_PTR MessageCallback (UINT uiMsg, ULONG_PTR pArg)
{
PRMEDIA_EXTRADATA extraData;
switch (uiMsg) {
case TRANSPORTMESSAGE_SIZE_SAVED:
return TRUE;
case TRANSPORTMESSAGE_RMEDIA_LOAD:
extraData = (PRMEDIA_EXTRADATA) pArg;
if (!extraData) {
return TRUE;
} else {
if (extraData->MediaNumber == 1) {
switch (extraData->LastError) {
case RMEDIA_ERR_NOERROR:
return TRUE;
break;
case RMEDIA_ERR_WRONGMEDIA:
g_fApplyDiskNotFound = TRUE;
return FALSE;
break;
case RMEDIA_ERR_DISKFULL:
return FALSE;
break;
case RMEDIA_ERR_WRITEPROTECT:
return FALSE;
break;
case RMEDIA_ERR_NOTREADY:
return FALSE;
break;
case RMEDIA_ERR_CRITICAL:
return FALSE;
break;
default:
return TRUE;
}
} else {
switch (extraData->LastError) {
case RMEDIA_ERR_NOERROR:
return TRUE;
break;
case RMEDIA_ERR_WRONGMEDIA:
g_fApplyDiskNotFound = TRUE;
return FALSE;
break;
case RMEDIA_ERR_DISKFULL:
return FALSE;
break;
case RMEDIA_ERR_WRITEPROTECT:
return FALSE;
break;
case RMEDIA_ERR_NOTREADY:
return FALSE;
break;
case RMEDIA_ERR_CRITICAL:
return FALSE;
break;
default:
return TRUE;
}
}
}
}
return APPRESPONSE_SUCCESS;
}
#define PHASEWIDTH_APPLY_TRANSPORT 1000
#define PHASEWIDTH_APPLY_ANALYSIS 1000
#define PHASEWIDTH_APPLY_APPLY 1000
#define PHASEWIDTH_APPLY_TOTAL (PHASEWIDTH_APPLY_TRANSPORT + PHASEWIDTH_APPLY_ANALYSIS + PHASEWIDTH_APPLY_APPLY)
typedef struct {
CMigWizEngine* pEngine;
IDispatch* pDispatch;
} APPLYPROGRESSCALLBACKSTRUCT;
VOID WINAPI ApplyProgressCallback (MIG_PROGRESSPHASE Phase, MIG_PROGRESSSTATE State, UINT uiWorkDone, UINT uiTotalWork, ULONG_PTR pArg)
{
INT iWork = 0;
INT iPhaseWidth = 0;
INT iTotal = PHASEWIDTH_APPLY_TOTAL;
APPLYPROGRESSCALLBACKSTRUCT* papcs = (APPLYPROGRESSCALLBACKSTRUCT*)pArg;
switch (Phase)
{
case MIG_TRANSPORT_PHASE:
iWork = 0;
iPhaseWidth = PHASEWIDTH_APPLY_TRANSPORT;
break;
case MIG_ANALYSIS_PHASE:
iWork = PHASEWIDTH_APPLY_TRANSPORT;
iPhaseWidth = PHASEWIDTH_APPLY_ANALYSIS;
break;
case MIG_APPLY_PHASE:
iWork = PHASEWIDTH_APPLY_TRANSPORT + PHASEWIDTH_APPLY_ANALYSIS;
iPhaseWidth = PHASEWIDTH_APPLY_APPLY;
break;
}
if (State == MIG_END_PHASE)
{
iWork += iPhaseWidth;
}
else if (uiTotalWork && uiWorkDone)
{
iWork += (iPhaseWidth * uiWorkDone) / uiTotalWork;
}
if (papcs && papcs->pEngine && papcs->pDispatch)
{
papcs->pEngine->_FireProgress(papcs->pDispatch, L"", iWork, iTotal);
}
}
HRESULT CMigWizEngine::_ApplySettingsThreadWorker ()
{
HRESULT hr = E_OUTOFMEMORY;
g_fApplyDiskNotFound = FALSE; // set up
IDispatch* pDispatch;
hr = CoGetInterfaceAndReleaseStream(m_pDispatchStream, IID_PPV_ARG(IDispatch, &pDispatch));
if (SUCCEEDED(hr))
{
APPLYPROGRESSCALLBACKSTRUCT apcs;
apcs.pEngine = this;
apcs.pEngine->AddRef();
apcs.pDispatch = pDispatch;
apcs.pDispatch->AddRef();
if (SUCCEEDED(hr))
{
TCHAR szFloppyPath[4] = TEXT("A:\\");
szFloppyPath[0] += (TCHAR)_GetFloppyNumber(TRUE);
hr = _DoApply(szFloppyPath, NULL, NULL, &m_fCancelled, ApplyProgressCallback, (ULONG_PTR)&apcs);
}
apcs.pEngine->Release();
apcs.pDispatch->Release();
m_fInBackgroundThread = FALSE;
if (m_fCancelled)
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_CANCEL);
}
else if (g_fApplyDiskNotFound)
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_NODISK);
}
else if (SUCCEEDED(hr))
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_OK);
}
else
{
_FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_FAIL);
}
}
m_fCancelled = TRUE;
m_fUserApplying = FALSE;
Release();
return hr;
}
DWORD WINAPI CMigWizEngine::_ApplySettingsThread (LPVOID lpParam)
{
if (lpParam)
{
((CMigWizEngine*)lpParam)->_ApplySettingsThreadWorker();
}
return 0;
}
STDMETHODIMP CMigWizEngine::ApplySettings(BSTR pszMigwizFiles)
{
HRESULT hr = E_FAIL;
if (!m_fInBackgroundThread)
{
m_fInBackgroundThread = TRUE;
hr = S_OK;
m_fUserApplying = TRUE;
IStream* pDispatchStream;
hr = _GetIDispatchStream(&pDispatchStream);
if (SUCCEEDED(hr))
{
m_fCancelled = FALSE;
CHAR szMigwizPathA[MAX_PATH];
if (SUCCEEDED(_SHUnicodeToAnsi(pszMigwizFiles, szMigwizPathA, ARRAYSIZE(szMigwizPathA))))
{
hr = Engine_Initialize(szMigwizPathA, FALSE, FALSE, TEXT("OOBE"), MessageCallback, NULL);
m_pDispatchStream = pDispatchStream;
m_pDispatchStream->AddRef();
AddRef();
if (!SHCreateThread(_ApplySettingsThread, this, (CTF_COINIT | CTF_PROCESS_REF | CTF_FREELIBANDEXIT), NULL))
{
Release();
}
}
else
{
hr = E_FAIL;
}
pDispatchStream->Release();
}
}
return hr;
}
STDMETHODIMP CMigWizEngine::Cancel()
{
HRESULT hr = S_OK;
m_fCancelled = TRUE;
if (m_fUserApplying)
{
Engine_Cancel();
}
return hr;
}