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.
1453 lines
36 KiB
1453 lines
36 KiB
// Upload.cpp : Implementation of CUpload
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "CompatUI.h"
|
|
#include "shlobj.h"
|
|
extern "C" {
|
|
#include "shimdb.h"
|
|
}
|
|
|
|
#include "Upload.h"
|
|
|
|
TCHAR szKeyDataFiles[] = TEXT("DataFiles");
|
|
|
|
|
|
//
|
|
// lives in util.cpp
|
|
//
|
|
BOOL
|
|
GetExePathFromObject(
|
|
LPCTSTR lpszPath, // path to an arbitrary object
|
|
CComBSTR& bstrExePath
|
|
);
|
|
|
|
|
|
//
|
|
// lives in proglist.cpp
|
|
//
|
|
|
|
wstring
|
|
LoadResourceString(UINT nID);
|
|
|
|
//
|
|
// lives in ntutil.c
|
|
//
|
|
extern "C"
|
|
BOOL
|
|
WINAPI
|
|
CheckFileLocation(
|
|
LPCWSTR pwszDosPath,
|
|
BOOL* pbRoot,
|
|
BOOL* pbLeaf
|
|
);
|
|
|
|
|
|
//
|
|
// conversion
|
|
//
|
|
BOOL VariantToBOOL(CComVariant& v)
|
|
{
|
|
if (SUCCEEDED(v.ChangeType(VT_BOOL))) {
|
|
return v.boolVal;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
wstring VariantToStr(CComVariant& v)
|
|
{
|
|
wstring str;
|
|
|
|
if (v.vt != VT_EMPTY && v.vt != VT_NULL) {
|
|
if (SUCCEEDED(v.ChangeType(VT_BSTR))) {
|
|
str = v.bstrVal;
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
HRESULT StringToVariant(VARIANT* pv, const wstring& str)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
pv->vt = VT_NULL;
|
|
pv->bstrVal = ::SysAllocString(str.c_str());
|
|
if (pv->bstrVal == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
} else {
|
|
pv->vt = VT_BSTR;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetTempFile(
|
|
LPCTSTR lpszPrefix,
|
|
CComBSTR& bstrFile
|
|
)
|
|
{
|
|
DWORD dwLength;
|
|
TCHAR szBuffer[MAX_PATH];
|
|
TCHAR szTempFile[MAX_PATH];
|
|
|
|
dwLength = GetTempPath(CHARCOUNT(szBuffer), szBuffer);
|
|
if (!dwLength || dwLength > CHARCOUNT(szBuffer)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// we got directory, generate the file now
|
|
//
|
|
|
|
dwLength = GetTempFileName(szBuffer, lpszPrefix, 0, szTempFile);
|
|
if (!dwLength) {
|
|
return FALSE;
|
|
}
|
|
|
|
bstrFile = szTempFile;
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
wstring StrUpCase(wstring& wstr)
|
|
{
|
|
ctype<wchar_t> _ct;
|
|
wstring::iterator iter;
|
|
|
|
for (iter = wstr.begin(); iter != wstr.end(); ++iter) {
|
|
(*iter) = _ct.toupper(*iter);
|
|
}
|
|
|
|
return wstr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CUpload
|
|
|
|
|
|
BOOL CUpload::GetDataFilesKey(CComBSTR& bstrVal)
|
|
{
|
|
// STRVEC::iterator iter;
|
|
MAPSTR2MFI::iterator iter;
|
|
|
|
bstrVal.Empty();
|
|
|
|
for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
|
|
if (bstrVal.Length()) {
|
|
bstrVal.Append(TEXT("|"));
|
|
}
|
|
bstrVal.Append((*iter).second.strFileName.c_str());
|
|
}
|
|
return bstrVal.Length() != 0;
|
|
|
|
}
|
|
|
|
STDMETHODIMP CUpload::SetKey(BSTR pszKey, VARIANT* pvValue)
|
|
{
|
|
wstring strKey = pszKey;
|
|
VARIANT vStr;
|
|
HRESULT hr;
|
|
HRESULT hrRet = S_OK;
|
|
|
|
//
|
|
// dwwin is case-sensitive
|
|
//
|
|
// StrUpCase(strKey);
|
|
|
|
if (strKey == szKeyDataFiles) { // data files cannot be set directly
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
VariantInit(&vStr);
|
|
|
|
hr = VariantChangeType(&vStr, pvValue, 0, VT_BSTR);
|
|
if (SUCCEEDED(hr)) {
|
|
wstring strVal = vStr.bstrVal;
|
|
|
|
m_mapManifest[strKey] = strVal;
|
|
} else if (pvValue->vt == VT_NULL || pvValue->vt == VT_EMPTY) {
|
|
m_mapManifest.erase(strKey);
|
|
} else {
|
|
hrRet = E_INVALIDARG;
|
|
}
|
|
VariantClear(&vStr);
|
|
|
|
return hrRet;
|
|
}
|
|
|
|
STDMETHODIMP CUpload::GetKey(BSTR pszKey, VARIANT *pValue)
|
|
{
|
|
CComBSTR bstrVal;
|
|
wstring strKey = pszKey;
|
|
|
|
// StrUpCase(strKey);
|
|
|
|
if (strKey == szKeyDataFiles) {
|
|
//
|
|
// data files -- handled separately
|
|
//
|
|
if (GetDataFilesKey(bstrVal)) {
|
|
pValue->vt = VT_BSTR;
|
|
pValue->bstrVal = bstrVal.Copy();
|
|
} else {
|
|
pValue->vt = VT_NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
MAPSTR2STR::iterator iter = m_mapManifest.find(strKey);
|
|
if (iter != m_mapManifest.end()) {
|
|
bstrVal = (*iter).second.c_str();
|
|
pValue->vt = VT_BSTR;
|
|
pValue->bstrVal = bstrVal.Copy();
|
|
} else {
|
|
pValue->vt = VT_NULL;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
#define DWWIN_HEADLESS_MODE 0x00000080
|
|
|
|
BOOL CUpload::IsHeadlessMode(void)
|
|
{
|
|
CComVariant varFlags;
|
|
HRESULT hr;
|
|
BOOL bHeadless = FALSE;
|
|
|
|
GetKey(TEXT("Flags"), &varFlags);
|
|
|
|
hr = varFlags.ChangeType(VT_I4);
|
|
if (SUCCEEDED(hr)) {
|
|
bHeadless = !!(varFlags.lVal & DWWIN_HEADLESS_MODE);
|
|
}
|
|
|
|
return bHeadless;
|
|
}
|
|
|
|
|
|
/*
|
|
DWORD CUpload::CountFiles(DWORD nLevel, LPCWSTR pszPath)
|
|
{
|
|
WIN32_FIND_DATA wfd;
|
|
wstring strPath = pszPath;
|
|
wstring::size_type nPos;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
DWORD dwCount = 0;
|
|
|
|
nPos = strPath.length();
|
|
if (strPath[nPos-1] != TEXT('\\')) {
|
|
strPath += TEXT('\\');
|
|
++nPos;
|
|
}
|
|
|
|
FindFirstFileExW(
|
|
|
|
strPath += TEXT('*');
|
|
|
|
hFind = FindFirstFile(strPath.c_str(), &wfd);
|
|
if (hFind != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
if (nLevel < 3 && wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
if (wcscmp(wfd.cFileName, TEXT(".")) && wcscmp(wfd.cFileName, TEXT(".."))) {
|
|
strPath.replace(nPos, wstring::nPos, wfd.cFileName);
|
|
dwCount += CountFiles(nLevel + 1, strPath.c_str());
|
|
}
|
|
} else { // file
|
|
++dwCount;
|
|
}
|
|
} while (FindNextFile(hFind, &wfd));
|
|
|
|
FindClose(hFind);
|
|
}
|
|
|
|
return dwCount;
|
|
}
|
|
*/
|
|
|
|
BOOL CALLBACK CUpload::_GrabmiCallback(
|
|
LPVOID lpvCallbackParam, // application-defined parameter
|
|
LPCTSTR lpszRoot, // root directory path
|
|
LPCTSTR lpszRelative, // relative path
|
|
PATTRINFO pAttrInfo, // attributes
|
|
LPCWSTR pwszXML // resulting xml
|
|
)
|
|
{
|
|
GMEPARAMS* pParams = (GMEPARAMS*)lpvCallbackParam;
|
|
|
|
CUpload* pT = pParams->first;
|
|
IProgressDialog* ppd = pParams->second;
|
|
|
|
if (ppd == NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
ppd->SetLine(2, lpszRoot, TRUE, NULL);
|
|
|
|
// ppd->SetLine(2, lpszRelative, TRUE, NULL);
|
|
|
|
return !ppd->HasUserCancelled();
|
|
}
|
|
|
|
|
|
STDMETHODIMP CUpload::AddMatchingInfo(
|
|
BSTR pszCommand,
|
|
VARIANT vFilter,
|
|
VARIANT vKey,
|
|
VARIANT vDescription,
|
|
VARIANT vProgress,
|
|
BOOL *pbSuccess)
|
|
{
|
|
|
|
/* HANDLE hThread = NULL;
|
|
DWORD dwExitCode = 0;
|
|
DWORD dwWait;
|
|
*/
|
|
|
|
if (!m_Safe) {
|
|
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
CComVariant varFilter(vFilter);
|
|
DWORD dwFilter = GRABMI_FILTER_NORMAL;
|
|
wstring strKey;
|
|
wstring strDescription;
|
|
|
|
if (SUCCEEDED(varFilter.ChangeType(VT_I4))) {
|
|
dwFilter = (DWORD)varFilter.lVal;
|
|
}
|
|
|
|
strKey = VariantToStr(CComVariant(vKey));
|
|
strDescription = VariantToStr(CComVariant(vDescription));
|
|
|
|
|
|
*pbSuccess = AddMatchingInfoInternal(::GetActiveWindow(),
|
|
pszCommand,
|
|
dwFilter,
|
|
VariantToBOOL(CComVariant(vProgress)),
|
|
strKey.empty() ? NULL : strKey.c_str(),
|
|
strDescription.empty() ? NULL : strDescription.c_str());
|
|
|
|
/*
|
|
|
|
MITHREADPARAMBLK* pParam = new MITHREADPARAMBLK;
|
|
CComVariant varFilter(vFilter);
|
|
|
|
if (!pParam) {
|
|
goto cleanup;
|
|
}
|
|
|
|
pParam->pThis = this;
|
|
pParam->strCommand = pszCommand;
|
|
pParam->hwndParent = ::GetActiveWindow();
|
|
pParam->dwFilter = GRABMI_FILTER_NORMAL;
|
|
|
|
if (SUCCEEDED(varFilter.ChangeType(VT_I4))) {
|
|
pParam->dwFilter = (DWORD)varFilter.lVal;
|
|
}
|
|
|
|
pParam->bNoProgress = VariantToBOOL(CComVariant(vProgress));
|
|
pParam->strKey = VariantToStr(CComVariant(vKey));
|
|
pParam->strDescription = VariantToStr(CComVariant(vDescription));
|
|
|
|
hThread = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)_AddMatchingInfoThreadProc,
|
|
(LPVOID)pParam,
|
|
0,
|
|
NULL);
|
|
if (!hThread) {
|
|
goto cleanup;
|
|
}
|
|
|
|
dwWait = WaitForSingleObject(hThread, INFINITE);
|
|
if (dwWait != WAIT_OBJECT_0) {
|
|
goto cleanup;
|
|
}
|
|
|
|
GetExitCodeThread(hThread, &dwExitCode);
|
|
|
|
cleanup:
|
|
if (hThread) {
|
|
CloseHandle(hThread);
|
|
}
|
|
|
|
*pbSuccess = !!dwExitCode;
|
|
*/
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
DWORD WINAPI
|
|
CUpload::_AddMatchingInfoThreadProc(LPVOID lpvThis)
|
|
{
|
|
BOOL bSuccess;
|
|
HRESULT hr;
|
|
|
|
MITHREADPARAMBLK* pParam = (MITHREADPARAMBLK*)lpvThis;
|
|
if (!pParam->bNoProgress) {
|
|
hr = CoInitialize(NULL);
|
|
if (!SUCCEEDED(hr)) {
|
|
pParam->bNoProgress = TRUE;
|
|
}
|
|
}
|
|
|
|
bSuccess = pParam->pThis->AddMatchingInfoInternal(::GetActiveWindow(),
|
|
pParam->strCommand.c_str(),
|
|
pParam->dwFilter,
|
|
pParam->bNoProgress,
|
|
pParam->strKey.empty() ? NULL : pParam->strKey.c_str(),
|
|
pParam->strDescription.empty() ? NULL : pParam->strDescription.c_str());
|
|
if (!pParam->bNoProgress) {
|
|
CoUninitialize();
|
|
}
|
|
delete pParam;
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
BOOL CUpload::AddMatchingInfoInternal(
|
|
HWND hwndParent,
|
|
LPCWSTR pszCommand,
|
|
DWORD dwFilter,
|
|
BOOL bNoProgress,
|
|
LPCTSTR pszKey,
|
|
LPCTSTR pszDescription)
|
|
{
|
|
CComBSTR bstrPath;
|
|
CComBSTR bstrGrabmiFile;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
IProgressDialog * ppd = NULL;
|
|
HRESULT hr;
|
|
GMEPARAMS GrabmiParams;
|
|
MFI MatchingFileInfo;
|
|
wstring strKey;
|
|
|
|
UINT DriveType;
|
|
BOOL bLeaf = NULL;
|
|
BOOL bRoot = NULL;
|
|
DWORD dwFilters[3];
|
|
wstring Paths[3];
|
|
int nDrive;
|
|
DWORD nPasses = 1;
|
|
wstring DriveRoot(TEXT("X:\\"));
|
|
|
|
//
|
|
// this is kinda dangerous, the way it works. We collect the info while yielding to the
|
|
// creating process (due to the start dialog
|
|
// so the calling window needs to be disabled -- or we need to trap doing something else
|
|
// while we're collecting data
|
|
//
|
|
|
|
|
|
if (!::GetExePathFromObject(pszCommand, bstrPath)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// bstrPath is exe path, create and grab matching info
|
|
//
|
|
|
|
if (!GetTempFile(TEXT("ACG"), bstrGrabmiFile)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// we are going to run grabmi!!!
|
|
//
|
|
|
|
//
|
|
// prepare callback
|
|
//
|
|
|
|
if (!bNoProgress) {
|
|
hr = CoCreateInstance(CLSID_ProgressDialog,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IProgressDialog,
|
|
(void **)&ppd);
|
|
if (!SUCCEEDED(hr)) {
|
|
ppd = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// check to see what happened to hr
|
|
//
|
|
if (ppd) {
|
|
wstring strCaption;
|
|
|
|
strCaption = LoadResourceString(IDS_COLLECTINGDATACAPTION);
|
|
ppd->SetTitle(strCaption.c_str()); // Set the title of the dialog.
|
|
|
|
ppd->SetAnimation (_Module.GetModuleInstance(), IDA_FINDANIM); // Set the animation to play.
|
|
|
|
strCaption = LoadResourceString(IDS_WAITCLEANUP);
|
|
ppd->SetCancelMsg (strCaption.c_str(), NULL); // Will only be displayed if Cancel
|
|
|
|
strCaption = LoadResourceString(IDS_GRABMISTATUS_COLLECTING);
|
|
ppd->SetLine(1, strCaption.c_str(), FALSE, NULL);
|
|
|
|
ppd->StartProgressDialog(hwndParent,
|
|
NULL,
|
|
PROGDLG_NOPROGRESSBAR|
|
|
PROGDLG_MODAL|
|
|
PROGDLG_NOMINIMIZE|
|
|
PROGDLG_NORMAL|
|
|
PROGDLG_NOTIME,
|
|
NULL); // Display and enable automatic estimated time remain
|
|
}
|
|
|
|
//
|
|
// this is where we have to determine whether grabmi is a going to be running wild
|
|
// Check the drive first to see whether it's removable media
|
|
// cases : leaf node / root node
|
|
// : system directory
|
|
// : cd-rom
|
|
// : temp directory
|
|
// there could be many combinations
|
|
//
|
|
|
|
if (ppd) {
|
|
wstring strCaption = LoadResourceString(IDS_CHECKING_FILES);
|
|
ppd->SetLine(2, strCaption.c_str(), FALSE, NULL);
|
|
}
|
|
|
|
//
|
|
// this is the default filter we shall use
|
|
//
|
|
dwFilters[0] = GRABMI_FILTER_PRIVACY;
|
|
Paths [0] = bstrPath;
|
|
nPasses = 1;
|
|
|
|
//
|
|
// determine if it's root/leaf node (could be both)
|
|
//
|
|
if (!CheckFileLocation(bstrPath, &bRoot, &bLeaf)) {
|
|
// we cannot check the file's location
|
|
goto GrabInformation;
|
|
}
|
|
|
|
DriveType = GetDriveTypeW(bstrPath); // this will give us *some* clue
|
|
|
|
// rules:
|
|
// cdrom and not root -- three passes
|
|
// root - add current file
|
|
//
|
|
|
|
if (bRoot || DRIVE_REMOTE == DriveType) {
|
|
|
|
dwFilters[0] |= GRABMI_FILTER_LIMITFILES;
|
|
|
|
} else if (DRIVE_CDROM == DriveType) {
|
|
|
|
nDrive = PathGetDriveNumber(bstrPath);
|
|
if (nDrive >= 0) {
|
|
dwFilters[0] |= GRABMI_FILTER_NOCLOSE|GRABMI_FILTER_APPEND;
|
|
|
|
dwFilters[1] = GRABMI_FILTER_NORECURSE|GRABMI_FILTER_APPEND;
|
|
Paths [1] = DriveRoot;
|
|
Paths [1].at(0) = (WCHAR)(TEXT('A') + nDrive);
|
|
nPasses = 2;
|
|
}
|
|
|
|
}
|
|
|
|
if (bLeaf) {
|
|
// we may want to do more here -- future dev
|
|
;
|
|
}
|
|
|
|
|
|
GrabInformation:
|
|
|
|
|
|
//
|
|
// set callback context
|
|
//
|
|
GrabmiParams.first = this;
|
|
GrabmiParams.second = ppd;
|
|
|
|
while (nPasses-- > 0) {
|
|
|
|
if (SdbGrabMatchingInfoEx(Paths[nPasses].c_str(),
|
|
dwFilters[nPasses],
|
|
bstrGrabmiFile,
|
|
_GrabmiCallback,
|
|
(LPVOID)&GrabmiParams) == GMI_FAILED) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// figure out the key/description
|
|
//
|
|
|
|
if (pszDescription) {
|
|
MatchingFileInfo.strDescription = pszDescription;
|
|
}
|
|
|
|
MatchingFileInfo.strFileName = bstrGrabmiFile;
|
|
MatchingFileInfo.bOwn = TRUE; // we have generated this file
|
|
//
|
|
// key
|
|
//
|
|
|
|
if (pszKey == NULL) {
|
|
strKey = MatchingFileInfo.strFileName;
|
|
} else {
|
|
strKey = pszKey;
|
|
}
|
|
StrUpCase(strKey);
|
|
|
|
m_DataFiles[strKey] = MatchingFileInfo;
|
|
|
|
// m_DataFiles.push_back(StrUpCase(wstring(bstrGrabmiFile)));
|
|
|
|
//
|
|
//
|
|
//
|
|
bSuccess = TRUE;
|
|
|
|
cleanup:
|
|
if (ppd) {
|
|
ppd->StopProgressDialog();
|
|
ppd->Release();
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
STDMETHODIMP CUpload::AddDataFile(
|
|
BSTR pszDataFile,
|
|
VARIANT vKey,
|
|
VARIANT vDescription,
|
|
VARIANT vOwn)
|
|
{
|
|
MFI MatchingFileInfo;
|
|
wstring strKey = VariantToStr(CComVariant(vKey));
|
|
BOOL bKeyFromName = FALSE;
|
|
|
|
if (strKey.empty()) {
|
|
strKey = pszDataFile;
|
|
bKeyFromName = TRUE;
|
|
}
|
|
StrUpCase(strKey);
|
|
|
|
if (m_DataFiles.find(strKey) != m_DataFiles.end() && !bKeyFromName) {
|
|
CComBSTR bstrKey = strKey.c_str();
|
|
RemoveDataFile(bstrKey);
|
|
}
|
|
|
|
MatchingFileInfo.strDescription = VariantToStr(CComVariant(vDescription));
|
|
MatchingFileInfo.strFileName = pszDataFile;
|
|
MatchingFileInfo.bOwn = VariantToBOOL(CComVariant(vOwn));
|
|
|
|
m_DataFiles[strKey] = MatchingFileInfo;
|
|
|
|
// m_DataFiles.push_back(StrUpCase(wstring(pszDataFile)));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CUpload::RemoveDataFile(BSTR pszDataFile)
|
|
{
|
|
// STRVEC::iterator iter;
|
|
MAPSTR2MFI::iterator iter;
|
|
wstring strFileName;
|
|
|
|
wstring strDataFile = pszDataFile;
|
|
|
|
StrUpCase(strDataFile);
|
|
|
|
iter = m_DataFiles.find(strDataFile);
|
|
if (iter != m_DataFiles.end()) {
|
|
if ((*iter).second.bOwn) {
|
|
::DeleteFile((*iter).second.strFileName.c_str());
|
|
}
|
|
|
|
m_DataFiles.erase(iter);
|
|
}
|
|
|
|
/*
|
|
for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
|
|
if (*iter == strDataFile) {
|
|
//
|
|
// found it
|
|
//
|
|
m_DataFiles.erase(iter);
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CUpload::CreateManifestFile(BOOL *pbSuccess)
|
|
{
|
|
//
|
|
// manifest file creation code
|
|
//
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
WCHAR UNICODE_MARKER[] = { (WCHAR)0xFEFF, L'\r', L'\n' };
|
|
MAPSTR2STR::iterator iter;
|
|
DWORD dwWritten;
|
|
wstring strLine;
|
|
CComBSTR bstrDataFiles;
|
|
BOOL bResult;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if (!m_Safe) {
|
|
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
if (!GetTempFile(TEXT("ACM"), m_bstrManifest)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// m_bstrManifest is our file
|
|
//
|
|
|
|
|
|
hFile = CreateFileW(m_bstrManifest,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
goto cleanup;
|
|
}
|
|
|
|
bResult = WriteFile(hFile, UNICODE_MARKER, sizeof(UNICODE_MARKER), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// done with the marker, now do the manifest strings
|
|
//
|
|
//
|
|
for (iter = m_mapManifest.begin(); iter != m_mapManifest.end(); ++iter) {
|
|
strLine = (*iter).first + TEXT('=') + (*iter).second + TEXT("\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// done with the general stuff, do the data files
|
|
//
|
|
|
|
if (GetDataFilesKey(bstrDataFiles)) {
|
|
strLine = wstring(szKeyDataFiles) + TEXT('=') + wstring(bstrDataFiles) + TEXT("\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
bSuccess = TRUE;
|
|
|
|
cleanup:
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (!bSuccess && m_bstrManifest.Length()) {
|
|
DeleteFile(m_bstrManifest);
|
|
m_bstrManifest.Empty();
|
|
}
|
|
*pbSuccess = bSuccess;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CUpload::SendReport(BOOL *pbSuccess)
|
|
{
|
|
UINT uSize;
|
|
TCHAR szSystemWindowsDirectory[MAX_PATH];
|
|
wstring strDWCmd;
|
|
wstring strDWPath;
|
|
STARTUPINFO StartupInfo = { 0 };
|
|
PROCESS_INFORMATION ProcessInfo = { 0 };
|
|
DWORD dwWait;
|
|
BOOL bSuccess = FALSE;
|
|
BOOL bResult;
|
|
DWORD dwExitCode;
|
|
BOOL bTerminated = FALSE;
|
|
DWORD dwTimeout = 10; // 10ms per ping
|
|
|
|
//
|
|
// Create Progress dialog
|
|
//
|
|
IProgressDialog * ppd = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// do not allow upload unless it is hc that is hosting us
|
|
//
|
|
|
|
if (!m_Safe) {
|
|
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
if (IsHeadlessMode()) {
|
|
|
|
hr = CoCreateInstance(CLSID_ProgressDialog,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IProgressDialog,
|
|
(void **)&ppd);
|
|
if (!SUCCEEDED(hr)) {
|
|
ppd = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check to see what happened to hr
|
|
//
|
|
if (ppd) {
|
|
wstring strCaption;
|
|
|
|
strCaption = LoadResourceString(IDS_SENDINGCAPTION);
|
|
ppd->SetTitle(strCaption.c_str()); // Set the title of the dialog.
|
|
|
|
ppd->SetAnimation (_Module.GetModuleInstance(), IDA_WATSONANIM); // Set the animation to play.
|
|
|
|
strCaption = LoadResourceString(IDS_WAITCLEANUP);
|
|
ppd->SetCancelMsg (strCaption.c_str(), NULL); // Will only be displayed if Cancel
|
|
|
|
strCaption = LoadResourceString(IDS_LAUNCHINGDR);
|
|
ppd->SetLine (1, strCaption.c_str(), FALSE, NULL);
|
|
|
|
ppd->StartProgressDialog(::GetActiveWindow(),
|
|
NULL,
|
|
PROGDLG_NOPROGRESSBAR|
|
|
PROGDLG_MODAL|
|
|
PROGDLG_NOMINIMIZE|
|
|
PROGDLG_NORMAL|
|
|
PROGDLG_NOTIME,
|
|
NULL); // Display and enable automatic estimated time remain
|
|
}
|
|
|
|
uSize = ::GetSystemWindowsDirectory(szSystemWindowsDirectory,
|
|
CHARCOUNT(szSystemWindowsDirectory));
|
|
if (uSize == 0 || uSize > CHARCOUNT(szSystemWindowsDirectory)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
strDWPath = szSystemWindowsDirectory;
|
|
if (strDWPath.at(strDWPath.length() - 1) != TCHAR('\\')) {
|
|
strDWPath.append(TEXT("\\"));
|
|
}
|
|
|
|
strDWPath += TEXT("system32\\dwwin.exe");
|
|
strDWCmd = strDWPath + TEXT(" -d ") + (LPCWSTR)m_bstrManifest;
|
|
|
|
StartupInfo.cb = sizeof(StartupInfo);
|
|
|
|
bResult = CreateProcess(strDWPath.c_str(),
|
|
(LPWSTR)strDWCmd.c_str(),
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
&ProcessInfo);
|
|
if (bResult) {
|
|
//
|
|
// recover an exit code please
|
|
//
|
|
if (ppd) {
|
|
wstring strSending = LoadResourceString(IDS_SENDINGINFO);
|
|
ppd->SetLine(1, strSending.c_str(), FALSE, NULL);
|
|
}
|
|
while(TRUE) {
|
|
dwWait = WaitForSingleObject(ProcessInfo.hProcess, dwTimeout);
|
|
if (dwWait == WAIT_OBJECT_0) {
|
|
if (GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode)) {
|
|
bSuccess = (dwExitCode == 0);
|
|
} else {
|
|
bSuccess = FALSE;
|
|
}
|
|
break;
|
|
|
|
} else if (dwWait == WAIT_TIMEOUT) {
|
|
|
|
//
|
|
// check the cancel button
|
|
//
|
|
|
|
if (ppd && !bTerminated && ppd->HasUserCancelled()) {
|
|
TerminateProcess(ProcessInfo.hProcess, (UINT)-1);
|
|
bTerminated = TRUE;
|
|
bSuccess = FALSE;
|
|
dwTimeout = 1000; // wait a bit longer
|
|
}
|
|
|
|
} else { // object somehow became abandoned
|
|
bSuccess = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (ppd) {
|
|
wstring strCleaningUp = LoadResourceString(IDS_CLEANINGUP);
|
|
ppd->SetLine(1, strCleaningUp.c_str(), FALSE, NULL);
|
|
}
|
|
|
|
|
|
cleanup:
|
|
|
|
|
|
if (ProcessInfo.hThread) {
|
|
CloseHandle(ProcessInfo.hThread);
|
|
}
|
|
if (ProcessInfo.hProcess) {
|
|
CloseHandle(ProcessInfo.hProcess);
|
|
}
|
|
|
|
if (ppd) {
|
|
ppd->StopProgressDialog();
|
|
ppd->Release();
|
|
}
|
|
|
|
*pbSuccess = bSuccess;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
wstring MakeXMLAttr(LPCTSTR lpszName, LPCTSTR lpszValue)
|
|
{
|
|
wstring str;
|
|
wstring strVal;
|
|
LPCTSTR pch;
|
|
wstring::size_type nPos = 0;
|
|
int nlen;
|
|
|
|
if (NULL != lpszValue) {
|
|
strVal = lpszValue;
|
|
}
|
|
|
|
// find and replace: all the instances of " & < >
|
|
//
|
|
while (nPos != wstring::npos && nPos < strVal.length()) {
|
|
|
|
nPos = strVal.find_first_of(TEXT("&\"<>"), nPos);
|
|
if (nPos == wstring::npos) {
|
|
break;
|
|
}
|
|
|
|
switch(strVal.at(nPos)) {
|
|
case TEXT('&'):
|
|
pch = TEXT("&");
|
|
break;
|
|
|
|
case TEXT('>'):
|
|
pch = TEXT(">");
|
|
break;
|
|
|
|
case TEXT('<'):
|
|
pch = TEXT("<");
|
|
break;
|
|
|
|
case TEXT('\"'):
|
|
pch = TEXT(""");
|
|
break;
|
|
default:
|
|
// lunacy, we saw it -- and now it's gone
|
|
pch = NULL;
|
|
break;
|
|
}
|
|
|
|
if (pch) {
|
|
strVal.replace(nPos, 1, pch); // one character
|
|
nPos += _tcslen(pch);
|
|
}
|
|
}
|
|
|
|
// once we got the string, assign
|
|
str = lpszName;
|
|
str += TEXT("=\"");
|
|
str += strVal;
|
|
str += TEXT("\"");
|
|
|
|
return str;
|
|
}
|
|
|
|
wstring MakeXMLAttr(LPCTSTR lpszName, LONG lValue)
|
|
{
|
|
WCHAR szBuf[32];
|
|
wstring str;
|
|
|
|
swprintf(szBuf, TEXT("\"0x%lx\""), lValue);
|
|
|
|
str = lpszName;
|
|
str += TEXT("=");
|
|
str += szBuf;
|
|
return str;
|
|
}
|
|
|
|
wstring MakeXMLLayers(LPCTSTR lpszLayers)
|
|
{
|
|
wstring str;
|
|
wstring strLayer;
|
|
LPCTSTR pch, pbrk;
|
|
|
|
//
|
|
// partition the string
|
|
//
|
|
pch = lpszLayers;
|
|
|
|
while (pch && *pch != TEXT('\0')) {
|
|
|
|
pch += _tcsspn(pch, TEXT(" \t"));
|
|
|
|
// check if we're not at the end
|
|
if (*pch == TEXT('\0')) {
|
|
break;
|
|
}
|
|
|
|
pbrk = _tcspbrk(pch, TEXT(" \t"));
|
|
if (pbrk == NULL) {
|
|
// from pch to the end of the string
|
|
strLayer.assign(pch);
|
|
} else {
|
|
strLayer.assign(pch, (int)(pbrk-pch));
|
|
}
|
|
|
|
if (!str.empty()) {
|
|
str += TEXT("\r\n");
|
|
}
|
|
str += TEXT(" "); // lead-in
|
|
str += TEXT("<LAYER NAME=\"");
|
|
str += strLayer;
|
|
str += TEXT("\"/>");
|
|
|
|
pch = pbrk;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CUpload::AddDescriptionFile(
|
|
BSTR pszApplicationName,
|
|
BSTR pszApplicationPath,
|
|
LONG lMediaType,
|
|
BOOL bCompatSuccess,
|
|
VARIANT* pvFixesApplied,
|
|
VARIANT vKey,
|
|
BOOL *pbSuccess
|
|
)
|
|
{
|
|
|
|
//
|
|
// manifest file creation code
|
|
//
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
WCHAR UNICODE_MARKER[] = { (WCHAR)0xFEFF, L'\r', L'\n' };
|
|
DWORD dwWritten;
|
|
wstring strLine;
|
|
CComBSTR bstrDescriptionFile;
|
|
BOOL bResult;
|
|
BOOL bSuccess = FALSE;
|
|
WCHAR szBuf[32];
|
|
VARIANT vFixes;
|
|
MFI MatchingFileInfo;
|
|
wstring strKey = VariantToStr(CComVariant(vKey));
|
|
wstring strLayers;
|
|
static TCHAR szTab[] = TEXT(" ");
|
|
static TCHAR szCRTab[] = TEXT("\r\n ");
|
|
VariantInit(&vFixes);
|
|
|
|
if (!m_Safe) {
|
|
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
if (!GetTempFile(TEXT("ACI"), bstrDescriptionFile)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// m_bstrManifest is our file
|
|
//
|
|
|
|
|
|
hFile = CreateFileW(bstrDescriptionFile,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
goto cleanup;
|
|
}
|
|
|
|
bResult = WriteFile(hFile, UNICODE_MARKER, sizeof(UNICODE_MARKER), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
// xml marker
|
|
strLine = TEXT("<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// compose compat wizard...
|
|
strLine = TEXT("<CompatWizardResults");
|
|
strLine += TEXT(' ');
|
|
strLine += MakeXMLAttr(TEXT("ApplicationName"), pszApplicationName);
|
|
strLine += szCRTab;
|
|
strLine += MakeXMLAttr(TEXT("ApplicationPath"), pszApplicationPath);
|
|
strLine += szCRTab;
|
|
strLine += MakeXMLAttr(TEXT("MediaType"), lMediaType);
|
|
strLine += szCRTab;
|
|
strLine += MakeXMLAttr(TEXT("CompatibilityResult"), bCompatSuccess ? TEXT("Success") : TEXT("Failure"));
|
|
strLine += TEXT(">\r\n");
|
|
|
|
if (SUCCEEDED(VariantChangeType(&vFixes, pvFixesApplied, 0, VT_BSTR))) {
|
|
strLayers = vFixes.bstrVal;
|
|
}
|
|
|
|
if (!strLayers.empty()) {
|
|
//
|
|
// parse the layers string and get all of them listed
|
|
//
|
|
strLine += MakeXMLLayers(strLayers.c_str());
|
|
strLine += TEXT("\r\n");
|
|
}
|
|
|
|
strLine += TEXT("</CompatWizardResults>\r\n");
|
|
|
|
// we are done generating data, write it all out
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
//
|
|
// after we get through the descriptions
|
|
// write out data
|
|
strLine = TEXT("[CompatWizardResults]\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// write out all the info
|
|
//
|
|
strLine = TEXT("ApplicationName=");
|
|
strLine += pszApplicationName;
|
|
strLine += TEXT("\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
strLine = TEXT("ApplicationPath=");
|
|
strLine += pszApplicationPath;
|
|
strLine += TEXT("\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
strLine = TEXT("MediaType=");
|
|
_sntprintf(szBuf, CHARCOUNT(szBuf), TEXT("0x%lx"), lMediaType);
|
|
strLine += szBuf;
|
|
strLine += TEXT("\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// success
|
|
//
|
|
strLine = TEXT("CompatibilityResult=");
|
|
strLine += bCompatSuccess ? TEXT("Success") : TEXT("Failure");
|
|
strLine += TEXT("\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// fixes applied
|
|
//
|
|
strLine = TEXT("Layers=");
|
|
if (!SUCCEEDED(VariantChangeType(&vFixes, pvFixesApplied, 0, VT_BSTR))) {
|
|
strLine += TEXT("none");
|
|
} else {
|
|
strLine += vFixes.bstrVal;
|
|
}
|
|
strLine += TEXT("\r\n");
|
|
bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
|
|
if (!bResult) {
|
|
goto cleanup;
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
// standard file -- manifesto
|
|
MatchingFileInfo.strDescription = TEXT("Application Compatibility Description File");
|
|
MatchingFileInfo.strFileName = bstrDescriptionFile;
|
|
MatchingFileInfo.bOwn = TRUE;
|
|
|
|
//
|
|
// key is the filename prefixed by ACI_c:\foo\bar.exe
|
|
//
|
|
if (strKey.empty()) {
|
|
strKey = TEXT("ACI_");
|
|
strKey += pszApplicationPath;
|
|
}
|
|
StrUpCase(strKey);
|
|
|
|
m_DataFiles[strKey] = MatchingFileInfo;
|
|
|
|
// m_DataFiles.push_back(StrUpCase(wstring(bstrDescriptionFile)));
|
|
bSuccess = TRUE;
|
|
|
|
cleanup:
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (!bSuccess && bstrDescriptionFile.Length()) {
|
|
DeleteFile(bstrDescriptionFile);
|
|
}
|
|
*pbSuccess = bSuccess;
|
|
|
|
VariantClear(&vFixes);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CUpload::DeleteTempFiles()
|
|
{
|
|
// kill all the supplemental files
|
|
|
|
// STRVEC::iterator iter;
|
|
MAPSTR2MFI::iterator iter;
|
|
|
|
for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
|
|
if ((*iter).second.bOwn) {
|
|
::DeleteFile((*iter).second.strFileName.c_str());
|
|
}
|
|
}
|
|
|
|
m_DataFiles.clear();
|
|
|
|
//
|
|
// kill the manifest
|
|
//
|
|
if (m_bstrManifest.Length() > 0) {
|
|
::DeleteFile((LPCTSTR)m_bstrManifest);
|
|
}
|
|
m_bstrManifest.Empty();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
VOID CUpload::ListTempFiles(wstring& str)
|
|
{
|
|
// STRVEC::iterator iter;
|
|
MAPSTR2MFI::iterator iter;
|
|
|
|
str = TEXT("");
|
|
|
|
for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
|
|
if (!str.empty()) {
|
|
str += TEXT(";");
|
|
}
|
|
str += (*iter).second.strFileName.c_str();
|
|
}
|
|
|
|
/* // this will show the manifest file as well -- but I don't think we need to
|
|
// do this as the manifest is irrelevant
|
|
if (!str.empty()) {
|
|
str += TEXT("\r\n");
|
|
}
|
|
str += (LPCTSTR)m_bstrManifest;
|
|
*/
|
|
}
|
|
|
|
STDMETHODIMP CUpload::ShowTempFiles()
|
|
{
|
|
TCHAR szMshtml[] = TEXT("mshtml.dll");
|
|
TCHAR szModuleFileName[MAX_PATH];
|
|
LPMONIKER pmk = NULL;
|
|
HRESULT hr;
|
|
CComVariant vargIn;
|
|
CComVariant vargOut;
|
|
DWORD dwLength;
|
|
TCHAR szUrl2[MAX_PATH];
|
|
wstring strURL = TEXT("res://");
|
|
wstring strArg;
|
|
SHOWHTMLDIALOGFN* pfnShowDlg = NULL;
|
|
|
|
if (!m_Safe) {
|
|
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
HMODULE hMshtml = ::GetModuleHandle(szMshtml);
|
|
if (NULL == hMshtml) {
|
|
hMshtml = ::LoadLibrary(szMshtml);
|
|
if (NULL == hMshtml) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
pfnShowDlg = (SHOWHTMLDIALOGFN*)GetProcAddress(hMshtml,
|
|
"ShowHTMLDialog");
|
|
|
|
if (NULL == pfnShowDlg) {
|
|
goto cleanup;
|
|
}
|
|
|
|
dwLength = ::GetModuleFileName(_Module.GetModuleInstance(),
|
|
szModuleFileName,
|
|
CHARCOUNT(szModuleFileName));
|
|
|
|
if (dwLength == 0 || dwLength >= CHARCOUNT(szModuleFileName)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
_sntprintf(szUrl2, CHARCOUNT(szUrl2),
|
|
TEXT("/#%d/%s"),
|
|
(int)PtrToInt(RT_HTML),
|
|
IDR_SHOWTEMPFILESDLG);
|
|
|
|
strURL += szModuleFileName;
|
|
strURL += szUrl2;
|
|
|
|
hr = CreateURLMoniker(NULL, strURL.c_str(), &pmk);
|
|
|
|
if (!SUCCEEDED(hr)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
ListTempFiles(strArg);
|
|
// create argument In
|
|
vargIn = strArg.c_str();
|
|
|
|
pfnShowDlg(::GetActiveWindow(),
|
|
pmk,
|
|
&vargIn,
|
|
TEXT("center:yes"),
|
|
&vargOut);
|
|
|
|
cleanup:
|
|
|
|
if (NULL != pmk) {
|
|
pmk->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CUpload::GetDataFile(VARIANT vKey, LONG InformationClass, VARIANT* pVal)
|
|
{
|
|
CComVariant varKey(vKey);
|
|
LONG lIndex;
|
|
MAPSTR2MFI::iterator iter;
|
|
wstring str;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_Safe) {
|
|
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
pVal->vt = VT_NULL;
|
|
|
|
switch(InformationClass) {
|
|
case InfoClassCount:
|
|
// requested: counter
|
|
pVal->vt = VT_I4;
|
|
pVal->lVal = m_DataFiles.size();
|
|
break;
|
|
|
|
case InfoClassKey:
|
|
|
|
if (!SUCCEEDED(varKey.ChangeType(VT_I4))) {
|
|
break;
|
|
}
|
|
lIndex = varKey.lVal;
|
|
iter = m_DataFiles.begin();
|
|
while (iter != m_DataFiles.end() && lIndex > 0) {
|
|
++iter;
|
|
--lIndex;
|
|
}
|
|
|
|
if (iter != m_DataFiles.end()) {
|
|
hr = StringToVariant(pVal, (*iter).first);
|
|
}
|
|
break;
|
|
|
|
case InfoClassFileName:
|
|
case InfoClassDescription:
|
|
|
|
if (SUCCEEDED(varKey.ChangeType(VT_I4))) {
|
|
lIndex = varKey.lVal;
|
|
iter = m_DataFiles.begin();
|
|
while (iter != m_DataFiles.end() && lIndex > 0) {
|
|
++iter;
|
|
--lIndex;
|
|
}
|
|
|
|
} else if (SUCCEEDED(varKey.ChangeType(VT_BSTR))) {
|
|
str = varKey.bstrVal;
|
|
iter = m_DataFiles.find(str);
|
|
}
|
|
|
|
if (iter != m_DataFiles.end()) {
|
|
switch(InformationClass) {
|
|
case InfoClassFileName:
|
|
str = (*iter).second.strFileName;
|
|
break;
|
|
|
|
case InfoClassDescription:
|
|
str = (*iter).second.strDescription;
|
|
break;
|
|
}
|
|
|
|
hr = StringToVariant(pVal, str);
|
|
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|