MSIMERG.CPP
#pragma message("Merge Database Utility.  Copyright 1997 - 1998 Microsoft Corp.") 
#if 0  // makefile definitions, to build: %vcbin%\nmake -fMsiMerg.cpp 
DESCRIPTION = Merge Database Utility 
MODULENAME = MsiMerg 
SUBSYSTEM = console 
FILEVERSION = Msi 
LINKLIBS = OLE32.lib 
!include <MsiTool.Mak> 
!if 0  #nmake skips the rest of this file 
#endif // end of makefile definitions 
 
#define W32DOWS_LEAN_AND_MEAN  // faster compile 
#define W32 
#define MSI 
 
#include <windows.h> 
#ifndef RC_INVOKED    // start of source code 
#include <tchar.h>    // define UNICODE=1 on nmake command line to build UNICODE 
#include "MsiQuery.h" // MSI API 
 
//________________________________________________________________________________ 
// 
// Constants and globals 
//________________________________________________________________________________ 
 
const TCHAR szHelp[] = TEXT("Msi Merge Tool --- Merge Two Databases\n\nMsiMerg(d).exe {base db} {ref db}\n"); 
const TCHAR szTable[] = TEXT("_MergeErrors"); 
 
const int cchDisplayBuf = 4096; 
HANDLE g_hStdOut; 
TCHAR g_rgchBuffer[4096]; 
 
//________________________________________________________________________________ 
// 
// Function prototypes 
//________________________________________________________________________________ 
 
void Display(LPCTSTR szMessage); 
void ErrorExit(UINT iError, LPCTSTR szMessage); 
void CheckError(UINT iError, LPCTSTR szMessage); 
void Merge(TCHAR* szBaseDb, TCHAR* szRefDb); 
 
//_____________________________________________________________________________________________________ 
// 
// main  
//_____________________________________________________________________________________________________ 
 
extern "C" int __cdecl _tmain(int argc, TCHAR* argv[]) 
{ 
// Determine handle 
g_hStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE); 
if (g_hStdOut == INVALID_HANDLE_VALUE) 
g_hStdOut = 0;  // non-zero if stdout redirected or piped 
 
if (argc == 2 && ((_tcscmp(argv[1], TEXT("-?")) == 0) || (_tcscmp(argv[1], TEXT("/?")) == 0))) 
ErrorExit( 0, szHelp); 
 
// Check for enough arguments and valid options 
CheckError(argc != 3, TEXT("msimerg(d).exe {base db} {ref db}")); 
Merge(argv[1], argv[2]); 
ErrorExit(0, TEXT("Done")); 
return 0; 
} 
 
 
//________________________________________________________________________________ 
// 
// Merge function 
//    Merge(...); 
//________________________________________________________________________________ 
 
void Merge(TCHAR* szBaseDb, TCHAR* szRefDb) 
{ 
PMSIHANDLE hBaseDb = 0; 
PMSIHANDLE hRefDb = 0; 
 
CheckError(MSI::MsiOpenDatabase(szBaseDb, MSIDBOPEN_TRANSACT, &hBaseDb), TEXT("Error Opening Base Database")); 
CheckError(MSI::MsiOpenDatabase(szRefDb, MSIDBOPEN_READONLY, &hRefDb), TEXT("Error Opening Reference Databaes")); 
UINT uiError = MSI::MsiDatabaseMerge(hBaseDb, hRefDb, szTable); 
CheckError(MSI::MsiDatabaseCommit(hBaseDb), TEXT("Error Saving Database")); 
CheckError(uiError, TEXT("Error Merging Database, Check _MergeErrors Table for Merge conflicts")); 
} 
 
//________________________________________________________________________________ 
// 
// Error handling and Display functions: 
//    Display(...); 
//   ErrorExit(...); 
//    CheckError(...); 
// 
//________________________________________________________________________________ 
 
void Display(LPCTSTR szMessage) 
{ 
if (szMessage) 
{ 
int cbOut = _tcsclen(szMessage);; 
if (g_hStdOut) 
{ 
#ifdef UNICODE 
char rgchTemp[cchDisplayBuf]; 
if (W32::GetFileType(g_hStdOut) == FILE_TYPE_CHAR) 
{ 
W32::WideCharToMultiByte(CP_ACP, 0, szMessage, cbOut, rgchTemp, sizeof(rgchTemp), 0, 0); 
szMessage = (LPCWSTR)rgchTemp; 
} 
else 
cbOut *= 2;   // write Unicode if not console device 
#endif 
DWORD cbWritten; 
W32::WriteFile(g_hStdOut, szMessage, cbOut, &cbWritten, 0); 
} 
else 
W32::MessageBox(0, szMessage, W32::GetCommandLine(), MB_OK); 
} 
} 
 
 
void ErrorExit(UINT iError, LPCTSTR szMessage) 
{ 
if (szMessage) 
{ 
int cbOut; 
TCHAR szBuffer[256];  // errors only, not used for display output 
if (iError == 0) 
cbOut = lstrlen(szMessage); 
else 
{ 
LPCTSTR szTemplate = (iError & 0x80000000L) 
? TEXT("Error 0x%X. %s\n") 
: TEXT("Error %i. %s\n"); 
cbOut = wsprintf(szBuffer, szTemplate, iError, szMessage); 
szMessage = szBuffer; 
} 
if (g_hStdOut) 
{ 
#ifdef UNICODE 
char rgchTemp[cchDisplayBuf]; 
if (W32::GetFileType(g_hStdOut) == FILE_TYPE_CHAR) 
{ 
W32::WideCharToMultiByte(CP_ACP, 0, szMessage, cbOut, rgchTemp, sizeof(rgchTemp), 0, 0); 
szMessage = (LPCWSTR)rgchTemp; 
} 
else 
cbOut *= 2;   // write Unicode if not console device 
#endif // UNICODE 
DWORD cbWritten; 
W32::WriteFile(g_hStdOut, szMessage, cbOut, &cbWritten, 0); 
} 
else 
W32::MessageBox(0, szMessage, W32::GetCommandLine(), MB_OK); 
} 
MSI::MsiCloseAllHandles(); 
W32::ExitProcess(szMessage != 0); 
} 
 
void CheckError(UINT iError, LPCTSTR szMessage) 
{ 
if (iError != ERROR_SUCCESS) 
ErrorExit(iError, szMessage); 
} 
 
#else // RC_INVOKED, end of source code, start of resources 
#endif // RC_INVOKED 
#if 0  
!endif // makefile terminator 
#endif