blob: b662668c33a9f3b362019fbc65dd27e819e6cd90 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#if defined _MSC_VER
#pragma warning(push, 1)
#pragma warning(disable:4917)
#endif
#include <windows.h>
#include <windowsx.h>
#include <mapi.h>
#include <commctrl.h>
#include <commdlg.h>
#include <psapi.h>
#include <shellapi.h>
#include <shlobj.h>
#define _UNICODE
#include <tchar.h>
#define _RICHEDIT_VER 0x0200
#include <richedit.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif
#if _RICHEDIT_VER >= 0x0200
#define RICHEDIT TEXT("riched20.dll")
#else
#define RICHEDIT TEXT("riched32.dll")
#endif
#include <systools/win32/uwinapi.h>
#include <rtl/digest.h>
#include <rtl/bootstrap.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <string>
#include <hash_map>
#include <winsock.h>
#include <malloc.h>
#include <process.h>
#include <_version.h>
#include "resource.h"
#include "base64.h"
#define FORMATBUFSIZE (8*1024)
#define MAX_TEXT_BUFFER (32*1024-1)
#define MAX_HOSTNAME (1024)
#ifdef __MINGW32__
#include <imagehlp.h>
#else
#include <dbghelp.h>
#endif
#ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif
using namespace ::std;
wstring g_wstrProductKey;
string g_strDefaultLanguage;
FILE *g_fpStackFile = NULL;
FILE *g_fpChecksumFile = NULL;
DWORD g_dwExceptionCode = 0;
CHAR g_szReportServerA[MAX_HOSTNAME] = "";
USHORT g_uReportPort = 80;
TCHAR g_szBuildId[256] = TEXT("");
TCHAR g_szDumpFileName[MAX_PATH] = TEXT("");
CHAR g_szDumpFileNameA[MAX_PATH] = "";
CHAR g_szCommentFileNameA[MAX_PATH] = "";
CHAR g_szReportFileNameA[MAX_PATH] = "";
bool g_bNoUserInterface = false;
bool g_bSendReport = false;
bool g_bLoadReport = false;
#define REPORT_SERVER g_szReportServerA
#define REPORT_PORT g_uReportPort
//***************************************************************************
// tmpfile from msvcrt creates the temporary file in the root of the current
// volume and can fail.
static FILE *_xfopen( const _TCHAR *file, const _TCHAR *mode )
{
#ifdef UNICODE
if ( (LONG)GetVersion() < 0 )
{
char afile[MAX_PATH];
char amode[16];
WideCharToMultiByte( CP_ACP, 0, file, -1, afile, MAX_PATH, NULL, NULL );
WideCharToMultiByte( CP_ACP, 0, mode, -1, amode, 16, NULL, NULL );
return fopen( afile, amode );
}
else
#endif
return _tfopen( file, mode );
}
static FILE *_tmpfile(void)
{
FILE *fp = NULL;
TCHAR szTempPath[MAX_PATH];
if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
{
TCHAR szFileName[MAX_PATH];
if ( GetTempFileName( szTempPath, TEXT("CRT"), 0, szFileName ) )
{
HANDLE hFile = CreateFile(
szFileName,
GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_NORMAL,
NULL );
if ( IsValidHandle( hFile ) )
{
int fd = _open_osfhandle( (int)hFile, 0 );
fp = _fdopen( fd, "w+b" );
}
}
}
return fp;
}
//***************************************************************************
static BOOL GetCrashDataPath( LPTSTR szBuffer )
{
::rtl::OUString ustrValue = ::rtl::OUString::createFromAscii("${$OOO_BASE_DIR/program/bootstrap.ini:UserInstallation}");
::rtl::Bootstrap::expandMacros( ustrValue );
if ( ustrValue.getLength() )
{
ustrValue += ::rtl::OUString::createFromAscii("/user/crashdata");
::osl::FileBase::RC result = ::osl::Directory::createPath( ustrValue );
if ( ::osl::FileBase::E_None == result || ::osl::FileBase::E_EXIST == result )
{
::rtl::OUString ustrPath;
result = ::osl::FileBase::getSystemPathFromFileURL( ustrValue, ustrPath );
if ( ::osl::FileBase::E_None == result )
{
_tcsncpy( szBuffer, reinterpret_cast<LPCWSTR>(ustrPath.getStr()), MAX_PATH );
return TRUE;
}
}
}
return FALSE;
}
static FILE *_open_reportfile( LPCTSTR lpExt, LPCTSTR lpMode )
{
FILE *fp = NULL;
TCHAR szAppDataPath[MAX_PATH] = _T("");
if ( GetCrashDataPath( szAppDataPath ) )
{
_tcscat( szAppDataPath, _T("\\crashdat") );
_tcscat( szAppDataPath, lpExt );
fp = _xfopen( szAppDataPath, lpMode );
}
return fp;
}
//***************************************************************************
struct CrashReportParams
{
BOOL fAllowContact;
tstring sEmail;
tstring sTitle;
tstring sComment;
ULONG uInternetConnection;
tstring sProxyServer;
tstring sProxyPort;
CrashReportParams();
void WriteToRegistry();
void ReadFromRegistry();
void ReadFromEnvironment();
};
bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams );
BOOL WriteCommentFile( LPCTSTR lpComment );
//***************************************************************************
LONG RegReadValue( HKEY hBaseKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPVOID lpData, DWORD cbData )
{
HKEY hKey = NULL;
LONG lResult;
lResult = RegOpenKeyEx( hBaseKey, lpSubKey, 0, KEY_QUERY_VALUE, &hKey );
if ( ERROR_SUCCESS == lResult )
{
lResult = RegQueryValueEx( hKey, lpValueName, NULL, NULL, (LPBYTE)lpData, &cbData );
RegCloseKey( hKey );
}
return lResult;
}
//***************************************************************************
LONG RegWriteValue( HKEY hBaseKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData )
{
HKEY hKey = NULL;
LONG lResult;
lResult = RegCreateKeyEx( hBaseKey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
if ( ERROR_SUCCESS == lResult )
{
lResult = RegSetValueEx( hKey, lpValueName, NULL, dwType, (CONST BYTE *)lpData, cbData );
RegCloseKey( hKey );
}
return lResult;
}
//***************************************************************************
CrashReportParams::CrashReportParams()
{
fAllowContact = FALSE;
sTitle = TEXT("");
sComment = TEXT("");
sEmail = TEXT("");
uInternetConnection = 0;
sProxyServer = TEXT("");
sProxyPort = TEXT("");
}
//***************************************************************************
void CrashReportParams::ReadFromRegistry()
{
TCHAR szBuffer[2048];
if ( ERROR_SUCCESS == RegReadValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("HTTPProxyServer"),
szBuffer,
sizeof(szBuffer) ) )
sProxyServer = szBuffer;
DWORD dwProxyPort;
if ( ERROR_SUCCESS == RegReadValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("HTTPProxyPort"),
&dwProxyPort,
sizeof(dwProxyPort) ) )
{
_stprintf( szBuffer, TEXT("%d"), dwProxyPort );
sProxyPort = szBuffer;
}
if ( ERROR_SUCCESS == RegReadValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("ReturnAddress"),
szBuffer,
sizeof(szBuffer) ) )
sEmail = szBuffer;
RegReadValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("AllowContact"),
&fAllowContact,
sizeof(fAllowContact) );
RegReadValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("HTTPConnection"),
&uInternetConnection,
sizeof(uInternetConnection) );
}
//***************************************************************************
void CrashReportParams::WriteToRegistry()
{
RegWriteValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("HTTPProxyServer"), REG_SZ,
sProxyServer.c_str(),
sizeof(TCHAR) * (sProxyServer.length() + 1) );
LPTSTR endptr = NULL;
DWORD dwProxyPort = _tcstoul( sProxyPort.c_str(), &endptr, 10 );
RegWriteValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("HTTPProxyPort"), REG_DWORD,
&dwProxyPort,
sizeof(DWORD) );
RegWriteValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("AllowContact"), REG_DWORD,
&fAllowContact,
sizeof(DWORD) );
RegWriteValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("HTTPConnection"), REG_DWORD,
&uInternetConnection,
sizeof(DWORD) );
RegWriteValue(
HKEY_CURRENT_USER,
TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
TEXT("ReturnAddress"), REG_SZ,
sEmail.c_str(),
sizeof(TCHAR) * (sEmail.length() + 1) );
}
//***************************************************************************
void CrashReportParams::ReadFromEnvironment()
{
TCHAR szBuffer[2048];
DWORD dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPPROXYSERVER"), szBuffer, elementsof(szBuffer) );
if ( dwResult && dwResult < elementsof(szBuffer) )
sProxyServer = szBuffer;
dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPPROXYPORT"), szBuffer, elementsof(szBuffer) );
if ( dwResult && dwResult < elementsof(szBuffer) )
sProxyPort = szBuffer;
dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_RETURNADDRESS"), szBuffer, elementsof(szBuffer) );
if ( dwResult && dwResult < elementsof(szBuffer) )
{
sEmail = szBuffer;
// fAllowContact = TRUE;
}
dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPCONNECTIONTYPE"), szBuffer, elementsof(szBuffer) );
if ( dwResult && dwResult < elementsof(szBuffer) )
{
if ( 0 == _tcsicmp( szBuffer, _T("DIRECT") ) )
uInternetConnection = 1;
else if ( 0 == _tcsicmp( szBuffer, _T("MANUALPROXY") ) )
uInternetConnection = 2;
else if ( 0 == _tcsicmp( szBuffer, _T("SYSTEMDEFAULT") ) )
uInternetConnection = 0;
}
dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_SUBJECT"), szBuffer, elementsof(szBuffer) );
if ( dwResult && dwResult < elementsof(szBuffer) )
sTitle = szBuffer;
dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_BODYFILE"), szBuffer, elementsof(szBuffer) );
if ( dwResult && dwResult < elementsof(szBuffer) )
{
FILE *fp = _xfopen( szBuffer, _T("rb") );
if ( fp )
{
CHAR aUTF8Buffer[256];
size_t nBytesRead;
sComment = TEXT("");
while ( 0 != (nBytesRead = fread( aUTF8Buffer, sizeof(aUTF8Buffer[0]), elementsof(aUTF8Buffer), fp )) )
{
TCHAR aBuffer[256+1];
DWORD dwCharacters = MultiByteToWideChar( CP_UTF8, 0, aUTF8Buffer, nBytesRead, aBuffer, elementsof(aBuffer) - 1 );
aBuffer[dwCharacters] = 0;
sComment += aBuffer;
}
fclose( fp );
}
}
}
//***************************************************************************
typedef BOOL (WINAPI *MiniDumpWriteDump_PROC)(
IN HANDLE hProcess,
IN DWORD ProcessId,
IN HANDLE hFile,
IN MINIDUMP_TYPE DumpType,
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
);
//***************************************************************************
static BOOL WINAPI InitRichEdit()
{
return (NULL != LoadLibrary( RICHEDIT ));
}
//***************************************************************************
static BOOL WINAPI DeinitRichEdit()
{
return FreeLibrary( GetModuleHandle( RICHEDIT ) );
}
//***************************************************************************
static string trim_string( const string& rString )
{
string temp = rString;
while ( temp.length() && temp[0] == ' ' || temp[0] == '\t' )
temp.erase( 0, 1 );
string::size_type len = temp.length();
while ( len && temp[len-1] == ' ' || temp[len-1] == '\t' )
{
temp.erase( len - 1, 1 );
len = temp.length();
}
return temp;
}
//***************************************************************************
static int LoadAndFormatString( HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax )
{
TCHAR szBuffer[FORMATBUFSIZE];
TCHAR szBuffer2[FORMATBUFSIZE];
LoadString( hInstance, uID, szBuffer, elementsof(szBuffer) );
LPCTSTR src;
LPTSTR dest;
for ( dest = szBuffer2, src = szBuffer; *src; src++, dest++ )
{
switch ( *src )
{
case '~':
*dest = '&';
break;
case '\\':
switch ( *(++src) )
{
case 'n':
*dest = '\n';
break;
case 'r':
*dest = '\r';
break;
default:
*dest = *src;
break;
}
break;
default:
*dest = *src;
break;
}
}
*dest = *src;
return ExpandEnvironmentStrings( szBuffer2, lpBuffer, nBufferMax );
}
//***************************************************************************
static string wstring2utf8( const wstring &rString )
{
int nBufSize = WideCharToMultiByte( CP_UTF8, 0, rString.c_str(), -1, NULL, 0, NULL, FALSE );
LPSTR pBuffer = (LPSTR)alloca( nBufSize );
WideCharToMultiByte( CP_UTF8, 0, rString.c_str(), -1, pBuffer, nBufSize, NULL, FALSE );
return string( pBuffer );
}
//***************************************************************************
static string xml_encode( const string &rString )
{
string temp = rString;
string::size_type pos = 0;
// First replace all occurences of '&' because it may occur in further
// encoded chardters too
for( pos = 0; (pos = temp.find( '&', pos )) != string::npos; pos += 4 )
temp.replace( pos, 1, "&amp;" );
for( pos = 0; (pos = temp.find( '<', pos )) != string::npos; pos += 4 )
temp.replace( pos, 1, "&lt;" );
for( pos = 0; (pos = temp.find( '>', pos )) != string::npos; pos += 4 )
temp.replace( pos, 1, "&gt;" );
return temp;
}
//***************************************************************************
static size_t fcopy( FILE *fpin, FILE *fpout )
{
char buffer[1024];
size_t nBytes;
size_t nBytesWritten = 0;
if ( fpin && fpout )
{
while ( 0 != (nBytes = fread( buffer, 1, sizeof(buffer), fpin )) )
{
nBytesWritten += fwrite( buffer, 1, nBytes, fpout );
}
}
return nBytesWritten;
}
//***************************************************************************
static string GetModuleDirectory( HMODULE hModule )
{
TCHAR szModuleName[MAX_PATH] = TEXT("");
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
TCHAR szFName[_MAX_FNAME];
TCHAR szExt[_MAX_EXT];
if ( GetModuleFileName( hModule, szModuleName, MAX_PATH ) )
{
_tsplitpath( szModuleName, szDrive, szDir, szFName, szExt );
_tmakepath( szModuleName, szDrive, szDir, _T(""), _T("") );
}
CHAR szModuleNameUTF8[MAX_PATH] = "";
WideCharToMultiByte( CP_UTF8, 0, szModuleName, -1, szModuleNameUTF8, elementsof(szModuleNameUTF8), NULL, NULL );
return string( szModuleNameUTF8 );
}
//***************************************************************************
string GetFileDirectory( const string& rFilePath )
{
string aDir = rFilePath;
size_t pos = aDir.rfind( '\\' );
if ( string::npos != pos )
aDir.erase( pos + 1 );
else
aDir = "";
return aDir;
}
//***************************************************************************
string GetFileName( const string& rFilePath )
{
string aName = rFilePath;
size_t pos = aName.rfind( '\\' );
if ( string::npos != pos )
return aName.substr( pos + 1 );
else
return aName;
}
//***************************************************************************
BOOL WriteReportFile( CrashReportParams *pParams )
{
BOOL fSuccess = FALSE;
TCHAR szTempPath[MAX_PATH];
if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
{
TCHAR szFileName[MAX_PATH];
if ( GetTempFileName( szTempPath, TEXT("RPM"), 0, szFileName ) )
{
HANDLE hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile )
{
int fd = _open_osfhandle( (LONG)hFile, _O_TEXT );
FILE *fp = _fdopen( fd, "w+t" );
CHAR szTitle[1024] = "";
CHAR szBuildId[1024] = "";
CHAR szEmail[1024] = "";
const char *pszUserType = getenv( "STAROFFICE_USERTYPE" );
WideCharToMultiByte( CP_UTF8, 0, pParams->sTitle.c_str(), -1, szTitle, sizeof(szTitle), NULL, NULL );
WideCharToMultiByte( CP_UTF8, 0, g_szBuildId, -1, szBuildId, sizeof(szBuildId), NULL, NULL );
WideCharToMultiByte( CP_UTF8, 0, pParams->sEmail.c_str(), -1, szEmail, sizeof(szEmail), NULL, NULL );
fprintf( fp,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE errormail:errormail PUBLIC \"-//OpenOffice.org//DTD ErrorMail 1.0//EN\" \"errormail.dtd\">\n"
"<errormail:errormail xmlns:errormail=\"http://openoffice.org/2002/errormail\" usertype=\"%s\">\n"
"<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.1\" feedback=\"%s\" email=\"%s\">\n",
pszUserType ? pszUserType : "",
pParams->fAllowContact ? "true" : "false",
pParams->fAllowContact ? xml_encode(szEmail).c_str() : ""
);
fprintf( fp,
"<reportmail:title>%s</reportmail:title>\n",
xml_encode(szTitle).c_str() );
fprintf( fp,
"<reportmail:attachment name=\"description.txt\" media-type=\"text/plain;charset=UTF-8\" class=\"UserComment\"/>\n"
"<reportmail:attachment name=\"user.dmp\" media-type=\"application/octet-stream\" class=\"UserDump\"/>\n"
"</reportmail:mail>\n"
"<officeinfo:officeinfo xmlns:officeinfo=\"http://openoffice.org/2002/officeinfo\" build=\"%s\" platform=\"%s\" language=\"%s\" procpath=\"%s\" exceptiontype=\"0x%08X\" product=\"%s\"/>\n",
szBuildId,
_INPATH,
xml_encode(g_strDefaultLanguage).c_str(),
xml_encode(GetModuleDirectory( NULL )).c_str(),
g_dwExceptionCode,
xml_encode(wstring2utf8(g_wstrProductKey)).c_str()
);
OSVERSIONINFO VersionInfo;
ZeroMemory( &VersionInfo, sizeof(VersionInfo) );
VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo );
GetVersionEx( &VersionInfo );
fprintf( fp,
"<systeminfo:systeminfo xmlns:systeminfo=\"http://openoffice.org/2002/systeminfo\">\n"
"<systeminfo:System name=\"%s\" version=\"%d.%d\" build=\"%d\" locale=\"0x%08x\"/>\n"
,
VER_PLATFORM_WIN32_NT == VersionInfo.dwPlatformId ? "Windows NT" : "Windows",
VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion,
VersionInfo.dwBuildNumber,
GetUserDefaultLangID()
);
fprintf( fp, "<systeminfo:CPU type=\"x86\"/>\n" );
fprintf( fp, "</systeminfo:systeminfo>\n" );
fseek( g_fpStackFile, 0, SEEK_SET );
fcopy( g_fpStackFile, fp );
fseek( g_fpChecksumFile, 0, SEEK_SET );
fcopy( g_fpChecksumFile, fp );
fprintf( fp, "</errormail:errormail>\n" );
fclose( fp );
fSuccess = TRUE;
WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szReportFileNameA, MAX_PATH, NULL, NULL );
}
if ( !fSuccess )
DeleteFile( szFileName );
}
}
return fSuccess;
}
//***************************************************************************
static BOOL SaveDumpFile( HWND hwndOwner )
{
OPENFILENAME ofn;
TCHAR szFileName[MAX_PATH] = TEXT("");
ZeroMemory( &ofn, sizeof(ofn) );
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwndOwner;
ofn.lpstrFilter = TEXT("*.dmp\0*.dmp\0*.*\0*.*\0");
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_ENABLESIZING | OFN_LONGNAMES | OFN_OVERWRITEPROMPT;
ofn.lpstrDefExt = TEXT("dmp");
if ( GetSaveFileName( &ofn ) )
{
return CopyFile( g_szDumpFileName, szFileName, FALSE );
}
return FALSE;
}
//***************************************************************************
static BOOL ScreenToClientRect( HWND hwnd, LPRECT lprc )
{
return ScreenToClient( hwnd, (LPPOINT)&lprc->left ) && ScreenToClient( hwnd, (LPPOINT)&lprc->right );
}
static BOOL SetWindowRect( HWND hwnd, const RECT *lprc, BOOL fRepaint )
{
return MoveWindow( hwnd, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top, fRepaint );
}
#define GM_LOX 0x01
#define GM_HIX 0x02
#define GM_LOY 0x04
#define GM_HIY 0x08
static BOOL SetGrowMode( HWND hwnd, DWORD dwGrowMode )
{
return SetProp( hwnd, TEXT("GrowMode"), (HANDLE)dwGrowMode );
}
static DWORD GetGrowMode( HWND hwnd )
{
return (DWORD)GetProp( hwnd, TEXT("GrowMode") );
}
static BOOL GrowWindow( HWND hwnd, LONG dxClient, LONG dyClient, BOOL fRepaint )
{
DWORD dwGrowMode = GetGrowMode( hwnd );
RECT rc;
GetWindowRect( hwnd, &rc );
if ( dwGrowMode & GM_LOX )
rc.left += dxClient;
if ( dwGrowMode & GM_HIX )
rc.right += dxClient;
if ( dwGrowMode & GM_LOY )
rc.top += dyClient;
if ( dwGrowMode & GM_HIY )
rc.bottom += dyClient;
ScreenToClientRect( GetParent( hwnd ), &rc );
SetWindowRect( hwnd, &rc, fRepaint );
return TRUE;
}
BOOL CALLBACK GrowChildWindows(
HWND hwnd, // handle to child window
LPARAM lParam // application-defined value
)
{
LONG cx = (SHORT)LOWORD( lParam );
LONG cy = (SHORT)HIWORD( lParam );
GrowWindow( hwnd, cx, cy, TRUE );
return TRUE;
}
/*
BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
{
HFONT aFont = *((HFONT*) lParam);
HDC hDC = GetDC( hwndChild );
SelectObject( hDC, aFont );
ReleaseDC( hwndChild, hDC );
return TRUE;
}
void ApplySystemFont( HWND hwndDlg )
{
NONCLIENTMETRICSA aNonClientMetrics;
aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
if ( SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
{
HFONT aSysFont = CreateFontIndirectA( &aNonClientMetrics.lfMessageFont );
EnumChildWindows(hwndDlg, EnumChildProc, (LPARAM) &aSysFont);
}
}
*/
BOOL CALLBACK PreviewDialogProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
static RECT rcClient;
switch ( uMsg )
{
case WM_SIZE:
{
LONG cx = LOWORD( lParam );
LONG cy = HIWORD( lParam );
LONG dxClient, dyClient;
dxClient = cx - rcClient.right;
dyClient = cy - rcClient.bottom;
EnumChildWindows( hwndDlg, GrowChildWindows, MAKELONG( (SHORT)dxClient, (SHORT)dyClient) );
GetClientRect( hwndDlg, &rcClient );
}
break;
case WM_INITDIALOG:
{
GetClientRect( hwndDlg, &rcClient );
SetGrowMode( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GM_HIX | GM_HIY );
SetGrowMode( GetDlgItem(hwndDlg, IDOK), GM_LOX | GM_HIX | GM_LOY | GM_HIY );
CrashReportParams *pParams = (CrashReportParams *)lParam;
TCHAR szBuffer[256] = TEXT("");
HINSTANCE hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE );
HWND hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT );
GetWindowText( hwndParent, szBuffer, elementsof(szBuffer) );
SetWindowText( hwndDlg, szBuffer );
LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer );
basic_string<TCHAR> aString;
aString.append( pParams->sTitle );
aString.append( _T("\r\n\r\n") );
aString.append( pParams->sComment );
aString.append( _T("\r\n---------- report ----------\r\n") );
FILE *fp = fopen( g_szReportFileNameA, "r" );
if ( fp )
{
char buf[1024];
while ( fgets( buf, elementsof(buf), fp ) != NULL )
{
WCHAR bufW[1024];
MultiByteToWideChar( CP_UTF8, 0, buf, -1, bufW, elementsof(bufW) );
aString.append( bufW );
}
fclose( fp );
}
aString.append( _T("\r\n---------- stack ----------\r\n") );
fp = fopen( g_szDumpFileNameA, "rb" );
if ( fp )
{
unsigned char buf[16];
int count;
do
{
int i;
count = fread( buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), fp );
for ( i = 0; i < count; i++ )
{
TCHAR output[16];
_sntprintf( output, elementsof(output), _T("%02X\x20"), buf[i] );
aString.append( output );
}
for ( ; i < elementsof(buf); i++ )
{
aString.append( _T("\x20\x20\x20") );
}
for ( i = 0; i < count; i++ )
{
TCHAR output[2];
if ( (int)buf[i] >= 0x20 && (int)buf[i] <= 0x7F )
output[0] = (TCHAR)buf[i];
else
output[0] = '.';
output[1] = 0;
aString.append( output );
}
aString.append( _T("\r\n") );
} while ( count );
fclose( fp );
}
Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), aString.c_str() );
SetWindowFont( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GetStockObject( SYSTEM_FIXED_FONT ), TRUE );
}
return TRUE;
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDOK:
case IDCANCEL:
EndDialog( hwndDlg, wParam );
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
//***************************************************************************
static void PreviewReport( HWND hwndParent, CrashReportParams *pParams )
{
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndParent, GWL_HINSTANCE );
WriteReportFile( pParams );
DialogBoxParam(
hInstance,
MAKEINTRESOURCE(IDD_PREVIEW_FRAME),
hwndParent,
PreviewDialogProc,
(LPARAM)pParams
);
DeleteFileA( g_szReportFileNameA );
}
//***************************************************************************
void UpdateOptionsDialogControls( HWND hwndDlg )
{
if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL) ) & BST_CHECKED )
{
EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), TRUE );
EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), TRUE );
}
else
{
EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), FALSE );
EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), FALSE );
}
}
//***************************************************************************
BOOL CALLBACK OptionsDialogProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
static CrashReportParams *pParams;
switch ( uMsg )
{
case WM_INITDIALOG:
{
TCHAR szBuffer[1024] = TEXT("");
HINSTANCE hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE );
//HWND hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT );
pParams = (CrashReportParams *)lParam;
LoadAndFormatString( hInstance, IDS_OPTIONS_CAPTION, szBuffer, elementsof(szBuffer) );
SetWindowText( hwndDlg, szBuffer );
LoadAndFormatString( hInstance, IDS_PROXY_SETTINGS_HEADER, szBuffer, elementsof(szBuffer) );
Static_SetText( GetDlgItem(hwndDlg, IDC_PROXY_SETTINGS), szBuffer );
LoadAndFormatString( hInstance, IDS_PROXY_SYSTEM, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM), szBuffer );
LoadAndFormatString( hInstance, IDS_PROXY_DIRECT, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT), szBuffer );
LoadAndFormatString( hInstance, IDS_PROXY_MANUAL, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL), szBuffer );
LoadAndFormatString( hInstance, IDS_LABEL_PROXYSERVER, szBuffer, elementsof(szBuffer) );
Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYSERVER), szBuffer );
LoadAndFormatString( hInstance, IDS_LABEL_PROXYPORT, szBuffer, elementsof(szBuffer) );
Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYPORT), szBuffer );
LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer );
LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), pParams->sProxyServer.c_str() );
Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), pParams->sProxyPort.c_str() );
Button_SetCheck( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM + pParams->uInternetConnection), BST_CHECKED );
SendMessage(
GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION),
EM_SETBKGNDCOLOR,
(WPARAM)FALSE,
GetSysColor( COLOR_3DFACE ) );
LoadAndFormatString( hInstance, IDS_PROXY_DESCRIPTION, szBuffer, elementsof(szBuffer) );
Edit_SetText( GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION), szBuffer );
UpdateOptionsDialogControls( hwndDlg );
}
return TRUE;
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDC_RADIO_SYSTEM:
case IDC_RADIO_DIRECT:
case IDC_RADIO_MANUAL:
if ( BN_CLICKED == HIWORD(wParam) )
UpdateOptionsDialogControls( hwndDlg );
break;
case IDOK:
{
TCHAR szBuffer[1024];
Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), szBuffer, elementsof(szBuffer) );
pParams->sProxyServer = szBuffer;
Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), szBuffer, elementsof(szBuffer) );
pParams->sProxyPort = szBuffer;
if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT) ) & BST_CHECKED )
pParams->uInternetConnection = 1;
else if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL) ) & BST_CHECKED )
pParams->uInternetConnection = 2;
else
pParams->uInternetConnection = 0;
}
case IDCANCEL:
EndDialog( hwndDlg, wParam );
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
//***************************************************************************
static void OptionsDialog( HWND hwndParent, CrashReportParams *pParams )
{
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndParent, GWL_HINSTANCE );
if ( IDOK == DialogBoxParam(
hInstance,
MAKEINTRESOURCE(IDD_OPTIONS_FRAME),
hwndParent,
OptionsDialogProc,
(LPARAM)pParams
) )
pParams->WriteToRegistry();
}
//***************************************************************************
void UpdateReportDialogControls( HWND hwndDlg )
{
EnableWindow(
GetDlgItem(hwndDlg, IDC_EDIT_EMAIL),
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT)) & BST_CHECKED ? TRUE : FALSE );
EnableWindow(
GetDlgItem(hwndDlg, IDC_LABEL_EMAIL),
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT)) & BST_CHECKED ? TRUE : FALSE );
}
//***************************************************************************
BOOL CALLBACK ReportDialogProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM
)
{
switch ( uMsg )
{
case WM_INITDIALOG:
{
CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
TCHAR szBuffer[FORMATBUFSIZE];
LoadAndFormatString( hInstance, IDS_REPORT_INTRO, szBuffer, elementsof(szBuffer) );
Static_SetText( GetDlgItem(hwndDlg, IDC_REPORT_INTRO), szBuffer );
Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT3), szBuffer );
LoadAndFormatString( hInstance, IDS_ENTER_TITLE, szBuffer, elementsof(szBuffer) );
Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_TITLE), szBuffer );
LoadAndFormatString( hInstance, IDS_ENTER_DESCRIPTION, szBuffer, elementsof(szBuffer) );
Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_DESCRIPTION), szBuffer );
LoadAndFormatString( hInstance, IDS_SHOW_REPORT_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_SHOW_REPORT), szBuffer );
LoadAndFormatString( hInstance, IDS_SAVE_REPORT_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), szBuffer );
const char *pszUserType = getenv( "STAROFFICE_USERTYPE" );
if ( pszUserType )
ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_SHOW );
else
ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_HIDE );
LoadAndFormatString( hInstance, IDS_OPTIONS_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_OPTIONS), szBuffer );
LoadAndFormatString( hInstance, IDS_ALLOW_CONTACT, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), szBuffer );
Button_SetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), pParams->fAllowContact ? BST_CHECKED : BST_UNCHECKED );
LoadAndFormatString( hInstance, IDS_LABEL_EMAIL, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDC_LABEL_EMAIL), szBuffer );
Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), pParams->sEmail.c_str() );
UpdateReportDialogControls( hwndDlg );
}
return TRUE;
case WM_SHOWWINDOW:
if ( (BOOL)wParam )
{
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
TCHAR szBuffer[FORMATBUFSIZE];
LoadAndFormatString( hInstance, IDS_REPORT_CAPTION, szBuffer, elementsof(szBuffer) );
SetWindowText( GetParent(hwndDlg), szBuffer );
LoadAndFormatString( hInstance, IDS_REPORT_HEADER, szBuffer, elementsof(szBuffer) );
SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer );
LoadAndFormatString( hInstance, IDS_DONOT_SEND_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer );
ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), TRUE );
ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), TRUE );
ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), FALSE );
Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), pParams->sTitle.c_str() );
Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), pParams->sComment.c_str() );
/*
SetWindowLong( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWL_STYLE,
GetWindowLong( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWL_STYLE) | BS_DEFPUSHBUTTON );
SetWindowLong( GetDlgItem(GetParent(hwndDlg),IDBACK), GWL_STYLE,
GetWindowLong( GetDlgItem(GetParent(hwndDlg),IDBACK), GWL_STYLE) &~ BS_DEFPUSHBUTTON );
*/
SetFocus( GetDlgItem(hwndDlg,IDC_EDIT_TITLE) );
}
break;
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDC_SHOW_REPORT:
{
TCHAR szBuffer[32767];
CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT) ) ? TRUE : FALSE;
Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) );
pParams->sTitle = szBuffer;
Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) );
pParams->sComment = szBuffer;
Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) );
pParams->sEmail = szBuffer;
PreviewReport( GetParent(hwndDlg), pParams );
}
return TRUE;
case IDC_SAVE_REPORT:
SaveDumpFile( GetParent(hwndDlg) );
return TRUE;
case IDC_OPTIONS:
{
CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
OptionsDialog( GetParent(hwndDlg), pParams );
}
return TRUE;
case IDC_ALLOW_CONTACT:
if ( BN_CLICKED == HIWORD(wParam) )
UpdateReportDialogControls( hwndDlg );
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
//***************************************************************************
BOOL CALLBACK WelcomeDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch ( uMsg )
{
case WM_INITDIALOG:
{
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
HWND hwndRichEdit = GetDlgItem(hwndDlg, IDC_RICHEDIT21);
TCHAR szBuffer[FORMATBUFSIZE];
TCHAR szBuffer2[FORMATBUFSIZE];
TCHAR szURL[256];
TCHAR szCaption[256];
SendMessage(
hwndRichEdit,
EM_SETBKGNDCOLOR,
(WPARAM)FALSE,
GetSysColor( COLOR_3DFACE ) );
SendMessage( hwndRichEdit, EM_SETEVENTMASK, 0, ENM_LINK );
SendMessage( hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0 );
LoadAndFormatString( hInstance, IDS_WELCOME_BODY1, szBuffer, elementsof(szBuffer) );
LoadAndFormatString( hInstance, IDS_WELCOME_BODY2, szBuffer2, elementsof(szBuffer2) );
_tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) );
LoadAndFormatString( hInstance, IDS_WELCOME_BODY3, szBuffer2, elementsof(szBuffer2) );
_tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) );
LoadString( hInstance, IDS_PRIVACY_URL, szURL, elementsof(szURL) );
_tcsncat( szBuffer, szURL, elementsof(szBuffer) );
SetWindowText( hwndRichEdit, szBuffer );
LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szCaption, elementsof(szCaption) );
SetWindowText( GetParent(hwndDlg), szCaption );
}
return TRUE;
case WM_SHOWWINDOW:
if ( (BOOL)wParam )
{
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
TCHAR szBuffer[FORMATBUFSIZE];
LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szBuffer, elementsof(szBuffer) );
SetWindowText( GetParent(hwndDlg), szBuffer );
LoadAndFormatString( hInstance, IDS_WELCOME_HEADER, szBuffer, elementsof(szBuffer) );
SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer );
LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer );
ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), FALSE );
ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), FALSE );
ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), TRUE );
SetFocus( GetDlgItem(GetParent(hwndDlg),IDNEXT) );
}
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
if ( pnmh->idFrom == IDC_RICHEDIT21 && pnmh->code == EN_LINK )
{
ENLINK *plink = (ENLINK*)lParam;
if ( plink->msg == WM_LBUTTONUP )
{
TCHAR szBuffer[256];
TEXTRANGE range;
range.chrg = plink->chrg;
range.lpstrText = szBuffer;
SendMessage( pnmh->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&range );
ShellExecute( hwndDlg, NULL, szBuffer, NULL, NULL, SW_SHOWDEFAULT );
}
}
}
break;
default:
break;
}
return FALSE;
}
//***************************************************************************
BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
static HWND hwndPages[2] = { NULL };
static int iActualPage = 0;
switch ( uMsg )
{
case WM_INITDIALOG:
{
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
TCHAR szBuffer[FORMATBUFSIZE];
SetWindowLong( hwndDlg, GWL_USERDATA, (LONG)lParam );
hwndPages[0] = CreateDialog(
hInstance,
MAKEINTRESOURCE(IDD_WELCOME_PAGE),
hwndDlg,
WelcomeDialogProc );
hwndPages[1] = CreateDialog(
hInstance,
MAKEINTRESOURCE(IDD_REPORT_PAGE),
hwndDlg,
ReportDialogProc );
CHARFORMAT chfmt;
chfmt.cbSize = sizeof(chfmt);
chfmt.dwMask = CFM_BOLD;
chfmt.dwEffects = CFE_BOLD;
SendMessage(
GetDlgItem(hwndDlg, IDC_HEADER),
EM_SETCHARFORMAT,
SCF_ALL,
(LPARAM)&chfmt );
LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
LoadAndFormatString( hInstance, IDS_NEXT_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDNEXT), szBuffer );
LoadAndFormatString( hInstance, IDS_SEND_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDFINISH), szBuffer );
LoadAndFormatString( hInstance, IDS_BACK_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDBACK), szBuffer );
ShowWindow( hwndPages[1], SW_HIDE );
ShowWindow( hwndPages[0], SW_SHOW );
// Let Crash Reporter window stay on top of all other windows
SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
}
return FALSE;
case WM_CTLCOLORSTATIC:
return (BOOL)CreateSolidBrush(GetSysColor(COLOR_WINDOW));
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDBACK:
if ( iActualPage > 0 )
{
ShowWindow( hwndPages[iActualPage], SW_HIDE );
ShowWindow( hwndPages[--iActualPage], SW_SHOW );
}
return TRUE;
case IDNEXT:
if ( iActualPage < elementsof(hwndPages) - 1 )
{
ShowWindow( hwndPages[iActualPage], SW_HIDE );
ShowWindow( hwndPages[++iActualPage], SW_SHOW );
}
return TRUE;
case IDFINISH:
{
TCHAR szBuffer[32767];
CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( hwndDlg, GWL_USERDATA );
pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndPages[1], IDC_ALLOW_CONTACT) ) ? TRUE : FALSE;
Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) );
pParams->sTitle = szBuffer;
Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) );
pParams->sComment = szBuffer;
Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) );
pParams->sEmail = szBuffer;
if ( pParams->fAllowContact && !pParams->sEmail.length() )
{
TCHAR szMessage[MAX_TEXT_BUFFER];
LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_NOEMAILADDRESS, szMessage, elementsof(szMessage) );
MessageBox( hwndDlg, szMessage, NULL, MB_ICONERROR | MB_OK );
break; // Don't end the dialog
}
else
{
pParams->WriteToRegistry();
WriteCommentFile( pParams->sComment.c_str() );
WriteReportFile( pParams );
if ( !SendCrashReport( hwndDlg, *pParams ) )
break; // Don't end the dialog
}
}
// Fallthrough !!!
case IDCANCEL:
EndDialog( hwndDlg, wParam );
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
//*****************************************************************************
//* Generate MD5 checksum
//*****************************************************************************
#define MAGIC_DESCRIPTION_FILLER 'x'
#define MAGIC_DESCRIPTION_COUNT 80
static void repatch_soffice_exe( void *pBuffer, size_t nBufSize )
{
wchar_t DescriptionBuffer[MAGIC_DESCRIPTION_COUNT];
memset( DescriptionBuffer, 0, sizeof(DescriptionBuffer) );
wcsncpy( DescriptionBuffer, g_wstrProductKey.c_str(), elementsof(DescriptionBuffer) - 1 );
bool bPatched = false;
do
{
void *pFound = memchr( pBuffer, ((char *)DescriptionBuffer)[0], nBufSize );
if ( pFound )
{
size_t distance = (char *)pFound - (char *)pBuffer;
if ( nBufSize >= distance )
{
nBufSize -= distance;
if ( nBufSize >= sizeof(DescriptionBuffer) &&
0 == memcmp( pFound, DescriptionBuffer, sizeof(DescriptionBuffer) ) )
{
for ( int i = 0; i < 80; i++ )
{
((wchar_t *)pFound)[i] = MAGIC_DESCRIPTION_FILLER;
}
bPatched = true;
}
else
{
pBuffer = (void *)(((char *)pFound) + 1);
nBufSize--;
}
}
else
nBufSize = 0;
}
else
nBufSize = 0;
} while ( !bPatched && nBufSize );
}
// Normalize executable/library images to prevent different MD5 checksums due
// to a different PE header date/checksum (this doesn't affect the code/data
// sections of a executable/library. Please see tools/source/bootstrp/md5.cxx
// where the same method is also used. The tool so_checksum creates the MD5
// checksums during build time. You have to make sure that both methods use the
// same algorithm otherwise there could be problems with stack reports.
static void normalize_pe_image(sal_uInt8* buffer, size_t nBufferSize)
{
const int OFFSET_PE_OFFSET = 0x3c;
const int OFFSET_COFF_TIMEDATESTAMP = 4;
const int PE_SIGNATURE_SIZE = 4;
const int COFFHEADER_SIZE = 20;
const int OFFSET_PE_OPTIONALHEADER_CHECKSUM = 64;
// Check the header part of the file buffer
if (buffer[0] == 'M' && buffer[1] == 'Z')
{
unsigned long PEHeaderOffset = (long)buffer[OFFSET_PE_OFFSET];
if (PEHeaderOffset < nBufferSize-4)
{
if ( buffer[PEHeaderOffset] == 'P' &&
buffer[PEHeaderOffset+1] == 'E' &&
buffer[PEHeaderOffset+2] == 0 &&
buffer[PEHeaderOffset+3] == 0 )
{
PEHeaderOffset += PE_SIGNATURE_SIZE;
if (PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP < nBufferSize-4)
{
// Set timedatestamp and checksum fields to a normalized
// value to enforce the same MD5 checksum for identical
// Windows executables/libraries.
buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP] = 0;
buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+1] = 0;
buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+2] = 0;
buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+3] = 0;
}
if (PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM < nBufferSize-4)
{
// Set checksum to a normalized value
buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM] = 0;
buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+1] = 0;
buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+2] = 0;
buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+3] = 0;
}
}
}
}
}
static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
{
const int MINIMAL_FILESIZE = 512;
sal_uInt32 nBytesProcessed = 0;
FILE *fp = fopen( filename, "rb" );
if ( fp )
{
long nFileSize;
if ( 0 == fseek( fp, 0, SEEK_END ) && -1 != (nFileSize = ftell(fp)) )
{
rewind( fp );
sal_uInt8 *pBuffer = new sal_uInt8[nFileSize];
size_t nBytesRead = fread( pBuffer, 1, nFileSize, fp );
if ( sal::static_int_cast<long>(nBytesRead) == nFileSize )
{
if ( 0 == stricmp( GetFileName(filename).c_str(), "soffice.bin" ) )
repatch_soffice_exe( pBuffer, nBytesRead );
else if ( nFileSize > MINIMAL_FILESIZE )
normalize_pe_image( pBuffer, nBytesRead );
rtlDigestError error = rtl_digest_MD5 (
pBuffer, nBytesRead,
pChecksum, nChecksumLen );
if ( rtl_Digest_E_None == error )
nBytesProcessed = nBytesRead;
}
delete[] pBuffer;
}
fclose( fp );
}
return nBytesProcessed;
}
#if 0
static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
{
sal_uInt32 nBytesProcessed = 0;
FILE *fp = fopen( filename, "rb" );
if ( fp )
{
rtlDigest digest = rtl_digest_createMD5();
if ( digest )
{
size_t nBytesRead;
sal_uInt8 buffer[4096];
rtlDigestError error = rtl_Digest_E_None;
while ( rtl_Digest_E_None == error &&
0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
{
error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
nBytesProcessed += nBytesRead;
}
if ( rtl_Digest_E_None == error )
{
error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
}
if ( rtl_Digest_E_None != error )
nBytesProcessed = 0;
rtl_digest_destroyMD5( digest );
}
fclose( fp );
}
return nBytesProcessed;
}
#endif
//***************************************************************************
static bool WriteStackFile( FILE *fout, hash_map< string, string >& rLibraries, DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers )
{
bool fSuccess = false;
if ( fout && dwProcessId && pExceptionPointers )
{
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
if ( IsValidHandle(hProcess) )
{
EXCEPTION_POINTERS aExceptionPointers;
CONTEXT aContextRecord;
ReadProcessMemory(
hProcess,
pExceptionPointers,
&aExceptionPointers,
sizeof(aExceptionPointers),
NULL );
ReadProcessMemory(
hProcess,
aExceptionPointers.ContextRecord,
&aContextRecord,
sizeof(aContextRecord),
NULL );
STACKFRAME frame;
ZeroMemory( &frame, sizeof(frame) );
frame.AddrPC.Offset = aContextRecord.Eip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = aContextRecord.Ebp;
frame.AddrFrame.Mode = AddrModeFlat;
BOOL bSuccess;
int frameNum = 0;
SymInitialize( hProcess, NULL, TRUE );
fprintf( fout, "<errormail:Stack type=\"Win32\">\n" );
do
{
fSuccess = true;
bSuccess = StackWalk( IMAGE_FILE_MACHINE_I386,
hProcess,
NULL,
&frame,
&aContextRecord,
(PREAD_PROCESS_MEMORY_ROUTINE)ReadProcessMemory,
SymFunctionTableAccess,
SymGetModuleBase,
NULL );
if ( bSuccess )
{
// Note: ImageHelp ANSI functions do not have an A postfix while
// Unicode versions have a W postfix. There's no macro
// that depends on define UNICODE
IMAGEHLP_MODULE moduleInfo;
ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
if ( SymGetModuleInfo( hProcess, frame.AddrPC.Offset, &moduleInfo ) )
{
rLibraries[ GetFileName( moduleInfo.LoadedImageName ).c_str() ] = moduleInfo.LoadedImageName;
DWORD dwRelOffset = 0;
BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 256 ];
PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
ZeroMemory( symbolBuffer, sizeof(symbolBuffer) );
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
pSymbol->MaxNameLength = 256;
if ( SymGetSymFromAddr( hProcess, frame.AddrPC.Offset, &dwRelOffset, pSymbol ) )
fprintf( fout, "<errormail:StackInfo " \
"pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" ordinal=\"%s+0x%p\" name=\"%s\" path=\"%s\"/>\n",
frameNum,
frame.AddrPC.Offset,
frame.AddrPC.Offset - moduleInfo.BaseOfImage,
xml_encode(pSymbol->Name).c_str(),
frame.AddrPC.Offset - pSymbol->Address,
xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
xml_encode( GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
);
else
fprintf( fout, "<errormail:StackInfo " \
"pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" name=\"%s\" path=\"%s\"/>\n",
frameNum,
frame.AddrPC.Offset,
frame.AddrPC.Offset - moduleInfo.BaseOfImage,
xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
xml_encode(GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
);
}
else
fprintf( fout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%p\"/>\n",
frameNum,
frame.AddrPC.Offset
);
frameNum++;
}
} while ( bSuccess );
fprintf( fout, "</errormail:Stack>\n" );
SymCleanup( hProcess );
CloseHandle( hProcess );
}
}
return fSuccess;
}
bool WriteChecksumFile( FILE *fchksum, const hash_map< string, string >& rLibraries )
{
bool success = false;
if ( fchksum && rLibraries.size() )
{
fprintf( fchksum, "<errormail:Checksums type=\"MD5\">\n" );
hash_map< string, string >::const_iterator iter;
for ( iter = rLibraries.begin();
iter != rLibraries.end();
iter++ )
{
sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
sal_uInt32 nBytesProcessed = calc_md5_checksum(
iter->second.c_str(),
checksum, sizeof(checksum) );
if ( nBytesProcessed )
{
fprintf( fchksum, "<errormail:Checksum sum=\"0x" );
for ( int i = 0; i < sizeof(checksum); fprintf( fchksum, "%02X", checksum[i++] ) );
fprintf( fchksum, "\" bytes=\"%d\" file=\"%s\"/>\n",
nBytesProcessed,
GetFileName( iter->first ).c_str() );
}
}
fprintf( fchksum, "</errormail:Checksums>\n" );
success = true;
}
return success;
}
//***************************************************************************
BOOL FindDumpFile()
{
TCHAR szFileName[MAX_PATH];
if ( GetCrashDataPath( szFileName ) )
{
_tcscat( szFileName, _T("\\crashdat.dmp") );
HANDLE hFile = CreateFile(
szFileName,
GENERIC_READ,
0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile )
{
CloseHandle( hFile );
WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
_tcscpy( g_szDumpFileName, szFileName );
return TRUE;
}
}
return FALSE;
}
BOOL WriteDumpFile( DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers, DWORD dwThreadId )
{
BOOL fSuccess = FALSE;
PMINIDUMP_EXCEPTION_INFORMATION lpExceptionParam = NULL;
MINIDUMP_EXCEPTION_INFORMATION ExceptionParam;
HMODULE hDbgHelp = LoadLibrary( _T("DBGHELP.DLL" ) );
MiniDumpWriteDump_PROC pMiniDumpWriteDump = NULL;
if ( hDbgHelp )
{
pMiniDumpWriteDump = (MiniDumpWriteDump_PROC)GetProcAddress( hDbgHelp, "MiniDumpWriteDump" );
if ( !pMiniDumpWriteDump )
{
FreeLibrary( hDbgHelp );
return false;
}
}
if ( !pMiniDumpWriteDump )
return false;
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
if ( IsValidHandle(hProcess) )
{
TCHAR szTempPath[MAX_PATH];
// if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
if ( GetCrashDataPath( szTempPath ) )
{
TCHAR szFileName[MAX_PATH];
// if ( GetTempFileName( szTempPath, TEXT("DMP"), 0, szFileName ) )
_tcscpy( szFileName, szTempPath );
_tcscat( szFileName, _T("\\crashdat.dmp") );
{
HANDLE hFile = CreateFile(
szFileName,
GENERIC_READ | GENERIC_WRITE,
0, NULL,
// OPEN_EXISTING,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile )
{
if ( pExceptionPointers && dwThreadId )
{
ExceptionParam.ThreadId = dwThreadId;
ExceptionParam.ExceptionPointers = pExceptionPointers;
ExceptionParam.ClientPointers = TRUE;
EXCEPTION_POINTERS aExceptionPointers;
EXCEPTION_RECORD aExceptionRecord;
ReadProcessMemory(
hProcess,
pExceptionPointers,
&aExceptionPointers,
sizeof(aExceptionPointers),
NULL );
ReadProcessMemory(
hProcess,
aExceptionPointers.ExceptionRecord,
&aExceptionRecord,
sizeof(aExceptionRecord),
NULL );
g_dwExceptionCode = aExceptionRecord.ExceptionCode;
lpExceptionParam = &ExceptionParam;
}
fSuccess = pMiniDumpWriteDump( hProcess, dwProcessId, hFile, MiniDumpNormal, lpExceptionParam, NULL, NULL );
CloseHandle( hFile );
WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
_tcscpy( g_szDumpFileName, szFileName );
}
if ( !fSuccess )
DeleteFile( szFileName );
}
}
CloseHandle( hProcess );
}
FreeLibrary( hDbgHelp );
return fSuccess;
}
//***************************************************************************
static DWORD FindProcessForImage( LPCTSTR lpImagePath )
{
DWORD dwProcessId = 0;
DWORD aProcesses[1024];
DWORD dwSize = 0;
TCHAR szShortImagePath[MAX_PATH];
if ( GetShortPathName( lpImagePath, szShortImagePath, elementsof(szShortImagePath) ) &&
EnumProcesses( aProcesses, sizeof(aProcesses), &dwSize ) )
{
unsigned nProcesses = dwSize / sizeof(aProcesses[0]);
for ( unsigned i = 0; !dwProcessId && i < nProcesses; i++ )
{
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
if ( IsValidHandle(hProcess) )
{
TCHAR szModulePath[MAX_PATH+1];
if ( GetModuleFileNameEx( hProcess, NULL, szModulePath, MAX_PATH ) )
{
TCHAR szShortModulePath[MAX_PATH];
if ( GetShortPathName( szModulePath, szShortModulePath, elementsof(szShortModulePath) ) )
{
if ( 0 == _tcsicmp( szShortModulePath, szShortImagePath ) )
dwProcessId = aProcesses[i];
}
}
CloseHandle( hProcess );
}
}
}
return dwProcessId;
}
//***************************************************************************
static bool ParseCommandArgs( LPDWORD pdwProcessId, PEXCEPTION_POINTERS* ppException, LPDWORD pdwThreadId )
{
int argc = __argc;
#ifdef __MINGW32__
#ifdef _UNICODE
TCHAR **argv = reinterpret_cast<TCHAR **>(alloca((argc+1)*sizeof(WCHAR*)));
int *sizes = reinterpret_cast<int *>(alloca(argc*sizeof(int)));
int argsize=0;
char **ptr;
int i;
ptr=__argv;
for (i = 0; i < argc; ++i)
{
sizes[i]=MultiByteToWideChar(CP_ACP, 0, *ptr, -1, NULL, 0);
argsize+=sizes[i]+1;
++ptr;
}
++argsize;
TCHAR *args = reinterpret_cast<TCHAR *>(alloca(argsize*sizeof(WCHAR)));
ptr=__argv;
TCHAR *cptr=args;
for (i = 0; i < argc; ++i)
{
argv[i]=cptr;
MultiByteToWideChar( CP_ACP, 0, *ptr, -1, cptr, sizes[i] );
++ptr;
cptr+=sizes[i];
*cptr=0;
++cptr;
}
argv[i]=cptr;
*cptr=0;
#else
TCHAR **argv = __argv;
#endif
#else
TCHAR **argv = __targv;
#endif
bool bSuccess = true;
for ( int argn = 1; bSuccess && argn < argc; argn++ )
{
if ( 0 == _tcsicmp( argv[argn], _T("-h") ) ||
0 == _tcsicmp( argv[argn], _T("/h") ) ||
0 == _tcsicmp( argv[argn], _T("-?") ) ||
0 == _tcsicmp( argv[argn], _T("/?") ) ||
0 == _tcsicmp( argv[argn], _T("/help") ) ||
0 == _tcsicmp( argv[argn], _T("-help") ) ||
0 == _tcsicmp( argv[argn], _T("--help") )
)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
TCHAR szUsage[FORMATBUFSIZE];
TCHAR szProcess[FORMATBUFSIZE];
TCHAR szProcessDescription[FORMATBUFSIZE];
TCHAR szHelpDescription[FORMATBUFSIZE];
LoadAndFormatString( hInstance, IDS_MSG_CMDLINE_USAGE, szUsage, elementsof(szUsage) );
LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID, szProcess, elementsof(szProcess) );
LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID_DESCRIPTION, szProcessDescription, elementsof(szProcessDescription) );
LoadAndFormatString( hInstance, IDS_MSG_PARAM_HELP_DESCRIPTION, szHelpDescription, elementsof(szHelpDescription) );
_tprintf(
TEXT("\n%s: crashrep %s\n\n")
TEXT("/?, -h[elp] %s\n\n")
TEXT("%-20s %s\n\n"),
szUsage, szProcess, szHelpDescription, szProcess, szProcessDescription
);
return true;
}
else if ( 0 == _tcsicmp( argv[argn], _T("-p") ) ||
0 == _tcsicmp( argv[argn], _T("/p") ) )
{
if ( ++argn < argc )
*pdwProcessId = _tcstoul( argv[argn], NULL, 0 );
else
bSuccess = false;
}
else if ( 0 == _tcsicmp( argv[argn], _T("-excp") ) ||
0 == _tcsicmp( argv[argn], _T("/excp") ) )
{
if ( ++argn < argc )
*ppException = (PEXCEPTION_POINTERS)_tcstoul( argv[argn], NULL, 0 );
else
bSuccess = false;
}
else if ( 0 == _tcsicmp( argv[argn], _T("-t") ) ||
0 == _tcsicmp( argv[argn], _T("/t") ) )
{
if ( ++argn < argc )
*pdwThreadId = _tcstoul( argv[argn], NULL, 0 );
else
bSuccess = false;
}
else if ( 0 == _tcsicmp( argv[argn], _T("-noui") ) ||
0 == _tcsicmp( argv[argn], _T("/noui") ) )
{
g_bNoUserInterface = true;
}
else if ( 0 == _tcsicmp( argv[argn], _T("-send") ) ||
0 == _tcsicmp( argv[argn], _T("/send") ) )
{
g_bSendReport = true;
}
else if ( 0 == _tcsicmp( argv[argn], _T("-load") ) ||
0 == _tcsicmp( argv[argn], _T("/load") ) )
{
g_bLoadReport = true;
}
else // treat parameter as image path
{
TCHAR szImagePath[MAX_PATH];
LPTSTR lpImageName;
if ( GetFullPathName( argv[argn], MAX_PATH, szImagePath, &lpImageName ) )
{
DWORD dwProcessId = FindProcessForImage( szImagePath );
if ( dwProcessId )
*pdwProcessId = dwProcessId;
else
bSuccess = false;
}
}
}
if ( !*pdwProcessId && !g_bLoadReport )
{
TCHAR szImagePath[MAX_PATH];
LPTSTR lpImageName;
if ( GetFullPathName( TEXT("soffice.exe"), MAX_PATH, szImagePath, &lpImageName ) )
{
DWORD dwProcessId = FindProcessForImage( szImagePath );
if ( dwProcessId )
*pdwProcessId = dwProcessId;
else
bSuccess = false;
}
}
return bSuccess;
}
//***************************************************************************
BOOL WriteCommentFile( LPCTSTR lpComment )
{
BOOL fSuccess = FALSE;
TCHAR szTempPath[MAX_PATH];
if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
{
TCHAR szFileName[MAX_PATH];
if ( GetTempFileName( szTempPath, TEXT("CMT"), 0, szFileName ) )
{
HANDLE hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile )
{
DWORD dwBytesWritten;
int needed = WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, NULL, 0, NULL, NULL );
if ( needed )
{
char *lpCommentUTF8 = (char *)alloca( needed );
WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, lpCommentUTF8, needed, NULL, NULL );
fSuccess = WriteFile( hFile, lpCommentUTF8, strlen(lpCommentUTF8), &dwBytesWritten, NULL );
}
else
fSuccess = TRUE;
CloseHandle( hFile );
WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szCommentFileNameA, MAX_PATH, NULL, NULL );
}
if ( !fSuccess )
DeleteFile( szFileName );
}
}
return fSuccess;
}
//***************************************************************************
static int _tsetenv( const _TCHAR *lpVar, const _TCHAR *lpValue )
{
if ( !lpValue )
lpValue = _T("");
_TCHAR *envstr = (TCHAR *)alloca( (_tcslen( lpVar ) + _tcslen( lpValue ) + 2) * sizeof(_TCHAR) );
_tcscpy( envstr, lpVar );
_tcscat( envstr, _T("=") );
_tcscat( envstr, lpValue );
return _tputenv( envstr );
}
static bool read_line( FILE *fp, string& rLine )
{
char szBuffer[1024];
bool bSuccess = false;
bool bEOL = false;
string line;
while ( !bEOL && fgets( szBuffer, sizeof(szBuffer), fp ) )
{
int len = strlen(szBuffer);
bSuccess = true;
while ( len && szBuffer[len - 1] == '\n' )
{
szBuffer[--len] = 0;
bEOL = true;
}
line.append( szBuffer );
}
rLine = line;
return bSuccess;
}
static string get_script_string( const char *pFileName, const char *pKeyName )
{
FILE *fp = fopen( pFileName, "rt" );
string retValue;
if ( fp )
{
string line;
string section;
while ( read_line( fp, line ) )
{
line = trim_string( line );
string::size_type iEqualSign = line.find( '=', 0 );
if ( iEqualSign != string::npos )
{
string keyname = line.substr( 0, iEqualSign );
keyname = trim_string( keyname );
string value = line.substr( sal::static_int_cast<string::size_type>(iEqualSign + 1) );
value = trim_string( value );
if ( value.length() && '\"' == value[0] )
{
value.erase( 0, 1 );
string::size_type iQuotes = value.find( '"', 0 );
if ( iQuotes != string::npos )
value.erase( iQuotes );
}
if ( 0 == stricmp( keyname.c_str(), pKeyName ) )
{
retValue = value;
break;
}
}
}
fclose( fp );
}
return retValue;
}
static bool ReadBootstrapParams( CrashReportParams &rParams )
{
TCHAR szBuffer[256] = TEXT("");
TCHAR szModuleName[MAX_PATH];
TCHAR szModuleVersionName[MAX_PATH];
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
TCHAR szFName[_MAX_FNAME];
TCHAR szExt[_MAX_EXT];
TCHAR szReportServer[MAX_HOSTNAME];
TCHAR szReportPort[256];
bool bSuccess = false;
GetModuleFileName( NULL, szModuleName, MAX_PATH );
_tsplitpath( szModuleName, szDrive, szDir, szFName, szExt );
_tmakepath( szModuleName, szDrive, szDir, _T("bootstrap"), _T(".ini") );
_tmakepath( szModuleVersionName, szDrive, szDir, _T("version"), _T(".ini") );
if (
GetPrivateProfileString(
TEXT("Bootstrap"),
TEXT("ProductKey"),
TEXT("OpenOffice.org"),
szBuffer,
elementsof(szBuffer),
szModuleName )
)
{
TCHAR *pVersion = _tcschr( szBuffer, ' ' );
g_wstrProductKey = szBuffer;
if ( pVersion )
{
*pVersion = 0;
pVersion++;
}
else
pVersion = TEXT("");
if ( !_tgetenv( _T("PRODUCTNAME") ) )
{
_tsetenv( TEXT("PRODUCTNAME"), szBuffer );
}
if ( !_tgetenv( _T("PRODUCTVERSION") ) )
_tsetenv( TEXT("PRODUCTVERSION"), pVersion );
}
GetPrivateProfileString(
TEXT("Version"),
TEXT("buildid"),
TEXT("unknown"),
g_szBuildId, elementsof(g_szBuildId),
szModuleVersionName );
g_strDefaultLanguage = get_script_string( "instdb.inf", "DefaultLanguage" );
if ( GetPrivateProfileString(
TEXT("ErrorReport"),
TEXT("ErrorReportPort"),
TEXT("80"),
szReportPort, elementsof(szReportPort),
szModuleName
) )
{
TCHAR *endptr = NULL;
unsigned short uReportPort = (unsigned short)_tcstoul( szReportPort, &endptr, 10 );
if ( uReportPort )
g_uReportPort = uReportPort;
}
if ( GetPrivateProfileString(
TEXT("ErrorReport"),
TEXT("ErrorReportServer"),
TEXT(""),
szReportServer, elementsof(szReportServer),
szModuleName
) )
{
bSuccess = 0 != WideCharToMultiByte( CP_ACP, 0, szReportServer, -1, g_szReportServerA, elementsof(g_szReportServerA), NULL, NULL );
}
LPCTSTR lpEnvString;
if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYSERVER") )) )
rParams.sProxyServer = lpEnvString;
if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYPORT") )) )
rParams.sProxyPort = lpEnvString;
if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_SENDERADDRESS") )) )
rParams.sEmail = lpEnvString;
return bSuccess;
}
//***************************************************************************
bool SendHTTPRequest(
FILE *fp,
const char *pszServer,
unsigned short uPort = 80,
const char *pszProxyServer = NULL,
unsigned short uProxyPort = 8080 )
{
bool success = false;
struct hostent *hp;
if ( pszProxyServer )
hp = gethostbyname( pszProxyServer );
else
hp = gethostbyname( pszServer );
if ( hp )
{
SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );
if ( s )
{
struct sockaddr_in address;
memcpy(&(address.sin_addr.s_addr), *(hp->h_addr_list),sizeof(struct in_addr));
address.sin_family = AF_INET;
if ( pszProxyServer )
address.sin_port = ntohs( uProxyPort );
else
address.sin_port = ntohs( uPort );
if ( 0 == connect( s, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) )
{
fseek( fp, 0, SEEK_END );
size_t length = ftell( fp );
fseek( fp, 0, SEEK_SET );
char buffer[2048];
if ( pszProxyServer )
sprintf( buffer,
"POST http://%s:%d/soap/servlet/rpcrouter HTTP/1.0\r\n"
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
"Content-Length: %d\r\n"
"SOAPAction: \"\"\r\n\r\n",
pszServer,
uPort,
length
);
else
sprintf( buffer,
"POST /soap/servlet/rpcrouter HTTP/1.0\r\n"
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
"Content-Length: %d\r\n"
"SOAPAction: \"\"\r\n\r\n",
length
);
if ( SOCKET_ERROR != send( s, buffer, strlen(buffer), 0 ) )
{
size_t nBytes;
do
{
nBytes = fread( buffer, 1, sizeof(buffer), fp );
if ( nBytes )
success = SOCKET_ERROR != send( s, buffer, nBytes, 0 );
} while( nBytes && success );
if ( success )
{
memset( buffer, 0, sizeof(buffer) );
success = SOCKET_ERROR != recv( s, buffer, sizeof(buffer), 0 );
if ( success )
{
char szHTTPSignature[sizeof(buffer)] = "";
unsigned uHTTPReturnCode = 0;
sscanf( buffer, "%s %d ", szHTTPSignature, &uHTTPReturnCode );
success = uHTTPReturnCode == 200;
}
}
}
}
closesocket( s );
}
}
return success;
}
//***************************************************************************
static void WriteSOAPRequest( FILE *fp )
{
fprintf( fp,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
"xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"
"xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\"\n"
"xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"\n"
"xmlns:rds=\"urn:ReportDataService\"\n"
"xmlns:apache=\"http://xml.apache.org/xml-soap\"\n"
"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
"<SOAP-ENV:Body>\n"
);
fprintf( fp, "<rds:submitReport>\n" );
fprintf( fp, "<body xsi:type=\"xsd:string\">This is an autogenerated crash report mail.</body>\n" );
fprintf( fp, "<hash xsi:type=\"apache:Map\">\n" );
FILE *fpin = fopen( g_szReportFileNameA, "r" );
if ( fpin )
{
fprintf( fp,
"<item>\n"
"<key xsi:type=\"xsd:string\">reportmail.xml</key>\n"
"<value xsi:type=\"xsd:string\"><![CDATA[" );
fcopy( fpin, fp );
fprintf( fp, "]]></value></item>\n" );
fclose( fpin );
}
fpin = fopen( g_szCommentFileNameA, "r" );
if ( fpin )
{
fprintf( fp,
"<item>\n"
"<key xsi:type=\"xsd:string\">description.txt</key>\n"
"<value xsi:type=\"xsd:string\"><![CDATA[" );
fcopy( fpin, fp );
fprintf( fp, "]]></value></item>\n" );
fclose( fpin );
};
fpin = fopen( g_szDumpFileNameA, "rb" );
if ( fpin )
{
FILE *fptemp = _tmpfile();
if ( fptemp )
{
if ( base64_encode( fpin, fptemp ) )
{
fseek( fptemp, 0, SEEK_SET );
fprintf( fp,
"<item>\n"
"<key xsi:type=\"xsd:string\">user.dmp</key>\n"
"<value xsi:type=\"xsd:string\">" );
fcopy( fptemp, fp );
fprintf( fp, "</value></item>\n" );
}
fclose( fptemp );
}
fclose( fpin );
}
fprintf( fp,
"</hash>\n"
"</rds:submitReport>\n"
"</SOAP-ENV:Body>\n"
"</SOAP-ENV:Envelope>\n"
);
}
//***************************************************************************
struct RequestParams
{
bool success;
FILE *fpin;
const char *lpServer;
unsigned short uPort;
const char *lpProxyServer;
unsigned short uProxyPort;
HWND hwndStatus;
};
void _cdecl SendingThread( void *lpArgs )
{
RequestParams *pParams = (RequestParams *)lpArgs;
pParams->success = SendHTTPRequest( pParams->fpin, pParams->lpServer, pParams->uPort, pParams->lpProxyServer, pParams->uProxyPort );
PostMessage( pParams->hwndStatus, WM_COMMAND, IDOK, 0 );
}
//***************************************************************************
BOOL CALLBACK SendingStatusDialogProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
static RequestParams *pRequest = NULL;
static HANDLE hSendingThread = NULL;
switch ( uMsg )
{
case WM_INITDIALOG:
{
TCHAR szBuffer[1024] = TEXT("");
HINSTANCE hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE );
//HWND hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT );
pRequest = (RequestParams *)lParam;
LoadAndFormatString( hInstance, IDS_SENDING_REPORT_HEADER, szBuffer, elementsof(szBuffer) );
SetWindowText( hwndDlg, szBuffer );
LoadAndFormatString( hInstance, IDS_SENDING_REPORT_STATUS, szBuffer, elementsof(szBuffer) );
Static_SetText( GetDlgItem(hwndDlg, IDC_SENDING_REPORT_STATUS), szBuffer );
LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
pRequest->hwndStatus = hwndDlg;
hSendingThread = (HANDLE)_beginthread( SendingThread, 0, pRequest );
}
return TRUE;
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDCANCEL:
TerminateThread( hSendingThread, 0 );
case IDOK:
WaitForSingleObject( hSendingThread, INFINITE );
CloseHandle( hSendingThread );
EndDialog( hwndDlg, wParam );
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
//***************************************************************************
bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams )
{
bool success = false;
char szProxyServer[1024] = "";
unsigned short uProxyPort = 8080;
TCHAR *endptr = NULL;
switch ( rParams.uInternetConnection )
{
case 2:
{
WideCharToMultiByte(
CP_ACP, 0, rParams.sProxyServer.c_str(), -1,
szProxyServer, sizeof(szProxyServer), NULL, NULL );
uProxyPort = (unsigned short)_tcstoul( rParams.sProxyPort.c_str(), &endptr, 10 );
}
break;
case 0:
{
DWORD dwProxyEnable = 0;
RegReadValue( HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
TEXT("ProxyEnable"),
&dwProxyEnable,
sizeof(dwProxyEnable) );
if ( dwProxyEnable )
{
TCHAR tszProxyServers[1024] = TEXT("");
if ( ERROR_SUCCESS == RegReadValue( HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), TEXT("ProxyServer"),
tszProxyServers,
sizeof(tszProxyServers) ) )
{
TCHAR *lpHttpStart = _tcsstr( tszProxyServers, TEXT("http=") );
if ( lpHttpStart )
lpHttpStart += 5;
else
lpHttpStart = tszProxyServers;
TCHAR *lpHttpEnd = _tcschr( lpHttpStart, ';' );
if ( lpHttpEnd )
*lpHttpEnd = 0;
char szHTTPProxyServer[1024] = "";
WideCharToMultiByte( CP_ACP, 0, lpHttpStart, -1, szHTTPProxyServer, sizeof(szHTTPProxyServer), NULL, NULL );
char *lpColon = strchr( szHTTPProxyServer, ':' );
if ( lpColon )
{
char *endptr = NULL;
*lpColon = 0;
uProxyPort = (unsigned short)strtoul( lpColon + 1, &endptr, 10 );
}
else
uProxyPort = 8080;
strcpy( szProxyServer, szHTTPProxyServer );
}
}
}
break;
default:
case 1:
break;
}
FILE *fptemp = _tmpfile();
if ( fptemp )
{
RequestParams request;
request.success = false;
request.fpin = fptemp;
request.lpServer = REPORT_SERVER;
request.uPort = REPORT_PORT;
request.lpProxyServer = szProxyServer[0] ? szProxyServer : NULL;
request.uProxyPort = uProxyPort;
request.hwndStatus = NULL;
WriteSOAPRequest( fptemp );
fseek( fptemp, 0, SEEK_SET );
if ( hwndParent )
{
int retid = DialogBoxParam(
GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_SENDING_STATUS),
hwndParent,
SendingStatusDialogProc,
(LPARAM)&request
);
success = request.success;
if ( IDOK == retid )
{
if ( !success )
{
TCHAR szMessage[1024];
LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
}
else
{
TCHAR szMessage[1024];
TCHAR szTitle[1024];
LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_HEADER, szTitle, elementsof(szTitle) );
MessageBox( hwndParent, szMessage, szTitle, MB_ICONINFORMATION | MB_OK );
}
}
}
else
{
HANDLE hSendingThread = (HANDLE)_beginthread( SendingThread, 0, (void *)&request );
WaitForSingleObject( hSendingThread, INFINITE );
success = request.success;
if ( !success )
{
TCHAR szMessage[1024];
LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
_ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
}
else
{
TCHAR szMessage[1024];
LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
_ftprintf( stderr, _T("SUCCESS: %s\n"), szMessage );
}
}
fclose( fptemp );
}
else
{
TCHAR szMessage[1024];
LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_DISK_FULL, szMessage, elementsof(szMessage) );
if ( hwndParent )
MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
else
_ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
}
return success;
}
//***************************************************************************
#ifdef __MINGW32__
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR /*lpCmdLine*/, int )
#else
int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR /*lpCmdLine*/, int )
#endif
{
int exitcode = -1;
int argc = __argc;
#ifdef __MINGW32__
char **argv = __argv;
#else
#ifdef _UNICODE
char **argv = new char *[argc + 1];
for ( int argn = 0; argn < argc; argn++ )
{
int nBytes = WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, NULL, 0, NULL, NULL );
argv[argn] = new char[nBytes];
WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, argv[argn], nBytes, NULL, NULL );
}
argv[argc] = NULL;
#else
char **argv = __targv;
#endif
#endif
osl_setCommandArgs( argc, argv );
PEXCEPTION_POINTERS pExceptionPointers = NULL;
DWORD dwProcessId = 0;
DWORD dwThreadId = 0;
WSADATA wsaData;
WORD wVersionRequested;
wVersionRequested = MAKEWORD(1, 1);
WSAStartup(wVersionRequested, &wsaData);
CrashReportParams Params;
Params.ReadFromRegistry();
Params.ReadFromEnvironment();
if ( ReadBootstrapParams( Params ) &&
ParseCommandArgs( &dwProcessId, &pExceptionPointers, &dwThreadId ) )
{
bool bGotDumpFile;
if ( g_bLoadReport )
bGotDumpFile = FindDumpFile();
else
bGotDumpFile = WriteDumpFile( dwProcessId, pExceptionPointers, dwThreadId );
if( bGotDumpFile )
{
hash_map< string, string > aLibraries;
if ( g_bLoadReport )
{
g_fpStackFile = _open_reportfile( _T(".stk"), _T("rb") );
g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("rb") );
}
else
{
if ( g_bSendReport )
{
g_fpStackFile = _tmpfile();
g_fpChecksumFile = _tmpfile();
}
else
{
g_fpStackFile = _open_reportfile( _T(".stk"), _T("w+b") );
g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("w+b") );
FILE *fpUnsent = _open_reportfile( _T(".lck"), _T("w+b") );
if ( fpUnsent )
{
fprintf( fpUnsent, "Unsent\r\n" );
fclose( fpUnsent );
}
}
WriteStackFile( g_fpStackFile, aLibraries, dwProcessId, pExceptionPointers );
WriteChecksumFile( g_fpChecksumFile, aLibraries );
WriteReportFile( &Params );
FILE *fpPreview = _open_reportfile( _T(".prv"), _T("w+b") );
if ( fpPreview )
{
FILE *fp = fopen( g_szReportFileNameA, "rb" );
if ( fp )
{
fcopy( fp, fpPreview );
fclose( fp );
}
fclose( fpPreview );
}
}
if ( g_bSendReport )
{
InitCommonControls();
// Actually this should never be true anymore
if ( !g_bNoUserInterface && InitRichEdit() )
{
INT_PTR result = DialogBoxParam( hInstance, MAKEINTRESOURCE(IDD_DIALOG_FRAME), NULL, DialogProc, (LPARAM)&Params );
if ( result > 0 )
{
exitcode = 0;
}
DeinitRichEdit();
}
else
{
WriteCommentFile( Params.sComment.c_str() );
WriteReportFile( &Params );
if ( SendCrashReport( NULL, Params ) )
exitcode = 0;
}
if ( g_szReportFileNameA[0] )
DeleteFileA( g_szReportFileNameA );
if ( g_szCommentFileNameA[0] )
DeleteFileA( g_szCommentFileNameA );
}
else
{
if ( g_szReportFileNameA[0] )
DeleteFileA( g_szReportFileNameA );
exitcode = 0;
}
if ( g_szDumpFileNameA[0] && g_bSendReport )
DeleteFileA( g_szDumpFileNameA );
if ( g_fpStackFile )
fclose( g_fpStackFile );
if ( g_fpChecksumFile )
fclose( g_fpChecksumFile );
}
}
return exitcode;
}