/****************************************************************************** Source File: Model Data.CPP Implementation of the code for handling GPC format data Copyright (c) 1997 by Microsoft Corporation. All Rights Resreved. A Pretty Penny Enterprises Production Change History: 02-19-97 Bob_Kjelgaard@Prodgy.Net Created it ******************************************************************************/ #include "StdAfx.h" #undef AFX_EXT_CLASS #define AFX_EXT_CLASS __declspec(dllimport) #include "..\FontEdit\ProjNode.H" #include "..\CodePage\CodePage.H" #undef AFX_EXT_CLASS #define AFX_EXT_CLASS __declspec(dllexport) #include "..\Resource.H" #include "Resource.H" #include "GPDFile.H" /****************************************************************************** COldMiniDriverData class This class is tasked with representing the GPC data. It will begin life as a stub, although it could become more functional, later. ******************************************************************************/ /****************************************************************************** ExtractList This is a private worker function. It takes a pointer to a null-terminated list of WORD font IDs, with the nasty complication that the first two elements of the list represent the endpoints of a range. It mashes these into a passed word map (of which we only use the indices). ******************************************************************************/ static void ExtractList(PWORD pw, CMapWordToDWord& cmw2d) { for (WORD w = *pw++; w && w < *pw; w++) cmw2d[w] = 0; if (!w) return; // The whole list was empty while (*pw) // We start at the endpoint (which we haven't mapped yet) cmw2d[*pw++] = 0; } /****************************************************************************** ColdMiniDriverData::Load This member function loads the mini-driver's GPC file, and extracts the number of models, the CTT IDs, and the model name IDs. ******************************************************************************/ BOOL COldMiniDriverData::Load(CFile& cfImage) { struct sGPCHeaderEntry { WORD m_wOffset, m_wcbItem, m_wcItems; }; struct sMaster { WORD m_wX, m_wY; }; struct sPrinterModelData { WORD m_wcbSize; WORD m_widName; // Stringtable id for model name. WORD m_wfGeneral; // TODO: Define enums WORD m_wfCurves; // TODO: Define enums WORD m_wfLines; // TODO: Define enums WORD m_wfPolygons; // TODO: Define enums WORD m_wfText; // TODO: Define enums WORD m_wfClipping; // TODO: Define enums WORD m_wfRaster;; // TODO: Define enums WORD m_wfLandscapeText; // TODO: Define enums WORD m_wLeftMargin; // Left-hand unprintable area WORD m_wMaximumWidth; // Of physica page sMaster m_smMaximum, m_smMinimum; // Max min page sizes WORD m_widDefaultFont; WORD m_wLookAhead; WORD m_wMaxFontsPerPage; WORD m_wcCartridges; WORD m_widDefaultCTT; enum {PortraitFonts, LandscapeFonts, Resolution, PaperSize, PaperQuality, PaperSource, PaperDestination, TextQuality, Compression, FontCartridge, Color, MemoryConfiguration}; WORD m_awofIndexLists[12]; // Uses the preceding enum WORD m_awIndices[16]; // Ditto WORD m_awVer3IndexLists[5]; // Ditto WORD m_wofDefaults; // List of defaults for index lists WORD m_wReserved; DWORD m_dwidICMManufactirer, m_dwidICMModel; DWORD m_adwReserved[8]; }; struct sGPCFileHeader { WORD m_widGPC; // 0x7F00 or it isn't valid. WORD m_wVersion; // Final version is 3, there was a V2 sMaster m_smMasterdpi; DWORD m_dwoHeap; // The GPC data is maintained in one DWORD m_dwcbFile; // Total GPC Image size, heap and all enum {Default, PCL4, CAPSL, PPDS, TTY, DBCS}; WORD m_wTechnology; // Use the preceding enum enum {PrivateHelp = 1, OneDraftFont}; WORD m_wfGeneral; // Again, use the preceding enum char m_acReserved[10]; WORD m_wcHeaderItems; // Number of valid header entries enum {ModelData, Resolution, PaperSize, PaperQuality, PaperSource, PaperDestination, TextQuality, Compression, FontCartridge, PageControl, CursorMovement, FontSimulation, DeviceColor, RectangleFill, DownloadInfo, VectorPage, Carousel, PenInfo, LineInfo, BrushInfo, VectorOutput, PolyVectorOutput, VectorSupport, ImageControl, PrintDensity, ColorTracking, MaximumDefined = 30}; sGPCHeaderEntry m_asgpche[MaximumDefined]; }; struct sFontCartridge { WORD m_wSize; // = 12 WORD m_widCartridge; // In the string table WORD m_wofPortraitList; WORD m_wofLandscapeList; WORD m_wfGeneral; WORD m_wReserved; }; // In case we get called more than once, dump any old info... m_cbaImage.RemoveAll(); m_csoaFonts.RemoveAll(); m_cwaidCTT.RemoveAll(); m_cwaidModel.RemoveAll(); m_cbaImage.SetSize(cfImage.GetLength()); cfImage.Read(m_cbaImage.GetData(), cfImage.GetLength()); sGPCFileHeader *psgfh = (sGPCFileHeader *) Image(); if (psgfh -> m_widGPC != 0x7F00 || psgfh -> m_wVersion > 0x3ff) return FALSE; // pull out the printer model data we care about- eventually, this may // be all of it for (unsigned u = 0; u < psgfh -> m_asgpche[sGPCFileHeader::ModelData].m_wcItems; u++) { sPrinterModelData& spmd = *(sPrinterModelData *) (Image() + psgfh -> m_asgpche[sGPCFileHeader::ModelData].m_wOffset + psgfh -> m_asgpche[sGPCFileHeader::ModelData].m_wcbItem * u); m_cwaidModel.Add(spmd.m_widName); m_cwaidCTT.Add(spmd.m_widDefaultCTT); // Build the font list- I use a CMapWordToOb to handle the duplicate // screening CMapWordToDWord& cmw2dThis = * (new CMapWordToDWord); // Extract the portrait resident fonts if (spmd.m_awofIndexLists[sPrinterModelData::PortraitFonts]) ExtractList((PWORD) (Image() + psgfh -> m_dwoHeap + spmd.m_awofIndexLists[sPrinterModelData::PortraitFonts]), cmw2dThis); // Extract the landscape resident fonts if (spmd.m_awofIndexLists[sPrinterModelData::LandscapeFonts]) ExtractList((PWORD) (Image() + psgfh -> m_dwoHeap + spmd.m_awofIndexLists[sPrinterModelData::LandscapeFonts]), cmw2dThis); // Extract the cartridge fonts if (spmd.m_awofIndexLists[sPrinterModelData::FontCartridge]) { PWORD pw = (PWORD) (Image() + psgfh -> m_dwoHeap + spmd.m_awofIndexLists[sPrinterModelData::FontCartridge]); // RAID 102890- Cartridge font index is 1-based, not 0-based while (*pw) { sFontCartridge* psfc = (sFontCartridge *) (Image() + psgfh -> m_asgpche[sGPCFileHeader::FontCartridge].m_wOffset + psgfh -> m_asgpche[sGPCFileHeader::FontCartridge].m_wcbItem * (-1 + *pw++)); // END RAID 102890 // Portrait if (psfc -> m_wofPortraitList) ExtractList((PWORD) (Image() + psgfh -> m_dwoHeap + psfc -> m_wofPortraitList), cmw2dThis); // Landscape if (psfc -> m_wofLandscapeList) ExtractList((PWORD) (Image() + psgfh -> m_dwoHeap + psfc -> m_wofLandscapeList), cmw2dThis); } } // Save the map in the font structure m_csoaFonts.Add(&cmw2dThis); } return TRUE; } /****************************************************************************** COldMiniDriverData::FontMap(unsigned u) This member returns the map which shows which fonts are used by the given model. ******************************************************************************/ CMapWordToDWord& COldMiniDriverData::FontMap(unsigned u) const { return *(CMapWordToDWord *) m_csoaFonts[u]; } /****************************************************************************** COldMiniDriverData::NoteTranslation This records the fact that model nn must translate instances of font ID xxx to font ID y. ******************************************************************************/ void COldMiniDriverData::NoteTranslation(unsigned uModel, unsigned uidOld, unsigned uidNew) { FontMap(uModel)[uidOld] = uidNew; } /****************************************************************************** CModelData class This class encapsulates the GPD file. It will start life as a big CStringArray, but as the editor gets more sophisticated, it may gain additional members to speed processing and/or manipulation of the data. ******************************************************************************/ IMPLEMENT_SERIAL(CModelData, CProjectNode, 0) /****************************************************************************** CModelData::FillViewer This static member function is a callback for the rich edit control. It receives a pointer to the CModelData in question, and calls its Fill from buffer member function. ******************************************************************************/ DWORD CALLBACK CModelData::FillViewer(DWORD dwthis, LPBYTE lpb, LONG lcb, LONG *plcb) { if (!dwthis) return TRUE; CModelData* pcmd = (CModelData *) dwthis; return pcmd -> Fill(lpb, lcb, plcb); } /****************************************************************************** CModelData::FromViewer This is a stream callback for moving data from the edit control to the GPD class. It receives a pointer to the CModelData being updated, and calls its UpdateFrom buffer member function to do the rest of the work ******************************************************************************/ DWORD CALLBACK CModelData::FromViewer(DWORD dwthis, LPBYTE lpb, LONG lcb, LONG *plcb) { if (!dwthis) return TRUE; // Stop the madness CModelData* pcmd = (CModelData *) dwthis; return pcmd -> UpdateFrom(lpb, lcb, plcb); } /****************************************************************************** CModelData::Fill(LPBYTE lpb, LONG lcb, LONG *plcb) This private method fills a buffer from the GPD contents in CString form. An internal buffer is used to handle partially moved strings. ******************************************************************************/ DWORD CModelData::Fill(LPBYTE lpb, LONG lcb, LONG *plcb) { int iTotalLines = m_csaGPD.GetSize(); if (!m_cbaBuffer.GetSize() && m_iLine >= iTotalLines) { *plcb = 0; return 0; // We be done! } unsigned ucb = (unsigned) lcb; union { LPTSTR lpstr; LPBYTE lpbThis; }; // First, empty anything buffered previously lpbThis = lpb; if (m_cbaBuffer.GetSize()) if ((unsigned) m_cbaBuffer.GetSize() <= ucb) { // Cool- the entire line will fit in the buffer. memcpy(lpbThis, m_cbaBuffer.GetData(), m_cbaBuffer.GetSize()); ucb -= m_cbaBuffer.GetSize(); lpbThis += m_cbaBuffer.GetSize(); m_cbaBuffer.RemoveAll(); } else { memcpy(lpbThis, m_cbaBuffer.GetData(), ucb); m_cbaBuffer.RemoveAt(0, ucb); *plcb = lcb; return 0; } for (; ucb && m_iLine < iTotalLines; m_iLine++) { CString csLine = m_csaGPD[m_iLine]; csLine += _TEXT("\r\n"); if ((csLine.GetLength()) * sizeof(TCHAR) <= ucb) { // Cool- the entire line will fit in the buffer. memcpy(lpbThis, (LPCTSTR) csLine, sizeof(TCHAR) * csLine.GetLength()); ucb -= sizeof(TCHAR) * csLine.GetLength(); lpstr += csLine.GetLength(); continue; } // This is a partial buffer- copy it to the internal buffer, and // finish filling the original. m_cbaBuffer.SetSize(sizeof(TCHAR) * csLine.GetLength()); memcpy(m_cbaBuffer.GetData(), (LPCTSTR) csLine, sizeof(TCHAR) * csLine.GetLength()); memcpy(lpbThis, m_cbaBuffer.GetData(), ucb); m_cbaBuffer.RemoveAt(0, ucb); ucb = 0; } *plcb = lcb - ucb; return 0; } /****************************************************************************** CModelData::UpdateFrom(LPBYTE lpb, LONG lcb, LONG* plcb) This is a private member- an overload which adds the contents of the given buffer to the GPD CStringArray, by parsing it into strings. A private buffer member is used to hold partial strings between calls. ******************************************************************************/ DWORD CModelData::UpdateFrom(LPBYTE lpb, LONG lcb, LONG* plcb) { // Copy the buffer to a byte buffer and null-terminate m_cbaBuffer.SetSize(1 + lcb); memcpy(m_cbaBuffer.GetData(), lpb, lcb); m_cbaBuffer.SetAt(-1 + m_cbaBuffer.GetSize(), 0); // Convert to string and append to any buffered data. CString csWork(m_cbaBuffer.GetData()); CString csEnd(_T("\r\x1A")); // These get dumped m_cbaBuffer.RemoveAll(); m_csBuffer += csWork; // Add any complete strings to the GPD contents. csWork = m_csBuffer.SpanExcluding(_T("\n")); while (csWork.GetLength() != m_csBuffer.GetLength()) { m_csBuffer = m_csBuffer.Mid(csWork.GetLength() + 1); // Remove any trailing whitespace. csWork.TrimRight(); // Add the string sans any leading control characters m_csaGPD.Add(csWork.Mid(csWork.SpanIncluding(csEnd).GetLength())); // While we're here, remove any leading control characters from buffer m_csBuffer = m_csBuffer.Mid(m_csBuffer.SpanIncluding(csEnd).GetLength()); csWork = m_csBuffer.SpanExcluding(_T("\n")); } // The leftover data (if any) may be used later... *plcb = lcb; return 0; } /****************************************************************************** CModelData::Classify This method identifies the line numbers for each warning comment, error comment, and any other sort of comment, so they can later be syntax colored. ******************************************************************************/ /****************************************************************************** CModelData::CModelData Constructs an empty CModelData object- includes building the Menu table ******************************************************************************/ CModelData::CModelData() { m_pcmdt = NULL; m_cfn.SetExtension(_T(".GPD")); m_cfn.AllowPathEdit(); // Build the context menu control m_cwaMenuID.Add(ID_OpenItem); m_cwaMenuID.Add(ID_RenameItem); m_cwaMenuID.Add(0); m_cwaMenuID.Add(ID_Import); m_cwaMenuID.Add(ID_DeleteItem); m_cwaMenuID.Add(0); m_cwaMenuID.Add(ID_ExpandBranch); m_cwaMenuID.Add(ID_CollapseBranch); } /****************************************************************************** CModelData::Load(CStdioFile csiofGPD) This overload loads the GPD from a text file directly. ******************************************************************************/ BOOL CModelData::Load(CStdioFile& csiofGPD) { CString csWork; m_csaGPD.RemoveAll(); while (csiofGPD.ReadString(csWork)) { csWork.TrimRight(); // Cut off the trailing line stuff m_csaGPD.Add(csWork); } // Note the correct name and path- the rename checks may fail, since the // file is opened elsewhere (possibly with sharing conflicts), so disable // them, for now. if (FileTitle().IsEmpty()) { m_cfn.EnableCreationCheck(FALSE); SetFileName(csiofGPD.GetFilePath()); m_cfn.EnableCreationCheck(); } return TRUE; } /****************************************************************************** CModelData::Load() This overload loads the GPD file from the disk using the stored name and path information. ******************************************************************************/ BOOL CModelData::Load() { if (FileTitle().IsEmpty()) return FALSE; try { CStdioFile csiofGPD(FileName(), CFile::modeRead | CFile::shareDenyWrite); return Load(csiofGPD); } catch (CException *pce) { pce -> ReportError(); pce -> Delete(); } return FALSE; } /****************************************************************************** CModelData::Store This method sends the GPD file to the disk. Since GPD infromation can be easily edited with an external editor, this avoids replication and consistency issues. ******************************************************************************/ BOOL CModelData::Store(LPCTSTR lpstrPath) { // Write the GPD file to the target location, with the traditional CR/LF // separators. If the given name is NULL, use the stored one. try { CStdioFile csiofGPD(lpstrPath ? lpstrPath : FileName(), CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeBinary); for (int i = 0; i < m_csaGPD.GetSize(); i++) csiofGPD.WriteString(m_csaGPD[i] + _T("\r\n")); } catch (CException *pce) { pce -> ReportError(); pce -> Delete(); return FALSE; } Changed(FALSE); return TRUE; } /****************************************************************************** CModelData::Parse This method is responsible for parsing the GPD file and collecting the resulting errors. The initial implementation will be a bit bizarre, because the GPD parser isn't stable, and converting it so it would work well for ma and then staying on top of the changes just doesn't make sense. ******************************************************************************/ extern "C" BOOL BcreateGPDbinary(LPCWSTR lpstrFile); // The parser hook extern "C" PVOID LoadRawBinaryData(LPCWSTR lpstrFile) ; extern "C" PVOID InitBinaryData(PVOID pv, PVOID pv2, PVOID pv3) ; extern "C" void FreeBinaryData(PVOID pInfoHdr); extern "C" void UnloadRawBinaryData(PVOID pRawData) ; extern "C" void UseLog(FILE *pfLog); BOOL CModelData::Parse() { // Step 1: Establish the correct directory for the parser, and // bang together a couple of file names CString csCurrent; GetCurrentDirectory(MAX_PATH + 1, csCurrent.GetBuffer(MAX_PATH + 1)); csCurrent.ReleaseBuffer(); SetCurrentDirectory(m_cfn.Path().Left(m_cfn.Path().ReverseFind(_T('\\')))); // Step 2: Fake out the error logging interface so it actually tosees // them all into a CString Array for us, the invoke the parser. SetLog(); // Step 3: Convert the file name to Unicode so we don't have to tweak the // parser code. CString csFile = FileTitle() + _T(".GPD"); CByteArray cbaIn; CWordArray cwaOut; cbaIn.SetSize(csFile.GetLength() + 1); lstrcpy((LPSTR) cbaIn.GetData(), csFile); CCodePageInformation ccpi; ccpi.Convert(cbaIn, cwaOut, GetACP()); if (BcreateGPDbinary(cwaOut.GetData())) { PVOID pRawData ; PVOID pInfoHdr ; pRawData = LoadRawBinaryData(cwaOut.GetData()); if(pRawData) pInfoHdr = InitBinaryData(pRawData, NULL, NULL); if (pRawData && pInfoHdr) FreeBinaryData(pInfoHdr); if (pRawData) UnloadRawBinaryData(pRawData) ; DeleteFile(FileTitle() + _T(".Bud")); } // Finally, clean up the mess by restoring the original working // directory. SetCurrentDirectory(csCurrent); return TRUE; } /****************************************************************************** CModelData::RemoveError This removes the given error from the log. ******************************************************************************/ void CModelData::RemoveError(unsigned u) { if (u >= Errors()) return; m_csaConvertLog.RemoveAt(u); Changed(); } /****************************************************************************** CModelData::Fill(CRichEditCtrl& crec) This overload fills the gven rich edit control with the GPD contents, either as currently cached in memory, or stored on the disk. ******************************************************************************/ void CModelData::Fill(CRichEditCtrl& crec) { EDITSTREAM es = {(DWORD) this, 0, FillViewer}; m_iLine = 0; if (!m_csaGPD.GetSize()) Load(); crec.StreamIn(SF_TEXT, es); } /****************************************************************************** CModelData::UpdateFrom(CRichEditCtrl& crec) This overloaded member function discards the current GPD cache and refills it from the given edit control. ******************************************************************************/ void CModelData::UpdateFrom(CRichEditCtrl& crec) { EDITSTREAM es = {(DWORD) this, 0, FromViewer}; m_csaGPD.RemoveAll(); m_csBuffer.Empty(); // Just in case... crec.StreamOut(SF_TEXT, es); Changed(); } /****************************************************************************** CModelData::CreateEditor This member function launches an editing view for the GPD Data. ******************************************************************************/ CMDIChildWnd* CModelData::CreateEditor() { CGPDContainer* pcgpdcMe= new CGPDContainer(this, FileName()); Load(); // Make up a cool title pcgpdcMe -> SetTitle(m_pcbnWorkspace -> Name() + _T(": ") + Name()); CMDIChildWnd *pcmcwNew = (CMDIChildWnd *) m_pcmdt -> CreateNewFrame(pcgpdcMe, NULL); if (pcmcwNew) { m_pcmdt -> InitialUpdateFrame(pcmcwNew, pcgpdcMe, TRUE); m_pcmdt -> AddDocument(pcgpdcMe); } return pcmcwNew; } /****************************************************************************** CModelData::Import This method walks one step up the tree and passes the call to the import method for the fixed node which owns us. ******************************************************************************/ void CModelData::Import() { ((CBasicNode *) m_pctcOwner -> GetItemData(m_pctcOwner -> GetParentItem(m_hti))) -> Import(); } /****************************************************************************** CModelData::Delete This is called when the user presses the Delete key or selects the Delete menu item from an appropriate context menu. We use a modal dialog to ask whether the user intends to really remove the file from the workspace, and whether or not they wish to delete the underlying file. ******************************************************************************/ void CModelData::Delete() { CGPDDeleteQuery cgdq; cgdq.FileName(Name()); if (cgdq.DoModal() != IDYES) return; if (cgdq.KillFile()) DeleteFile(m_cfn.FullName()); // Walk back up the hierarchy to find the owning Fixed node, and // remove us from the array for that node- since that member is a // reference to the array, all will work as it should. CFixedNode& cfnGPD = * (CFixedNode *) m_pctcOwner -> GetItemData( m_pctcOwner -> GetParentItem(m_hti)); ASSERT(cfnGPD.IsKindOf(RUNTIME_CLASS(CFixedNode))); cfnGPD.Zap(this); // WARNING: the object pointed to by this has been deleted do NOTHING // from this point on that could cause the pointer to be dereferenced! } /****************************************************************************** CModelData::Serialize Stores the image, as we need it stored. ******************************************************************************/ void CModelData::Serialize(CArchive& car) { CProjectNode::Serialize(car); m_csaConvertLog.Serialize(car); } /****************************************************************************** CGPDContainer class implementation This class is a document class which contains one GPD file and its assorted control mechanisms ******************************************************************************/ IMPLEMENT_DYNCREATE(CGPDContainer, CDocument) CGPDContainer::CGPDContainer(CModelData *pcmd, CString csPath) { m_bEmbedded = TRUE; m_pcmd = pcmd; SetPathName(csPath, FALSE); m_pcmd -> NoteOwner(*this); } CGPDContainer::CGPDContainer() { m_bEmbedded = FALSE; m_pcmd = new CModelData; m_pcmd -> NoteOwner(*this); } /****************************************************************************** CGPDContainer::OnNewDocument We just pass it back to the default handler. Could mean this one can be toasted ******************************************************************************/ BOOL CGPDContainer::OnNewDocument() { return CDocument::OnNewDocument(); } /****************************************************************************** CGPDContainer::~CGPDContainer If this wasn't created from the workspace, then zap the data! ******************************************************************************/ CGPDContainer::~CGPDContainer() { if (!m_bEmbedded && m_pcmd) delete m_pcmd; } BEGIN_MESSAGE_MAP(CGPDContainer, CDocument) //{{AFX_MSG_MAP(CGPDContainer) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CGPDContainer diagnostics #ifdef _DEBUG void CGPDContainer::AssertValid() const { CDocument::AssertValid(); } void CGPDContainer::Dump(CDumpContext& dc) const { CDocument::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CGPDContainer serialization void CGPDContainer::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here } else { // TODO: add loading code here } } ///////////////////////////////////////////////////////////////////////////// // CGPDContainer commands /****************************************************************************** CGPDContainer::OnSaveDocument We bypass the normal serialization process, and simple blast it to the drive. ******************************************************************************/ BOOL CGPDContainer::OnSaveDocument(LPCTSTR lpszPathName) { return ModelData() -> Store(lpszPathName); } /****************************************************************************** CDPSContainer::OnOpenDocument Again, blow off serialization- if I haven't figured out how to read a text file by now, I'm definitely in the wrong place. ******************************************************************************/ BOOL CGPDContainer::OnOpenDocument(LPCTSTR lpszPathName) { try { CStdioFile csiofGPD(lpszPathName, CFile::modeRead | CFile::shareDenyWrite | CFile::typeText); return ModelData() -> Load(csiofGPD); } catch (CException *pce) { pce -> ReportError(); pce -> Delete(); } return FALSE; } /****************************************************************************** CGPDDeleteQuery dialog This implements the dialog that validates and verifies the removal of a GPD file from the workspace. ******************************************************************************/ CGPDDeleteQuery::CGPDDeleteQuery(CWnd* pParent /*=NULL*/) : CDialog(CGPDDeleteQuery::IDD, pParent) { //{{AFX_DATA_INIT(CGPDDeleteQuery) m_csTarget = _T(""); m_bRemoveFile = FALSE; //}}AFX_DATA_INIT } void CGPDDeleteQuery::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CGPDDeleteQuery) DDX_Text(pDX, IDC_FileName, m_csTarget); DDX_Check(pDX, IDC_Remove, m_bRemoveFile); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CGPDDeleteQuery, CDialog) //{{AFX_MSG_MAP(CGPDDeleteQuery) ON_BN_CLICKED(IDNO, OnNo) ON_BN_CLICKED(IDYES, OnYes) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CGPDDeleteQuery message handlers void CGPDDeleteQuery::OnYes() { if (UpdateData()) EndDialog(IDYES); } void CGPDDeleteQuery::OnNo() { EndDialog(IDNO); }