1348 lines
33 KiB
C++
1348 lines
33 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 2000
|
|
//
|
|
// File: xmlwiz.cpp
|
|
//
|
|
// Contents: code for generating app matching XML
|
|
//
|
|
// History: ~12-Jan-00 dmunsil created
|
|
// 18-Feb-00 dmunsil ver 0.8 -- added changing '&' to "&"
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "commdlg.h"
|
|
#include "stdio.h"
|
|
#include "assert.h"
|
|
#include "xmlwizres.h"
|
|
#include "verread.h"
|
|
|
|
extern "C" {
|
|
#include "shimdb.h"
|
|
}
|
|
|
|
#undef _GATHER_TIME
|
|
|
|
#define MAX_LINE_LEN 500
|
|
#define MAX_NUM_LINES 100
|
|
#define MAX_TEXT_BUF 32768
|
|
#define MAX_WORKING_BUFFER_SIZE 65536
|
|
|
|
// Types
|
|
|
|
typedef struct _MATCH_INFO {
|
|
DWORD dwSize;
|
|
DWORD dwChecksum;
|
|
char szTime[20];
|
|
LARGE_INTEGER liBinFileVersion;
|
|
LARGE_INTEGER liBinProdVersion;
|
|
char szProductName[50];
|
|
} MATCH_INFO, *PMATCH_INFO;
|
|
|
|
// Global Variables:
|
|
HINSTANCE g_hInst; // current instance
|
|
HWND g_hMainDlg;
|
|
|
|
char g_szExeName[260];
|
|
char g_szExeFullPath[1000];
|
|
char g_szParentExeName[260];
|
|
char g_szParentExeFullPath[1000];
|
|
|
|
char g_szEditText[MAX_TEXT_BUF];
|
|
char g_aszEditLines[MAX_NUM_LINES][MAX_LINE_LEN];
|
|
UINT g_unEditLines;
|
|
|
|
char g_szAppIndent[] = " "; // 4 spaces
|
|
char g_szExeIndent[] = " "; // 8 spaces
|
|
char g_szMatchIndent[] = " "; // 12 spaces
|
|
|
|
char g_szMatchAttributeIndent[] = " "; // 27 spaces
|
|
char g_szExeAttributeIndent[] = " "; // 13 spaces
|
|
BOOL g_bSelectedParentExe = FALSE;
|
|
|
|
DWORD g_dwSystemDlls = 0;
|
|
|
|
HFONT g_hFont;
|
|
|
|
// Foward declarations of functions included in this code module:
|
|
ATOM MyRegisterClass(HINSTANCE hInstance);
|
|
BOOL InitInstance(HINSTANCE, int);
|
|
LRESULT CALLBACK DlgMain(HWND, UINT, WPARAM, LPARAM);
|
|
LRESULT CALLBACK DlgDlls(HWND, UINT, WPARAM, LPARAM);
|
|
void GetExeNames(HWND hDlg);
|
|
void GetMatchFile(HWND hDlg);
|
|
void UnpackEditLines(HWND hDlg);
|
|
void PackEditLines(HWND hDlg);
|
|
void DeleteLines(UINT unBegin, UINT unLen);
|
|
void InsertLine(UINT unLine, char *szLine);
|
|
void InsertExeLines(UINT unLine);
|
|
BOOL bFindLine(char *szSearch, UINT *punLine);
|
|
BOOL bFindLineFrom(char *szSearch, UINT unStart, UINT *punLine);
|
|
void InitEditLines(void);
|
|
void GetMatchInfo(char *szFile, PMATCH_INFO pMatch);
|
|
DWORD GetFileChecksum(HANDLE handle);
|
|
char *szGetRelativePath(char *pExeFile, char *pMatchFile);
|
|
BOOL bSameDrive(char *szPath1, char *szPath2);
|
|
void MySelectAll(HWND hDlg);
|
|
|
|
void vEnumerateSystemDlls(HWND hDlg);
|
|
void vAddSelectedDlls(HWND hDlg);
|
|
void vWriteSysTest(void);
|
|
|
|
char *szConvertSpecialChars(char *szString);
|
|
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
MSG msg;
|
|
HACCEL hAccel;
|
|
|
|
// Perform application initialization:
|
|
if (!InitInstance (hInstance, nCmdShow))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
|
|
|
|
if (hAccel == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
g_hMainDlg = CreateDialog(hInstance, (LPCTSTR)IDD_MAIN, NULL, (DLGPROC)DlgMain);
|
|
|
|
// Main message loop:
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
if (!TranslateAccelerator(g_hMainDlg, hAccel, &msg)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return msg.wParam;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// FUNCTION: InitInstance(HANDLE, int)
|
|
//
|
|
// PURPOSE: Saves instance handle and creates main window
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// In this function, we save the instance handle in a global variable and
|
|
// create and display the main program window.
|
|
//
|
|
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
|
{
|
|
//HWND hWnd;
|
|
|
|
g_hInst = hInstance; // Store instance handle in our global variable
|
|
g_szExeName[0] = '\0';
|
|
g_szExeFullPath[0] = '\0';
|
|
g_szParentExeName[0] = '\0';
|
|
g_szParentExeFullPath[0] = '\0';
|
|
InitEditLines();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Message handler for DLL dialog.
|
|
LRESULT CALLBACK DlgDlls(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
vEnumerateSystemDlls(hDlg);
|
|
return TRUE;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch LOWORD(wParam) {
|
|
|
|
case IDOK:
|
|
vAddSelectedDlls(hDlg);
|
|
// falls through
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Message handler for main dialog.
|
|
LRESULT CALLBACK DlgMain(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HDC hDC;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
if (!g_szExeName[0]) {
|
|
HWND hBtn;
|
|
|
|
hBtn = GetDlgItem(hDlg, IDC_BTN_ADD_MATCH);
|
|
EnableWindow(hBtn, FALSE);
|
|
hBtn = GetDlgItem(hDlg, IDC_BTN_ADD_DLL);
|
|
EnableWindow(hBtn, FALSE);
|
|
}
|
|
|
|
// set the edit window to fixed-width font
|
|
hDC = GetDC(hDlg);
|
|
if (hDC) {
|
|
g_hFont = CreateFont(
|
|
-MulDiv(9, GetDeviceCaps(hDC, LOGPIXELSY), 72), // 9-pt font
|
|
0,
|
|
0,
|
|
0,
|
|
FW_REGULAR,
|
|
FALSE,
|
|
FALSE,
|
|
FALSE,
|
|
ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
ANTIALIASED_QUALITY,
|
|
FIXED_PITCH | FF_MODERN,
|
|
NULL);
|
|
if (g_hFont) {
|
|
HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
|
|
SendMessage(hEdit, WM_SETFONT, (WPARAM)g_hFont, TRUE);
|
|
}
|
|
ReleaseDC(hDlg, hDC);
|
|
}
|
|
|
|
return TRUE;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch LOWORD(wParam) {
|
|
case IDA_SELECT_ALL:
|
|
MySelectAll(hDlg);
|
|
break;
|
|
|
|
case IDC_BTN_SET_EXE:
|
|
GetExeNames(hDlg);
|
|
break;
|
|
|
|
case IDC_BTN_ADD_MATCH:
|
|
GetMatchFile(hDlg);
|
|
break;
|
|
|
|
case IDC_BTN_ADD_DLL:
|
|
DialogBox(g_hInst, (LPCTSTR)IDD_DLL_LIST, hDlg, (DLGPROC)DlgDlls);
|
|
break;
|
|
|
|
case IDC_BTN_WRITE_SYSTEST:
|
|
vWriteSysTest();
|
|
break;
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
PostQuitMessage(0);
|
|
DeleteObject(g_hFont);
|
|
return TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void GetMatchFile(HWND hDlg)
|
|
{
|
|
OPENFILENAME ofn;
|
|
MATCH_INFO MatchInfo;
|
|
char szMatchFile[1000];
|
|
char szInitialPath[1000];
|
|
char szFileTitle[260];
|
|
|
|
char szDrive[_MAX_DRIVE];
|
|
char szDir[_MAX_DIR];
|
|
UINT unLine;
|
|
char szTemp[MAX_LINE_LEN];
|
|
char szTime[MAX_LINE_LEN];
|
|
char szProdVer[MAX_LINE_LEN];
|
|
char szFileVer[MAX_LINE_LEN];
|
|
char szProdName[MAX_LINE_LEN];
|
|
char *szMatch;
|
|
|
|
szMatchFile[0] = '\0';
|
|
szFileTitle[0] = '\0';
|
|
szInitialPath[0] = '\0';
|
|
if (g_szParentExeFullPath[0]) {
|
|
_splitpath(g_szParentExeFullPath, szDrive, szDir, NULL, NULL);
|
|
strcpy(szInitialPath, szDrive);
|
|
strcat(szInitialPath, szDir);
|
|
}
|
|
|
|
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hDlg;
|
|
ofn.lpstrFile = szMatchFile;
|
|
ofn.nMaxFile = sizeof(szMatchFile);
|
|
ofn.lpstrFilter = "All\0*.*\0Exe\0*.EXE\0";
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFileTitle = szFileTitle;
|
|
ofn.nMaxFileTitle = sizeof(szFileTitle);
|
|
ofn.lpstrInitialDir = szInitialPath;
|
|
ofn.lpstrTitle = "Select Matching File";
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NODEREFERENCELINKS;
|
|
|
|
// get the matching file name
|
|
if (GetOpenFileName(&ofn) == FALSE) {
|
|
goto err1;
|
|
}
|
|
|
|
// get the lines out of the edit dialog
|
|
UnpackEditLines(hDlg);
|
|
|
|
// check if we need to get an parent exe
|
|
if (!bSameDrive(szMatchFile, g_szParentExeFullPath) && !g_bSelectedParentExe) {
|
|
char szParentFile[1000];
|
|
|
|
// get the parent exe
|
|
szParentFile[0] = '\0';
|
|
szInitialPath[0] = '\0';
|
|
if (szMatchFile[0]) {
|
|
_splitpath(szMatchFile, szDrive, szDir, NULL, NULL);
|
|
strcpy(szInitialPath, szDrive);
|
|
strcat(szInitialPath, szDir);
|
|
}
|
|
|
|
// most of ofn is already filled-in
|
|
ofn.lpstrTitle = "Select Parent Exe";
|
|
ofn.lpstrFile = szParentFile;
|
|
ofn.nMaxFile = sizeof(szParentFile);
|
|
|
|
if (GetOpenFileName(&ofn) == TRUE) {
|
|
strcpy(g_szParentExeName, szFileTitle);
|
|
strcpy(g_szParentExeFullPath, szParentFile);
|
|
g_bSelectedParentExe = TRUE;
|
|
|
|
// delete any previous parent exe comments
|
|
while (bFindLine("<!-- Parent exe", &unLine)) {
|
|
DeleteLines(unLine, 1);
|
|
}
|
|
|
|
// reconstruct the EXE if necessary
|
|
if (!bFindLine("<EXE", &unLine)) {
|
|
// insert it right after <APP> or at the beginning
|
|
if (bFindLine("<APP", &unLine)) {
|
|
unLine += 1;
|
|
} else {
|
|
unLine = 0;
|
|
}
|
|
|
|
InsertExeLines(unLine);
|
|
}
|
|
|
|
// if the parent exe is different, insert a comment
|
|
if (strcmp(g_szExeFullPath, g_szParentExeFullPath) != 0) {
|
|
char *szPathWithoutDrive = g_szParentExeFullPath + 2;
|
|
|
|
if (bSameDrive(g_szExeFullPath, g_szParentExeFullPath)) {
|
|
sprintf(szTemp, "%s<!-- Parent exe \"%s\" on same drive.-->", g_szMatchIndent, szPathWithoutDrive);
|
|
} else {
|
|
sprintf(szTemp, "%s<!-- Parent exe \"%s\" on different drive.-->", g_szMatchIndent, szPathWithoutDrive);
|
|
}
|
|
|
|
if (bFindLine("<EXE", &unLine)) {
|
|
if (bFindLineFrom(">", unLine, &unLine)) {
|
|
InsertLine(unLine + 1, szTemp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// check the drive letters to see which drive the match file is on
|
|
// then calculate a relative path to the matching file
|
|
if (bSameDrive(szMatchFile, g_szParentExeFullPath)) {
|
|
|
|
szMatch = szGetRelativePath(g_szParentExeFullPath, szMatchFile);
|
|
|
|
} else if (bSameDrive(szMatchFile, g_szExeFullPath)) {
|
|
|
|
szMatch = szGetRelativePath(g_szExeFullPath, szMatchFile);
|
|
|
|
} else {
|
|
|
|
MessageBox(hDlg, "Match file is not on same drive as either EXE or Parent EXE. "
|
|
"Can't generate relative path.", "Error", MB_ICONEXCLAMATION);
|
|
goto err2;
|
|
}
|
|
|
|
// reconstruct the EXE if necessary
|
|
if (!bFindLine("<EXE", &unLine)) {
|
|
// insert it right after <APP> or at the beginning
|
|
if (!bFindLine("<APP", &unLine)) {
|
|
unLine = 0;
|
|
} else {
|
|
unLine += 1;
|
|
}
|
|
|
|
InsertExeLines(unLine);
|
|
}
|
|
|
|
// find the </EXE> line and insert if necessary
|
|
if (!bFindLine("</EXE>", &unLine)) {
|
|
if (!bFindLine("</APP>", &unLine)) {
|
|
unLine = g_unEditLines + 1;
|
|
}
|
|
sprintf(szTemp, "%s</EXE>", g_szExeIndent);
|
|
InsertLine(unLine, szTemp);
|
|
}
|
|
|
|
GetMatchInfo(szMatchFile, &MatchInfo);
|
|
|
|
// now insert the line right before </EXE>
|
|
#ifdef _SPLIT_LINES
|
|
sprintf(szTemp, "%s<MATCHING_FILE NAME=\"%s\"",
|
|
g_szMatchIndent,
|
|
szMatch
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
|
|
sprintf(szTemp, "%sSIZE=\"%u\"",
|
|
g_szMatchAttributeIndent,
|
|
MatchInfo.dwSize
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
|
|
sprintf(szTemp, "%sCHECKSUM=\"0x%8.8X\"",
|
|
g_szMatchAttributeIndent,
|
|
MatchInfo.dwChecksum
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
|
|
sprintf(szTemp, "%sTIME=\"%s\"",
|
|
g_szMatchAttributeIndent,
|
|
MatchInfo.szTime
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
|
|
sprintf(szTemp, "%s/>",
|
|
g_szMatchIndent
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
#else
|
|
if (MatchInfo.szTime[0] != 0) {
|
|
sprintf(szTime, " TIME=\"%s\"", MatchInfo.szTime);
|
|
} else {
|
|
szTime[0] = 0;
|
|
}
|
|
|
|
if (MatchInfo.liBinFileVersion.QuadPart) {
|
|
sprintf(szFileVer, " BIN_FILE_VERSION=\"%d.%d.%d.%d\"",
|
|
HIWORD(MatchInfo.liBinFileVersion.HighPart),
|
|
LOWORD(MatchInfo.liBinFileVersion.HighPart),
|
|
HIWORD(MatchInfo.liBinFileVersion.LowPart),
|
|
LOWORD(MatchInfo.liBinFileVersion.LowPart));
|
|
} else {
|
|
szFileVer[0] = 0;
|
|
}
|
|
|
|
if (MatchInfo.liBinProdVersion.QuadPart) {
|
|
sprintf(szProdVer, " BIN_PRODUCT_VERSION=\"%d.%d.%d.%d\"",
|
|
HIWORD(MatchInfo.liBinProdVersion.HighPart),
|
|
LOWORD(MatchInfo.liBinProdVersion.HighPart),
|
|
HIWORD(MatchInfo.liBinProdVersion.LowPart),
|
|
LOWORD(MatchInfo.liBinProdVersion.LowPart));
|
|
} else {
|
|
szProdVer[0] = 0;
|
|
}
|
|
|
|
if (MatchInfo.szProductName[0]) {
|
|
sprintf(szProdName, " PRODUCT_NAME=\"%s\"", MatchInfo.szProductName);
|
|
} else {
|
|
szProdName[0] = 0;
|
|
}
|
|
|
|
sprintf(szTemp, "%s<MATCHING_FILE NAME=\"%s\" SIZE=\"%u\" CHECKSUM=\"0x%8.8X\"%s%s%s%s/>",
|
|
g_szMatchIndent,
|
|
szMatch,
|
|
MatchInfo.dwSize,
|
|
MatchInfo.dwChecksum,
|
|
szTime,
|
|
szFileVer,
|
|
szProdVer,
|
|
szProdName
|
|
);
|
|
InsertLine(unLine, szTemp);
|
|
#endif
|
|
|
|
|
|
err2:
|
|
// put them back into the dialog
|
|
PackEditLines(hDlg);
|
|
err1:
|
|
return;
|
|
}
|
|
|
|
void GetExeNames(HWND hDlg)
|
|
{
|
|
OPENFILENAME ofn;
|
|
char szFile[1000];
|
|
char szFileTitle[260];
|
|
HWND hBtn;
|
|
char szTemp[MAX_LINE_LEN];
|
|
|
|
szFile[0] = '\0';
|
|
szFileTitle[0] = '\0';
|
|
|
|
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hDlg;
|
|
ofn.lpstrFile = szFile;
|
|
ofn.nMaxFile = sizeof(szFile);
|
|
ofn.lpstrFilter = "All\0*.*\0Exe\0*.EXE\0";
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFileTitle = szFileTitle;
|
|
ofn.nMaxFileTitle = sizeof(szFileTitle);
|
|
ofn.lpstrInitialDir = NULL;
|
|
ofn.lpstrTitle = "Select Exe to Shim";
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NODEREFERENCELINKS;
|
|
|
|
// get the main exe name
|
|
if (GetOpenFileName(&ofn) == FALSE) {
|
|
return;
|
|
}
|
|
|
|
strcpy(g_szExeName, szFileTitle);
|
|
strcpy(g_szExeFullPath, szFile);
|
|
|
|
// the parent exe defaults to the same as the EXE
|
|
strcpy(g_szParentExeName, szFileTitle);
|
|
strcpy(g_szParentExeFullPath, szFile);
|
|
g_bSelectedParentExe = FALSE;
|
|
|
|
// construct our new dialog text
|
|
InitEditLines();
|
|
sprintf(szTemp, "%s<APP NAME=\"\" VENDOR=\"\">", g_szAppIndent);
|
|
InsertLine(0, szTemp);
|
|
|
|
InsertExeLines(1);
|
|
|
|
sprintf(szTemp, "%s</EXE>", g_szExeIndent);
|
|
InsertLine(999, szTemp);
|
|
|
|
sprintf(szTemp, "%s</APP>", g_szAppIndent);
|
|
InsertLine(999, szTemp);
|
|
|
|
// stick it in the dialog box
|
|
PackEditLines(hDlg);
|
|
|
|
hBtn = GetDlgItem(hDlg, IDC_BTN_ADD_MATCH);
|
|
EnableWindow(hBtn, TRUE);
|
|
hBtn = GetDlgItem(hDlg, IDC_BTN_ADD_DLL);
|
|
EnableWindow(hBtn, TRUE);
|
|
}
|
|
|
|
#define SECS_IN_DAY 86400
|
|
#define HUNDRED_NSECS_IN_SEC 10000000
|
|
|
|
void GetMatchInfo(char *szFile, PMATCH_INFO pMatch)
|
|
{
|
|
HANDLE hFile;
|
|
FILETIME ft;
|
|
SYSTEMTIME st;
|
|
|
|
ZeroMemory(pMatch, sizeof(MATCH_INFO));
|
|
|
|
hFile = CreateFile(
|
|
szFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE ) {
|
|
DWORD dwAttributes;
|
|
|
|
pMatch->dwSize = GetFileSize(hFile, NULL);
|
|
|
|
pMatch->dwChecksum = GetFileChecksum(hFile);
|
|
|
|
pMatch->szTime[0] = 0;
|
|
|
|
#ifdef _GATHER_TIME
|
|
// only get the time if the file is not read only, and the date is
|
|
// not within 2 days of today
|
|
dwAttributes = GetFileAttributes(szFile);
|
|
if (dwAttributes != -1 && (dwAttributes & FILE_ATTRIBUTE_READONLY)) {
|
|
SYSTEMTIME stMachine;
|
|
FILETIME ftMachine;
|
|
DWORD dwDayFile;
|
|
DWORD dwDayMachine;
|
|
LARGE_INTEGER liFile;
|
|
LARGE_INTEGER liMachine;
|
|
LARGE_INTEGER liDifference;
|
|
|
|
GetFileTime(hFile, &ft, NULL, NULL);
|
|
FileTimeToSystemTime(&ft, &st);
|
|
|
|
GetSystemTime(&stMachine);
|
|
SystemTimeToFileTime(&stMachine, &ftMachine);
|
|
|
|
liFile.LowPart = ft.dwLowDateTime;
|
|
liFile.HighPart = ft.dwHighDateTime;
|
|
liMachine.LowPart = ftMachine.dwLowDateTime;
|
|
liMachine.HighPart = ftMachine.dwHighDateTime;
|
|
liDifference.QuadPart = liMachine.QuadPart - liFile.QuadPart;
|
|
|
|
// this goofy math is because I can't specify more than a 32-bit
|
|
// value as a constant in this compiler
|
|
if ((liDifference.QuadPart / HUNDRED_NSECS_IN_SEC) > SECS_IN_DAY * 2) {
|
|
|
|
sprintf(pMatch->szTime, "%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d",
|
|
st.wMonth,
|
|
st.wDay,
|
|
st.wYear,
|
|
st.wHour,
|
|
st.wMinute,
|
|
st.wSecond);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CloseHandle(hFile);
|
|
|
|
// now get resource info
|
|
VERSION_DATA VersionData;
|
|
|
|
if (bInitVersionData(szFile, &VersionData)) {
|
|
char *szProductName = NULL;
|
|
|
|
pMatch->liBinFileVersion.QuadPart = qwGetBinFileVer(&VersionData);
|
|
pMatch->liBinProdVersion.QuadPart = qwGetBinProdVer(&VersionData);
|
|
|
|
#if 0
|
|
szProductName = szGetVersionString(&VersionData, "ProductName");
|
|
if (szProductName) {
|
|
int nLen;
|
|
|
|
nLen = sizeof(pMatch->szProductName) - 1;
|
|
|
|
strncpy(pMatch->szProductName, szProductName, nLen);
|
|
pMatch->szProductName[nLen] = 0;
|
|
}
|
|
#endif
|
|
|
|
vReleaseVersionData(&VersionData);
|
|
}
|
|
} else {
|
|
MessageBox(NULL, "Can't open match file for READ. Matching info inaccurate.",
|
|
"Error", MB_ICONEXCLAMATION);
|
|
pMatch->dwSize = 0;
|
|
pMatch->dwChecksum = 0xDEADBEEF;
|
|
pMatch->szTime[0] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void InitEditLines(void)
|
|
{
|
|
g_unEditLines = 0;
|
|
}
|
|
|
|
void UnpackEditLines(HWND hDlg)
|
|
{
|
|
char *szTemp, *szBegin;
|
|
|
|
GetDlgItemText(hDlg, IDC_EDIT1, g_szEditText, MAX_TEXT_BUF - 1);
|
|
|
|
szBegin = g_szEditText;
|
|
|
|
g_unEditLines = 0;
|
|
if (!szBegin[0]) {
|
|
return;
|
|
}
|
|
|
|
while (szTemp = strstr(szBegin, "\r\n")) {
|
|
// temporarily terminate the string and copy
|
|
*szTemp = '\0';
|
|
strcpy(g_aszEditLines[g_unEditLines], szBegin);
|
|
g_unEditLines++;
|
|
|
|
// back to normal
|
|
*szTemp = '\r';
|
|
|
|
szBegin = szTemp + 2;
|
|
}
|
|
|
|
// copy in the final line, if any
|
|
if (szBegin[0]) {
|
|
strcpy(g_aszEditLines[g_unEditLines], szBegin);
|
|
g_unEditLines++;
|
|
}
|
|
}
|
|
|
|
void PackEditLines(HWND hDlg)
|
|
{
|
|
UINT i;
|
|
char *szTemp = g_szEditText;
|
|
HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
|
|
|
|
for (i = 0; i < g_unEditLines; ++i) {
|
|
int nLen = strlen(g_aszEditLines[i]);
|
|
|
|
memcpy(szTemp, g_aszEditLines[i], nLen);
|
|
szTemp += nLen;
|
|
memcpy(szTemp, "\r\n", 2 * sizeof(char));
|
|
szTemp += 2;
|
|
}
|
|
|
|
*szTemp = '\0';
|
|
|
|
SetDlgItemText(hDlg, IDC_EDIT1, g_szEditText);
|
|
|
|
SendMessage(hEdit, EM_SETSEL, 0, -1); // select everything
|
|
|
|
SetFocus(hEdit);
|
|
|
|
}
|
|
|
|
void MySelectAll(HWND hDlg)
|
|
{
|
|
HWND hEdit = GetDlgItem(hDlg, IDC_EDIT1);
|
|
|
|
SendMessage(hEdit, EM_SETSEL, 0, -1); // select everything
|
|
|
|
SetFocus(hEdit);
|
|
}
|
|
|
|
void DeleteLines(UINT unBegin, UINT unLen)
|
|
{
|
|
UINT unEnd = unBegin + unLen;
|
|
|
|
if (unBegin > g_unEditLines) {
|
|
return;
|
|
}
|
|
if (unEnd > g_unEditLines) {
|
|
unEnd = g_unEditLines;
|
|
}
|
|
|
|
while (unEnd < g_unEditLines) {
|
|
strcpy(g_aszEditLines[unBegin++], g_aszEditLines[unEnd++]);
|
|
}
|
|
|
|
g_unEditLines -= unLen;
|
|
}
|
|
|
|
void InsertLine(UINT unLine, char *szLine)
|
|
{
|
|
UINT unTemp;
|
|
|
|
if (unLine > g_unEditLines) {
|
|
unLine = g_unEditLines;
|
|
}
|
|
|
|
unTemp = g_unEditLines;
|
|
|
|
while (unTemp != unLine) {
|
|
strcpy(g_aszEditLines[unTemp], g_aszEditLines[unTemp - 1]);
|
|
unTemp--;
|
|
}
|
|
|
|
strcpy(g_aszEditLines[unLine], szConvertSpecialChars(szLine));
|
|
|
|
g_unEditLines++;
|
|
}
|
|
|
|
void InsertExeLines(UINT unLine)
|
|
{
|
|
char szTemp[MAX_LINE_LEN];
|
|
MATCH_INFO MatchInfo;
|
|
char szTime[MAX_LINE_LEN];
|
|
char szProdVer[MAX_LINE_LEN];
|
|
char szFileVer[MAX_LINE_LEN];
|
|
|
|
GetMatchInfo(g_szExeFullPath, &MatchInfo);
|
|
|
|
#ifdef _SPLIT_LINES
|
|
sprintf(szTemp, "%s<EXE NAME=\"%s\"",
|
|
g_szExeIndent,
|
|
g_szExeName
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
|
|
sprintf(szTemp, "%sSIZE=\"%u\"",
|
|
g_szExeAttributeIndent,
|
|
MatchInfo.dwSize
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
|
|
sprintf(szTemp, "%sCHECKSUM=\"0x%8.8X\"",
|
|
g_szExeAttributeIndent,
|
|
MatchInfo.dwChecksum
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
|
|
if (MatchInfo.szTime[0] != 0) {
|
|
sprintf(szTemp, "%sTIME=\"%s\"",
|
|
g_szExeAttributeIndent,
|
|
MatchInfo.szTime
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
}
|
|
|
|
sprintf(szTemp, "%s>",
|
|
g_szExeIndent
|
|
);
|
|
InsertLine(unLine++, szTemp);
|
|
#else
|
|
if (MatchInfo.szTime[0] != 0) {
|
|
sprintf(szTime, " TIME=\"%s\"", MatchInfo.szTime);
|
|
} else {
|
|
szTime[0] = 0;
|
|
}
|
|
|
|
if (MatchInfo.liBinFileVersion.QuadPart) {
|
|
sprintf(szFileVer, " BIN_FILE_VERSION=\"%d.%d.%d.%d\"",
|
|
HIWORD(MatchInfo.liBinFileVersion.HighPart),
|
|
LOWORD(MatchInfo.liBinFileVersion.HighPart),
|
|
HIWORD(MatchInfo.liBinFileVersion.LowPart),
|
|
LOWORD(MatchInfo.liBinFileVersion.LowPart));
|
|
} else {
|
|
szFileVer[0] = 0;
|
|
}
|
|
|
|
if (MatchInfo.liBinProdVersion.QuadPart) {
|
|
sprintf(szProdVer, " BIN_PRODUCT_VERSION=\"%d.%d.%d.%d\"",
|
|
HIWORD(MatchInfo.liBinProdVersion.HighPart),
|
|
LOWORD(MatchInfo.liBinProdVersion.HighPart),
|
|
HIWORD(MatchInfo.liBinProdVersion.LowPart),
|
|
LOWORD(MatchInfo.liBinProdVersion.LowPart));
|
|
} else {
|
|
szProdVer[0] = 0;
|
|
}
|
|
|
|
sprintf(szTemp, "%s<EXE NAME=\"%s\" SIZE=\"%u\" CHECKSUM=\"0x%8.8X\"%s%s%s>",
|
|
g_szExeIndent,
|
|
g_szExeName,
|
|
MatchInfo.dwSize,
|
|
MatchInfo.dwChecksum,
|
|
szTime,
|
|
szFileVer,
|
|
szProdVer
|
|
);
|
|
InsertLine(unLine, szTemp);
|
|
#endif
|
|
}
|
|
|
|
BOOL bFindLine(char *szSearch, UINT *punLine)
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0; i < g_unEditLines; ++i) {
|
|
if (g_aszEditLines[i][0] && strstr(g_aszEditLines[i], szSearch)) {
|
|
*punLine = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bFindLineFrom(char *szSearch, UINT unStart, UINT *punLine)
|
|
{
|
|
UINT i;
|
|
|
|
for (i = unStart; i < g_unEditLines; ++i) {
|
|
if (g_aszEditLines[i][0] && strstr(g_aszEditLines[i], szSearch)) {
|
|
*punLine = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
char *szGetRelativePath(char *pExeFile, char *pMatchFile)
|
|
{
|
|
int iLenp = 0;
|
|
int iLenq = 0;
|
|
//int index = 0;
|
|
BOOL bCommonBegin = FALSE; // do the two paths have a common beginning
|
|
char *p = NULL;
|
|
char *q = NULL;
|
|
|
|
// BUGBUG -- if you call this function twice in a row
|
|
// without copying the result, the second call will overwrite
|
|
// the first -- consider changing to a passed-in string
|
|
//
|
|
static char result[MAX_PATH] = { '\0' };
|
|
|
|
char *resultIdx = result;
|
|
|
|
p = strchr(pExeFile, '\\');
|
|
q = strchr(pMatchFile, '\\');
|
|
|
|
while( p && q )
|
|
{
|
|
iLenp = p - pExeFile;
|
|
iLenq = q - pMatchFile;
|
|
|
|
if ( iLenp != iLenq )
|
|
break;
|
|
|
|
if ( !(_strnicmp(pExeFile, pMatchFile, iLenp) == 0) )
|
|
break;
|
|
|
|
bCommonBegin = TRUE;
|
|
pExeFile = p + 1;
|
|
pMatchFile = q + 1;
|
|
|
|
p = strchr(pExeFile, '\\');
|
|
q = strchr(pMatchFile, '\\');
|
|
}
|
|
|
|
if (bCommonBegin)
|
|
{
|
|
while( p )
|
|
{
|
|
strcpy(resultIdx, "..\\");
|
|
resultIdx = resultIdx + 3;
|
|
pExeFile = p + 1;
|
|
p = strchr(pExeFile, '\\');
|
|
}
|
|
|
|
strcpy(resultIdx, pMatchFile);
|
|
|
|
return result;
|
|
}
|
|
|
|
// the two paths don't have a common beginning,
|
|
// and there is no relative path
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL bSameDrive(char *szPath1, char *szPath2)
|
|
{
|
|
char szDrive1[256];
|
|
char szDrive2[256];
|
|
char *szTemp1, *szTemp2;
|
|
|
|
BOOL bReturn = FALSE;
|
|
|
|
assert(szPath1 && szPath1[0] && szPath2 && szPath2[0]);
|
|
|
|
if (szPath1[1] != szPath2[1]) {
|
|
// if the 2nd characters don't match, then one
|
|
// is a DOS style path and the other is UNC,
|
|
// and we're definitely not on the same drive
|
|
goto out;
|
|
}
|
|
|
|
if (szPath1[1] == ':') {
|
|
// these are both DOS-style paths
|
|
|
|
if (szPath1[0] == szPath2[0]) {
|
|
// if the first characters match, it's the same drive
|
|
bReturn = TRUE;
|
|
}
|
|
goto out;
|
|
}
|
|
|
|
// now we're sure we have two UNC-style paths
|
|
|
|
// skip past the "\\"
|
|
szTemp1 = szPath1 + 2;
|
|
szTemp2 = szPath2 + 2;
|
|
|
|
// skip to the next '\'
|
|
szTemp1 = strchr(szTemp1, '\\');
|
|
szTemp2 = strchr(szTemp2, '\\');
|
|
|
|
// if we didn't find another backslash, bail
|
|
if (!szTemp1 || !szTemp2) {
|
|
goto out;
|
|
}
|
|
|
|
// skip to the next '\' again
|
|
szTemp1++;
|
|
szTemp2++;
|
|
szTemp1 = strchr(szTemp1, '\\');
|
|
szTemp2 = strchr(szTemp2, '\\');
|
|
|
|
// if we didn't find another backslash, bail
|
|
if (!szTemp1 || !szTemp2) {
|
|
goto out;
|
|
}
|
|
|
|
// are they different sizes?
|
|
if (szTemp1 - szPath1 != szTemp2 - szPath2) {
|
|
goto out;
|
|
}
|
|
|
|
// they're the same size, are they the same string?
|
|
if (memcmp(szPath1, szPath2, szTemp1-szPath1) == 0) {
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
out:
|
|
return bReturn;
|
|
}
|
|
|
|
#define CHECKSUM_SIZE 4096
|
|
#define CHECKSUM_OFFSET 512
|
|
#define CHECKSUM_BUFFER (CHECKSUM_SIZE+CHECKSUM_OFFSET)
|
|
|
|
DWORD GetFileChecksum(HANDLE handle)
|
|
{
|
|
PBYTE pBuffer;
|
|
DWORD dwCheckSum;
|
|
DWORD dwBytesRead;
|
|
DWORD dwReadSize;
|
|
|
|
dwCheckSum = 0;
|
|
|
|
dwReadSize = GetFileSize(handle,
|
|
NULL);
|
|
|
|
if ( dwReadSize > CHECKSUM_BUFFER ) {
|
|
dwReadSize = CHECKSUM_BUFFER;
|
|
}
|
|
|
|
pBuffer = new BYTE[dwReadSize];
|
|
if ( !pBuffer ) {
|
|
dwCheckSum = 0xDEADBEEF;
|
|
goto err1;
|
|
}
|
|
|
|
SetFilePointer(handle,
|
|
0L,
|
|
NULL,
|
|
FILE_BEGIN);
|
|
|
|
|
|
ZeroMemory(pBuffer, dwReadSize);
|
|
|
|
//
|
|
// We can get away with this since if the read fails then the check sum will also fail.
|
|
//
|
|
if ( !ReadFile(handle, (PBYTE)pBuffer, dwReadSize, &dwBytesRead, NULL) ) {
|
|
dwCheckSum = 0xDEADBEEF;
|
|
goto err2;
|
|
}
|
|
|
|
{
|
|
INT i,size = CHECKSUM_SIZE;
|
|
DWORD startAddr = CHECKSUM_OFFSET;
|
|
PBYTE pTemp = pBuffer;
|
|
|
|
if (dwBytesRead < (ULONG)size) {
|
|
//
|
|
// File size is less than 4096. We set the start address to 0 and set the size for the checksum
|
|
// to the actual file size.
|
|
//
|
|
startAddr = 0;
|
|
size = dwBytesRead;
|
|
} else if (startAddr + size > dwBytesRead) {
|
|
//
|
|
// File size is too small. We set the start address so that size of checksum can be 4096 bytes
|
|
//
|
|
startAddr = dwBytesRead - size;
|
|
}
|
|
|
|
if (size < 4) {
|
|
//
|
|
// we need at least 4 bytes to be able to do something here.
|
|
//
|
|
dwCheckSum = 0;
|
|
goto err2;
|
|
}
|
|
|
|
// start at the offset
|
|
pTemp = pTemp + startAddr;
|
|
|
|
// walk through adding in DWORDs and rotating the result to guard against
|
|
// transposition
|
|
for (i = 0; i < (size - 3); i += 4) {
|
|
dwCheckSum += *((PDWORD) (pTemp + i));
|
|
dwCheckSum = _rotr (dwCheckSum, 1);
|
|
}
|
|
}
|
|
|
|
err2:
|
|
delete [] pBuffer;
|
|
|
|
err1:
|
|
return dwCheckSum;
|
|
}
|
|
|
|
void vWriteSysTest(void)
|
|
{
|
|
char szHeader[] = "<?xml version=\"1.0\"?>\r\n<DATABASE>\r\n";
|
|
char szTrailer[] = "\r\n</DATABASE>\r\n";
|
|
char szCommand[_MAX_PATH * 3];
|
|
char szSDBPath[_MAX_PATH];
|
|
char szXMLPath[_MAX_PATH];
|
|
char szLOGPath[_MAX_PATH];
|
|
DWORD dwBytesWritten = 0;
|
|
BOOL bRet;
|
|
PROCESS_INFORMATION ProcInfo;
|
|
|
|
STARTUPINFO si;
|
|
|
|
GetDlgItemText(g_hMainDlg, IDC_EDIT1, g_szEditText, MAX_TEXT_BUF - 1);
|
|
|
|
ExpandEnvironmentStrings("%windir%\\AppPatch\\systest.xml", szXMLPath, _MAX_PATH);
|
|
ExpandEnvironmentStrings("%windir%\\AppPatch\\systest.sdb", szSDBPath, _MAX_PATH);
|
|
ExpandEnvironmentStrings("%windir%\\AppPatch\\systest.log", szLOGPath, _MAX_PATH);
|
|
|
|
HANDLE hFile = CreateFile(
|
|
szXMLPath,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
goto out;
|
|
}
|
|
|
|
if (!WriteFile(hFile, szHeader, sizeof(szHeader) - 1, &dwBytesWritten, NULL)) {
|
|
goto out;
|
|
}
|
|
|
|
if (!WriteFile(hFile, g_szEditText, strlen(g_szEditText), &dwBytesWritten, NULL)) {
|
|
goto out;
|
|
}
|
|
|
|
if (!WriteFile(hFile, szTrailer, sizeof(szTrailer) - 1, &dwBytesWritten, NULL)) {
|
|
goto out;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
|
|
// Set up the start up info struct.
|
|
ZeroMemory(&si,sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
ZeroMemory(&ProcInfo, sizeof(PROCESS_INFORMATION));
|
|
|
|
sprintf(szCommand, "cmd /c shimdbc fix \"%s\" \"%s\" > \"%s\"", szXMLPath, szSDBPath, szLOGPath);
|
|
bRet = CreateProcess(NULL,
|
|
szCommand,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NO_WINDOW,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&ProcInfo);
|
|
if (!bRet) {
|
|
MessageBox(g_hMainDlg, "Couldn't launch shimdbc to generate systest.sdb. Check systest.log for more.", "Error", MB_ICONEXCLAMATION);
|
|
goto out;
|
|
}
|
|
|
|
if (WaitForSingleObject(ProcInfo.hProcess, 10000) == WAIT_OBJECT_0) {
|
|
|
|
// wait a bit to ensure everything is all done, and the .SDB file is done closing.
|
|
Sleep(100);
|
|
|
|
// Set up the start up info struct.
|
|
ZeroMemory(&si,sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
ZeroMemory(&ProcInfo, sizeof(PROCESS_INFORMATION));
|
|
|
|
// pop open notepad to see the log
|
|
sprintf(szCommand, "notepad \"%s\"", szLOGPath);
|
|
bRet = CreateProcess(NULL,
|
|
szCommand,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&ProcInfo);
|
|
}
|
|
|
|
|
|
out:
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hFile);
|
|
}
|
|
}
|
|
|
|
void vEnumerateSystemDlls(HWND hDlg)
|
|
{
|
|
PDB pdb = NULL;
|
|
WCHAR wszPath[_MAX_PATH];
|
|
HWND hList;
|
|
TAGID tiDatabase;
|
|
TAGID tiLibrary;
|
|
TAGID tiDll;
|
|
|
|
hList = GetDlgItem(hDlg, IDC_DLL_LIST);
|
|
if (!hList) {
|
|
goto out;
|
|
}
|
|
|
|
g_dwSystemDlls = 0;
|
|
|
|
ExpandEnvironmentStringsW(L"%windir%\\AppPatch\\sysmain.sdb", wszPath, _MAX_PATH);
|
|
|
|
pdb = SdbOpenDatabase(wszPath, DOS_PATH);
|
|
if (!pdb) {
|
|
goto out;
|
|
}
|
|
|
|
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
|
|
if (!tiDatabase) {
|
|
goto out;
|
|
}
|
|
|
|
tiLibrary = SdbFindFirstTag(pdb, tiDatabase, TAG_LIBRARY);
|
|
if (!tiLibrary) {
|
|
goto out;
|
|
}
|
|
|
|
tiDll = SdbFindFirstTag(pdb, tiLibrary, TAG_SHIM);
|
|
while (tiDll) {
|
|
TAGID tiName;
|
|
WCHAR wszName[_MAX_PATH];
|
|
|
|
wszName[0] = 0;
|
|
tiName = SdbFindFirstTag(pdb, tiDll, TAG_NAME);
|
|
if (tiName) {
|
|
|
|
SdbReadStringTag(pdb, tiName, wszName, _MAX_PATH * sizeof(WCHAR));
|
|
}
|
|
if (wszName[0]) {
|
|
char szName[_MAX_PATH];
|
|
|
|
sprintf(szName, "%S", wszName);
|
|
SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)szName);
|
|
g_dwSystemDlls++;
|
|
}
|
|
|
|
tiDll = SdbFindNextTag(pdb, tiLibrary, tiDll);
|
|
}
|
|
|
|
out:
|
|
if (pdb) {
|
|
SdbCloseDatabase(pdb);
|
|
}
|
|
}
|
|
|
|
void vAddSelectedDlls(HWND hDlg)
|
|
{
|
|
HWND hList;
|
|
DWORD *pdwItems = new DWORD[g_dwSystemDlls];
|
|
DWORD dwItems = 0;
|
|
DWORD i;
|
|
UINT unLine;
|
|
char szTemp[MAX_LINE_LEN];
|
|
|
|
if (!pdwItems) {
|
|
goto out;
|
|
}
|
|
|
|
hList = GetDlgItem(hDlg, IDC_DLL_LIST);
|
|
if (!hList) {
|
|
goto out;
|
|
}
|
|
|
|
UnpackEditLines(g_hMainDlg);
|
|
|
|
// find the </EXE> line and insert if necessary
|
|
if (!bFindLine("</EXE>", &unLine)) {
|
|
if (!bFindLine("</APP>", &unLine)) {
|
|
unLine = g_unEditLines + 1;
|
|
}
|
|
sprintf(szTemp, "%s</EXE>", g_szExeIndent);
|
|
InsertLine(unLine, szTemp);
|
|
}
|
|
|
|
|
|
dwItems = SendMessage(hList, LB_GETSELITEMS, g_dwSystemDlls, (LPARAM)pdwItems);
|
|
for (i = 0; i < dwItems; ++i) {
|
|
char szName[_MAX_PATH];
|
|
|
|
szName[0] = 0;
|
|
SendMessage(hList, LB_GETTEXT, pdwItems[i], (LPARAM)szName);
|
|
|
|
if (szName[0]) {
|
|
sprintf(szTemp, "%s<DLL NAME=\"%s\"/>", g_szMatchIndent, szName);
|
|
InsertLine(unLine, szTemp);
|
|
}
|
|
}
|
|
|
|
PackEditLines(g_hMainDlg);
|
|
|
|
out:
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Does an in-place expansion of special characters for XML into the equivalents.
|
|
|
|
Specifically, converts '&' to '&'.
|
|
|
|
*/
|
|
|
|
char *szConvertSpecialChars(char *szString)
|
|
{
|
|
char *szPtr;
|
|
char *szEnd;
|
|
|
|
assert(szString);
|
|
|
|
szPtr = szString;
|
|
szEnd = szString;
|
|
while (*szEnd) {
|
|
szEnd++;
|
|
}
|
|
|
|
szEnd++; // now points one past end
|
|
|
|
//
|
|
// now go looking for ampersands
|
|
//
|
|
while (*szPtr) {
|
|
if (*szPtr == '&') {
|
|
memmove(szPtr + 3, szPtr, szEnd-szPtr);
|
|
memcpy(szPtr, "&", 4);
|
|
szPtr += 3;
|
|
szEnd += 3;
|
|
}
|
|
szPtr++;
|
|
}
|
|
|
|
return szString;
|
|
}
|
|
|
|
|
|
|
|
|