Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Borland C++ 4.5 and OLE 2.0 Programming


APR95: Borland C++ 4.5 and OLE 2.0 Programming

Borland C++ 4.5 and OLE 2.0 Programming

Upgrading a familiar toolset

Ted Faison

Ted, who has written several books and articles on C++ and Windows, is president of Faison Computing, a firm that develops C++ applications, class libraries, and custom controls for Windows. Ted can be reached on CompuServe at 76350,1013.


In the C++ wars, Watcom, Symantec, Borland, Microsoft, and others have been battling for the hearts, minds, and pocketbooks of programmers. Since the release of Microsoft's Visual C++, the primary weapon in this battle has been the addition of code-generation tools and increased functionality within application frameworks. Borland C++ 4.0, for example, featured a revamped ObjectWindows Application Framework (OWL) and eliminated nonstandard C++ notation to support Windows event-handling. However, Visual C++ 1.5 included features such as database and OLE support that Borland C++ wouldn't have for some time. With the introduction of Borland C++ 4.5 (BC++ 4.5), Borland is back on the front lines, particularly when it comes to creating OLE-enabled applications. In fact, BC++ 4.5 allows you to create OLE servers and containers with the same ease as non-OLE applications. For developers writing database applications in 4.5, Borland is providing an add-on database package. In this article, however, I'll focus on the OLE additions to BC++ 4.5, along with other interesting changes to the toolset. In doing so, I'll draw occasional parallels to Microsoft's recently released Visual C++ 2.0 and provide a comparison of OWL and the Microsoft Foundation Class (MFC) library. (For details on VC++ 2.0, see "Building an OLE Server Using Visual C++ 2.0," by John LaPlante, DDJ, February 1995.) Finally, I'll show how easy it is to develop a simple OLE server.

BC++ 4.5 Arsenal

Borland C++ 4.5 requires about 100 Mbytes of disk space and is delivered on CD-ROM (or 28 3.5-inch diskettes). It includes everything you need to create fully polished Windows applications--an integrated development environment, profilers, several text-editor environments (Borland Classic, Brief, or Epsilon), and the Resource Workshop resource editor. Resource Workshop allows you to work with standard Windows controls, enhanced Borland controls, 16- and 32-bit VBX controls, and third-party custom-control DLLs. (In comparison, Microsoft's AppStudio supports only standard Windows controls and 16-bit VBX controls.) Although Resource Workshop can be invoked from the integrated environment, it runs as a separate program. (In contrast, the version of AppStudio that ships with VC++ 2.0 runs in-place. When you run AppStudio, you don't leave the Visual Workbench environment at all.)

Borland also provides several debugging tools: an integrated debugger that lets you debug programs without leaving the development environment; the stand-alone Turbo Debugger; and a remote debugger requiring a separate computer connected by a serial link. Another postmortem utility, Winspector, allows you to track down problems when a general-protection fault (GPF) occurs. Winspector captures the information that leads to the fault and creates a report indicating the modules and functions involved. Winspector works with an application's symbol table, translating arcane addresses into symbols.

New to BC++4.5 is the OpenHelp system, which lets you configure how the various help files are searched. With over a dozen help files to deal with--Windows, DOS, OWL, OLE, Resource Workshop, and so on--it's nice to be able to configure the IDE help system to search only specific files. OpenHelp is a help-system manager that uses named groups of help files called "search ranges." The default search range, called "BC 4.5," includes all the help files. You can create your own search ranges to use only selected help files. For example, you might create a range called "OWL and OCF" that includes only C++, OWL, and OCF help files. You can create as many search ranges as you want. To run OpenHelp, you bring up the regular Help system by using the Help menu or clicking Control-F1 on a selected word. From the Help toolbar, you click SelectAll, and the OpenHelp dialog box appears. Perhaps the most useful feature of OpenHelp is its ability to handle searches of regular expressions. To find all the occurrences of words beginning with the string WM_GET, click the Regular Expression option and specify the search string WM_GET.

The ObjectComponents Framework

For Windows programmers, the single most-useful component of BC++ 4.5 (apart from the compiler) is OWL 2.5, with its support for OLE 2.0. Although it is backward compatible with OWL 2.0, OWL 2.5 lets you create OLE servers, containers, server/containers, and automated OLE programs. You can create servers both as DLLs and as EXEs. DLL servers are handy when you want to minimize the overhead of function calls between your application and a stand-alone OLE server running as a separate EXE application. With a DLL server, the OLE server runs in the same process space as your application, obviating the need for function calls to cross process boundaries.

OWL 2.5 was extended to support OLE by enlisting the services of an entirely new OLE class hierarchy, the "ObjectComponents Framework" (OCF). OCF completely encapsulates low-level OLE interfaces and details, providing an exterior C++ look-and-feel that lets you work at a much-higher level of abstraction than the OLE API. Using OCF, Borland was able to incorporate full OLE support into OWL 2.5 with relatively minimal additions to OWL itself. (In comparison, MFC was OLE empowered by adding some 20,000 lines of code to MFC.)

OWL was extended by creating a few new classes, such as TOleDocument and TOleWindow and by using code that manipulated a series of OCF objects. The hierarchy of the OCF classes used by OWL is shown in Figure 1. (OCF has several other classes used internally, but since OWL has no knowledge of them, I won't discuss them.) OCF doesn't completely encapsulate OLE on its own. Borland also provides BOCOLE (Borland ObjectComponents OLE), a DLL that wraps some of the lower-level details of OLE. BOCOLE allows you to access all of the OLE interfaces and functionality, but in addition defines a set of interfaces of its own. The idea was to alleviate the so-called "impedance mismatch" between applications objects and OLE objects. Applications deal with entities like documents, views, and windows. OLE is concerned with class factories, data objects, and memory allocators. Borland created interfaces in BOCOLE that match some of the abstractions used in applications. Consequently, BOCOLE has interfaces like IBApplication, IBDocument, and IBContainer. All the interfaces are derived from the standard OLE interface IUnknown and begin with the letters IB (Interface Borland). Figure 2 shows the entire class for the BOCOLE interfaces.

When you create OLE servers and containers using the AppExpert facility, you get OWL applications that use new OWL classes like TOleDocument and TOleWindow. These classes have internal OCF objects to handle OLE. The OCF classes make calls to BOCOLE, which in turn calls OLE interfaces. The good news is that everything is transparent to you; you never need to get involved with the OLE details unless you want to change one of the OLE mechanisms built into OWL.

MFC versus OWL

New C++ programmers frequently ask questions about application frameworks. The bottom line is that the framework you prefer depends on the tasks your application performs, your programming style, and how object oriented you are. In short, the choice is subjective. I prefer OWL because of its excellent container classes, great GDI encapsulation, multiple inheritance, and the large number of classes it supports. On the other hand, MFC 3.0 supports a few things OWL doesn't--ODBC database programming, OCX controls, mini-framed windows, dockable windows, and tabbed dialog boxes. Those differences may be important to you. Listings One through Thirty-one show a number of common programming operations, coded in both MFC and OWL code. In each listing, "(a)" refers to MFC code, while "(b)" refers to OWL.

From the outset, MFC was designed with C programmers in mind. It provides a relatively thin encapsulation of underlying Windows API functions, often foregoing C++ features that would have made life easier. Consider creating a pen. Using Windows API code with C, you do something like Example 1(a). Because pens are most often created with the PS_SOLID style, a width of "1," and the color "black," it would have made sense for MFC to use C++ default arguments. Instead, a pen must be created as in Example 1(b). The OWL approach shown in Example 1(c) exemplifies how default arguments allow you to use a simpler notation. Declaring a TPen object creates not only the object, but also a corresponding Windows pen. The pen is automatically initialized with default arguments, which you can always change if necessary.

When you use a pen to draw a line, Windows API code looks something like Example 2(a). Note that the MFC code in Example 2(b) is almost identical. When you are done using the pen, MFC requires you to deselect it from the device context, before the pen is destroyed by going out of scope. By comparison, OWL GDI objects are smart, because they track the TDC object they are selected into and automatically deselect themselves before destroying the associated Windows GDI object; see Example 2(c). If you have a lot of GDI code in your application, using OWL will simplify things considerably, saving you from tracking GDI memory leaks due to undeleted objects.

Creating an OLE Application

To show how to get an OLE app up and running, I've created a simple OLE server which I'll test by embedding in it into a Word for Windows 6.0 document. Developing an OLE server or container with BC++ 4.5 couldn't be easier. AppExpert has been beefed up to include support for all OLE application types. You can create servers, containers, server/containers, and automated applications. The first step in creating any OLE app is always AppExpert. Using the menu Project|AppExpert, bring up the AppExpert Options dialog (see Figure 3) from which you can create servers as either DLLs or EXEs. The latter are more versatile, because they can be used from both 16- and 32-bit applications. 16-bit server DLLs can only be used with 16-bit applications. 32-bit DLLs are restricted to 32-bit applications. By clicking the Generate button, I created a new project named MYTEST, containing nearly 40 files.

Building a project with AppExpert is only the starting point; invariably, you will need to add some code of your own to make a useful application. AppExpert allows you to create applications with or without the Doc/View model. By default, AppExpert will use the Doc/View model, whereby the data used in a window is stored in a class derived from the OWL class TDocument. The data is not displayed by the document object, but by a viewer object, derived from the OWL class TView. A document manager is created by the application object to handle the connection between a document and a view. The viewer is actually a child window that occupies the client area of a parent window. In an MDI app, the parent window is an MDI child window derived from class TMDIChild. In an SDI app, the parent window is a regular window derived from TFrameWindow.

If you select one of the OLE options with AppExpert, your application will use the Doc/View model regardless of whether you checked the Doc/View option or not, because OLE requires an application to support independent entities for its data and the displaying of the data.

I tested MYTEST by embedding it in a Word 6.0 document. Using Word's Insert|Object menu, I opened the OLE dialog box, selected the OLE object type MYTEST, and inserted it into my document. Double-clicking the MYTEST object to activate it in place, Word's menus are merged with those of MYTEST. The text inside the embedded MYTEST object is painted by the default code created by AppExpert. To change what MYTEST objects display, you need to add your own code to the Paint function in the server's TOleView-derived class.

The painting code created by AppExpert for the MYTEST example program is shown in Listing Thirty-two . Note the statement dc.TextOut(0, 30, "mytest OLE Server"); at the end of the listing. To change what MYTEST objects display, replace this statement with whatever code you need. Typically, the data contained in the view's document is accessed, using the TDocument pointer data member Doc.

Final Comments

Although most developers are still shying away from OLE 2.0 support in their programs, I think that will begin to change later this year, with the release of Windows 95. Borland C++ 4.5 gives you all the support you need for OLE, with one exception: OLE controls. The good news is that OLE controls aren't used by any applications I know of yet. However, this will soon change, and they will become essential with Windows 95. Presumably, Borland will update OWL to support not only OLE controls, but all the new gadgets and widgets in Windows 95.

For More Information

Borland C++ 4.5

Borland International

100 Borland Way

Scotts Valley, CA 95066-3249

408-431-1000

$499.95

Figure 1 The OCF classes used directly by OWL. Figure 2 The complete BOCOLE hierarchy.

Example 1: (a) Creating a pen using C and the Windows API; (b) MFC does not take advantage of default arguments; (c) OWL's use of default arguments allows for simpler notation.

(a)
HPEN pen;
pen = CreatePen(PS_SOLID, 1,
             RGB(0, 0, 0) );

(b)
Cpen pen;
pen.Create(PS_SOLID, 1,
             RGB(0, 0, 0) );

(c)
 TPen pen;

Example 2: (a) Making Windows API calls from C to draw a line; (b) drawing a line using MFC; (c) drawing a line using OWL.

(a)
void DrawLine(HDC dc)
{
  HPEN pen;
  pen=CreatePen(PS_SOLID, 1, RGB(0,0,0) );
  HPEN pOldPen = SelectObject(dc, pen);
  MoveTo(dc, 10, 10);
  LineTo(dc, 20, 30);
  SelectObject(dc, oldPen);
}

(b)
void CMyWnd::DrawLine(CDC& dc)
{
  CPen pen;
  pen.CreatePen(PS_SOLID, 1, RGB(0,0,0) );
  CPen* pOldPen = dc.SelectObject(&pen);
  dc.MoveTo(10, 10);
  dc.LineTo(20, 30);
  dc.SelectObject(pOldPen);
}

(c)
void TMyWnd::Line(TDC& dc)
{
 TPen pen;
 dc.SelectObject(pen);
 dc.MoveTo(0, 100);
 dc.LineTo(100, 20);
}

Figure 3 The AppExpert Options dialog box.

Listing One: Creating a window.


(a)     CMyWnd* myWnd = new CMyWnd;

myWnd->Create(...);

(b)     TMyWindow* w = new 

TMyWindow(...);


Listing Two: Creating an MDI frame window.


(a)     class CMyWnd : 

public CMDIFrameWnd {...};

class CMyApp : 

public CWinApp {

public:

// ...

virtual BOOL InitInstance() {

CMyWnd* w = new CMyWnd;

if (!w)->LoadFrame(IDRES) )

return FALSE;

w->ShowWindow(m_nCmdShow);

w->UpdateWindow();

m_pMainWnd = w;

return TRUE;

}

};

(b)     class TMyWnd : 

public TMDIFrame {...};

class TMDIFileApp : 

public TApplication {

public:

void InitMainWindow() {

Frame = new TMDIFrame(..);

Frame->Attr.AccelTable = IDRES;

Frame->SetMenuDescr(...);

}

};


Listing Three: Creating an SDI frame window.


(a)     class CMyWnd : 

public CFrameWnd {...};

class CMyApp : public CWinApp {

public:

// ...

virtual BOOL InitInstance(){

CMyWnd* w = new CMyWnd;

if (!w->LoadFrame(IDRES) )

return FALSE;

w->ShowWindow(m_nCmdShow);

w->UpdateWindow();

m_pMainWnd = w;

return TRUE;

}

};

(b)     class TMyWnd :

public TFrameWindow {...};

class TSDIFileApp : public

TApplication {

public:

void InitMainWindow() {

Frame = new 

TFrameWindow(...);

Frame->Attr.AccelTable = IDRES;

Frame->SetMenuDescr(...);

}

};


Listing Four: Creating Doc/View templates.


(a)     class CMyWnd : public

CMDIChildWnd {..};

class CMyApp : public CWinApp {

public:

// ...

virtual BOOL InitInstance() {

AddDocTemplate(new

CMultiDocTemplate(IDRES,

RUNTIME_CLASS(CMyDoc),

RUNTIME_CLASS(CMyWnd),

RUNTIME_CLASS(CMyView)));

CMyWnd* w = new CMyWnd;

if (!w->LoadFrame(IDRES) )

return FALSE;

w->ShowWindow(m_nCmdShow);

w->UpdateWindow();

m_pMainWnd = w;

}

};

(b)     DEFINE_DOC_TEMPLATE_CLASS(

TMyDocument, TMyView, MyTemplate);

MyTemplate btpl("My files", "*.txt", 0, "TXT", dtAutoDelete);

class TMyApp : public 

TApplication {

public:

// ...

void  InitMainWindow() {

DocManager = new 

TDocManager(dmSDI | dmMenu);

}

};


Listing Five: Iterating over child windows.


(a)     void CMyWnd::Iterate()

{

for (CWnd* w = GetTopWindow();

w != NULL;

w = w->GetNextWindow()) {

// use child window 'w

}

}

(b)     static void f(TWindow* w, void*)

{...do something with 'w'}

void TMyWindow::g()

{   ForEach(f); }



Listing Six: Locating a child window.


(a)     CWnd* CMyWnd::FindChild()

{

for (CWnd* w = GetTopWindow();

w != NULL;

w = w->GetNextWindow()) {

// see if child window found

if (w is the right window)

return w;

}

return 0;

}

(b)     static BOOL f(TWindow* win, void*)

{

if (win satisfies some condition)

return TRUE;

else

return FALSE;

}

void TMyWindow::g()

{

TWindow* first = FirstThat(f);

TWindow* last  = LastThat(f);

}


Listing Seven: Finding active MDI child window.


(a)     class CMyWnd: public 

CMDIFrameWnd {

// ...

public:

void f() {

CMDIChildWnd* w = MDIGetActive();

if (!w) return;

// use w ...

}

};

(b)     class TMDIFileApp : public 

TApplication {

public:

// ...

MDIClient* Client;

protected:

void f() {

TMDIChild* w = Client->GetActiveMDIChild();

if (!w) return;

// use w..

}

};


Listing Eight: Initializing controls in a dialog box.


(a)     class CMyDlg : public CDialog {

public:

// ...

//{{AFX_DATA(CMyDlg)

int m_Value1;

int m_Value2;

//}}AFX_DATA

protected:

DECLARE_MESSAGE_MAP()

};

void CMyDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

DDX_Text(pDX, IDC_EDIT1, m_Value1);

DDV_MinMaxInt(pDX, m_Value1, -10, 20);

DDX_Text(pDX, IDC_EDIT2, m_Value2);

DDV_MinMaxInt(pDX, m_Value2, 0, 100);

}

(b)     struct {

// transfer buffer

// ...

} Buffer

class TMyDlg : public 

TDialog {

public:

// ...

TMyDlg(...) {

// .. create controls

TransferBuffer = &Buffer;

}

};


Listing Nine: Bitmapped buttons.


(a)     ass CMyDlg : public CDialog {

public:

enum {IDD = IDD_BITMAPDLG};

CMyDlg();

// ...

protected:

CBitmapButton button1;

};

CMyDlg::CMyDlg() : CDialog(CMyDlg::IDD) 

{

if (!button1.LoadBitmaps("Up","Down","Focus")) {

TRACE("Problem!");

AfxThrowResourceException();

}

}

(b)     no code necessary


Listing Ten: Creating a pen.


(a)     CPen pen;

pen.CreatePen(PS_SOLID, 1, RGB(0,0,0));

(b)     TPen pen(TColor(0, 0, 0) );


Listing Eleven: Drawing a line.


(a)     void CMyWnd::Line(CDC& dc)

{

CPen pen;

pen.CreatePen(PS_SOLID, 1, RGB(0,0,0) );

CPen* pOldPen = dc.SelectObject(&pen);

dc.MoveTo(10, 10);

dc.LineTo(20, 30);

dc.SelectObject(pOldPen);

}

(b)     void TMyWnd::Line(TDC& dc)

{

TPen pen(TColor(0, 0, 0) );

dc.SelectObject(pen);

dc.MoveTo(0, 100);

dc.LineTo(100, 20);

dc.RestorePen();

}


Listing Twelve: Painting with a brush.


(a)     void CMyWnd::Box(CDC& dc)

{

CBrush brush(RGB(0, 0, 0) );

CBrush* pOldBrush = pDC->SelectObject(&brush);

dc.Rectangle(30, 30, 100, 100);

dc.SelectObject(pOldBrush);

}

(b)     void TMyWnd::Box(TDC& dc)

{

dc.SelectObject(

TBrush(Color(0,0,0)));

dc.Rectangle(0,20,30,400);

dc.RestoreBrush();

}


Listing Thirteen: Creating fonts.


(a)     void CMyWnd::Font(CDC& dc)

{

LOGFONT lf;

memset(&lf, 0, sizeof(lf));

lf.lfHeight = 20;

lf.lfWeight = FW_BOLD;

strcpy(lf.lfFaceName, "Arial");

CFont font;

font.CreateFontIndirect(&lf));

}

(b)     void TMyWnd::Font(TDC& dc)

{

LOGFONT lf;

memset(&lf, 0, sizeof(lf));

lf.lfHeight = 20;

lf.lfWeight = FW_BOLD;

strcpy(lf.lfFaceName, "Arial");

TFont font(&lf);

}


Listing Fourteen: Displaying bitmaps.


(a)     void CMyWnd::DrawBM(CDC& dc)

{

CBitmap bm;

bm.Create("MYBITMAP");

CBitmap* pbmOld;

CDC dcMem;

dcMem.CreateCompatibleDC(&dc);

pbmOld = dcMem.SelectObject(&bm);

dc.BitBlt(100, 100, 50, 50, &dcMem, 0, 0, SRCCOPY);

dcMem.SelectObject(pbmOld);

dcMem.DeleteDC();

}



(b)     void TMyWnd::Draw(TDC& dc)

{

TBitmap* bm = new 

TBitmap(*GetModule(), "ID");

TMemoryDC memoryDC(dc);

memoryDC.SelectObject(*Bitmap);

TRect rect(0, 0, 40, 40);

dc.BitBlt(rect, memoryDC, TPoint(0,0), SRCCOPY);

}


Listing Fifteen: Creating an array.


(a)     CByteArray myArray;

(b)     TIArrayAsVector<int>myArray(5,0,5);;


Listing Sixteen: Copying an array.


(a)     CByteArray myArray;    // array to be copied

CByteArray copyArray;  // array copied into

for (int i=0; i < 

myArray.GetSize(); i++)

copyArray [i] = myArray [i];


(b)     TVectorImp<int> myArray;

TVectorImp<int> copyArray;

for (int i = 0; 

i < myArray.Count();

i++)

copyArray [i] = myArray [i];


Listing Seventeen: Adding elements to an array.


(a)     CByteArray myA;

BYTE value = 2;

myA.Add(value);

(b)     TIArrayAsVector<int> myA(5,0,5);

int value = 5;

myA.AddAt(&value, 5);


Listing Eighteen: Removing elements from an array.


(a)     CByteArray myArray;

myArray.RemoveAt(10);


(b)     TIArrayAsVector<int> myArray(5,0,5);

myArray.Detach(3);


Listing Nineteen: Searching an array for an item.


(a)     CByteArray myArray;

int FindItem(BYTE value)

{

for (int i=0; i < 

myArray.GetSize(); i++) {

if (myArray [i] == value)

return i;

}

return -1;

}

(b)     TIArrayAsVector<int> myArray(5,0,5);

int value = 5;

int index = myArray.Find(&value);


Listing Twenty: Deleting the items in an array.


(a)     CStringArray myArray;

void DeleteArray()

{

for (int i=0; i < 

myArray.GetSize(); i++) delete myArray [i];

myArray.RemoveAll();

}

(b)     TIArrayAsVector<int> myArray(5,0,5);

myArray.Flush();


Listing Twenty-one: Creating a list.


(a)     CStringList myList;

(b)     TListImp<string> myList();


Listing Twenty-two: Copying a list.


(a)     CStringList myList;  // list to copy

CStringList copyList; // list copied to

void CopyList()

{

POSITION pos = myList.GetHeadPosition();

while (pos)

copyList.AddTail(myList.GetNext(pos) 

);

}

(b)     TListImp<string> myList;

TListImp<string> copyList;

static void DoCopy(string& s, void*)

{copyList.Add(s);}

void f()

{ myList.ForEach(DoCopy, 0); }

Listing Twenty-three: Adding items to a list.


(a)     CStringList myList;

myList.AddTail("Hello");

myList.AddHead("Good-bye");

(b)     TListImp<string> myList;

string s("Test");

myList.Add(s);


Listing Twenty-four: Removing items from a list.


(a)     CStringList myList;

void RemoveItem(CString& target)

{

POSITION pos = myList.GetHeadPosition();

while (pos) {

CString& str = myList.GetNext(pos);

if (str == target)

myList.RemoveAt(pos);

delete str;

}

}


(b)     TListImp<string> myList;

string s("Test");

myList.Detach(s);


Listing Twenty-five: Searching a list for an item.


(a)     CStringList myList;

BOOL HasString(CString& target)

{

POSITION pos = myList.GetHeadPosition();

while (pos) {

CString& str = myList.GetNext(pos);

if (str == target)

return TRUE;

}

return FALSE;

}

(b)     TListImp<string> myList;

string s("Test");

if (myList.Find(s) ) {

// the item was found...

}



Listing Twenty-six: Deleting all the items in a list.


(a)     CStringList myList;

void DeleteList()

{

POSITION pos = myList.GetHeadPosition();

while (pos)

delete 

myList.GetNext(pos);

myList.RemoveAll();

}

(b)     TListImp<string> myList;

myList.Flush();


Listing Twenty-seven: Creating a dictionary.


(a)     CMapStringToOb myMap;

(b)     // create a hashable class

class HashString : public 

string {

public:

HashString() : string() {}

HashString(const char* s) : string(s) {}

unsigned HashValue() const 

{ return hash(); }

};

void f()

{   typedef

TDDAssociation<HashString, HashString> symbol;

TDictionaryAsHashTable <symbol> Dictionary;


Listing Twenty-eight: Copying a dictionary.


(a)     CMapStringToOb myMap;  // map to copy

CMapStringToOb myCopy; // map copied to

POSITION pos = myMap.GetStartPosition();

while (pos) {

CString string;

CObject* pObject;

myMap.GetNextAssoc(pos, string, pObject);

copyMap.SetAt(string, pObject);

}

(b)     typedef TDDAssociation

<HashString, HashString> symbol;

typedef 

TDictionaryAsHashTable <symbol> dictionary;

dictionary myTable;

dictionary copyTable;

static void DoCopy(symbol& s, void*)

{ copyTable.Add(s); }

void f()

{ myTable.ForEach(DoCopy, 0);

}


Listing Twenty-nine: Adding items to a dictionary.


(a)     CMapStringToOb myMap;

CString string;

CObject* pObject;

myMap.SetAt(string, pObject);

(b)     symbol s(HashString("K"), HashString("V"));

myTable.Add(s);


Listing Thirty: Removing items from a dictionary.


(a)     CMapStringToOb myMap;

void RemoveItem(CString& str)

{

CObject* pObject;

if (!myMap.Lookup(str,&pObject))

return;

myMap.RemoveKey(str);

delete str;

delete *pObject;

}

(b)     symbol s(HashString("K"), HashString("V") );

myTable.Detach(s);


Listing Thirty-one: Searching a dictionary for an item.


(a)     CMapStringToOb myMap;

BOOL HasItem(CString& str)

{

CObject* pObj;

return myMap.Lookup(str,&pObj) ;

}

(b)     symbol s(HashString("K"), HashString("V") );

symbol* r = myTable.Find(s);

if (r) {

// found...

}

Listing Thirty-two:


// Paint routine for Window, Printer, and PrintPreview for a TOleView client.
void mytestOleView::Paint (TDC& dc, bool erase, TRect& rect)
{
    mytestApp *theApp = TYPESAFE_DOWNCAST(GetApplication(), mytestApp);
    if (theApp) {
        // Only paint if we're printing and we have something 
        // to paint, otherwise do nothing.
        if (theApp->Printing && 
            theApp->Printer && 
            !rect.IsEmpty()) {
            // Use pageSize to get the size of the window to render into.
            // For a Window it's the client area; for a printer, it's the
            // printer DC dimensions; for print preview, it's layout window.
            TSize pageSize(rect.right - rect.left, rect.bottom - rect.top);
            TPrintDialog::TData &printerData = theApp->Printer->GetSetup();
            // Compute the number of pages to print.
            printerData.MinPage = 1;
            printerData.MaxPage = 1;
            TOcView* ocView = GetOcView();
            // Default TOcPart painting
            TRect clientRect = GetClientRect();
            TRect logicalRect = clientRect + (Tsize&) ocView->GetOrigin();
            for (TOcPartCollectionIter i(GetOcDoc()->GetParts()); 
                 i; 
                 i++) {
                TOcPart& p = *i.Current();
                if (p.IsVisible(logicalRect)) {
                TRect r = p.GetRect();
                r -= ocView->GetOrigin();
                 // Draw the embedded object
                p.Draw(dc, r, clientRect);
                if (p.IsSelected()) {
                TUIHandle handle(r, TUIHandle::HandlesIn |
                                        TUIHandle::Grapples    |
                            TUIHandle::HatchBorder, 5);
                handle.Paint(dc);
                } 
                 else {
                  TUIHandle handle(r, TUIHandle::HatchBorder, 5);
                  handle.Paint(dc);
                }
                }
            }
            // INSERT>> Special printing code goes here.
        } else {
            TOleView::Paint(dc, erase, rect);
            // INSERT>> Normal painting code goes here.
        }
        dc.TextOut(0, 30, "mytest OLE Server");
    }
}


Copyright © 1995, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.