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.
1038 lines
27 KiB
1038 lines
27 KiB
/*******************************************************************
|
|
*
|
|
* DESCRIPTION: Upload.cpp : Generates and sends out AppCompat report
|
|
*
|
|
* DATE:6/13/2002
|
|
*
|
|
*******************************************************************/
|
|
#include <wtypes.h>
|
|
#include <malloc.h>
|
|
#include <strsafe.h>
|
|
#include <commdlg.h>
|
|
#include <shimdb.h>
|
|
#include <faultrep.h>
|
|
#include "upload.h"
|
|
#include <wchar.h>
|
|
|
|
|
|
// These values are directly fron the web page and it must be in
|
|
// sync with it in order for report to work properly
|
|
LPCWSTR g_ProblemTypeDescs[] = {
|
|
L"Uninitialized",
|
|
L"Install_Fail",
|
|
L"System_Slow",
|
|
L"App_Faulting",
|
|
L"App_ErrorOSVer",
|
|
L"App_HWDevice",
|
|
L"App_OSUpgrade",
|
|
L"Uninstall_Fail",
|
|
L"App_CDError",
|
|
L"App_UserError",
|
|
L"App_Internet",
|
|
L"App_Print",
|
|
L"App_PartlyWork",
|
|
NULL
|
|
};
|
|
|
|
|
|
ULONG
|
|
GetProblemTypeId(
|
|
LPWSTR wszProblemType
|
|
)
|
|
{
|
|
ULONG len;
|
|
|
|
len = wcslen(wszProblemType);
|
|
|
|
while (len && isdigit(wszProblemType[len-1]))
|
|
{
|
|
--len;
|
|
}
|
|
if (wszProblemType[len])
|
|
{
|
|
return _wtoi(wszProblemType+len);
|
|
}
|
|
return 0;
|
|
}
|
|
// ***************************************************************************
|
|
DWORD GetAppCompatFlag(LPCWSTR wszPath)
|
|
{
|
|
LPWSTR pwszFile, wszSysDirLocal = NULL, pwszDir = NULL;
|
|
DWORD dwOpt = 0;
|
|
DWORD cchPath, cch;
|
|
UINT uiDrive;
|
|
WCHAR wszSysDir[MAX_PATH+2];
|
|
LPWSTR wszBuffer = NULL;
|
|
DWORD BufferChCount;
|
|
|
|
if (wszPath == NULL)
|
|
{
|
|
goto exitGetACF;
|
|
}
|
|
|
|
// can't be a valid path if it's less than 3 characters long
|
|
cchPath = wcslen(wszPath);
|
|
if (cchPath < 3)
|
|
{
|
|
goto exitGetACF;
|
|
}
|
|
|
|
if (!GetSystemDirectoryW(wszSysDir, MAX_PATH+1))
|
|
{
|
|
goto exitGetACF;
|
|
}
|
|
|
|
// do we have a UNC path?
|
|
if (wszPath[0] == L'\\' && wszPath[1] == L'\\')
|
|
{
|
|
dwOpt = GRABMI_FILTER_THISFILEONLY;
|
|
goto exitGetACF;
|
|
}
|
|
|
|
BufferChCount = cchPath+1;
|
|
wszBuffer = (LPWSTR) malloc(BufferChCount * sizeof(WCHAR));
|
|
if (!wszBuffer)
|
|
{
|
|
goto exitGetACF;
|
|
}
|
|
|
|
// ok, maybe a remote mapped path or system32?
|
|
StringCchCopyW(wszBuffer, BufferChCount, wszPath);
|
|
for(pwszFile = wszBuffer + cchPath;
|
|
*pwszFile != L'\\' && pwszFile > wszBuffer;
|
|
pwszFile--);
|
|
if (*pwszFile == L'\\')
|
|
*pwszFile = L'\0';
|
|
else
|
|
goto exitGetACF;
|
|
|
|
cch = wcslen(wszSysDir) + 1;
|
|
|
|
// see if it's in system32 or in any parent folder of it.
|
|
pwszDir = wszSysDir + cch;
|
|
do
|
|
{
|
|
if (_wcsicmp(wszBuffer, wszSysDir) == 0)
|
|
{
|
|
dwOpt = GRABMI_FILTER_SYSTEM;
|
|
goto exitGetACF;
|
|
}
|
|
|
|
for(;
|
|
*pwszDir != L'\\' && pwszDir > wszSysDir;
|
|
pwszDir--);
|
|
if (*pwszDir == L'\\')
|
|
*pwszDir = L'\0';
|
|
|
|
}
|
|
while (pwszDir > wszSysDir);
|
|
|
|
// is the file sitting in the root of a drive?
|
|
if (pwszFile <= &wszBuffer[3])
|
|
{
|
|
dwOpt = GRABMI_FILTER_THISFILEONLY;
|
|
goto exitGetACF;
|
|
}
|
|
|
|
|
|
// well, if we've gotten this far, then the path is in the form of
|
|
// X:\<something>, so cut off the <something> and find out if we're on
|
|
// a mapped drive or not
|
|
*pwszFile = L'\\';
|
|
wszBuffer[3] = L'\0';
|
|
switch(GetDriveTypeW(wszBuffer))
|
|
{
|
|
case DRIVE_UNKNOWN:
|
|
case DRIVE_NO_ROOT_DIR:
|
|
goto exitGetACF;
|
|
|
|
case DRIVE_REMOTE:
|
|
dwOpt = GRABMI_FILTER_THISFILEONLY;
|
|
goto exitGetACF;
|
|
}
|
|
|
|
dwOpt = GRABMI_FILTER_PRIVACY;
|
|
|
|
exitGetACF:
|
|
if (wszBuffer)
|
|
{
|
|
free (wszBuffer);
|
|
}
|
|
return dwOpt;
|
|
}
|
|
|
|
//
|
|
// Check if the registry settings allow for user to send the error report
|
|
//
|
|
BOOL
|
|
RegSettingsAllowSend()
|
|
{
|
|
HKEY hkey, hkeyDoRpt;
|
|
BOOL fDoReport = FALSE;
|
|
DWORD dw, cb;
|
|
|
|
cb = sizeof(fDoReport);
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRegErrRpt, 0,
|
|
KEY_READ | KEY_WOW64_64KEY, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
|
|
if (RegQueryValueEx(hkey, L"DoReport", NULL, NULL, (PBYTE)&fDoReport,
|
|
&cb) != ERROR_SUCCESS)
|
|
{
|
|
fDoReport = TRUE;
|
|
}
|
|
RegCloseKey(hkey);
|
|
if (!fDoReport)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRegDWPolicy, 0,
|
|
KEY_READ | KEY_WOW64_64KEY, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
ULONG TreeRpt=0, NeverUpload=0;
|
|
|
|
if (RegQueryValueEx(hkey, L"DWFileTreeReport", NULL, NULL, (PBYTE)&TreeRpt,
|
|
&cb) != ERROR_SUCCESS)
|
|
{
|
|
TreeRpt = TRUE;
|
|
}
|
|
if (RegQueryValueEx(hkey, L"NeverUpload", NULL, NULL, (PBYTE)&NeverUpload,
|
|
&cb) != ERROR_SUCCESS)
|
|
{
|
|
NeverUpload = FALSE;
|
|
}
|
|
RegCloseKey(hkey);
|
|
if (NeverUpload || !TreeRpt)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// If registry key did not exist we still want to report
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Retrive filevesion
|
|
//
|
|
HRESULT
|
|
GetAppFileVersion(
|
|
LPWSTR wszAppName,
|
|
PULONG pVersion // Should be ULONG[4]
|
|
)
|
|
{
|
|
PVOID pVerBuf;
|
|
ULONG dwSize;
|
|
HRESULT Hr = S_OK;
|
|
|
|
dwSize = GetFileVersionInfoSizeW(wszAppName, 0);
|
|
|
|
pVerBuf = malloc(dwSize);
|
|
if (!pVerBuf)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (GetFileVersionInfoW(wszAppName, 0, dwSize, pVerBuf))
|
|
{
|
|
VS_FIXEDFILEINFO *verinfo;
|
|
UINT dwVerLen;
|
|
|
|
if (VerQueryValueW(pVerBuf, L"\\", (LPVOID *)&verinfo, &dwVerLen))
|
|
{
|
|
pVersion[0] = verinfo->dwFileVersionMS >> 16;
|
|
pVersion[1] = verinfo->dwFileVersionMS & 0xFFFF;
|
|
pVersion[2] = verinfo->dwFileVersionLS >> 16;
|
|
pVersion[3] = verinfo->dwFileVersionLS & 0xFFFF;
|
|
|
|
} else
|
|
{
|
|
Hr = E_FAIL;
|
|
}
|
|
} else
|
|
{
|
|
// Hr = E_FAIL;
|
|
}
|
|
free ( pVerBuf );
|
|
return Hr;
|
|
}
|
|
|
|
//
|
|
// Create a temp dir and return full path name of file
|
|
//
|
|
HRESULT
|
|
GetTempFileFullPath(
|
|
LPWSTR wszFileName,
|
|
LPWSTR *pwszFullPath
|
|
)
|
|
{
|
|
ULONG cch, cchFile, cchDir;
|
|
ULONG Suffix;
|
|
LPWSTR wszTempFile;
|
|
|
|
if (pwszFullPath == NULL || wszFileName == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
cchFile = wcslen(wszFileName);
|
|
if (cchFile == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
cch = GetTempPathW(0, NULL);
|
|
if (cch == 0)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
cch += cchFile+2+10;
|
|
wszTempFile = (LPWSTR) malloc(cch * sizeof(WCHAR));
|
|
if (wszTempFile == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (GetTempPathW(cch, wszTempFile) == 0 ||
|
|
StringCchCatW(wszTempFile, cch, L"ACW.00") != S_OK)
|
|
{
|
|
free (wszTempFile);
|
|
return E_FAIL;
|
|
}
|
|
cchDir = wcslen(wszTempFile);
|
|
Suffix = 0;
|
|
// Create temp dir for our files
|
|
do
|
|
{
|
|
BOOL fRet;
|
|
fRet = CreateDirectoryW(wszTempFile, NULL);
|
|
if (fRet)
|
|
break;
|
|
|
|
wszTempFile[cchDir-2] = L'0' + (WCHAR)(Suffix / 10);
|
|
wszTempFile[cchDir-1] = L'0' + (WCHAR)(Suffix % 10);
|
|
Suffix++;
|
|
}
|
|
while (Suffix <= 100);
|
|
|
|
if (Suffix > 100 ||
|
|
StringCchCatW(wszTempFile, cch, L"\\") != S_OK ||
|
|
StringCchCatW(wszTempFile, cch, wszFileName) != S_OK)
|
|
{
|
|
free (wszTempFile);
|
|
return E_FAIL;
|
|
}
|
|
*pwszFullPath = wszTempFile;
|
|
return S_OK;
|
|
}
|
|
|
|
typedef BOOL (APIENTRY *pfn_SDBGRABMATCHINGINFOW)(LPCWSTR, DWORD, LPCWSTR);
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GenerateAppCompatText
|
|
// Generates application compatibility report in a temporary file
|
|
// File is created un user temp directory
|
|
//////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
GenerateAppCompatText(
|
|
LPWSTR wszAppName,
|
|
LPWSTR *pwszAppCompatReport
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
LPWSTR wszFile = NULL;
|
|
HMODULE hMod = NULL;
|
|
pfn_SDBGRABMATCHINGINFOW pSdbGrabMatchingInfo;
|
|
|
|
if (pwszAppCompatReport == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
hMod = LoadLibraryW(L"apphelp.dll");
|
|
if (hMod == NULL)
|
|
{
|
|
return E_FAIL;
|
|
} else
|
|
{
|
|
pSdbGrabMatchingInfo = (pfn_SDBGRABMATCHINGINFOW) GetProcAddress(hMod, "SdbGrabMatchingInfo");
|
|
if (pSdbGrabMatchingInfo != NULL)
|
|
{
|
|
Hr = GetTempFileFullPath(L"appcompat.txt", &wszFile);
|
|
if (SUCCEEDED(Hr))
|
|
{
|
|
if ((*pSdbGrabMatchingInfo)(wszAppName,
|
|
GetAppCompatFlag(wszAppName),
|
|
wszFile))
|
|
{
|
|
*pwszAppCompatReport = wszFile;
|
|
FreeLibrary(hMod);
|
|
return S_OK;
|
|
} else
|
|
{
|
|
Hr = E_FAIL;
|
|
}
|
|
free (wszFile);
|
|
}
|
|
} else
|
|
{
|
|
Hr = E_FAIL;
|
|
}
|
|
FreeLibrary(hMod);
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// This allocates returns full file-path for wszFileName in same directory as wszDirFile
|
|
//
|
|
LPWSTR
|
|
GenerateFilePath(
|
|
LPCWSTR wszDirFile,
|
|
LPCWSTR wszFileName
|
|
)
|
|
{
|
|
ULONG cch;
|
|
LPWSTR wszFile;
|
|
|
|
if (!wszFileName || !wszDirFile)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Build the filename
|
|
cch = wcslen(wszDirFile) + 1;
|
|
cch+= wcslen(wszFileName);
|
|
|
|
wszFile = (LPWSTR) malloc(cch * sizeof(WCHAR));
|
|
if (!wszFile)
|
|
{
|
|
return NULL;
|
|
}
|
|
StringCchCopyW(wszFile, cch, wszDirFile);
|
|
LPWSTR wszTemp = wcsrchr(wszFile, L'\\');
|
|
if (!wszTemp)
|
|
{
|
|
free (wszFile);
|
|
return NULL;
|
|
}
|
|
wszTemp++; *wszTemp = L'\0';
|
|
StringCchCatW(wszFile, cch, wszFileName);
|
|
return wszFile;
|
|
}
|
|
|
|
//
|
|
// Creates usrrpt.txt file and puts this data in it
|
|
//
|
|
HRESULT
|
|
BuildUserReport(
|
|
LPWSTR wszProblemType,
|
|
LPWSTR wszComment,
|
|
LPWSTR wszAppComWiz,
|
|
LPWSTR wszAppCompatFile,
|
|
LPWSTR *pwszUserReport
|
|
)
|
|
{
|
|
|
|
#define BYTE_ORDER_MARK 0xFEFF
|
|
enum REPORT_TYPE {
|
|
LT_ANSI,
|
|
LT_UNICODE
|
|
};
|
|
LPWSTR wszFile, wszTemp;
|
|
DWORD dwRptType = LT_UNICODE;
|
|
static WCHAR wchBOM = BYTE_ORDER_MARK;
|
|
ULONG cch;
|
|
|
|
if (wszProblemType == NULL || wszComment == NULL || wszAppComWiz == NULL ||
|
|
wszAppCompatFile == NULL || pwszUserReport == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
// Build the filename
|
|
wszFile = GenerateFilePath(wszAppCompatFile, L"usrrpt.txt");
|
|
if (wszFile == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Now write data to the file
|
|
//
|
|
HANDLE hFile;
|
|
hFile = CreateFileW(wszFile, GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL,
|
|
CREATE_ALWAYS, 0, NULL);
|
|
if (hFile == NULL ||
|
|
hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
free (wszFile);
|
|
return E_FAIL;
|
|
}
|
|
#define ByteCount(wsz) wcslen(wsz)*sizeof(WCHAR)
|
|
ULONG bw;
|
|
if (!WriteFile(hFile, &wchBOM, sizeof(WCHAR), &bw, NULL ) ||
|
|
!WriteFile(hFile, c_wszLblType, sizeof(c_wszLblType), &bw, NULL) ||
|
|
!WriteFile(hFile, wszProblemType, ByteCount(wszProblemType), &bw, NULL) ||
|
|
!WriteFile(hFile, c_wszLblACW, sizeof(c_wszLblACW), &bw, NULL) ||
|
|
!WriteFile(hFile, wszAppComWiz, ByteCount(wszAppComWiz), &bw, NULL) ||
|
|
!WriteFile(hFile, c_wszLblComment, sizeof(c_wszLblComment), &bw, NULL) ||
|
|
!WriteFile(hFile, wszComment, min(ByteCount(wszComment), 2000*sizeof(WCHAR)), &bw, NULL))
|
|
{
|
|
CloseHandle(hFile);
|
|
free (wszFile);
|
|
return E_FAIL;
|
|
}
|
|
CloseHandle(hFile);
|
|
*pwszUserReport = wszFile;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
MyReportEREventDW(
|
|
EEventType eet,
|
|
LPCWSTR wszDump,
|
|
SEventInfoW *pei
|
|
)
|
|
{
|
|
HMODULE hMod = NULL;
|
|
pfn_REPORTEREVENTDW pReportEREventDW;
|
|
HRESULT Hr = E_FAIL;
|
|
|
|
hMod = LoadLibraryW(L"faultrep.dll"); //"H:\\binaries.x86chk\\"
|
|
if (hMod == NULL)
|
|
{
|
|
return E_FAIL;
|
|
} else
|
|
{
|
|
pReportEREventDW = (pfn_REPORTEREVENTDW) GetProcAddress(hMod, "ReportEREventDW");
|
|
if (pReportEREventDW != NULL)
|
|
{
|
|
Hr = (HRESULT) (*pReportEREventDW)(eet, wszDump, pei);
|
|
}
|
|
FreeLibrary(hMod);
|
|
}
|
|
return Hr;
|
|
}
|
|
|
|
LPWSTR
|
|
GetDefaultServer( void )
|
|
{
|
|
return (LPWSTR) c_wszServer;
|
|
}
|
|
HRESULT
|
|
ReportDwManifest(
|
|
LPWSTR wszAppCompatFile,
|
|
SEventInfoW *pei
|
|
)
|
|
{
|
|
LPWSTR wszManifest;
|
|
WCHAR wszBuffer[500], wszBufferApp[MAX_PATH], wszDir[100];
|
|
HANDLE hManifest;
|
|
HRESULT Hr;
|
|
DWORD dw, dwFlags, cbToWrite;
|
|
LPWSTR pwszServer, pwszBrand, pwszUiLcid;
|
|
STARTUPINFOW si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
wszManifest = GenerateFilePath(wszAppCompatFile, L"manifest.txt");
|
|
|
|
if (!wszManifest)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
hManifest = CreateFileW(wszManifest, GENERIC_WRITE, FILE_SHARE_READ,
|
|
NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
if (hManifest == INVALID_HANDLE_VALUE)
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
// write the leading 0xFFFE out to the file
|
|
wszBuffer[0] = 0xFEFF;
|
|
if (!WriteFile(hManifest, wszBuffer, sizeof(wszBuffer[0]), &dw,
|
|
NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
|
|
|
|
// write out the server, LCID, Brand, Flags, & title
|
|
// Server=<server>
|
|
// UI LCID=GetSystemDefaultLCID()
|
|
// Flags=fDWWhister + fDWUserHKLM + headless if necessary
|
|
// Brand=<Brand> ("WINDOWS" by default)
|
|
// TitleName=<title>
|
|
|
|
pwszBrand = (LPWSTR) c_wszBrand;
|
|
|
|
// determine what server we're going to send the data to.
|
|
pwszServer = GetDefaultServer();
|
|
|
|
dwFlags = fDwWhistler | fDwUseHKLM | fDwAllowSuspend | fDwMiniDumpWithUnloadedModules;
|
|
|
|
dwFlags |= fDwUseLitePlea ;
|
|
|
|
Hr = StringCbPrintfW(wszBuffer, sizeof(wszBuffer), c_wszManHdr,
|
|
pwszServer, GetUserDefaultUILanguage(), dwFlags, c_wszBrand);
|
|
if (FAILED(Hr))
|
|
goto exitReportDwManifest;
|
|
cbToWrite = wcslen(wszBuffer);
|
|
cbToWrite *= sizeof(WCHAR);
|
|
Hr = WriteFile(hManifest, wszBuffer, cbToWrite, &dw, NULL) ? S_OK : E_FAIL;
|
|
if (FAILED(Hr))
|
|
goto exitReportDwManifest;
|
|
|
|
// write out the title text
|
|
if (pei->wszTitle != NULL)
|
|
{
|
|
LPCWSTR wszOut;
|
|
|
|
wszOut = pei->wszTitle;
|
|
cbToWrite = wcslen(wszOut);
|
|
cbToWrite *= sizeof(WCHAR);
|
|
|
|
Hr = WriteFile(hManifest, wszOut, cbToWrite, &dw, NULL) ? S_OK : E_FAIL;
|
|
if (FAILED(Hr))
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
// write out dig PID path
|
|
// DigPidRegPath=HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\DigitalProductId
|
|
|
|
if (!WriteFile(hManifest, c_wszManPID,
|
|
sizeof(c_wszManPID) - sizeof(WCHAR), &dw,
|
|
NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
// write out the registry subpath for policy info
|
|
// RegSubPath==Microsoft\\PCHealth\\ErrorReporting\\DW
|
|
|
|
if (!WriteFile(hManifest, c_wszManSubPath,
|
|
sizeof(c_wszManSubPath) - sizeof(WCHAR), &dw,
|
|
NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
|
|
// write out the error message if we have one
|
|
// ErrorText=<error text read from resource>
|
|
|
|
if (pei->wszErrMsg != NULL)
|
|
{
|
|
LPCWSTR wszOut;
|
|
|
|
if (!WriteFile(hManifest, c_wszManErrText,
|
|
sizeof(c_wszManErrText) - sizeof(WCHAR), &dw,
|
|
NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
wszOut = pei->wszErrMsg;
|
|
cbToWrite = wcslen(wszOut);
|
|
cbToWrite *= sizeof(WCHAR);
|
|
|
|
if (!WriteFile(hManifest, wszOut, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
// write out the header text if we have one
|
|
// HeaderText=<header text read from resource>
|
|
|
|
if (pei->wszHdr != NULL)
|
|
{
|
|
LPCWSTR wszOut;
|
|
|
|
wszOut = pei->wszHdr;
|
|
cbToWrite = wcslen(wszOut);
|
|
cbToWrite *= sizeof(WCHAR);
|
|
|
|
if (!WriteFile(hManifest, c_wszManHdrText,
|
|
sizeof(c_wszManHdrText) - sizeof(WCHAR), &dw,
|
|
NULL) ||
|
|
!WriteFile(hManifest, wszOut, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
|
|
// write out the plea text if we have one
|
|
// Plea=<plea text>
|
|
|
|
if (pei->wszPlea != NULL)
|
|
{
|
|
cbToWrite = wcslen(pei->wszPlea) * sizeof(WCHAR);
|
|
if (!WriteFile(hManifest, c_wszManPleaText,
|
|
sizeof(c_wszManPleaText) - sizeof(WCHAR), &dw,
|
|
NULL) ||
|
|
!WriteFile(hManifest, pei->wszPlea, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// write out the ReportButton text if we have one
|
|
// ReportButton=<button text>
|
|
|
|
if (pei->wszSendBtn != NULL)
|
|
{
|
|
cbToWrite = wcslen(pei->wszSendBtn) * sizeof(WCHAR);
|
|
if (!WriteFile(hManifest, c_wszManSendText,
|
|
sizeof(c_wszManSendText) - sizeof(WCHAR), &dw,
|
|
NULL) ||
|
|
!WriteFile(hManifest, pei->wszSendBtn, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
// write out the NoReportButton text if we have one
|
|
// NoReportButton=<button text>
|
|
|
|
if (pei->wszNoSendBtn != NULL)
|
|
{
|
|
cbToWrite = wcslen(pei->wszNoSendBtn) * sizeof(WCHAR);
|
|
if (!WriteFile(hManifest, c_wszManNSendText,
|
|
sizeof(c_wszManNSendText) - sizeof(WCHAR), &dw,
|
|
NULL) ||
|
|
!WriteFile(hManifest, pei->wszNoSendBtn, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
// write out the EventLog text if we have one
|
|
// EventLogSource=<button text>
|
|
|
|
if (pei->wszEventSrc != NULL)
|
|
{
|
|
cbToWrite = wcslen(pei->wszEventSrc) * sizeof(WCHAR);
|
|
if (!WriteFile(hManifest, c_wszManEventSrc,
|
|
sizeof(c_wszManEventSrc) - sizeof(WCHAR), &dw,
|
|
NULL) ||
|
|
!WriteFile(hManifest, pei->wszEventSrc, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
|
|
// write out the stage 1 URL if there is one
|
|
// Stage1URL=<stage 1 URL>
|
|
|
|
if (pei->wszStage1 != NULL)
|
|
{
|
|
cbToWrite = wcslen(pei->wszStage1) * sizeof(WCHAR);
|
|
if (!WriteFile(hManifest, pei->wszStage1, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
|
|
// write out the stage 2 URL
|
|
// Stage2URL=<stage 2 URL>
|
|
if (pei->wszStage2 != NULL)
|
|
{
|
|
cbToWrite = wcslen(pei->wszStage2) * sizeof(WCHAR);
|
|
if (!WriteFile(hManifest, pei->wszStage2, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
// write out files to collect if we have any
|
|
// DataFiles=<list of files to include in cab>
|
|
|
|
if (pei->wszFileList != NULL)
|
|
{
|
|
cbToWrite = wcslen(pei->wszFileList) * sizeof(WCHAR);
|
|
if (!WriteFile(hManifest, c_wszManFiles,
|
|
sizeof(c_wszManFiles) - sizeof(WCHAR), &dw,
|
|
NULL) ||
|
|
!WriteFile(hManifest, pei->wszFileList, cbToWrite, &dw, NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
}
|
|
|
|
// write out the final "\r\n"
|
|
|
|
wszBuffer[0] = L'\r';
|
|
wszBuffer[1] = L'\n';
|
|
if (!WriteFile(hManifest, wszBuffer, 2 * sizeof(wszBuffer[0]), &dw,
|
|
NULL))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
CloseHandle(hManifest);
|
|
hManifest = INVALID_HANDLE_VALUE;
|
|
|
|
// create the process
|
|
GetSystemDirectoryW(wszDir, sizeof(wszDir)/sizeof(WCHAR));
|
|
StringCbPrintfW(wszBufferApp, sizeof(wszBufferApp), c_wszDWExe, wszDir);
|
|
StringCbPrintfW(wszBuffer, sizeof(wszBuffer), c_wszDWCmdLine, wszManifest);
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
// check and see if the system is shutting down. If so, CreateProcess is
|
|
// gonna pop up some annoying UI that we can't get rid of, so we don't
|
|
// want to call it if we know it's gonna happen.
|
|
if (GetSystemMetrics(SM_SHUTTINGDOWN))
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
// we're creating the process in the same user context that we're in
|
|
si.lpDesktop = L"Winsta0\\Default";
|
|
if (!CreateProcessW(wszBufferApp, wszBuffer, NULL, NULL, TRUE,
|
|
CREATE_DEFAULT_ERROR_MODE |
|
|
NORMAL_PRIORITY_CLASS,
|
|
NULL, wszDir, &si, &pi))
|
|
{
|
|
Hr = ERROR_APPRPT_DW_LAUNCH;
|
|
goto exitReportDwManifest;
|
|
}
|
|
|
|
// don't need the thread handle & we gotta close it, so close it now
|
|
CloseHandle(pi.hThread);
|
|
pi.hThread = NULL;
|
|
|
|
// wait 5 minutes for DW to close. If it doesn't close by then, just
|
|
// return.
|
|
dw = WaitForSingleObject(pi.hProcess, 5*60*1000);
|
|
|
|
if (dw == WAIT_TIMEOUT)
|
|
{
|
|
CloseHandle(pi.hProcess);
|
|
Hr = ERROR_APPRPT_DW_TIMEOUT;
|
|
goto exitReportDwManifest;
|
|
}
|
|
else if (dw == WAIT_FAILED)
|
|
{
|
|
CloseHandle(pi.hProcess);
|
|
goto exitReportDwManifest;
|
|
}
|
|
CloseHandle(pi.hProcess);
|
|
|
|
GetExitCodeProcess(pi.hProcess, &dw);
|
|
if (dw == STILL_ACTIVE)
|
|
{
|
|
// "DW process still active!"
|
|
// Kill dw and let user know dw timed out
|
|
TerminateProcess(pi.hProcess, 1);
|
|
Hr = ERROR_APPRPT_DW_TIMEOUT;
|
|
|
|
} else if (dw == 0)
|
|
{
|
|
Hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
Hr = E_FAIL;
|
|
}
|
|
|
|
pi.hProcess = NULL;
|
|
|
|
|
|
|
|
exitReportDwManifest:
|
|
|
|
// Note again that we assume there was no previous impersonation token
|
|
// on the the thread before we did the impersonation above.
|
|
|
|
if (hManifest != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hManifest);
|
|
|
|
if (FAILED(Hr) || wszManifest != NULL)
|
|
{
|
|
DeleteFileW(wszManifest);
|
|
free (wszManifest);
|
|
}
|
|
|
|
return Hr;
|
|
|
|
}
|
|
|
|
//
|
|
// Calls up faultrep.dll to launch DwWin for uploading the error report
|
|
//
|
|
HRESULT
|
|
UploadAppProblem(
|
|
LPWSTR wszAppName,
|
|
LPWSTR wszProblemType,
|
|
LPWSTR wszUserComment,
|
|
LPWSTR wszMiscData,
|
|
LPWSTR wszAppCompatText
|
|
)
|
|
{
|
|
EEventType eet;
|
|
SEventInfoW ei = {0};
|
|
LPWSTR wszUerRpt = NULL;
|
|
HRESULT Hr;
|
|
LPWSTR wszFileList = NULL;
|
|
LPWSTR wszStage1URL = NULL;
|
|
LPWSTR wszStage2URL = NULL;
|
|
LPWSTR wszBaseName;
|
|
ULONG cch;
|
|
ULONG VerInfo[4];
|
|
ULONG OffsetFromProbType;
|
|
|
|
if ((wszAppName == NULL) || (wszProblemType == NULL) ||
|
|
(wszMiscData == NULL) || (wszAppCompatText == NULL))
|
|
{
|
|
goto exitUpload;
|
|
}
|
|
|
|
if (wszUserComment == NULL)
|
|
{
|
|
wszUserComment = L"";
|
|
}
|
|
|
|
if (!RegSettingsAllowSend())
|
|
{
|
|
Hr = E_FAIL;
|
|
goto exitUpload;
|
|
}
|
|
if ((Hr = GetAppFileVersion(wszAppName, &VerInfo[0])) != S_OK)
|
|
{
|
|
goto exitUpload;
|
|
}
|
|
|
|
if ((Hr = BuildUserReport(wszProblemType, wszUserComment, wszMiscData,
|
|
wszAppCompatText, &wszUerRpt)) != S_OK)
|
|
{
|
|
goto exitUpload;
|
|
}
|
|
|
|
OffsetFromProbType = GetProblemTypeId(wszProblemType);
|
|
wszFileList = (LPWSTR) malloc((cch = (wcslen(wszAppCompatText) + wcslen(wszUerRpt) + 2)) * sizeof(WCHAR));
|
|
if (!wszFileList)
|
|
{
|
|
Hr = E_OUTOFMEMORY;
|
|
goto exitUpload;
|
|
}
|
|
StringCchPrintfW(wszFileList, cch, L"%ws|%ws", wszAppCompatText, wszUerRpt);
|
|
|
|
wszBaseName = wcsrchr(wszAppName, L'\\');
|
|
if (wszBaseName == NULL)
|
|
{
|
|
Hr = E_INVALIDARG;
|
|
goto exitUpload;
|
|
}
|
|
wszBaseName++;
|
|
cch = wcslen(wszBaseName) + sizeof(c_wszStage1)/sizeof(WCHAR) + 4*5 + 2;
|
|
wszStage1URL = (LPWSTR) malloc( cch * sizeof (WCHAR));
|
|
if (!wszStage1URL)
|
|
{
|
|
Hr = E_OUTOFMEMORY;
|
|
goto exitUpload;
|
|
}
|
|
Hr = StringCchPrintfW(wszStage1URL, cch, c_wszStage1, wszBaseName,
|
|
VerInfo[0], VerInfo[1], VerInfo[2], VerInfo[3],
|
|
OffsetFromProbType);
|
|
if (FAILED(Hr))
|
|
{
|
|
goto exitUpload;
|
|
}
|
|
|
|
cch = wcslen(wszBaseName) + sizeof(c_wszStage2)/sizeof(WCHAR) + 4*5 + 2;
|
|
wszStage2URL = (LPWSTR) malloc( cch * sizeof (WCHAR));
|
|
if (!wszStage2URL)
|
|
{
|
|
Hr = E_OUTOFMEMORY;
|
|
goto exitUpload;
|
|
}
|
|
Hr = StringCchPrintfW(wszStage2URL, cch, c_wszStage2, wszBaseName,
|
|
VerInfo[0], VerInfo[1], VerInfo[2], VerInfo[3],
|
|
OffsetFromProbType);
|
|
if (FAILED(Hr))
|
|
{
|
|
goto exitUpload;
|
|
}
|
|
|
|
eet = eetUseEventInfo;
|
|
ei.cbSEI = sizeof(ei);
|
|
ei.wszTitle = L"Microsoft Windows";
|
|
ei.wszErrMsg = L"Thank-you for creating an application compatibility report.";
|
|
ei.wszHdr = L"Report an Application Compatibility Issue";
|
|
ei.wszPlea = L"We have created an error report that you can send to help us improve "
|
|
L"Microsoft Windows. We will treat this report as confidential and anonymous.";
|
|
ei.wszEventName = L"User initiated report";
|
|
ei.fUseLitePlea = FALSE;
|
|
ei.wszStage1 = wszStage1URL;
|
|
ei.wszStage2 = wszStage2URL;
|
|
ei.wszCorpPath = NULL;
|
|
ei.wszSendBtn = L"&Send Error Report";
|
|
ei.wszNoSendBtn = L"&Don't Send";
|
|
ei.wszFileList = wszFileList;
|
|
|
|
if ((Hr = ReportDwManifest(wszAppCompatText, &ei)) != S_OK)
|
|
// if ((Hr = MyReportEREventDW(eet, NULL, &ei)) != S_OK)
|
|
{
|
|
// we failed
|
|
}
|
|
|
|
exitUpload:
|
|
|
|
if (wszFileList != NULL) free( wszFileList );
|
|
if (wszStage1URL != NULL) free( wszStage1URL );
|
|
if (wszStage2URL != NULL) free( wszStage2URL );
|
|
|
|
// Delete all temporary files
|
|
if (wszUerRpt != NULL)
|
|
{
|
|
DeleteFileW(wszUerRpt);
|
|
free (wszUerRpt );
|
|
}
|
|
if (wszAppCompatText != NULL)
|
|
{
|
|
DeleteFileW(wszAppCompatText);
|
|
wszBaseName = wcsrchr(wszAppCompatText, L'\\');
|
|
if (wszBaseName)
|
|
{
|
|
*wszBaseName = L'\0';
|
|
RemoveDirectoryW(wszAppCompatText);
|
|
*wszBaseName = L'\\';
|
|
}
|
|
}
|
|
return Hr;
|
|
}
|
|
|
|
|