1490 lines
35 KiB
C++
1490 lines
35 KiB
C++
/************************************************************************
|
|
* *
|
|
* HCWMISC.CPP *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1993-1995 *
|
|
* All Rights reserved. *
|
|
* *
|
|
* Miscellanious routins for HCW *
|
|
* *
|
|
************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
#include <stdlib.h>
|
|
|
|
#ifndef _DLGSH_INCLUDED_
|
|
#include <dlgs.h>
|
|
#endif
|
|
|
|
#include "..\hwdll\cbrdcast.h"
|
|
|
|
#include "mainfrm.h"
|
|
#include "..\hwdll\cinput.h"
|
|
#include <direct.h>
|
|
|
|
// Hack so we can include shlobj.h (we don't care about network stuff).
|
|
typedef int NETRESOURCE;
|
|
#include <shlobj.h>
|
|
|
|
// Typedefs to make it easier to run-time link to SHBrowseForFolder
|
|
// and SHGetPathFromIDList.
|
|
typedef LPITEMIDLIST
|
|
(WINAPI *PFN_SHBrowseForFolder)
|
|
(LPBROWSEINFO lpbi);
|
|
typedef BOOL
|
|
(WINAPI *PFN_SHGetPathFromIDList)
|
|
(LPCITEMIDLIST pidl, LPSTR pszPath);
|
|
typedef HRESULT
|
|
(WINAPI *PFN_SHGetSpecialFolderLocation)
|
|
(HWND hwndOwner, int nFolder, LPITEMIDLIST * ppidl);
|
|
typedef HRESULT
|
|
(WINAPI *PFN_SHGetMalloc)
|
|
(LPMALLOC * ppMalloc);
|
|
|
|
static int BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
|
|
|
|
// Static functions
|
|
static BOOL STDCALL ChangePath(PCSTR pszPath);
|
|
static int CALLBACK EnumFontFamProc(const LOGFONT*, const TEXTMETRIC*, DWORD, LPARAM lParam);
|
|
|
|
void STDCALL OpenLogFile(int idType)
|
|
{
|
|
// Open existing log file, or create a new one.
|
|
|
|
CPtrList* m_pList = (CPtrList*) theApp.GetPtrList();
|
|
|
|
POSITION pos = m_pList->GetHeadPosition();
|
|
CString logType;
|
|
logType.LoadString(idType);
|
|
|
|
while (pos != NULL) {
|
|
CDocTemplate* pTemplate = (CDocTemplate*) m_pList->GetNext(pos);
|
|
CString strTypeName;
|
|
if (pTemplate->GetDocString(strTypeName, CDocTemplate::fileNewName) &&
|
|
!strTypeName.IsEmpty()) {
|
|
if (strstr(strTypeName, logType)) {
|
|
pTemplate->OpenDocumentFile(NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
::UpdateWindow(APP_WINDOW); // Update all windows before our launch
|
|
}
|
|
|
|
int STDCALL MsgBox(UINT idString)
|
|
{
|
|
return AfxMessageBox(idString, MB_OK, 0);
|
|
}
|
|
|
|
int STDCALL szMsgBox(PCSTR pszMsg)
|
|
{
|
|
return AfxMessageBox(pszMsg);
|
|
}
|
|
|
|
void STDCALL DDV_NonEmptyString(CDataExchange* pDX,
|
|
CString const& value, UINT idPrompt)
|
|
{
|
|
if (pDX->m_bSaveAndValidate && value.IsEmpty()) {
|
|
MsgBox(idPrompt, MB_OK);
|
|
pDX->Fail();
|
|
}
|
|
}
|
|
|
|
// Require a valid Topic ID
|
|
|
|
void STDCALL DDV_ValidTopicID(CDataExchange* pDX, CString const& value)
|
|
{
|
|
if (pDX->m_bSaveAndValidate && (value.IsEmpty() ||
|
|
!IsValidContextSz(value))) {
|
|
MsgBox(IDS_INVALID_TOPIC_ID, MB_OK);
|
|
pDX->Fail();
|
|
}
|
|
}
|
|
|
|
void STDCALL DDX_TextHex(CDataExchange* pDX, UINT idCtl, UINT &value)
|
|
{
|
|
char ach[16];
|
|
|
|
// REVIEW (niklasb): Is the following language independent?
|
|
if (pDX->m_bSaveAndValidate) {
|
|
pDX->m_pDlgWnd->GetDlgItemText(idCtl, ach, sizeof(ach));
|
|
|
|
UINT uVal = 0;
|
|
for (int i = 0; i < 16; i++) {
|
|
UINT uDigit;
|
|
|
|
if (ach[i] == '\0')
|
|
break;
|
|
else if (ach[i] >= '0' && ach[i] <= '9')
|
|
uDigit = ach[i] - '0';
|
|
else if (ach[i] >= 'A' && ach[i] <= 'F')
|
|
uDigit = ach[i] - ('A' - 10);
|
|
else if (ach[i] >= 'a' && ach[i] <= 'f')
|
|
uDigit = ach[i] - ('a' - 10);
|
|
else if (ach[i] == 'x')
|
|
continue;
|
|
else {
|
|
MsgBox(IDS_INVALID_HEX, MB_OK);
|
|
pDX->Fail();
|
|
return;
|
|
}
|
|
|
|
uVal = (uVal << 4) | uDigit;
|
|
}
|
|
value = uVal;
|
|
}
|
|
else {
|
|
wsprintf(ach, "%X", value);
|
|
pDX->m_pDlgWnd->SetDlgItemText(idCtl, ach);
|
|
}
|
|
}
|
|
|
|
enum PATH_TYPE {
|
|
PT_RELATIVE,
|
|
PT_FROM_ROOT,
|
|
PT_UNC
|
|
};
|
|
|
|
class CParsePath {
|
|
public:
|
|
CParsePath(PCSTR pszPath = NULL, BOOL fDir = FALSE);
|
|
~CParsePath();
|
|
|
|
BOOL IsInitialized() { return (BOOL) m_pBuffer; }
|
|
|
|
BOOL GetRelativePath(CParsePath& base, PSTR pszOut);
|
|
BOOL GetFullPath(CParsePath& base, PSTR pszOut);
|
|
|
|
BOOL IsRelative() { return m_nType == PT_RELATIVE; }
|
|
BOOL IsFull() { return m_nType == PT_FROM_ROOT; }
|
|
BOOL IsUNC() { return m_nType == PT_UNC; }
|
|
BOOL IsDrive() { return *m_szDrive; }
|
|
|
|
protected:
|
|
PSTR m_pBuffer;
|
|
PSTR* m_papTok;
|
|
PSTR m_pszFilename;
|
|
PSTR m_pszComment;
|
|
PSTR m_pszShare;
|
|
|
|
int m_cBackup;
|
|
int m_cTok;
|
|
|
|
int m_nType; // PATH_TYPE
|
|
char m_szDrive[2];
|
|
};
|
|
|
|
CParsePath::CParsePath(PCSTR pszPath, BOOL fDir)
|
|
{
|
|
m_papTok = NULL;
|
|
m_pszComment = NULL;
|
|
m_pszFilename = NULL;
|
|
m_pszShare = NULL;
|
|
m_cBackup = 0;
|
|
m_cTok = 0;
|
|
m_nType = 0;
|
|
m_szDrive[0] = m_szDrive[1] = '\0';
|
|
|
|
// Allocate a copy of the path and remove extraneous junk.
|
|
PSTR pszStart;
|
|
if (pszPath) {
|
|
|
|
// Skip leading spaces.
|
|
pszStart = m_pBuffer = lcStrDup(pszPath);
|
|
if (isspace(*pszStart))
|
|
pszStart = FirstNonSpace(pszStart + 1, _fDBCSSystem);
|
|
|
|
// Look for comment.
|
|
m_pszComment = StrChr(pszStart, ';', _fDBCSSystem);
|
|
if (m_pszComment) {
|
|
*m_pszComment = '\0';
|
|
m_pszComment = FirstNonSpace(m_pszComment + 1, _fDBCSSystem);
|
|
}
|
|
|
|
// Remove punctuation.
|
|
char chClose;
|
|
switch (*pszStart) {
|
|
case '`':
|
|
chClose = '\'';
|
|
goto remove_quotes;
|
|
|
|
case '<':
|
|
chClose = '>';
|
|
goto remove_quotes;
|
|
|
|
case '\"':
|
|
chClose = '\"';
|
|
|
|
remove_quotes:
|
|
pszStart++;
|
|
PSTR pszEnd = StrChr(pszStart, chClose, _fDBCSSystem);
|
|
if (!pszEnd)
|
|
goto fail;
|
|
|
|
*pszEnd = '\0';
|
|
}
|
|
RemoveTrailingSpaces(pszStart);
|
|
|
|
// If it's not a directory, get the filename.
|
|
if (!fDir) {
|
|
m_pszFilename = StrRChr(pszStart, '\\', _fDBCSSystem);
|
|
if (m_pszFilename) {
|
|
*m_pszFilename++ = '\0';
|
|
}
|
|
else {
|
|
m_pszFilename = pszStart;
|
|
pszStart = NULL;
|
|
}
|
|
}
|
|
}
|
|
else { // no path: use current directory
|
|
pszStart = m_pBuffer = (PSTR) lcMalloc(MAX_PATH);
|
|
GetCurrentDirectory(MAX_PATH, m_pBuffer);
|
|
fDir = TRUE;
|
|
}
|
|
|
|
// Parse the path.
|
|
if (pszStart) {
|
|
|
|
// Handle UNC names.
|
|
if (*pszStart == '\\' && pszStart[1] == '\\') {
|
|
m_nType = PT_UNC;
|
|
m_pszShare = pszStart;
|
|
|
|
pszStart = StrChr(pszStart + 2, '\\', _fDBCSSystem);
|
|
if (!pszStart)
|
|
goto fail;
|
|
|
|
pszStart = StrChr(pszStart + 1, '\\', _fDBCSSystem);
|
|
if (!pszStart)
|
|
goto fail;
|
|
|
|
*pszStart++ = '\0';
|
|
}
|
|
else { // not a UNC name
|
|
|
|
// Get drive letter if any.
|
|
if (pszStart[1] == ':') {
|
|
*m_szDrive = *pszStart;
|
|
CharLower(m_szDrive);
|
|
pszStart += 2;
|
|
}
|
|
|
|
// Get initial backslash if any.
|
|
if (*pszStart == '\\') {
|
|
m_nType = PT_FROM_ROOT;
|
|
pszStart++;
|
|
}
|
|
else if (pszStart + 1 == m_pszFilename)
|
|
m_nType = PT_FROM_ROOT;
|
|
}
|
|
|
|
// Tokenize the rest of the path.
|
|
int cAlloc = 0;
|
|
while (*pszStart) {
|
|
if (*pszStart == '.') {
|
|
if (pszStart[1] == '.') {
|
|
if (m_cTok)
|
|
m_cTok--;
|
|
else {
|
|
if (m_nType == PT_FROM_ROOT)
|
|
goto fail;
|
|
m_cBackup++;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (m_cTok == cAlloc) {
|
|
cAlloc += 16;
|
|
m_papTok = m_papTok ?
|
|
(PSTR*) lcReAlloc(m_papTok, cAlloc * sizeof(PSTR)) :
|
|
(PSTR*) lcMalloc(cAlloc * sizeof(PSTR));
|
|
}
|
|
m_papTok[m_cTok++] = pszStart;
|
|
}
|
|
|
|
pszStart = StrChr(pszStart, '\\', _fDBCSSystem);
|
|
if (!pszStart)
|
|
break;
|
|
|
|
*pszStart++ = '\0';
|
|
}
|
|
}
|
|
return;
|
|
|
|
fail:
|
|
if (m_pBuffer) {
|
|
lcFree(m_pBuffer);
|
|
m_pBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
CParsePath::~CParsePath()
|
|
{
|
|
if (m_pBuffer)
|
|
lcFree(m_pBuffer);
|
|
if (m_papTok)
|
|
lcFree(m_papTok);
|
|
}
|
|
|
|
BOOL CParsePath::GetRelativePath(CParsePath& base, PSTR pszOut)
|
|
{
|
|
ASSERT(pszOut);
|
|
|
|
if (!IsInitialized() || !base.IsInitialized())
|
|
return FALSE;
|
|
|
|
// Fail if this cannot be a relative path from base.
|
|
if (base.m_nType == PT_RELATIVE || m_nType == PT_UNC ||
|
|
(*m_szDrive && *m_szDrive != *base.m_szDrive))
|
|
return FALSE;
|
|
|
|
int cBackup = 0; // number of initial double dots
|
|
int iFirstTok = m_cTok; // first directory name to write
|
|
|
|
if (m_nType == PT_FROM_ROOT) {
|
|
for (int cMatch = 0;; cMatch++) {
|
|
|
|
// This is subset of base path.
|
|
if (cMatch == m_cTok) {
|
|
cBackup = base.m_cTok - cMatch;
|
|
break;
|
|
}
|
|
|
|
// This is superset of base path.
|
|
if (cMatch == base.m_cTok) {
|
|
iFirstTok = cMatch;
|
|
break;
|
|
}
|
|
|
|
// Filenames differ.
|
|
if (lstrcmpi(m_papTok[cMatch], base.m_papTok[cMatch])) {
|
|
cBackup = base.m_cTok - cMatch;
|
|
iFirstTok = cMatch;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Point to the first token in this path.
|
|
iFirstTok = 0;
|
|
|
|
// Point to the corresponding token in the base path.
|
|
int iBase = base.m_cTok - m_cBackup;
|
|
if (iBase < 0)
|
|
return FALSE;
|
|
|
|
// Compare tokens.
|
|
while ((iFirstTok < m_cTok) && (iBase < base.m_cTok) &&
|
|
!lstrcmpi(m_papTok[iFirstTok], base.m_papTok[iBase])) {
|
|
iFirstTok++;
|
|
iBase++;
|
|
}
|
|
|
|
cBackup = m_cBackup - iFirstTok;
|
|
}
|
|
|
|
// If it's exactly the same directory output a single dot.
|
|
// Otherwise output double dots and/or directory names.
|
|
PSTR psz;
|
|
if (!cBackup && iFirstTok == m_cTok) {
|
|
*pszOut = '.';
|
|
pszOut[1] = '\\';
|
|
psz = pszOut + 2;
|
|
}
|
|
else {
|
|
for (psz = pszOut; cBackup; cBackup--) {
|
|
lstrcpy(psz, "..\\");
|
|
psz += 3;
|
|
}
|
|
while (iFirstTok < m_cTok) {
|
|
psz += lstrlen(lstrcpy(psz, m_papTok[iFirstTok++]));
|
|
*psz++ = '\\';
|
|
}
|
|
}
|
|
|
|
// Add the filename, or remove the backslash if none.
|
|
if (m_pszFilename)
|
|
psz += lstrlen(lstrcpy(psz, m_pszFilename));
|
|
else {
|
|
ASSERT(psz > pszOut);
|
|
psz--;
|
|
*psz = '\0';
|
|
}
|
|
|
|
// Add the comment if there is one.
|
|
if (m_pszComment) {
|
|
psz = AddTabbedComment(pszOut);
|
|
lstrcpy(psz, m_pszComment);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CParsePath::GetFullPath(CParsePath& base, PSTR pszOut)
|
|
{
|
|
ASSERT(pszOut);
|
|
|
|
if (!IsInitialized() || !base.IsInitialized())
|
|
return FALSE;
|
|
|
|
// Fail if the base is not a full path or this is not relative.
|
|
if (base.m_nType == PT_RELATIVE || m_nType == PT_UNC ||
|
|
(*m_szDrive && *m_szDrive != *base.m_szDrive))
|
|
return FALSE;
|
|
|
|
// Invalid case.
|
|
if (m_cBackup > base.m_cTok)
|
|
return FALSE;
|
|
|
|
// Point to the start of the output buffer.
|
|
PSTR psz = pszOut;
|
|
|
|
// Add the share name or drive letter.
|
|
if (base.m_nType == PT_UNC) {
|
|
ASSERT(base.m_pszShare);
|
|
psz += lstrlen(lstrcpy(psz, base.m_pszShare));
|
|
}
|
|
else if (*base.m_szDrive) {
|
|
*psz = *base.m_szDrive;
|
|
psz[1] = ':';
|
|
psz += 2;
|
|
}
|
|
*psz++ = '\\';
|
|
|
|
// Add directory names from base path if appropriate.
|
|
if (m_nType == PT_RELATIVE) {
|
|
int cTok = base.m_cTok - m_cBackup;
|
|
for (int iTok = 0; iTok < cTok; iTok++) {
|
|
psz += lstrlen(lstrcpy(psz, base.m_papTok[iTok]));
|
|
*psz++ = '\\';
|
|
}
|
|
}
|
|
|
|
// Add directory names from this path.
|
|
for (int iTok = 0; iTok < m_cTok; iTok++) {
|
|
psz += lstrlen(lstrcpy(psz, m_papTok[iTok]));
|
|
*psz++ = '\\';
|
|
}
|
|
|
|
// Add any filename.
|
|
if (m_pszFilename) {
|
|
psz += lstrlen(lstrcpy(psz, m_pszFilename));
|
|
}
|
|
else {
|
|
|
|
// If no filename and we're not at the root of a lettered
|
|
// drive, remove the trailing backslash.
|
|
if (psz > pszOut && !(psz == pszOut + 3 && pszOut[1] == ':'))
|
|
psz--;
|
|
*psz = '\0';
|
|
}
|
|
|
|
// Add any comment.
|
|
if (m_pszComment) {
|
|
if (psz > pszOut)
|
|
psz = AddTabbedComment(pszOut);
|
|
else {
|
|
*psz = ';';
|
|
psz[1] = ' ';
|
|
psz += 2;
|
|
}
|
|
lstrcpy(psz, m_pszComment);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// ConvertToRelative - Converts the given filename to a relative path,
|
|
// using the specified base filename.
|
|
// Returns TRUE if successful, FALSE if the filename was not changed.
|
|
// pszBaseFile - base path or NULL for current directory
|
|
// pszFilename - filename to convert; may be enclosed in quotes or
|
|
// angle brackets and followed by semicolon + comment
|
|
// fDirectory - TRUE if pszFilename does not include a filename or
|
|
// trailing backslash
|
|
// fVerify - TRUE if we should fail to convert paths that don't exist
|
|
BOOL ConvertToRelative(PCSTR pszBaseFile, PSTR pszFilename,
|
|
BOOL fDirectory /* =FALSE */, BOOL fVerify /* =FALSE */)
|
|
{
|
|
// Parse the given path.
|
|
CParsePath file(pszFilename, fDirectory);
|
|
|
|
// Ignore UNC paths.
|
|
if (file.IsUNC())
|
|
return FALSE;
|
|
|
|
// Ignore relative paths unless they contain drive letters.
|
|
if (file.IsRelative() && !file.IsDrive())
|
|
return FALSE;
|
|
|
|
// Parse the base path and fail if it's relative.
|
|
CParsePath base(pszBaseFile);
|
|
if (base.IsRelative())
|
|
return FALSE;
|
|
|
|
// Test for existence if specified. An invalid path, if left alone,
|
|
// might still resolve correctly due to a REPLACE command.
|
|
if (fVerify) {
|
|
|
|
// Get full path relative to the specified base.
|
|
char szPath[MAX_PATH];
|
|
if (!file.GetFullPath(base, szPath))
|
|
return FALSE;
|
|
|
|
// Test for existence.
|
|
WIN32_FIND_DATA wfd;
|
|
HANDLE hFind = FindFirstFile(szPath, &wfd);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
FindClose(hFind);
|
|
}
|
|
|
|
// Get the relative path.
|
|
return file.GetRelativePath(base, pszFilename);
|
|
}
|
|
|
|
BOOL STDCALL ConvertToRelative(PCSTR pszBaseFile, CString* pcszFilename,
|
|
BOOL fDirectory, BOOL fVerify)
|
|
{
|
|
char szFile[MAX_PATH];
|
|
lstrcpy(szFile, *pcszFilename);
|
|
|
|
if (ConvertToRelative(pszBaseFile, szFile, fDirectory, fVerify)) {
|
|
*pcszFilename = szFile;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// ConvertToFull - Converts the given relative filename to a full path,
|
|
// using the specified base filename.
|
|
// Returns TRUE if successful, FALSE if the filename was not changed.
|
|
// pszBaseFile - base path or NULL for current directory
|
|
// pszFilename - filename to convert; may be enclosed in quotes or
|
|
// angle brackets and followed by semicolon + comment
|
|
// fDirectory - TRUE if pszFilename does not include a filename or
|
|
// trailing backslash
|
|
BOOL ConvertToFull(PCSTR pszBaseFile, PSTR pszFilename, BOOL fDirectory)
|
|
{
|
|
CParsePath base(pszBaseFile);
|
|
if (!base.IsInitialized())
|
|
return FALSE;
|
|
|
|
CParsePath file(pszFilename, fDirectory);
|
|
if (!file.IsInitialized())
|
|
return FALSE;
|
|
|
|
return file.GetFullPath(base, pszFilename);
|
|
}
|
|
|
|
// ChangeBasePath - Converts a filename to a relative path.
|
|
// Returns TRUE if successful, FALSE of the filename was not changed.
|
|
// pszOldBase - previous base directory (if pszFilename is a relative
|
|
// path, it is assumed to be relative to this directory)
|
|
// pszNewBase - new base directory (the returned filename is relative
|
|
// to this directory)
|
|
// pszFilename - filename to convert
|
|
// fDirectory - TRUE if pszFilename does not include a filename or
|
|
// trailing backslash
|
|
// fVerify - TRUE if we should fail to convert paths that don't exist
|
|
BOOL ChangeBasePath(PCSTR pszOldBase, PCSTR pszNewBase, PSTR pszFilename,
|
|
BOOL fDirectory, BOOL fVerify)
|
|
{
|
|
char achTemp[MAX_PATH];
|
|
lstrcpy(achTemp, pszFilename);
|
|
|
|
if (!ConvertToFull(pszOldBase, achTemp, fDirectory))
|
|
return FALSE;
|
|
|
|
if (!ConvertToRelative(pszNewBase, achTemp, fDirectory, fVerify))
|
|
return FALSE;
|
|
|
|
lstrcpy(pszFilename, achTemp);
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ChangePathCase
|
|
|
|
PURPOSE: Changes path to lower case, and filename to upper case
|
|
|
|
PARAMETERS:
|
|
pszPath
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
10-Feb-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void STDCALL ChangePathCase(PSTR pszPath)
|
|
{
|
|
PSTR psz = StrRChr(pszPath, CH_BACKSLASH, _fDBCSSystem);
|
|
if (psz) {
|
|
*psz = '\0';
|
|
AnsiLower(pszPath);
|
|
AnsiUpper(psz + 1);
|
|
*psz = CH_BACKSLASH;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: FillTableFromList
|
|
|
|
PURPOSE: Fill a CTable from a list box
|
|
|
|
PARAMETERS:
|
|
pptbl address of the table
|
|
plistbox
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
The table may be created or deleted depending on whether there are
|
|
any items in the list box and whether the table already exists.
|
|
|
|
MODIFICATION DATES:
|
|
10-Feb-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void STDCALL FillTableFromList(CTable** pptbl, CListBox* plistbox)
|
|
{
|
|
|
|
// ptbl is purely for our debugging convenience -- we could just use *pptbl
|
|
|
|
CTable* ptbl;
|
|
int citems = plistbox->GetCount();
|
|
|
|
if (!*pptbl) {
|
|
if (!citems)
|
|
return; // no table, no items
|
|
|
|
*pptbl = new CTable();
|
|
ptbl = *pptbl;
|
|
}
|
|
else {
|
|
if (!citems) { // no items, so delete table
|
|
delete *pptbl;
|
|
*pptbl = NULL;
|
|
return;
|
|
}
|
|
ptbl = *pptbl;
|
|
ptbl->Empty();
|
|
}
|
|
|
|
CString cszBuf;
|
|
for (int i = 0; i < citems; i++) {
|
|
plistbox->GetText(i, cszBuf);
|
|
if (!cszBuf.IsEmpty())
|
|
ptbl->AddString(cszBuf);
|
|
}
|
|
|
|
}
|
|
|
|
void STDCALL FillListFromTable(CTable* ptbl, CListBox* plistbox, BOOL fRedraw)
|
|
{
|
|
if (fRedraw)
|
|
plistbox->SendMessage(WM_SETREDRAW, FALSE, 0);
|
|
|
|
for (int pos = 1; pos <= ptbl->CountStrings(); pos++)
|
|
plistbox->AddString(ptbl->GetPointer(pos));
|
|
|
|
if (fRedraw)
|
|
plistbox->SendMessage(WM_SETREDRAW, TRUE, 0);
|
|
}
|
|
|
|
static CStr* g_cszCaption;
|
|
static BOOL g_fSkipShell = FALSE;
|
|
|
|
typedef UINT (CALLBACK* COMMDLGPROC)(HWND, UINT, UINT, LONG);
|
|
|
|
// SetupBrowseDirectory - Browses for a folder and returns its
|
|
// path relative to the specified base file.
|
|
// Returns TRUE on Ok, FALSE on Cancel.
|
|
// idsCaption - caption to use for browse dialog (used for
|
|
// common dialog implementation only)
|
|
// idsDescription - descriptive/instructional text to display
|
|
// in browse dialog (used for shell implementation only)
|
|
// fSaveDirectory - if TRUE, save/restore current directory
|
|
// pszNewPath - buffer to receive relative path (must be
|
|
// greater than or equal to MAX_PATH bytes in size)
|
|
// hwndOwner - handle of owner window
|
|
// pszBaseFile - base filename (path is relative to this)
|
|
// pszOldFile - matching file types (e.g.; "*.foo;*.bar")
|
|
// idsError - error to display if the base folder is selected;
|
|
// specify zero if the base folder is valid.
|
|
BOOL STDCALL SetupBrowseDirectory(UINT idsCaption, UINT idsDescription,
|
|
BOOL fSaveDirectory, PSTR pszNewPath, HWND hwndOwner, PCSTR pszBaseFile,
|
|
PCSTR pszOldFile, UINT idsError)
|
|
{
|
|
// Assume we'll have to use the commdlg implementation.
|
|
BOOL fUseCommdlg = TRUE;
|
|
BOOL fResult;
|
|
|
|
char szOldPath[MAX_PATH];
|
|
char szSrcPath[MAX_PATH];
|
|
|
|
// Try to load the shell DLL if we haven't already failed.
|
|
if (!g_fSkipShell) {
|
|
|
|
// Assume SHBrowseForFolder is not implemented until our
|
|
// BrowseCallbackProc is called.
|
|
g_fSkipShell = TRUE;
|
|
|
|
// Try to run-time link to shell functions.
|
|
HINSTANCE hinstShellLib = LoadLibrary("SHELL32.DLL");
|
|
if (hinstShellLib) {
|
|
PFN_SHBrowseForFolder pfnSHBrowseForFolder =
|
|
(PFN_SHBrowseForFolder) GetProcAddress(
|
|
hinstShellLib, "SHBrowseForFolder"
|
|
);
|
|
PFN_SHGetPathFromIDList pfnSHGetPathFromIDList =
|
|
(PFN_SHGetPathFromIDList) GetProcAddress(
|
|
hinstShellLib, "SHGetPathFromIDList"
|
|
);
|
|
PFN_SHGetSpecialFolderLocation pfnSHGetSpecialFolderLocation =
|
|
(PFN_SHGetSpecialFolderLocation) GetProcAddress(
|
|
hinstShellLib, "SHGetSpecialFolderLocation"
|
|
);
|
|
PFN_SHGetMalloc pfnSHGetMalloc =
|
|
(PFN_SHGetMalloc) GetProcAddress(
|
|
hinstShellLib, "SHGetMalloc"
|
|
);
|
|
|
|
// If we linked Ok, try to browse.
|
|
if (pfnSHBrowseForFolder &&
|
|
pfnSHGetPathFromIDList &&
|
|
pfnSHGetSpecialFolderLocation &&
|
|
pfnSHGetMalloc) {
|
|
LPMALLOC pMalloc = NULL;
|
|
LPITEMIDLIST pidl = NULL;
|
|
BROWSEINFO bi;
|
|
|
|
// Get the shell's IMalloc interface.
|
|
if (!SUCCEEDED((*pfnSHGetMalloc)(&pMalloc)) || !pMalloc)
|
|
goto sh_fail;
|
|
|
|
// Display the browse dialog box.
|
|
g_cszCaption = new CStr(idsDescription);
|
|
bi.hwndOwner = hwndOwner;
|
|
bi.pidlRoot = NULL; // desktop (namespace root)
|
|
bi.pszDisplayName = NULL;
|
|
bi.lpszTitle = g_cszCaption->psz;
|
|
bi.ulFlags = BIF_RETURNONLYFSDIRS;
|
|
bi.lpfn = BrowseCallbackProc;
|
|
bi.lParam = (LPARAM) pszBaseFile;
|
|
|
|
if (typeTcard == TCARD_BITMAPS)
|
|
CallTcard(IDH_TCARD_BITMAPS_LOCATION);
|
|
|
|
pidl = (*pfnSHBrowseForFolder)(&bi);
|
|
|
|
// Validate the PIDL and convert it to a relative path.
|
|
if (pidl && (*pfnSHGetPathFromIDList)(pidl, pszNewPath)) {
|
|
ConvertToRelative(pszBaseFile, pszNewPath, TRUE);
|
|
fResult = TRUE;
|
|
}
|
|
else
|
|
fResult = FALSE;
|
|
|
|
// Clean up (jump down here on error).
|
|
sh_fail:
|
|
if (pMalloc) {
|
|
if (pidl)
|
|
pMalloc->Free(pidl);
|
|
pMalloc->Release();
|
|
}
|
|
}
|
|
FreeLibrary(hinstShellLib);
|
|
}
|
|
}
|
|
|
|
// If SHBrowseForFolder is not available, use common dialog.
|
|
if (g_fSkipShell) {
|
|
GetCurrentDirectory(MAX_PATH, szSrcPath);
|
|
if (fSaveDirectory)
|
|
lstrcpy(szOldPath, szSrcPath);
|
|
|
|
OPENFILENAME of;
|
|
char szFile[MAX_PATH];
|
|
|
|
memset(&of, 0, sizeof(of));
|
|
|
|
g_cszCaption = new CStr(idsDescription);
|
|
|
|
of.lStructSize = sizeof(OPENFILENAME);
|
|
of.hwndOwner = hwndOwner;
|
|
of.lpstrInitialDir = szSrcPath;
|
|
of.Flags = OFN_ENABLEHOOK | OFN_ENABLETEMPLATE;
|
|
strcpy(szFile, (pszOldFile ? pszOldFile : "*.*"));
|
|
of.lpstrFile = szFile;
|
|
of.nMaxFile = sizeof(szFile);
|
|
|
|
// Add hook procedure
|
|
of.hInstance = AfxGetInstanceHandle();
|
|
of.lpfnHook = (COMMDLGPROC) BrowseDlgProc;
|
|
of.lpTemplateName = MAKEINTRESOURCE(IDD_PROJECTBROWSEDIRS);
|
|
|
|
if (typeTcard == TCARD_BITMAPS)
|
|
CallTcard(IDH_TCARD_BITMAPS_LOCATION);
|
|
|
|
fResult = GetOpenFileName((OPENFILENAME FAR *) &of);
|
|
|
|
GetCurrentDirectory(MAX_PATH, pszNewPath);
|
|
|
|
ConvertToRelative(pszBaseFile, pszNewPath, TRUE);
|
|
|
|
// Restore the previous directory if specified.
|
|
if (fSaveDirectory)
|
|
ChangePath(szOldPath);
|
|
}
|
|
|
|
// Fail if the base folder is specified and idsError != 0.
|
|
if (fResult && idsError &&
|
|
*pszNewPath == '.' && pszNewPath[1] == '\0') {
|
|
AfxMessageBox(idsError);
|
|
return FALSE;
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
#ifndef BFFM_SETSELECTION
|
|
#define BFFM_SETSELECTION (WM_USER + 102)
|
|
#endif
|
|
|
|
static int BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
|
{
|
|
// lpData is pszBaseFile
|
|
if (uMsg == BFFM_INITIALIZED) {
|
|
g_fSkipShell = FALSE;
|
|
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL STDCALL BrowseDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
char szBuf[MAX_PATH];
|
|
|
|
switch (msg) {
|
|
case WM_INITDIALOG:
|
|
SetWindowText(hwndDlg, g_cszCaption->psz);
|
|
SetChicagoDialogStyles(hwndDlg, FALSE);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch (wParam) {
|
|
case IDOK:
|
|
GetWindowText(GetDlgItem(hwndDlg, IDEDIT_DIR_NAME), szBuf,
|
|
sizeof(szBuf));
|
|
|
|
/*
|
|
* Three dots means that common dialog is supplying
|
|
* the directory, in which case the current directory is
|
|
* what we really want (it won't have the three dots).
|
|
* Avoid the tempatition to always do this, because the
|
|
* user could also have entered a path name which would
|
|
* be different then the current directory.
|
|
*/
|
|
|
|
if (strstr(szBuf, "..."))
|
|
GetCurrentDirectory(sizeof(szBuf), szBuf);
|
|
|
|
if (!ChangePath(szBuf)) {
|
|
MsgBox(IDS_INVALID_DIRECTORY, MB_OK);
|
|
break;
|
|
}
|
|
EndDialog(hwndDlg, TRUE);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// ChangePath - Changes to the specified drive and directory.
|
|
// Returns TRUE if successful, FALSE otherwise.
|
|
// pszPath - path to change to
|
|
//
|
|
// Modified:
|
|
// 2/28/95 (niklasb) - no longer truncates filename at first
|
|
// space character because long filenames may contain
|
|
// spaces (fixes bug 18907).
|
|
static BOOL STDCALL ChangePath(PCSTR pszPath)
|
|
{
|
|
if (pszPath == NULL || !*pszPath)
|
|
return FALSE;
|
|
|
|
// Change the path unless we have something like "c:"
|
|
if (pszPath[2] != '\0' || pszPath[1] != ':') {
|
|
if (_chdir(pszPath) != 0)
|
|
return FALSE;
|
|
}
|
|
|
|
// Change the drive (if a drive was specified)
|
|
if (pszPath[1] == ':') { // was a drive letter specified?
|
|
if (_chdrive(tolower(pszPath[0]) - ('a' - 1)) != 0)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: AddTabbedComment
|
|
|
|
PURPOSE: Given a CString, add spaces to bring it to be equivalent
|
|
to two tabs and a semi-colon
|
|
|
|
PARAMETERS:
|
|
csz
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
14-Feb-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static char const txtSpaced[] = " ; ";
|
|
|
|
void STDCALL AddTabbedComment(CString& csz)
|
|
{
|
|
PSTR psz = _strdup(csz);
|
|
SzTrimSz(psz);
|
|
csz = psz;
|
|
free(psz);
|
|
|
|
char szSpace[9];
|
|
int cSpaces = csz.GetLength() % 8;
|
|
|
|
for (int i = 0; i < cSpaces; i++)
|
|
szSpace[i] = ' ';
|
|
szSpace[i] = '\0';
|
|
csz += szSpace;
|
|
csz += txtSpaced;
|
|
}
|
|
|
|
PSTR STDCALL AddTabbedComment(PSTR psz)
|
|
{
|
|
int cch = lstrlen(psz);
|
|
int cSpaces = 8 + cch % 8;
|
|
|
|
for (psz += cch; cSpaces; cSpaces--)
|
|
*psz++ = ' ';
|
|
|
|
*psz = ';';
|
|
psz[1] = ' ';
|
|
psz[2] = '\0';
|
|
|
|
return psz + 2;
|
|
}
|
|
|
|
void STDCALL RemoveListItem(CListBox* plistbox)
|
|
{
|
|
int cursel;
|
|
if ((cursel = plistbox->GetCurSel()) != LB_ERR) {
|
|
|
|
// Delete current selection, and select the item below it
|
|
|
|
plistbox->DeleteString(cursel);
|
|
if (cursel < plistbox->GetCount())
|
|
plistbox->SetCurSel(cursel);
|
|
else if (cursel > 0)
|
|
plistbox->SetCurSel(--cursel);
|
|
else if (plistbox->GetCount())
|
|
plistbox->SetCurSel(0);
|
|
}
|
|
}
|
|
|
|
char szParentString[512];
|
|
void STDCALL SendStringToParent(PCSTR pszString)
|
|
{
|
|
DBWIN(pszString);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ProcessHmkFile
|
|
|
|
PURPOSE: Read a .HMK file into the global ptblHpjFiles table
|
|
|
|
PARAMETERS:
|
|
pszFile
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
An .HMK file contains a list of .HPJ files to build.
|
|
|
|
MODIFICATION DATES:
|
|
17-Mar-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void STDCALL ProcessHmkFile(PCSTR pszFile)
|
|
{
|
|
fTrackErrors = TRUE;
|
|
if (fMinimizeWhileCompiling)
|
|
::SendMessage(theApp.m_pMainWnd->m_hWnd, WMP_AUTO_MINIMIZE, 0, 0);
|
|
CInput input(pszFile);
|
|
if (!input.fInitialized) {
|
|
CString cstr;
|
|
AfxFormatString1(cstr, IDS_CANT_OPEN, pszFile);
|
|
AfxMessageBox(cstr);
|
|
return;
|
|
}
|
|
char szFile[_MAX_PATH];
|
|
while (input.getline(szFile)) {
|
|
PSTR psz = StrChr(szFile, ';', _fDBCSSystem);
|
|
if (psz)
|
|
*psz = '\0';
|
|
SzTrimSz(szFile);
|
|
if (szFile[0]) {
|
|
if (!ptblHpjFiles)
|
|
ptblHpjFiles = new CTable;
|
|
ptblHpjFiles->AddString(szFile);
|
|
}
|
|
}
|
|
ChangeDirectory(pszFile);
|
|
}
|
|
|
|
void STDCALL InitializeSharedMemory(void)
|
|
{
|
|
hfShare = CreateFileMapping((HANDLE) -1, NULL, PAGE_READWRITE, 0,
|
|
MAX_PASS_STRING, txtSharedMem);
|
|
ConfirmOrDie(hfShare);
|
|
pszMap = (PSTR) MapViewOfFile(hfShare, FILE_MAP_READ | FILE_MAP_WRITE,
|
|
0, 0, 0);
|
|
ASSERT(pszMap);
|
|
}
|
|
|
|
#ifndef DS_CONTEXTHELP
|
|
#define DS_CONTEXTHELP 0x2000L // ;Internal 4.0
|
|
#endif
|
|
|
|
BOOL STDCALL SetupExecBuffer(PSTR pszBuf)
|
|
{
|
|
if (fMinimizeWhileCompiling)
|
|
strcpy(pszBuf, "-nga "); // no grinder window
|
|
else {
|
|
if (ptblHpjFiles && ptblHpjFiles->GetPosition() <
|
|
ptblHpjFiles->CountStrings())
|
|
strcpy(pszBuf, "-na "); // no grinder window
|
|
else
|
|
*pszBuf = '\0';
|
|
}
|
|
if (fNoCompress)
|
|
strcat(pszBuf, "-nc ");
|
|
if (fRunWinHelp)
|
|
strcat(pszBuf, "-r ");
|
|
if (fAddSource)
|
|
strcat(pszBuf, "-a ");
|
|
|
|
if (ptblHpjFiles && !ptblHpjFiles->GetString(pszBuf + strlen(pszBuf))) {
|
|
delete ptblHpjFiles;
|
|
ptblHpjFiles = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SetChicagoDialogStyles
|
|
|
|
PURPOSE: Assumes hfontSmall and CBroadCastChildren class
|
|
|
|
PARAMETERS:
|
|
hwnd
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
06-Jul-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
#ifndef DS_CONTEXTHELP
|
|
#define DS_CONTEXTHELP 0x2000L // Chicago style
|
|
#endif
|
|
|
|
static BOOL __stdcall EnumFontProc(HWND hwnd, LPARAM lval);
|
|
|
|
void STDCALL SetChicagoDialogStyles(HWND hwnd, BOOL fCsHelp)
|
|
{
|
|
EnumChildWindows(hwnd, (WNDENUMPROC) EnumFontProc, 0);
|
|
}
|
|
|
|
static BOOL __stdcall EnumFontProc(HWND hwnd, LPARAM lval)
|
|
{
|
|
/*
|
|
* We assume that any control with a -1 id value doesn't care about
|
|
* what font we use for input, so we use an ANSI charset version of
|
|
* MS Sans Serif.
|
|
*/
|
|
|
|
SendMessage(hwnd, WM_SETFONT,
|
|
(WPARAM) ((GetDlgCtrlID(hwnd) == -1) ? hfontSansSerif : hfontSmall), FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
typedef struct {
|
|
BYTE charset;
|
|
PCSTR pszName;
|
|
} CHARSET_NAMES;
|
|
|
|
const CHARSET_NAMES aszCharSets[] = {
|
|
{ 0, "ANSI" },
|
|
{ 1, "DEFAULT" },
|
|
{ 2, "SYMBOL" },
|
|
{ 77, "MAC" },
|
|
{ 128, "SHIFTJIS" },
|
|
{ 129, "HANGEUL" },
|
|
{ 134, "GB2312" },
|
|
{ 136, "CHINESEBIG5" },
|
|
{ 161, "GREEK" },
|
|
{ 162, "TURKISH" },
|
|
{ 177, "HEBREW" },
|
|
{ 178, "ARABIC Simplified" },
|
|
{ 179, "ARABIC Traditional" },
|
|
{ 179, "ARABIC User" },
|
|
{ 186, "BALTIC" },
|
|
{ 204, "RUSSIAN" },
|
|
{ 222, "THAI" },
|
|
{ 238, "EASTEUROPE" },
|
|
{ 254, "PC437" },
|
|
{ 255, "OEM" },
|
|
|
|
{ 0, NULL }
|
|
};
|
|
|
|
PCSTR STDCALL ConvertCharsetToString(BYTE charset)
|
|
{
|
|
for (int i = 0; aszCharSets[i].pszName; i++) {
|
|
if (aszCharSets[i].charset == charset)
|
|
return aszCharSets[i].pszName;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
BYTE STDCALL ConvertStringToCharset(PCSTR pszName)
|
|
{
|
|
if (isdigit(*pszName))
|
|
return (BYTE) atoi(pszName);
|
|
|
|
for (int i = 0; aszCharSets[i].pszName; i++) {
|
|
if (_stricmp(aszCharSets[i].pszName, pszName) == 0)
|
|
return aszCharSets[i].charset;
|
|
}
|
|
return ANSI_CHARSET;
|
|
}
|
|
|
|
void STDCALL AddCharsetNames(CComboBox* pcombo)
|
|
{
|
|
for (int i = 0; aszCharSets[i].pszName; i++) {
|
|
int iItem = pcombo->AddString(aszCharSets[i].pszName);
|
|
pcombo->SetItemData(iItem, aszCharSets[i].charset);
|
|
}
|
|
}
|
|
|
|
BOOL STDCALL SelectCharset(CComboBox* pcombo, BYTE charset)
|
|
{
|
|
for (int i = 0; aszCharSets[i].pszName; i++) {
|
|
if (aszCharSets[i].charset == charset) {
|
|
pcombo->SelectString(-1, aszCharSets[i].pszName);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void STDCALL AddFontNames(CComboBox* pcombo)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
ASSERT(hdc);
|
|
|
|
EnumFonts(hdc, NULL, EnumFontFamProc, (LPARAM) pcombo);
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
static int CALLBACK EnumFontFamProc(const LOGFONT* lplf,
|
|
const TEXTMETRIC* lptm, DWORD FontType, LPARAM lParam)
|
|
{
|
|
((CComboBox*) lParam)->AddString(lplf->lfFaceName);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL STDCALL OurExec(PCSTR pszCmdLine, PCSTR pszFile)
|
|
{
|
|
STARTUPINFO si;
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.dwFlags = STARTF_FORCEOFFFEEDBACK; // so the cursor doesn't change
|
|
|
|
/*
|
|
* We add the quotes because the file might be in a directory whose
|
|
* name contains a space.
|
|
*/
|
|
|
|
char szFile[512];
|
|
#if 0
|
|
strcpy(szFile, "\"");
|
|
strcpy(szFile + 1, pszFile);
|
|
strcat(szFile, "\" ");
|
|
#else
|
|
strcpy(szFile, pszFile);
|
|
strcat(szFile, " ");
|
|
#endif
|
|
|
|
strcat(szFile, FirstNonSpace(pszCmdLine, _fDBCSSystem));
|
|
|
|
/*
|
|
* This nonsense is because on build 122, if you specify both the
|
|
* process and command line parameters, then the command line won't make
|
|
* it through. However, according to the spec, this will also fail if the
|
|
* help compiler is in a directory with a space in the directory name.
|
|
*/
|
|
|
|
return CreateProcess(NULL, szFile, NULL, NULL,
|
|
FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL,
|
|
&si, &piHcRtf);
|
|
|
|
// return CreateProcess(pszFile, (PSTR) pszCmdLine, NULL, NULL,
|
|
// FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL,
|
|
// &si, &piHcRtf);
|
|
}
|
|
|
|
#ifndef _INC_CTYPE
|
|
#include <ctype.h>
|
|
#endif
|
|
|
|
void STDCALL RemoveTrailingSpaces(PSTR pszString)
|
|
{
|
|
if (!_fDBCSSystem) {
|
|
PSTR psz = pszString + strlen(pszString) - 1;
|
|
|
|
while (*psz == ' ' || *psz == '\t') {
|
|
if (--psz <= pszString) {
|
|
*pszString = '\0';
|
|
return;
|
|
}
|
|
}
|
|
psz[1] = '\0';
|
|
}
|
|
else {
|
|
|
|
/*
|
|
* Removing trailing spaces in DBCS requires stepping through
|
|
* from the beginning of the string since we can't know if a
|
|
* trailing space is really a space or the second byte of a lead
|
|
* byte.
|
|
*/
|
|
|
|
PSTR psz;
|
|
for (;;) {
|
|
psz = pszString;
|
|
while (*psz) {
|
|
if (*psz & 0x80 && IsDBCSLeadByte(*psz)) {
|
|
psz += 2;
|
|
if (!*psz)
|
|
return;
|
|
}
|
|
else
|
|
psz++;
|
|
}
|
|
psz--;
|
|
if (!isspace(*psz))
|
|
return;
|
|
while (isspace(*psz)) {
|
|
if (--psz <= pszString) {
|
|
*pszString = '\0';
|
|
return;
|
|
}
|
|
psz[1] = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* SzTrimSz( sz )
|
|
*
|
|
* Description:
|
|
* This function removes whitespaces (blank, tab, or newline) from
|
|
* the beginning and ending of the string sz.
|
|
*
|
|
* Arguments:
|
|
* sz -- string to be trimmed of whitespace.
|
|
*
|
|
* Returns:
|
|
* returns the pointer to the trimmed string.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
* This function changes the original string.
|
|
*-----------------------------------------------------------------------------*/
|
|
|
|
PSTR STDCALL SzTrimSz(PSTR pszOrg)
|
|
{
|
|
if (!pszOrg)
|
|
return NULL;
|
|
|
|
// Skip over leading whitespace
|
|
|
|
PSTR psz = FirstNonSpace(pszOrg, _fDBCSSystem);
|
|
if (psz != pszOrg)
|
|
strcpy(pszOrg, psz);
|
|
|
|
RemoveTrailingSpaces(pszOrg);
|
|
|
|
return pszOrg;
|
|
}
|
|
|
|
BOOL STDCALL CalcMinSize(POINT &ptRet, enum MINSIZE val, UINT uFlags)
|
|
{
|
|
static const POINT ptHPJ = { 100, 134 }; // HACK: hard-coded in dialog units
|
|
static const POINT ptCNT = { 190, 136 }; // HACK: hard-coded in dialog units
|
|
|
|
ASSERT(val == MS_HPJ || val == MS_CNT);
|
|
ASSERT((uFlags & ~MSF_MASK) == 0);
|
|
|
|
POINT pt = (val == MS_HPJ) ? ptHPJ : ptCNT;
|
|
DWORD dw = GetDialogBaseUnits();
|
|
pt.x = (pt.x * LOWORD(dw)) / 4;
|
|
pt.y = (pt.y * HIWORD(dw)) / 8;
|
|
|
|
if (uFlags & MSF_CAPTION)
|
|
pt.y += GetSystemMetrics(SM_CYCAPTION);
|
|
if (uFlags & MSF_BORDER) {
|
|
pt.x += 2 * GetSystemMetrics(SM_CXSIZEFRAME);
|
|
pt.y += 2 * GetSystemMetrics(SM_CYSIZEFRAME);
|
|
}
|
|
if (uFlags & MSF_MENU)
|
|
pt.y += GetSystemMetrics(SM_CYMENU) + 1;
|
|
if (uFlags & MSF_STATUS)
|
|
pt.y += HIWORD(dw); // HACK: aproximation based on system-font size
|
|
if (uFlags & MSF_TOOLBAR)
|
|
pt.y += 32; // HACK: hard-coded toolbar height
|
|
|
|
ptRet = pt;
|
|
return TRUE;
|
|
}
|
|
|
|
// HelpOverview - Displays the specified help topic in a Proc4 window.
|
|
// hwndOwner - handle of owner window or dialog box
|
|
// dwHelpID - help topic identifier
|
|
void STDCALL HelpOverview(HWND hwndOwner, DWORD dwHelpID)
|
|
{
|
|
PSTR pszFilename = (PSTR) lcMalloc(
|
|
lstrlen(AfxGetApp()->m_pszHelpFilePath)
|
|
+ 8
|
|
);
|
|
|
|
lstrcat(
|
|
lstrcpy(pszFilename, AfxGetApp()->m_pszHelpFilePath),
|
|
">Proc4"
|
|
);
|
|
|
|
::WinHelp(hwndOwner, pszFilename, HELP_CONTEXT, dwHelpID);
|
|
|
|
lcFree(pszFilename);
|
|
}
|
|
|
|
BOOL STDCALL IsValidFile(PCSTR pszFile, BOOL fConfirmReadOnly)
|
|
{
|
|
DWORD attribute = GetFileAttributes(pszFile);
|
|
if (attribute == HFILE_ERROR || attribute & FILE_ATTRIBUTE_DIRECTORY) {
|
|
CString cstr;
|
|
AfxFormatString1(cstr, IDS_CANT_OPEN, pszFile);
|
|
AfxMessageBox(cstr);
|
|
return FALSE;
|
|
}
|
|
|
|
// Find out if it is a read-only file, and if so, confirm opening it
|
|
|
|
if (fConfirmReadOnly && attribute & FILE_ATTRIBUTE_READONLY) {
|
|
CString cstr;
|
|
AfxFormatString1(cstr, IDS_READ_ONLY, pszFile);
|
|
if (AfxMessageBox(cstr, MB_YESNO, 0) == IDNO)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void STDCALL BevelRect(CDC& dc, RECT &rc, CPen* ppen1, CPen* ppen2)
|
|
{
|
|
CGdiObject* ppenSav = dc.SelectObject(ppen2);
|
|
|
|
dc.MoveTo(rc.right - 1, rc.top);
|
|
dc.LineTo(rc.right - 1, rc.bottom - 1);
|
|
dc.LineTo(rc.left, rc.bottom - 1);
|
|
|
|
dc.SelectObject(ppen1);
|
|
|
|
dc.LineTo(rc.left, rc.top);
|
|
dc.LineTo(rc.right - 1, rc.top);
|
|
|
|
dc.SelectObject(ppenSav);
|
|
}
|
|
|
|
void STDCALL BevelRect(CDC& dc, RECT &rc, RECT &rcExclude,
|
|
CPen* ppen1, CPen* ppen2)
|
|
{
|
|
CGdiObject* ppenSav = dc.SelectObject(ppen1);
|
|
dc.MoveTo(rcExclude.left - 2, rc.top);
|
|
dc.LineTo(rc.left, rc.top);
|
|
dc.LineTo(rc.left, rc.bottom - 1);
|
|
|
|
dc.SelectObject(ppen2);
|
|
dc.LineTo(rc.right - 1, rc.bottom - 1);
|
|
dc.LineTo(rc.right - 1, rc.top);
|
|
|
|
dc.SelectObject(ppen1);
|
|
dc.LineTo(rcExclude.right, rc.top);
|
|
|
|
dc.SelectObject(ppenSav);
|
|
}
|
|
|
|
void STDCALL SizeButtonToFit(CButton *pCtl, RECT& rcWnd)
|
|
{
|
|
// Get the window's text.
|
|
char sz[256];
|
|
int cch = pCtl->GetWindowText(sz, sizeof(sz));
|
|
|
|
// Get the text extent using the window's DC.
|
|
CDC *pdc = pCtl->GetDC();
|
|
pdc->SelectObject(pCtl->GetFont());
|
|
CSize siz = pdc->GetTextExtent(sz, cch);
|
|
pCtl->ReleaseDC(pdc);
|
|
|
|
// Add in space for the check mark, plus some extra.
|
|
int cx = LOWORD(GetMenuCheckMarkDimensions()) + siz.cx;
|
|
|
|
pCtl->GetWindowRect(&rcWnd);
|
|
if (rcWnd.right - rcWnd.left != cx) {
|
|
pCtl->SetWindowPos(NULL, 0, 0, cx, rcWnd.bottom - rcWnd.top,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
rcWnd.right = rcWnd.left + cx;
|
|
}
|
|
}
|