windows-nt/Source/XPSP1/NT/shell/osshell/accesory/mspaint/pbrush.cpp
2020-09-26 16:20:57 +08:00

1749 lines
53 KiB
C++

// pbrush.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "global.h"
#include "pbrush.h"
#include "pbrusfrm.h"
#include "ipframe.h"
#include "pbrusdoc.h"
#include "pbrusvw.h"
#include "bmobject.h"
#include "imgsuprt.h"
#include "imgwnd.h"
#include "imgwell.h"
#include "imgtools.h"
#include "ferr.h"
#include "cmpmsg.h"
#include "settings.h"
#include "undo.h"
#include "colorsrc.h"
#include "printres.h"
#include "loadimag.h"
#include "image.h"
#include <dlgs.h>
#include <shlobj.h>
#include "ofn.h"
#include "imaging.h"
// turn on visibility of GIF filter
#define GIF_SUPPORT
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
typedef BOOL(WINAPI* SHSPECPATH)(HWND,LPTSTR,int,BOOL);
#include "memtrace.h"
BOOL NEAR g_bShowAllFiles = FALSE;
#ifdef USE_MIRRORING
HINSTANCE ghInstGDI32=NULL;
DWORD WINAPI PBGetLayoutPreNT5(HDC hdc) {
return 0; // No mirroring on systems before NT5 or W98-CS
}
DWORD (WINAPI *PBGetLayout) (HDC hdc) = &PBGetLayoutInit;
DWORD WINAPI PBGetLayoutInit(HDC hdc) {
PBGetLayout = (DWORD (WINAPI *) (HDC hdc)) GetProcAddress(ghInstGDI32, "GetLayout");
if (!PBGetLayout) {
PBGetLayout = PBGetLayoutPreNT5;
}
return PBGetLayout(hdc);
}
//// RESetLayout - Set layout of DC
//
// Sets layout flags in an NT5/W98 or later DC.
DWORD WINAPI PBSetLayoutPreNT5(HDC hdc, DWORD dwLayout) {
return 0; // No mirroring on systems before NT5 or W98-CS
}
DWORD (WINAPI *PBSetLayout) (HDC hdc, DWORD dwLayout) = &PBSetLayoutInit;
DWORD WINAPI PBSetLayoutInit(HDC hdc, DWORD dwLayout) {
PBSetLayout = (DWORD (WINAPI *) (HDC hdc, DWORD dwLayout)) GetProcAddress(ghInstGDI32, "SetLayout");
if (!PBSetLayout) {
PBSetLayout = PBSetLayoutPreNT5;
}
return PBSetLayout(hdc, dwLayout);
}
#endif
/***************************************************************************/
// CPBApp
BEGIN_MESSAGE_MAP(CPBApp, CWinApp)
//{{AFX_MSG_MAP(CPBApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, OnFileNew)
ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
/***************************************************************************/
// CPBApp construction
CPBApp::CPBApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
#ifdef _DEBUG
m_bLogUndo = FALSE;
#endif
// This is the minimum amount of free memory we like to have
// (NOTE: These are overwritten by ReadInitFile)
m_dwLowMemoryBytes = 1024L * 2200;
m_nLowGdiPercent = 10;
m_nLowUserPercent = 10;
m_nFileErrorCause = 0; // from CFileException::m_cause
m_wEmergencyFlags = 0;
m_tickLastWarning = 0;
m_iCurrentUnits = 0;
m_bShowStatusbar = TRUE;
m_bShowThumbnail = FALSE;
m_bShowTextToolbar = TRUE;
m_bShowIconToolbar = TRUE;
m_bEmbedded = FALSE;
m_bLinked = FALSE;
m_bHidden = FALSE;
m_bActiveApp = FALSE;
m_bPenSystem = FALSE;
m_bPaletted = FALSE;
m_pPalette = NULL;
m_bPrintOnly = FALSE;
#ifdef PCX_SUPPORT
m_bPCXfile = FALSE;
#endif
m_rectFloatThumbnail.SetRectEmpty();
m_rectMargins.SetRect(MARGINS_DEFAULT, MARGINS_DEFAULT, MARGINS_DEFAULT,
MARGINS_DEFAULT);
m_bCenterHorizontally = TRUE;
m_bCenterVertically = TRUE;
m_bScaleFitTo = FALSE;
m_nAdjustToPercent = 100;
m_nFitToPagesWide = 1;
m_nFitToPagesTall = 1;
m_pwndInPlaceFrame = NULL;
m_hwndInPlaceApp = NULL;
m_pColors = NULL;
m_iColors = 0;
for (int index = 0; index < nSysBrushes + nOurBrushes; index++)
{
m_pbrSysColors[index] = NULL;
}
m_nFilters = 0;
m_guidFltType = NULL;
m_guidFltTypeUsed = WiaImgFmt_UNDEFINED;
m_nFilterInIdx = -1; // default is All Pictures
m_nFilterOutIdx = 1;
#ifdef USE_MIRRORING
ghInstGDI32 = GetModuleHandle(TEXT("gdi32.dll"));
#endif
}
/***************************************************************************/
// CPBApp destruction
CPBApp::~CPBApp()
{
delete [] m_guidFltType;
}
/***************************************************************************/
// The one and only CPBApp object
CPBApp theApp;
// This identifier was generated to be statistically unique for your app.
// You may change it if you prefer to choose a specific identifier.
const CLSID BASED_CODE CLSID_Paint =
{ 0xd3e34b21, 0x9d75, 0x101a, { 0x8c, 0x3d, 0x0, 0xaa, 0x0, 0x1a, 0x16, 0x52 } };
const CLSID BASED_CODE CLSID_PaintBrush =
{ 0x0003000A, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
/***************************************************************************/
// Stolen from WordPad
BOOL MatchOption(LPTSTR lpsz, LPTSTR lpszOption)
{
if (lpsz[0] == TEXT('-') || lpsz[0] == TEXT('/'))
{
lpsz++;
if (lstrcmpi(lpsz, lpszOption) == 0)
return TRUE;
}
return FALSE;
}
void CPBApp::ParseCommandLine()
{
BOOL bPrintTo = FALSE;
#ifdef UNICODE
int argcw;
LPWSTR *argvw;
argvw = CommandLineToArgvW (GetCommandLine (), &argcw);
#define ARGV argvw
#define ARGC argcw
#else
#define ARGV __argv
#define ARGC __argc
#endif
// start at 1 -- the first is the exe
for (int i=1; i< ARGC; i++)
{
if (MatchOption(ARGV[i], TEXT("pt")))
bPrintTo = m_bPrintOnly = TRUE;
else if (MatchOption(ARGV[i], TEXT("p")))
m_bPrintOnly = TRUE;
else if (MatchOption(ARGV[i], TEXT("wia")))
m_bWiaCallback = TRUE;
else if (m_bWiaCallback && m_strWiaDeviceId.IsEmpty())
m_strWiaDeviceId = ARGV[i];
else if (m_bWiaCallback && m_strWiaEventId.IsEmpty())
m_strWiaEventId = ARGV[i];
// else if (MatchOption(__argv[i], "t"))
// m_bForceTextMode = TRUE;
// else if (MatchOption(__argv[i], "Embedding"))
// m_bEmbedded = TRUE;
// else if (MatchOption(__argv[i], "Automation"))
// m_bEmbedded = TRUE;
else if (m_strDocName.IsEmpty())
m_strDocName = ARGV[i];
else if (bPrintTo && m_strPrinterName.IsEmpty())
m_strPrinterName = ARGV[i];
else if (bPrintTo && m_strDriverName.IsEmpty())
m_strDriverName = ARGV[i];
else if (bPrintTo && m_strPortName.IsEmpty())
m_strPortName = ARGV[i];
else
{
ASSERT(FALSE);
}
}
#ifdef UNICODE
GlobalFree (argvw);
#endif
}
void GetShortModuleFileName(HINSTANCE hInst, LPTSTR pszName, UINT uLen)
{
TCHAR szLongName[_MAX_PATH];
GetModuleFileName(hInst, szLongName, _MAX_PATH);
// APPCOMPAT GSPN sometimes fails on UNC's. Try this until that is tracked down
lstrcpyn(pszName, szLongName, uLen);
if (!GetShortPathName(szLongName, pszName, uLen))
{
GetLastError();
}
}
#if 0
// Pulling self-registration out. This is to be done once during setup only
void CPBApp::RegisterShell(CSingleDocTemplate *pDocTemplate)
{
const struct
{
LPCTSTR pszActionID;
LPCTSTR pszCommand;
} aActions[] =
{
{ TEXT("Open") , TEXT("\"%s\" \"%%1\"") },
{ TEXT("Print") , TEXT("\"%s\" /p \"%%1\"") },
{ TEXT("PrintTo"), TEXT("\"%s\" /pt \"%%1\" \"%%2\" \"%%3\" \"%%4\"") },
} ;
// We now need quotes around the file name, and MFC doesn't do this
CString strTypeID;
if (!pDocTemplate->GetDocString(strTypeID, CDocTemplate::regFileTypeId))
{
return;
}
strTypeID += TEXT("\\shell");
CRegKey rkShellInfo(HKEY_CLASSES_ROOT, strTypeID);
if (!(HKEY)rkShellInfo)
{
return;
}
TCHAR szFile[MAX_PATH];
::GetShortModuleFileName(AfxGetInstanceHandle(), szFile, ARRAYSIZE(szFile));
int i;
for (i=0; i<ARRAYSIZE(aActions); ++i)
{
CRegKey rkAction(rkShellInfo, aActions[i].pszActionID);
if (!(HKEY)rkAction)
{
continue;
}
// Note I do not set the name of the action; I will need to add this
// if I use anything other than "Open", "Print", or "PrintTo"
TCHAR szCommand[MAX_PATH + 80];
wsprintf(szCommand, aActions[i].pszCommand, szFile);
RegSetValue(rkAction, TEXT("command"), REG_SZ, szCommand, 0);
}
// Set the OLE server for PBrush objects
CRegKey rkPBrushInfo(HKEY_CLASSES_ROOT, TEXT("PBrush\\protocol\\StdFileEditing\\server"));
if ((HKEY)rkPBrushInfo)
{
RegSetValue(rkPBrushInfo, TEXT(""), REG_SZ, szFile, 0);
}
}
#endif
/***************************************************************************/
// CPBApp initialization
BOOL CPBApp::InitInstance()
{
SetRegistryKey( IDS_REGISTRY_PATH );
if (m_pszProfileName)
{
free((void*)m_pszProfileName);
}
m_pszProfileName = _tcsdup(TEXT("Paint"));
HDC hdc = ::GetDC( NULL );
ASSERT( hdc != NULL );
GetSystemSettings( CDC::FromHandle( hdc ) );
::ReleaseDC( NULL, hdc );
// Because we cannot LoadString when these strings are needed (in
// WarnUserOfEmergency) load them here in private member variables
// of CTheApp...
//
m_strEmergencyNoMem.LoadString ( IDS_ERROR_NOMEMORY );
m_strEmergencyLowMem.LoadString( IDS_ERROR_LOWMEMORY );
// Initialize OLE 2.0 libraries
if (! AfxOleInit())
{
AfxMessageBox( IDP_OLE_INIT_FAILED );
return FALSE;
}
// disable the annoying "server busy" dialog that pops up
// during long blocking WIA calls
COleMessageFilter* pFilter = AfxOleGetMessageFilter();
ASSERT( pFilter );
if (pFilter)
{
pFilter->EnableNotRespondingDialog(FALSE);
pFilter->EnableBusyDialog(FALSE);
}
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
// SetDialogBkColor(); // Set dialog background color to gray
LoadProfileSettings(); // Load standard INI file options (including MRU)
InitCustomData();
if (! g_pColors)
{
g_pColors = new CColors;
if (! g_pColors->GetColorCount())
{
theApp.SetMemoryEmergency();
return -1;
}
}
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate( ID_MAINFRAME,
RUNTIME_CLASS( CPBDoc ),
RUNTIME_CLASS( CPBFrame ), // main SDI frame window
RUNTIME_CLASS( CPBView ) );
pDocTemplate->SetServerInfo( IDR_SRVR_EMBEDDED, IDR_SRVR_INPLACE,
RUNTIME_CLASS( CInPlaceFrame ),
RUNTIME_CLASS( CPBView ) );
AddDocTemplate( pDocTemplate );
// Connect the COleTemplateServer to the document template.
// The COleTemplateServer creates new documents on behalf
// of requesting OLE containers by using information
// specified in the document template.
m_server.ConnectTemplate( CLSID_Paint, pDocTemplate, TRUE );
// Note: SDI applications register server objects only if /Embedding
// or /Automation is present on the command line.
#if 0
// Pulling self-registration out. This is to be done once during setup only
RegisterShell(pDocTemplate);
#endif
m_bEmbedded = RunEmbedded();
// Parse the command line to see if launched as OLE server
if (m_bEmbedded || RunAutomated())
{
// Register all OLE server (factories) as running. This enables the
// OLE 2.0 libraries to create objects from other applications.
COleTemplateServer::RegisterAll();
// Application was run with /Embedding or /Automation. Don't show the
// main window in this case.
return TRUE;
}
#if 0
// Pulling self-registration out. This is to be done once during setup only
// When a server application is launched stand-alone, it is a good idea
// to update the system registry in case it has been damaged.
m_server.UpdateRegistry( OAT_INPLACE_SERVER );
#endif
ParseCommandLine();
if (m_bWiaCallback)
{
USES_CONVERSION;
GUID guidEventId;
ASSERT(!m_strWiaEventId.IsEmpty() && !m_strWiaDeviceId.IsEmpty());
// check that we have received the WIA_EVENT_DEVICE_CONNECTED event and
// a valid device id. If not, we should exit before going any further
if (m_strWiaEventId.IsEmpty() ||
m_strWiaDeviceId.IsEmpty() ||
CLSIDFromString((LPOLESTR) T2COLE(m_strWiaEventId), &guidEventId) != S_OK ||
guidEventId != WIA_EVENT_DEVICE_CONNECTED)
{
return FALSE;
}
}
// simple command line parsing
if (m_strDocName.IsEmpty())
{
// create a new (empty) document
OnFileNew();
}
else
{
CString sExt = GetExtension( m_strDocName );
if (sExt.IsEmpty())
{
if (pDocTemplate->GetDocString( sExt, CDocTemplate::filterExt )
&& ! sExt.IsEmpty())
m_strDocName += sExt;
}
WIN32_FIND_DATA finddata;
HANDLE hFind = FindFirstFile(m_strDocName, &finddata);
if (hFind != INVALID_HANDLE_VALUE)
{
FindClose(hFind);
// Find the file name and replace it with the long file name
int iBS = m_strDocName.ReverseFind(TEXT('\\'));
if (iBS == -1)
{
iBS = m_strDocName.ReverseFind(TEXT(':'));
}
// HACK: Notice this is correct even if iBS==-1
++iBS;
// Resize the memory string
m_strDocName.GetBuffer(iBS);
m_strDocName.ReleaseBuffer(iBS);
m_strDocName += finddata.cFileName;
}
OpenDocumentFile( m_strDocName );
}
if (m_pMainWnd)
{
m_pMainWnd->DragAcceptFiles();
if (m_bWiaCallback)
{
// select the device and post a message to popup the WIA dialog
((CPBFrame*)m_pMainWnd)->m_pMgr->Select(m_strWiaDeviceId);
m_pMainWnd->PostMessage(WM_COMMAND, ID_FILE_SCAN_NEW, 0);
}
}
return TRUE;
}
/***************************************************************************/
int CPBApp::ExitInstance()
{
CustomExit(); // clean up in customiz
CleanupImages();
if (g_pColors)
{
delete g_pColors;
g_pColors = NULL;
}
if (m_fntStatus.m_hObject != NULL)
m_fntStatus.DeleteObject();
ResetSysBrushes();
CTracker::CleanUpTracker();
return CWinApp::ExitInstance();
}
/***************************************************************************/
void CPBApp::GetSystemSettings( CDC* pdc )
{
NONCLIENTMETRICS ncMetrics;
ncMetrics.cbSize = sizeof( NONCLIENTMETRICS );
if (SystemParametersInfo( SPI_GETNONCLIENTMETRICS,
sizeof( NONCLIENTMETRICS ),
&ncMetrics, 0 ))
{
if (m_fntStatus.m_hObject != NULL)
m_fntStatus.DeleteObject();
m_fntStatus.CreateFontIndirect( &ncMetrics.lfMenuFont );
}
ScreenDeviceInfo.iWidthinMM = pdc->GetDeviceCaps( HORZSIZE );
ScreenDeviceInfo.iHeightinMM = pdc->GetDeviceCaps( VERTSIZE );
ScreenDeviceInfo.iWidthinPels = pdc->GetDeviceCaps( HORZRES );
ScreenDeviceInfo.iHeightinPels = pdc->GetDeviceCaps( VERTRES );
ScreenDeviceInfo.ixPelsPerINCH = pdc->GetDeviceCaps( LOGPIXELSX );
ScreenDeviceInfo.iyPelsPerINCH = pdc->GetDeviceCaps( LOGPIXELSY );
/* get the pels per decameter '.1' rounded */
ScreenDeviceInfo.ixPelsPerDM = (int)(((((long)ScreenDeviceInfo.iWidthinPels * 1000L) / (long)ScreenDeviceInfo.iWidthinMM ) + 5L) / 10);
ScreenDeviceInfo.iyPelsPerDM = (int)(((((long)ScreenDeviceInfo.iHeightinPels * 1000L) / (long)ScreenDeviceInfo.iHeightinMM) + 5L) / 10);
ScreenDeviceInfo.ixPelsPerMM = (ScreenDeviceInfo.ixPelsPerDM + 50) / 100;
ScreenDeviceInfo.iyPelsPerMM = (ScreenDeviceInfo.iyPelsPerDM + 50) / 100;
ScreenDeviceInfo.iWidthinINCH = (int)(((long)ScreenDeviceInfo.iWidthinMM * 100L / 245L + 5L) / 10L); //24.5 mm to the inch
ScreenDeviceInfo.iHeightinINCH = (int)(((long)ScreenDeviceInfo.iHeightinMM * 100L / 245L + 5L) / 10L);
ScreenDeviceInfo.iBitsPixel = pdc->GetDeviceCaps( BITSPIXEL );
ScreenDeviceInfo.iPlanes = pdc->GetDeviceCaps( PLANES );
m_cxFrame = GetSystemMetrics( SM_CXFRAME );
m_cyFrame = GetSystemMetrics( SM_CYFRAME );
m_cxBorder = GetSystemMetrics( SM_CXBORDER );
m_cyBorder = GetSystemMetrics( SM_CYBORDER );
m_cyCaption = GetSystemMetrics( SM_CYSMCAPTION );
m_bPenSystem = GetSystemMetrics( SM_PENWINDOWS )? TRUE: FALSE;
m_bPaletted = (pdc->GetDeviceCaps( RASTERCAPS ) & RC_PALETTE);
m_bMonoDevice = ((ScreenDeviceInfo.iBitsPixel
* ScreenDeviceInfo.iPlanes) == 1);
SetErrorMode( SEM_NOOPENFILEERRORBOX );
}
/***************************************************************************/
CPoint CPBApp::CheckWindowPosition( CPoint ptPosition, CSize& sizeWindow )
{
CPoint ptNew = ptPosition;
sizeWindow.cx = max( sizeWindow.cx, 0 );
sizeWindow.cy = max( sizeWindow.cy, 0 );
if (sizeWindow.cx
&& sizeWindow.cy)
{
sizeWindow.cx = min( sizeWindow.cx, ScreenDeviceInfo.iWidthinPels );
sizeWindow.cy = min( sizeWindow.cy, ScreenDeviceInfo.iHeightinPels );
}
ptNew.x = max( ptNew.x, 0 );
ptNew.y = max( ptNew.y, 0 );
if (ptNew.x
&& ptNew.y)
{
if (ptNew.x >= ScreenDeviceInfo.iWidthinPels)
ptNew.x = ScreenDeviceInfo.iWidthinPels - sizeWindow.cx;
if (ptNew.y >= ScreenDeviceInfo.iHeightinPels)
ptNew.y = ScreenDeviceInfo.iHeightinPels - sizeWindow.cy;
}
return ptNew;
}
/***************************************************************************/
void CPBApp::WinHelp( DWORD dwData, UINT nCmd /* = HELP_CONTEXT */ )
{
// This app has been converted to use HtmlHelp. This is a safety to prevent someone
// from accidentally adding WinHelp calls for proceedural help
ASSERT( (nCmd != HELP_FINDER) && (nCmd != HELP_INDEX) && (nCmd != HELP_CONTENTS) );
CWinApp::WinHelp( dwData, nCmd );
}
/***************************************************************************/
BOOL CPBApp::OnIdle( LONG lCount )
{
if (m_bHidden)
return CWinApp::OnIdle( lCount );
if (! lCount)
{
if (CheckForEmergency())
{
TryToFreeMemory();
WarnUserOfEmergency();
}
if (m_nFileErrorCause != CFileException::none && m_pMainWnd)
{
CWnd* pWnd = AfxGetMainWnd();
pWnd->PostMessage( WM_USER + 1001 );
}
}
extern void IdleImage();
IdleImage();
return CWinApp::OnIdle(lCount) || lCount <= 4;
}
/***************************************************************************/
// Map a file error code to a string id.
struct FERRID
{
int ferr;
int ids;
} mpidsferr[] =
{
{ ferrIllformedGroup, IDS_ERROR_BOGUSFILE },
{ ferrReadFailed, IDS_ERROR_BOGUSFILE }, // error while reading a file or file corupt
{ ferrIllformedFile, IDS_ERROR_BOGUSFILE }, // not a valid palette file or zero length pcx file
{ ferrCantProcNewExeHdr, IDS_ERROR_EXE_HDR },
{ ferrCantProcOldExeHdr, IDS_ERROR_EXE_HDR },
{ ferrBadMagicNewExe, IDS_ERROR_EXE_HDRMZ },
{ ferrBadMagicOldExe, IDS_ERROR_EXE_HDRMZ },
{ ferrNotWindowsExe, IDS_ERROR_EXE_HDRNW },
{ ferrExeWinVer3, IDS_ERROR_EXE_HDRWV },
{ ferrNotValidRc, IDS_ERROR_NOTVALID_RC },
{ ferrNotValidExe, IDS_ERROR_NOTVALID_EXE },
{ ferrNotValidRes, IDS_ERROR_NOTVALID_RES },
{ ferrNotValidBmp, IDS_ERROR_NOTVALID_BMP }, // invalid bitmap
{ ferrNotValidIco, IDS_ERROR_NOTVALID_ICO },
{ ferrNotValidCur, IDS_ERROR_NOTVALID_CUR },
{ ferrRcInvalidExt, IDS_ERROR_RCPROB },
{ ferrFileAlreadyOpen, IDS_ERROR_COMPEX },
{ ferrExeTooLarge, IDS_ERROR_EXE_ALIGN },
{ ferrCantCopyOldToNew, IDS_ERROR_EXE_SAVE },
{ ferrReadLoad, IDS_ERROR_READLOAD },
{ ferrExeAlloc, IDS_ERROR_EXE_ALLOC },
{ ferrExeInUse, IDS_ERROR_EXE_INUSE },
{ ferrExeEmpty, IDS_ERROR_EXE_EMPTY },
{ ferrGroup, IDS_ERROR_GROUP },
{ ferrResSave, IDS_ERROR_RES_SAVE },
{ ferrSaveOverOpen, IDS_ERROR_SAVEOVEROPEN },
{ ferrSaveOverReadOnly, IDS_ERROR_SAVERO },
{ ferrCantDetermineType, IDS_ERROR_WHAAAT }, // bad pcx file
{ ferrSameName, IDS_ERROR_SAMENAME },
{ ferrSaveAborted, IDS_ERROR_SAVE_ABORTED },
{ ferrLooksLikeNtRes, IDS_ERROR_NT_RES },
{ ferrCantSaveReadOnly, IDS_ERROR_CANT_SAVERO }, // trying to save over a read only file
};
int IdsFromFerr(int ferr)
{
if (ferr < ferrFirst)
return IDS_ERROR_FILE + ferr; // was an exception cause
for (int i = 0; i < sizeof (mpidsferr) / sizeof (FERRID); i++)
{
if (mpidsferr[i].ferr == ferr)
return mpidsferr[i].ids;
}
ASSERT(FALSE); // You forgot to stick an entry in the above table!
return 0;
}
/***************************************************************************/
// Display a message box informing the user of a file related exception.
// The format of the box is something like:
//
// <file name>
// <operation failed>
// <reason>
//
// <file name> describes what file has the problem, <operation files>
// indicated what kind of thing failed (e.g. "Cannot save file"), and
// <reason> provides more information about why the operation failed
// (e.g. "Disk full").
//
// All the parameters must have been setup previously via a call to
// CWinApp::SetFileError().
//
void CPBApp::FileErrorMessageBox( void )
{
static BOOL bInUse = FALSE;
if (m_nFileErrorCause != CFileException::none && ! bInUse)
{
bInUse = TRUE;
CString strOperation;
VERIFY( strOperation.LoadString( m_uOperation ) );
CString strReason;
VERIFY( strReason.LoadString( IdsFromFerr( m_nFileErrorCause ) ) );
CString strFmt;
CString strMsg;
if (m_sLastFile.IsEmpty())
{
strFmt.LoadString(IDS_FORMATERR_NOFILE);
strMsg.Format(strFmt, (LPCTSTR)strOperation, (LPCTSTR)strReason);
}
else
{
strFmt.LoadString(IDS_FORMATERR_FILE);
strMsg.Format(strFmt, (LPCTSTR)m_sLastFile, (LPCTSTR)strOperation, (LPCTSTR)strReason);
}
AfxMessageBox( strMsg, MB_TASKMODAL | MB_OK | MB_ICONEXCLAMATION );
bInUse = FALSE;
}
m_nFileErrorCause = CFileException::none;
}
/***************************************************************************/
void CPBApp::SetFileError( UINT uOperation, int nCause, LPCTSTR lpszFile )
{
m_nFileErrorCause = nCause;
m_uOperation = uOperation;
if (lpszFile)
m_sLastFile = lpszFile;
}
/***************************************************************************/
// Memory/resource emergency handling functions
void CPBApp::SetMemoryEmergency(BOOL bFailed)
{
TRACE(TEXT("Memory emergency!\n"));
m_wEmergencyFlags |= memoryEmergency | warnEmergency;
if (bFailed)
m_wEmergencyFlags |= failedEmergency;
}
/***************************************************************************/
void CPBApp::SetGdiEmergency(BOOL bFailed)
{
TRACE(TEXT("GDI emergency!\n"));
m_wEmergencyFlags |= gdiEmergency | warnEmergency;
if (bFailed)
m_wEmergencyFlags |= failedEmergency;
}
/***************************************************************************/
void CPBApp::SetUserEmergency(BOOL bFailed)
{
TRACE(TEXT("USER emergency!\n"));
m_wEmergencyFlags |= userEmergency | warnEmergency;
if (bFailed)
m_wEmergencyFlags |= failedEmergency;
}
/***************************************************************************/
void CPBApp::WarnUserOfEmergency()
{
if ((m_wEmergencyFlags & warnEmergency) == 0)
{
// We have nothing to warn the user about!
return;
}
if ((m_wEmergencyFlags & failedEmergency) == 0 &&
GetTickCount() < m_tickLastWarning + ticksBetweenWarnings)
{
// We've warned the user recently, so keep quiet for now...
// The warning flag is cleared so we don't just warn the
// user after the delay is up unless another emergency
// occurs AFTER then...
m_wEmergencyFlags &= ~warnEmergency;
return;
}
// Don't go invoking message boxes when we're not the active app!
if (! m_bActiveApp)
return;
const TCHAR* szMsg = (m_wEmergencyFlags & failedEmergency) != 0 ?
m_strEmergencyNoMem : m_strEmergencyLowMem;
if (AfxMessageBox(szMsg, MB_TASKMODAL | MB_OK | MB_ICONSTOP) == IDOK)
{
m_wEmergencyFlags &= ~(warnEmergency | failedEmergency);
m_tickLastWarning = GetTickCount();
}
#ifdef _DEBUG
else
TRACE(TEXT("Emergency warning message box failed!\n"));
#endif
// Update status bar warning message...
if ( ::IsWindow( ((CPBFrame*)m_pMainWnd)->m_statBar.m_hWnd ) )
((CPBFrame*)m_pMainWnd)->m_statBar.Invalidate(FALSE);
}
/***************************************************************************/
void CPBApp::TryToFreeMemory()
{
// We are in a memory/resource emergency state! Add things to this
// function to flush caches and do anything else to free up memory
// we don't really need to be using right now...
if (m_wEmergencyFlags & memoryEmergency)
{
CPBDoc* pDoc = (CPBDoc*)((CFrameWnd*)AfxGetMainWnd())->GetActiveDocument();
if (pDoc && pDoc->m_pBitmapObj && ! pDoc->m_pBitmapObj->IsDirty()
&& pDoc->m_pBitmapObj->m_hThing)
pDoc->m_pBitmapObj->Free();
}
if (m_wEmergencyFlags & gdiEmergency)
{
// theUndo.Flush();
ResetSysBrushes();
}
}
/***************************************************************************/
// App command to run the dialog
void CPBApp::OnAppAbout()
{
CString sTitle;
CString sBrag;
HICON hIcon = LoadIcon( ID_MAINFRAME );
sTitle.LoadString( AFX_IDS_APP_TITLE );
sBrag.LoadString( IDS_PerContractSoDontChange );
ShellAbout( AfxGetMainWnd()->GetSafeHwnd(), sTitle, sBrag, hIcon );
if (hIcon != NULL)
::DestroyIcon( hIcon );
}
/***************************************************************************/
void CPBApp::SetDeviceHandles(HANDLE hDevNames, HANDLE hDevMode)
{
// The old ones should already be freed
m_hDevNames = hDevNames;
m_hDevMode = hDevMode;
}
/***************************************************************************/
#if 0
class CFileOpenSaveDlg : public CFileDialog
{
public:
BOOL m_bOpenFile;
CFileOpenSaveDlg( BOOL bOpenFileDialog );
virtual void OnLBSelChangedNotify( UINT nIDBox, UINT iCurSel, UINT nCode );
DECLARE_MESSAGE_MAP()
};
/***************************************************************************/
BEGIN_MESSAGE_MAP(CFileOpenSaveDlg, CFileDialog)
END_MESSAGE_MAP()
/***************************************************************************/
CFileOpenSaveDlg::CFileOpenSaveDlg( BOOL bOpenFileDialog )
:CFileDialog( bOpenFileDialog )
{
m_bOpenFile = bOpenFileDialog;
}
/***************************************************************************/
void CFileOpenSaveDlg::OnLBSelChangedNotify( UINT nIDBox, UINT iCurSel, UINT nCode )
{
if (! m_bOpenFile && iCurSel <= 5 && nIDBox == cmb1
&& nCode == CD_LBSELCHANGE)
{
// change in the file type
CWnd* pText = GetDlgItem( edt1 );
CWnd* pType = GetDlgItem( cmb1 );
CString sFname;
CString sDfltExt;
switch (iCurSel)
{
#ifdef PCX_SUPPORT
case 4:
sDfltExt.LoadString( IDS_EXTENSION_PCX );
break;
#endif
case 5:
sDfltExt.LoadString( IDS_EXTENSION_ICO );
break;
default:
sDfltExt.LoadString( IDS_EXTENSION_BMP );
break;
}
pText->GetWindowText( sFname );
if (sDfltExt.CompareNoCase( GetExtension( sFname ) ))
{
sFname = StripExtension( sFname ) + sDfltExt;
pText->SetWindowText( sFname );
}
}
}
#endif //0
/***************************************************************************/
extern BOOL AFXAPI AfxFullPath( LPTSTR lpszPathOut, LPCTSTR lpszFileIn );
CDocument*
CPBApp::OpenDocumentFile(
LPCTSTR lpszFileName
)
{
CancelToolMode(FALSE);
TCHAR szPath[_MAX_PATH];
AfxFullPath( szPath, lpszFileName );
return(m_pDocManager->OpenDocumentFile(szPath));
// CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
//
// ASSERT( pTemplate->IsKindOf( RUNTIME_CLASS( CDocTemplate ) ) );
//
// return pTemplate->OpenDocumentFile( szPath );
}
void CancelToolMode(BOOL bSelectionCommand)
{
if (bSelectionCommand)
{
// Check if a selection tool is the current one
if ((CImgTool::GetCurrentID() == IDMB_PICKTOOL)
|| (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL))
{
// Don't try canceling the mode, since the command works on a
// selection
return;
}
}
// Just select the current tool again to reset everything
CImgTool *pImgTool = CImgTool::GetCurrent();
if (pImgTool)
{
pImgTool->Select();
}
}
/***************************************************************************/
// CPBApp commands
void CPBApp::OnFileNew()
{
CancelToolMode(FALSE);
CWinApp::OnFileNew();
}
void CPBApp::OnFileOpen()
{
CancelToolMode(FALSE);
// prompt the user (with all document templates)
CString newName;
int iColor = 0;
if (! DoPromptFileName( newName, AFX_IDS_OPENFILE,
OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
TRUE, iColor, FALSE ))
return; // open cancelled
#ifdef PCX_SUPPORT
m_bPCXfile = (iColor == 4);
#endif
CPBDoc* pDoc = (CPBDoc*)((CFrameWnd*)AfxGetMainWnd())->GetActiveDocument();
// prompt to save the current document if it was modified
if (pDoc && pDoc->SaveModified())
{
pDoc->SetModifiedFlag(FALSE);
if (OpenDocumentFile( newName )==NULL)
{
// attempt to open a file failed, so make sure any new doc just
// created in the process gets destroyed
POSITION tPos = GetFirstDocTemplatePosition();
CDocTemplate* pTemplate = GetNextDocTemplate(tPos);
POSITION dPos = pTemplate->GetFirstDocPosition ();
CPBDoc *pDoc= (CPBDoc *)(pTemplate->GetNextDoc(dPos));
if (pDoc->m_pBitmapObjNew)
{
delete pDoc->m_pBitmapObjNew;
pDoc->m_pBitmapObjNew =NULL;
}
OnFileNew(); // then start anew...
}
}
}
/****************************************************************************/
// prompt for file name - used for open and save as
BOOL CPBApp::DoPromptFileName( CString& fileName, UINT nIDSTitle, DWORD lFlags,
BOOL bOpenFileDialog, int& iColors, BOOL bOnlyBmp )
{
COpenFileName dlgFile( bOpenFileDialog );
ASSERT(dlgFile.m_pofn);
if (!dlgFile.m_pofn)
return FALSE;
CString title;
VERIFY( title.LoadString( nIDSTitle ) );
lFlags |= OFN_EXPLORER;
if (!bOpenFileDialog)
lFlags |= OFN_OVERWRITEPROMPT;
dlgFile.m_pofn->Flags |= lFlags;
dlgFile.m_pofn->Flags &= ~OFN_SHOWHELP;
CString strFilter;
// CString strDefault;
CDocTemplate* pTemplate = NULL;
POSITION pos = m_pDocManager->GetFirstDocTemplatePosition();
if (pos != NULL)
pTemplate = m_pDocManager->GetNextDocTemplate(pos);
CString strFilterExt;
CString strFilterName;
CString strAllPictureFiles;
ASSERT(pTemplate != NULL);
pTemplate->GetDocString( strFilterExt , CDocTemplate::filterExt );
pTemplate->GetDocString( strFilterName, CDocTemplate::filterName );
ASSERT( strFilterExt[0] == TEXT('.') );
// set the default extension
// strDefault = ((const TCHAR*)strFilterExt) + 1; // skip the '.'
// dlgFile.m_pofn->nFilterIndex = iColors + 1; // 1 based number
dlgFile.m_pofn->lpstrDefExt = ((LPCTSTR)strFilterExt) + 1; // skip the '.'
if (bOpenFileDialog)
{
// add to filter
strFilter = strFilterName;
strFilter += _T('\0'); // next string please
strFilter += _T("*") + strFilterExt;
VERIFY(strFilterExt.LoadString(IDS_EXTENSION_DIB));
strFilter += _T(";*") + strFilterExt;
strAllPictureFiles += _T(";*") + strFilterExt;
VERIFY(strFilterExt.LoadString(IDS_EXTENSION_BMP));
strAllPictureFiles += _T(";*") + strFilterExt;
VERIFY(strFilterExt.LoadString(IDS_EXTENSION_RLE));
strFilter += _T(";*") + strFilterExt;
strFilter += _T('\0'); // next string please
dlgFile.m_pofn->nMaxCustFilter++;
}
else
{
for (int i = IDS_BMP_MONO; i <= IDS_BMP_TRUECOLOR; i++)
{
strFilterName.LoadString( i );
// add to filter
strFilter += strFilterName;
strFilter += _T('\0'); // next string please
strFilter += _T("*") + strFilterExt;
strFilter += _T('\0'); // next string please
dlgFile.m_pofn->nMaxCustFilter++;
}
}
// get a list of GDI+ codecs (if available)
Gdiplus::ImageCodecInfo *pCodecs = 0;
UINT nCodecs = 0;
if (bOpenFileDialog)
{
GetGdiplusDecoders(&nCodecs, &pCodecs);
}
else
{
GetGdiplusEncoders(&nCodecs, &pCodecs);
}
if (nCodecs && !bOnlyBmp)
{
delete [] m_guidFltType;
m_guidFltType = new GUID[nCodecs];
m_nFilters = 0;
for (UINT i = 0; i < nCodecs; ++i)
{
if (pCodecs[i].FormatID != WiaImgFmt_BMP &&
pCodecs[i].FormatID != WiaImgFmt_EMF &&
pCodecs[i].FormatID != WiaImgFmt_WMF) // GDI+ does not handle WMF/EMF well
{
m_guidFltType[m_nFilters++] = pCodecs[i].FormatID;
strFilter += pCodecs[i].FormatDescription;
strFilter += _T(" (");
strFilter += pCodecs[i].FilenameExtension;
strFilter += _T(')');
strFilter += _T('\0'); // next string please
strFilter += pCodecs[i].FilenameExtension;
strFilter += _T('\0'); // next string please
strAllPictureFiles += _T(';');
strAllPictureFiles += pCodecs[i].FilenameExtension;
dlgFile.m_pofn->nMaxCustFilter++;
}
}
LocalFree(pCodecs);
}
else
{
//
// get list of all installed filters and add those to the list...
//
delete [] m_guidFltType;
m_guidFltType = new GUID[16]; // max # of filters
TCHAR name[128];
TCHAR ext[sizeof("jpg;*.jpeg") + 1];
BOOL bImageAPI;
for (int i=0, j=0; !bOnlyBmp && GetInstalledFilters(bOpenFileDialog,
i, name, sizeof(name), ext, sizeof(ext), NULL, 0, bImageAPI); i++)
{
if (!bImageAPI)
{
continue;
}
if (ext[0] == 0 || name[0] == 0)
continue;
// if there are multiple extensions, take the first one...
PTSTR pComma = _tcschr(ext, _T(','));
if (pComma)
*pComma = 0;
PTSTR pSemiColon = _tcschr(ext, _T(';'));
if (pSemiColon)
*pSemiColon = 0;
PTSTR pSpace = _tcschr(ext, _T(' '));
if (pSpace)
*pSpace = 0;
if (lstrlen(ext) > 3)
continue;
// dont show these, we already handle these
if (lstrcmpi(ext,_T("bmp")) == 0 ||
lstrcmpi(ext,_T("dib")) == 0 ||
lstrcmpi(ext,_T("rle")) == 0)
continue;
#ifndef GIF_SUPPORT
if (lstrcmpi(ext, _T("gif") == 0)
{
continue;
}
#endif
#if 0 // only use known good filters
if (!g_bShowAllFiles &&
(GetKeyState(VK_SHIFT) & 0x8000) == 0 &&
lstrcmpi(ext,_T("pcx")) != 0)
continue;
#endif
// save a list of available filter types
if (lstrcmpi(ext,_T("gif")) == 0)
{
m_guidFltType[j++] = WiaImgFmt_GIF;
}
else if (lstrcmpi(ext,_T("jpg")) == 0)
{
m_guidFltType[j++] = WiaImgFmt_JPEG;
_tcscat (ext, _T(";*.jpeg"));
}
#ifdef SUPPORT_ALL_FILTERS
else if (lstrcmpi(ext,_T("png")) == 0)
{
#ifdef PNG_SUPPORT
m_guidFltType[j++] = WiaImgFmt_PNG;
#else
continue;
#endif // PNG_SUPPORT
}
else if (lstrcmpi(ext,_T("pcd")) == 0)
{
m_guidFltType[j++] = WiaImgFmt_PHOTOCD;
}
/*else if (lstrcmpi(ext,_T("pic")) == 0)
{
m_guidFltType[j++] = IFLT_PICT;
_tcscat(ext, _T(";*.pict"));
}
else if (lstrcmpi(ext,_T("tga")) == 0)
{
m_iflFltType[j++] = IFLT_TGA;
}*/
else if (lstrcmpi(ext,_T("tif")) == 0)
{
m_guidFltType[j++] = WiaImgFmt_TIFF;
_tcscat(ext, _T(";*.tiff"));
}
else
{
m_guidFltType[j++] = WiaImgFmt_UNDEFINED;
}
#else
else continue;
#endif
// add to filter
strFilter += name;
strFilter += _T(" ( *.");
strFilter += ext;
strFilter += _T(" )");
strFilter += _T('\0'); // next string please
strFilter += _T("*.");
strFilter += ext;
strFilter += _T('\0'); // next string please
strAllPictureFiles = strAllPictureFiles + _T(";*.")+ext;
dlgFile.m_pofn->nMaxCustFilter++;
}
}
if (!bOnlyBmp && bOpenFileDialog)
{
// append "All Picture Files" only if opening a file
VERIFY(strFilterName.LoadString(IDS_TYPE_ALLPICTURES));
strFilter+= strFilterName;
strFilter += _T('\0');
strFilter += strAllPictureFiles;
strFilter += _T('\0');
dlgFile.m_pofn->nMaxCustFilter++;
if (m_nFilterInIdx == -1)
{
m_nFilterInIdx = dlgFile.m_pofn->nMaxCustFilter;
}
// append the "*.*" filter only if "Open"ing a file
VERIFY( strFilterName.LoadString( IDS_TYPE_ALLFILES ) );
strFilter += strFilterName;
strFilter += _T('\0'); // next string please
strFilter += _T("*.*");
strFilter += _T('\0'); // last string
dlgFile.m_pofn->nMaxCustFilter++;
}
// prompt the user with the appropriate filter pre-selected
if (bOpenFileDialog)
{
dlgFile.m_pofn->nFilterIndex = m_nFilterInIdx;
}
else
{
DWORD dwIndex;
if (m_guidFltTypeUsed != WiaImgFmt_UNDEFINED &&
(dwIndex = GetFilterIndex(m_guidFltTypeUsed))) // has an export filter?
dlgFile.m_pofn->nFilterIndex = dwIndex + 4; // skip the first 4 BMP types
else if (m_nFilterOutIdx >= 4)
dlgFile.m_pofn->nFilterIndex = m_nFilterOutIdx;
else
dlgFile.m_pofn->nFilterIndex = iColors + 1; // 1 based number
}
dlgFile.m_pofn->lpstrFilter = strFilter;
dlgFile.m_pofn->hwndOwner = AfxGetMainWnd()->GetSafeHwnd();
dlgFile.m_pofn->hInstance = AfxGetResourceHandle();
dlgFile.m_pofn->lpstrTitle = title;
dlgFile.m_pofn->lpstrFile = fileName.GetBuffer(_MAX_PATH);
dlgFile.m_pofn->nMaxFile = _MAX_PATH;
TCHAR szInitPath[MAX_PATH];
::LoadString (GetModuleHandle (NULL), AFX_IDS_UNTITLED, szInitPath, MAX_PATH);
//
// Look in "My Documents" on NT 5, Win98, and later.
//
if (!theApp.GetLastFile() || !*(theApp.GetLastFile()))
{
static SHSPECPATH pfnSpecialPath = NULL;
if (!pfnSpecialPath)
{
#ifdef UNICODE
pfnSpecialPath = (SHSPECPATH)GetProcAddress (
GetModuleHandle(_T("shell32.dll")),
"SHGetSpecialFolderPathW");
#else
pfnSpecialPath = (SHSPECPATH)GetProcAddress (
GetModuleHandle(_T("shell32.dll")),
"SHGetSpecialFolderPathA");
#endif //UNICODE
}
if (pfnSpecialPath)
{
(pfnSpecialPath)(NULL, szInitPath, CSIDL_MYPICTURES, FALSE);
dlgFile.m_pofn->lpstrInitialDir = szInitPath;
}
}
BOOL bRet = dlgFile.DoModal() == IDOK? TRUE : FALSE;
fileName.ReleaseBuffer();
// keep track of the filter selected by the user
if (bOpenFileDialog)
m_nFilterInIdx = dlgFile.m_pofn->nFilterIndex;
else
m_nFilterOutIdx = dlgFile.m_pofn->nFilterIndex;
iColors = (int)dlgFile.m_pofn->nFilterIndex - 1;
CString sExt = dlgFile.m_pofn->lpstrFile + dlgFile.m_pofn->nFileExtension;
#ifdef ICO_SUPPORT
if (! bOpenFileDialog && dlgFile.m_pofn->nFileExtension)
// did the user try to sneak a icon extension past us
if (! sExt.CompareNoCase( ((const TCHAR *)strFilterExt) + 1 ))
iColors = 5;
#endif
return bRet;
}
DWORD CPBApp::GetFilterIndex( REFGUID guidFltType )
{
for (int i = 0; i < m_nFilters; i++)
if (m_guidFltType[i] == guidFltType)
return i+1;
return 0;
}
// fix the file extension based on export filter selected - used for save as
void CPBApp::FixExtension( CString& fileName, int iflFltType )
{
CString sDfltExt;
switch (iflFltType)
{
case IFLT_GIF:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_GIF ));
break;
case IFLT_JPEG:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_JPEG ));
break;
case IFLT_PCD:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_PCD ));
break;
case IFLT_PCX:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_PCX ));
break;
case IFLT_PICT:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_PICT ));
break;
#ifdef PNG_SUPPORT
case IFLT_PNG:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_PNG ));
break;
#endif // PNG_SUPPORT
case IFLT_TGA:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_TGA ));
break;
case IFLT_TIFF:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_TIFF ));
break;
case IFLT_UNKNOWN: // unknown or unsupported file type
default:
VERIFY(sDfltExt.LoadString( IDS_EXTENSION_BMP ));
break;
}
if (sDfltExt.CompareNoCase( GetExtension( (LPCTSTR)fileName ) ))
{
fileName = StripExtension( fileName ) + sDfltExt;
}
}
#if 0
// Pulling self-registration out. This is to be done once during setup only
/***************************************************************************/
// Mostly stolen from MFC
// I made no attempt to strip out stuff I do not actually use
// I just modified this so it used short module file name
//
//////////////////////////////////////////////////////////////////////////////
// data for UpdateRegistry functionality
// %1 - class ID
// %2 - class name
// %3 - executable path
// %4 - short type name
// %5 - long type name
// %6 - long application name
// %7 - icon index
static const TCHAR sz00[] = TEXT("%2\0") TEXT("%5");
static const TCHAR sz01[] = TEXT("%2\\CLSID\0") TEXT("%1");
static const TCHAR sz02[] = TEXT("%2\\Insertable\0") TEXT("");
static const TCHAR sz03[] = TEXT("%2\\protocol\\StdFileEditing\\verb\\0\0") TEXT("&Edit");
static const TCHAR sz04[] = TEXT("%2\\protocol\\StdFileEditing\\server\0") TEXT("%3");
static const TCHAR sz05[] = TEXT("CLSID\\%1\0") TEXT("%5");
static const TCHAR sz06[] = TEXT("CLSID\\%1\\ProgID\0") TEXT("%2");
#ifndef _USRDLL
static const TCHAR sz07[] = TEXT("CLSID\\%1\\InprocHandler32\0") TEXT("ole32.dll");
static const TCHAR sz08[] = TEXT("CLSID\\%1\\LocalServer32\0") TEXT("%3");
#else
static const TCHAR sz07[] = TEXT("\0") TEXT("");
static const TCHAR sz08[] = TEXT("CLSID\\%1\\InProcServer32\0") TEXT("%3");
#endif
static const TCHAR sz09[] = TEXT("CLSID\\%1\\Verb\\0\0") TEXT("&Edit,0,2");
static const TCHAR sz10[] = TEXT("CLSID\\%1\\Verb\\1\0") TEXT("&Open,0,2");
static const TCHAR sz11[] = TEXT("CLSID\\%1\\Insertable\0") TEXT("");
static const TCHAR sz12[] = TEXT("CLSID\\%1\\AuxUserType\\2\0") TEXT("%4");
static const TCHAR sz13[] = TEXT("CLSID\\%1\\AuxUserType\\3\0") TEXT("%6");
static const TCHAR sz14[] = TEXT("CLSID\\%1\\DefaultIcon\0") TEXT("%3,%7");
static const TCHAR sz15[] = TEXT("CLSID\\%1\\MiscStatus\0") TEXT("32");
// registration for OAT_INPLACE_SERVER
static const LPCTSTR rglpszInPlaceRegister[] =
{
sz00, sz02, sz03, sz05, sz09, sz10, sz11, sz12,
sz13, sz15, NULL
};
// registration for OAT_SERVER
static const LPCTSTR rglpszServerRegister[] =
{
sz00, sz02, sz03, sz05, sz09, sz11, sz12,
sz13, sz15, NULL
};
// overwrite entries for OAT_SERVER & OAT_INPLACE_SERVER
static const LPCTSTR rglpszServerOverwrite[] =
{
sz01, sz04, sz06, sz07, sz08, sz14, NULL
};
// registration for OAT_CONTAINER
static const LPCTSTR rglpszContainerRegister[] =
{
sz00, sz05, NULL
};
// overwrite entries for OAT_CONTAINER
static const LPCTSTR rglpszContainerOverwrite[] =
{
sz01, sz06, sz07, sz08, sz14, NULL
};
// registration for OAT_DISPATCH_OBJECT
static const LPCTSTR rglpszDispatchRegister[] =
{
sz00, sz05, NULL
};
// overwrite entries for OAT_CONTAINER
static const LPCTSTR rglpszDispatchOverwrite[] =
{
sz01, sz06, sz08, NULL
};
struct STANDARD_ENTRY
{
const LPCTSTR* rglpszRegister;
const LPCTSTR* rglpszOverwrite;
};
static const STANDARD_ENTRY rgStdEntries[] =
{
{ rglpszInPlaceRegister, rglpszServerOverwrite },
{ rglpszServerRegister, rglpszServerOverwrite },
{ rglpszContainerRegister, rglpszContainerOverwrite },
{ rglpszDispatchRegister, rglpszDispatchOverwrite }
};
/////////////////////////////////////////////////////////////////////////////
// Special registration for apps that wish not to use REGLOAD
BOOL AFXAPI PBOleRegisterServerClass(
REFCLSID clsid, LPCTSTR lpszClassName,
LPCTSTR lpszShortTypeName, LPCTSTR lpszLongTypeName,
OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister, LPCTSTR* rglpszOverwrite)
{
ASSERT(AfxIsValidString(lpszClassName));
ASSERT(AfxIsValidString(lpszShortTypeName));
ASSERT(*lpszShortTypeName != 0);
ASSERT(AfxIsValidString(lpszLongTypeName));
ASSERT(*lpszLongTypeName != 0);
ASSERT(nAppType == OAT_INPLACE_SERVER || nAppType == OAT_SERVER ||
nAppType == OAT_CONTAINER || nAppType == OAT_DISPATCH_OBJECT);
// use standard registration entries if non given
if (rglpszRegister == NULL)
rglpszRegister = (LPCTSTR*)rgStdEntries[nAppType].rglpszRegister;
if (rglpszOverwrite == NULL)
rglpszOverwrite = (LPCTSTR*)rgStdEntries[nAppType].rglpszOverwrite;
LPTSTR rglpszSymbols[7];
// 0 - class ID
// 1 - class name
// 2 - executable path
// 3 - short type name
// 4 - long type name
// 5 - long application name
// 6 - icon index
// convert the CLSID to a string
LPWSTR lpszClassID;
::StringFromCLSID(clsid, &lpszClassID);
if (lpszClassID == NULL)
{
TRACE0("Warning: StringFromCLSID failed in AfxOleRegisterServerName --\n");
TRACE0("\tperhaps AfxOleInit() has not been called.\n");
return FALSE;
}
#ifdef UNICODE
rglpszSymbols[0] = lpszClassID;
#else
int cc = WideCharToMultiByte (CP_ACP, 0, lpszClassID, -1,
(LPSTR)&rglpszSymbols[0], 0,
NULL, NULL);
rglpszSymbols[0] = (LPSTR)new char[cc];
WideCharToMultiByte (CP_ACP, 0, lpszClassID, -1,
rglpszSymbols[0], cc,
NULL, NULL);
#endif // UNICODE
rglpszSymbols[1] = (LPTSTR)lpszClassName;
// get path name to server
TCHAR szPathName[_MAX_PATH];
LPTSTR pszTemp = szPathName;
::GetShortModuleFileName(AfxGetInstanceHandle(), pszTemp, _MAX_PATH);
rglpszSymbols[2] = szPathName;
// fill in rest of symbols
rglpszSymbols[3] = (LPTSTR)lpszShortTypeName;
rglpszSymbols[4] = (LPTSTR)lpszLongTypeName;
rglpszSymbols[5] = (LPTSTR)AfxGetAppName(); // will usually be long, readable name
LPCTSTR lpszIconIndex;
HICON hIcon = ExtractIcon(AfxGetInstanceHandle(), szPathName, 1);
if (hIcon != NULL)
{
lpszIconIndex = TEXT("1");
DestroyIcon(hIcon);
}
else
{
lpszIconIndex = TEXT("0");
}
rglpszSymbols[6] = (LPTSTR)lpszIconIndex;
// update the registry with helper function
BOOL bResult;
bResult = AfxOleRegisterHelper(rglpszRegister, (LPCTSTR*)rglpszSymbols, 7, FALSE);
if (bResult && rglpszOverwrite != NULL)
bResult = AfxOleRegisterHelper(rglpszOverwrite, (LPCTSTR*)rglpszSymbols, 7, TRUE);
// free memory for class ID
ASSERT(lpszClassID != NULL);
AfxFreeTaskMem(lpszClassID);
#ifndef UNICODE
delete[](LPSTR)rglpszSymbols[0];
#endif
return bResult;
}
void CPBTemplateServer::UpdateRegistry(OLE_APPTYPE nAppType,
LPCTSTR* rglpszRegister, LPCTSTR* rglpszOverwrite)
{
ASSERT(m_pDocTemplate != NULL);
// get registration info from doc template string
CString strServerName;
CString strLocalServerName;
CString strLocalShortName;
if (!m_pDocTemplate->GetDocString(strServerName,
CDocTemplate::regFileTypeId) || strServerName.IsEmpty())
{
TRACE0("Error: not enough information in DocTemplate to register OLE server.\n");
return;
}
if (!m_pDocTemplate->GetDocString(strLocalServerName,
CDocTemplate::regFileTypeName))
strLocalServerName = strServerName; // use non-localized name
if (!m_pDocTemplate->GetDocString(strLocalShortName,
CDocTemplate::fileNewName))
strLocalShortName = strLocalServerName; // use long name
ASSERT(strServerName.Find(TEXT(' ')) == -1); // no spaces allowed
// place entries in system registry
if (!PBOleRegisterServerClass(m_clsid, strServerName, strLocalShortName,
strLocalServerName, nAppType, rglpszRegister, rglpszOverwrite))
{
// not fatal (don't fail just warn)
TRACE0("mspaint: Unable to register server class.\n");
}
}
#endif