PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 1/10 TITLE : Giving Edit Controls their own heap. QUESTION: How do I make an edit control, or a TEdit or TEditWindow or TFileWindow handle a file greater then 32k? ANSWER: The 32k limit is a limitation of the architecture of the edit control window which is standard in the Windows operating system. In order to get one edit control to use more than 64k of memory would take a fair amount of hacking. However, there is a little that you can do. All edit controls in your app. will by default use memory from the local heap. So there will also be a limit of 64K for all the edit controls you can use in your app. There is a trick to give each edit control its own heap space. If you were calling CreateWindow yourself, it would be done by passing a global memory handle in as the hInst parameter. In OWL this is done by building a TModule object to use when constructing the TEdit control. Here is a step by step process to do this. This is a modified version of the OpenFile function from MFILEAPP.CPP in the \BORLANDC\OWL\EXAMPLES\MFILEAPP directory. /* Respond to "Open" command by constructing, creating, and setting up a new TFileWindow MDI child */ void TMDIFileWindow::OpenFile(RTMessage) { char FileName[MAXPATH]; char ChildName[14]; wsprintf(ChildName,"MDI Child %d", ChildNum++); if ( GetApplication()->ExecDialog(new TFileDialog(this, SD_FILEOPEN, _fstrcpy(FileName, "*.*"))) == IDOK ) { // STEPS for making a TEditWindow or TFileWindow use its own // heap instead of yours. PTFileWindow pw= new TFileWindow(this, ChildName, FileName); // STEP 1: save the attributes of the existing editor in the // TFileWindow TWindowAttr aw = pw->Editor->Attr; PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 2/10 TITLE : Giving Edit Controls their own heap. // STEP 2: Delete the old editor delete pw->Editor; // STEP 3: Allocate the memory for the edit control using GlobalAlloc HGLOBAL gh = GlobalAlloc( GMEM_ZEROINIT, 0xFFFF ); // STEP 4: Construct a TModule around the global memory handle PTModule pm = new TModule( "", (HMODULE)gh , "" ); // STEP 4: Make a new TEdit object using that TModule pointer pw->Editor = new TEdit( pw , aw.Id, "", aw.X, aw.Y, aw.W, aw.H, -1, TRUE , pm ); // STEP 5: create the TFileWindow GetApplication()->MakeWindow( pw ); } // One thing this example does not address is freeing the memory allocated // with GlobalAlloc. Since it is only used by the TEdit, it would be // appropiate to call GlobalFree on it in the destructor for the TEdit // object. The steps for this would be deriving from TEdit and doing a // GlobalFree on Module->hInstance. Then using the derived TEdit in // the steps above. } // // The remainder of this document contains a modified version // of MFILEAPP which implements the technique described above. // // // MFILEAPP.CPP PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 3/10 TITLE : Giving Edit Controls their own heap. // #include #include #include #include #include #include "mfileapp.h" const char DskFile[] = "MFILEAPP.SAV"; _CLASSDEF(TMDIFileApp) _CLASSDEF(TMDIFileWindow) // Declare TMDIFileApp, a TApplication descendant class _CLASSTYPE TMDIFileApp : public TApplication { public: TMDIFileApp(LPSTR name, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmd, int nCmdShow) : TApplication(name, hInstance, hPrevInstance, lpCmd, nCmdShow) {}; virtual void InitMainWindow(); virtual void InitInstance(); }; // Declare TMDIFileWindow, a TMDIFrame descendant class _CLASSTYPE TMDIFileWindow : public TMDIFrame { public: WORD ChildNum; TMDIFileWindow(LPSTR ATitle, LPSTR MenuName); virtual void NewFile(RTMessage Msg) = [CM_FIRST + CM_MDIFILENEW]; virtual void OpenFile(RTMessage Msg) = [CM_FIRST + CM_MDIFILEOPEN]; virtual void NewFileWordWrap(RTMessage Msg) = [CM_FIRST + CM_FILENEW_WORDWRAP]; virtual void OpenFileOwnHeap(RTMessage Msg) = [CM_FIRST + CM_FILEOPEN_OWNHEAP]; virtual void SaveState(RTMessage Msg) = [CM_FIRST + CM_SAVESTATE]; virtual void RestoreState(RTMessage Msg) = PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 4/10 TITLE : Giving Edit Controls their own heap. [CM_FIRST + CM_RESTORESTATE]; }; TMDIFileWindow::TMDIFileWindow(LPSTR ATitle, LPSTR MenuName) : TMDIFrame(ATitle, MenuName) { ChildNum = 1; } /* Respond to "New" command by constructing, creating, and setting up a new TFileWindow MDI child */ void TMDIFileWindow::NewFile(RTMessage) { char ChildName[14]; wsprintf(ChildName,"MDI Child %d", ChildNum++); PTFileWindow pw = new TFileWindow( this , ChildName , "" ); GetApplication()->MakeWindow( pw ); } /* Respond to "Open" command by constructing, creating, and setting up a new TFileWindow MDI child */ void TMDIFileWindow::OpenFile(RTMessage) { char FileName[MAXPATH]; char ChildName[14]; wsprintf(ChildName,"MDI Child %d", ChildNum++); if ( GetApplication()->ExecDialog(new TFileDialog(this, SD_FILEOPEN, _fstrcpy(FileName, "*.*"))) == IDOK ) { PTFileWindow pw= new TFileWindow(this, ChildName, FileName); GetApplication()->MakeWindow( pw ); } } void TMDIFileWindow::NewFileWordWrap(RTMessage) { char ChildName[14]; wsprintf(ChildName,"MDI Child %d", ChildNum++); PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 5/10 TITLE : Giving Edit Controls their own heap. PTFileWindow pw = new TFileWindow( this , ChildName , "" ); DWORD temp = pw->Editor->Attr.Style; // to make an edit control word wrap, take out the following two // styles temp ^= WS_HSCROLL; temp ^= ES_AUTOHSCROLL; pw->Editor->Attr.Style &= temp; GetApplication()->MakeWindow( pw ); } /* Respond to "Open" command by constructing, creating, and setting up a new TFileWindow MDI child */ void TMDIFileWindow::OpenFileOwnHeap(RTMessage) { char FileName[MAXPATH]; char ChildName[14]; wsprintf(ChildName,"MDI Child %d", ChildNum++); if ( GetApplication()->ExecDialog(new TFileDialog(this, SD_FILEOPEN, _fstrcpy(FileName, "*.*"))) == IDOK ) { // STEPS for making a TEditWindow or TFileWindow use its own // heap instead of yours. PTFileWindow pw= new TFileWindow(this, ChildName, FileName); // STEP 1: save the attributes of the existing editor in the TFileWindow TWindowAttr aw = pw->Editor->Attr; // STEP 2: Delete the old editor delete pw->Editor; // STEP 3: Allocate the memory for the edit control using GlobalAlloc HGLOBAL gh = GlobalAlloc( GMEM_ZEROINIT, 0xFFFF ); // STEP 4: Construct a TModule around the global memory handle PTModule pm = new TModule( "", (HMODULE)gh , "" ); // STEP 4: Make a new TEdit object using that TModule pointer pw->Editor = new TEdit( pw , aw.Id, "", aw.X, aw.Y, aw.W, aw.H, -1, TRUE , pm ); PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 6/10 TITLE : Giving Edit Controls their own heap. // STEP 5: create the TFileWindow GetApplication()->MakeWindow( pw ); // One thing this example does not address is cleaning up the memory // that was allocated for the Editor. Ideally one would derive from // TFileWindow and use GlobalFree in the destructor. } } /* Save the the position and contents of the windows to the "desk top" file. */ void TMDIFileWindow::SaveState(RTMessage) { ofpstream os(DskFile); PutChildren(os); os.close(); if ( os.bad() ) { unlink(DskFile); MessageBox(HWindow, "Unable to write desktop file.", "Disk error", MB_OK | MB_ICONEXCLAMATION); } } void DoCreateChild(Pvoid P, Pvoid) { if ( ((PTWindowsObject)P)->IsFlagSet(WB_AUTOCREATE) ) ((PTWindowsObject)P)->Create(); } /* Read windows positions and contents from the "desk top" file. */ void TMDIFileWindow::RestoreState(RTMessage) { LPSTR ErrorMsg = NULL; ifpstream is(DskFile); if ( is.bad() ) ErrorMsg = _fstrdup("Unable to open desktop file."); else PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 7/10 TITLE : Giving Edit Controls their own heap. { if ( CloseChildren() ) { GetChildren(is); if ( is.bad() ) ErrorMsg = _fstrdup("Error reading desktop file."); if ( GetApplication()->LowMemory() ) { CloseChildren(); ErrorMsg = _fstrdup("Not enough memory to open file."); } else ForEach(DoCreateChild, NULL); } } if ( ErrorMsg ) MessageBox(HWindow, ErrorMsg, "Disk error", MB_OK | MB_ICONEXCLAMATION); } /* Construct the TMDIFileApp's MainWindow of type TMDIFileWindow, loading its menu */ void TMDIFileApp::InitMainWindow() { MainWindow = new TMDIFileWindow("MDI Files", "Commands"); ((PTMDIFileWindow)MainWindow)->ChildMenuPos = 3; } /* Initialize each MS-Windows application instance, loading an accelerator table */ void TMDIFileApp::InitInstance() { TApplication::InitInstance(); if ( Status == 0 ) { HAccTable = LoadAccelerators(hInstance, "FileCommands"); if ( HAccTable == 0 ) Status = EM_INVALIDWINDOW; } } // Run the MDIFileApp PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 8/10 TITLE : Giving Edit Controls their own heap. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmd, int nCmdShow) { TMDIFileApp MDIFileApp("MDIFileApp", hInstance, hPrevInstance, lpCmd, nCmdShow); MDIFileApp.Run(); return MDIFileApp.Status; } // // MFILEAPP.H // #define CM_SAVESTATE 200 #define CM_RESTORESTATE 201 #define CM_FILENEW_WORDWRAP 202 #define CM_FILEOPEN_OWNHEAP 203 // // MFILEAPP.RC // #include "windows.h" #include "owlrc.h" #include "mfileapp.h" #include "filedial.dlg" #include "fileacc.rc" #include "stdwnds.dlg" Commands MENU LOADONCALL MOVEABLE PURE DISCARDABLE BEGIN POPUP "&File" PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 9/10 TITLE : Giving Edit Controls their own heap. BEGIN MENUITEM "LineCount" , 325 MENUITEM "&New", CM_MDIFILENEW, MENUITEM "&Open", CM_MDIFILEOPEN, MENUITEM "New with &Word Wrap", CM_FILENEW_WORDWRAP, MENUITEM "Open with own &Heap", CM_FILEOPEN_OWNHEAP, MENUITEM "&Save", CM_FILESAVE, MENUITEM "Save &As...", CM_FILESAVEAS, MENUITEM SEPARATOR MENUITEM "E&xit", CM_EXIT, END POPUP "&Edit" BEGIN MENUITEM "&Undo\aAlt+BkSp", CM_EDITUNDO MENUITEM SEPARATOR MENUITEM "&Cut\aShift+Del", CM_EDITCUT MENUITEM "C&opy\aCtrl+Ins", CM_EDITCOPY MENUITEM "&Paste\aShift+Ins", CM_EDITPASTE MENUITEM "&Delete\aDel", CM_EDITDELETE MENUITEM "C&lear All\aCtrl+Del", CM_EDITCLEAR END POPUP "&Search" BEGIN MENUITEM "&Find...", CM_EDITFIND MENUITEM "&Replace...", CM_EDITREPLACE MENUITEM "&Next\aF3", CM_EDITFINDNEXT END POPUP "&Window" BEGIN MENUITEM "&Tile", CM_TILECHILDREN, MENUITEM "&Cascade", CM_CASCADECHILDREN, MENUITEM "Arrange &Icons", CM_ARRANGEICONS, MENUITEM "C&lose All", CM_CLOSECHILDREN MENUITEM SEPARATOR MENUITEM "&Save state", CM_SAVESTATE MENUITEM "&Restore state", CM_RESTORESTATE END END PRODUCT : Borland C++ NUMBER : 1167 VERSION : 3.1 OS : WIN DATE : October 22, 1993 PAGE : 10/10 TITLE : Giving Edit Controls their own heap. DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.