📄 ch17.htm
字号:
creating. You can create this new project using the same steps you used to create
the MFC extension DLL project, but specify on the DLL Wizard that you are creating
a regular DLL. (You can leave the wizard at the default settings.) Once you create
the project, you can copy the line and drawing class source code and header files
into the project directory and add these files to the project. Once you add these
files to the project, you need to begin the process of converting the drawing class
into a series of straight function calls.</P>
<P>
<DL>
<DT><B>Altering the Header File</B></DT>
</DL>
<P>To start with, you need to radically alter the header file for the drawing class
so that it will work for a regular DLL. You have to eliminate every trace of the
actual class from the header file, leaving only the function calls. All of these
functions must be passed in any objects that they need to work with. (Every function
will need to be passed the object array as one of its arguments.) Next, you need
to slightly modify all the function names so that the compiler does not get mixed
up and call a member function of any class by mistake (such as the Serialize function).
Finally, each of the public functions must be declared as an exportable function.
Making these changes to the header file, you end up replacing the entire class declaration
with the function prototypes in Listing 17.5.</P>
<P>
<H4>LISTING 17.5. THE MODIFIED ModArt HEADER FILE.</H4>
<PRE>1: extern "C" void PASCAL EXPORT ModArtNewDrawing(CRect pRect,
ÂCObArray *poaLines);
2: extern "C" void PASCAL EXPORT ModArtSerialize(CArchive &ar,
ÂCObArray *poaLines);
3: extern "C" void PASCAL EXPORT ModArtDraw(CDC *pDC, CObArray *poaLines);
4: extern "C" void PASCAL EXPORT ModArtClearDrawing(CObArray *poaLines);
5: void NewLine(CRect pRect, CObArray *poaLines);
</PRE>
<BLOCKQUOTE>
<P>
<HR>
<STRONG>NOTE:</STRONG> Notice that the object array is always passed as a pointer to each
of these functions. Because these functions are adding and removing objects from
the array, they need to work with the actual array and not a copy of it.
<HR>
</BLOCKQUOTE>
<H4>Adapting the Drawing Generation Functions</H4>
<P>Moving to the source-code file, you need to make numerous small yet significant
changes to these functions. Starting with the NewDrawing function, you need to pass
in the CRect object to get the drawing area. You dropped the function for setting
the drawing area because you have no local variables in which you can hold this object.
As a result, you are better off passing it to the drawing generation functions. The
other change is where you pass in the object array as another argument to the function.
You aren't doing anything with either of these arguments in this function, just passing
them along to the squiggle generating function. The other alteration in this function
is the addition of the AFX_MANAGE_STATE macro as the first line in the body of the
function. After making these changes, the NewDrawing function will look like the
one in Listing 17.6.</P>
<P>
<H4>LISTING 17.6. THE ModArtNewDrawing FUNCTION.</H4>
<PRE>1: extern "C" void PASCAL EXPORT ModArtNewDrawing(CRect pRect,
ÂCObArray *poaLines)
2: {
3: AFX_MANAGE_STATE(AfxGetStaticModuleState());
4: // normal function body here
5: int lNumLines;
6: int lCurLine;
7:
8: // Initialize the random number generator
9: srand((unsigned)time(NULL));
10: // Determine how many lines to create
11: lNumLines = rand() % 50;
12: // Are there any lines to create?
13: if (lNumLines > 0)
14: {
15: // Loop through the number of lines
16: for (lCurLine = 0; lCurLine < lNumLines; lCurLine++)
17: {
18: // Create the new line
19: NewLine(pRect, poaLines);
20: }
21: }
22: }
</PRE>
<P>Another change that is required in the NewDrawing function is the addition of
the random number generator seeding on line 9. Because there is no class constructor
any more, you cannot seed the random number generator in it. Therefore, the next
logical place to add this is in the NewDrawing function before any random numbers
are generated.</P>
<P>On the NewLine function, the changes are more extensive. First, the CRect object
and the object array are passed in as arguments. Second, because this is not an exported
function, you do not need to add the AFX_MANAGE_STATE macro. Third, all the places
where the CRect member variable is used must be changed to use the CRect that is
passed as an argument to the function. Finally, when adding objects to the object
array, you need to change this to use the object array pointer that was passed as
an argument. Making these changes leaves you with the code in Listing 17.7.</P>
<P>
<H4>LISTING 17.7. THE NewLine FUNCTION.</H4>
<PRE> 1: void NewLine(CRect pRect, CObArray *poaLines)
2: {
3: int lNumLines;
4: int lCurLine;
5: // int nCurColor;
6: UINT nCurWidth;
7: CPoint pTo;
8: CPoint pFrom;
9: int cRed;
10: int cBlue;
11: int cGreen;
12:
13: // Normalize the rectangle before determining the width and Âheight
14: pRect.NormalizeRect();
15: // get the area width and height
16: int lWidth = pRect.Width();
17: int lHeight = pRect.Height();
18:
19: // COLORREF crColors[8] = {
20: // RGB( 0, 0, 0), // Black
21: // RGB( 0, 0, 255), // Blue
22: // RGB( 0, 255, 0), // Green
23: // RGB( 0, 255, 255), // Cyan
24: // RGB( 255, 0, 0), // Red
25: // RGB( 255, 0, 255), // Magenta
26: // RGB( 255, 255, 0), // Yellow
27: // RGB( 255, 255, 255) // White
28: // };
29:
30: // Determine the number of parts to this squiggle
31: lNumLines = rand() % 200;
32: // Are there any parts to this squiggle?
33: if (lNumLines > 0)
34: {
35: // Determine the color
36: // nCurColor = rand() % 8;
37: cRed = rand() % 256;
38: cBlue = rand() % 256;
39: cGreen = rand() % 256;
40: // Determine the pen width
41: nCurWidth = (rand() % 8) + 1;
42: // Determine the starting point for the squiggle
43: pFrom.x = (rand() % lWidth) + pRect.left;
44: pFrom.y = (rand() % lHeight) + pRect.top;
45: // Loop through the number of segments
46: for (lCurLine = 0; lCurLine < lNumLines; lCurLine++)
47: {
48: // Determine the end point of the segment
49: pTo.x = ((rand() % 20) - 10) + pFrom.x;
50: pTo.y = ((rand() % 20) - 10) + pFrom.y;
51: // Create a new CLine object
52: CLine *pLine = new CLine(pFrom, pTo, nCurWidth,
ÂRGB(cRed, cGreen, cBlue));
53: try
54: {
55: // Add the new line to the object array
56: poaLines->Add(pLine);
57: }
58: // Did we run into a memory exception?
59: catch (CMemoryException* perr)
60: {
61: // Display a message for the user, giving him the
62: // bad news
63: AfxMessageBox("Out of memory", MB_ICONSTOP | MB_OK);
64: // Did we create a line object?
65: if (pLine)
66: {
67: // Delete it
68: delete pLine;
69: pLine = NULL;
70: }
71: // Delete the exception object
72: perr->Delete();
73: }
74: // Set the starting point to the end point
75: pFrom = pTo;
76: }
77: }
78: }
</PRE>
<H4>Adapting the Other Functions</H4>
<P>Making the necessary changes to the other functions is less involved than the
changes to the drawing generation functions. With the rest of the functions, you
must add a pointer to the object array as a function argument and then alter the
uses of the array to use the pointer instead of the no longer existing member variable.
You also need to add the AFX_MANAGE_STATE macro as the first line in each of the
remaining functions. This leaves you with the functions shown in Listings 17.8, 17.9,
and 17.10.</P>
<P>
<H4>LISTING 17.8. THE ModArtDraw FUNCTION.</H4>
<PRE>1: extern "C" void PASCAL EXPORT ModArtDraw(CDC *pDC, CObArray *poaLines)
2: {
3: AFX_MANAGE_STATE(AfxGetStaticModuleState());
4: // normal function body here
5: // Get the number of lines in the object array
6: int liCount = poaLines.GetSize();
7: int liPos;
8:
9: // Are there any objects in the array?
10: if (liCount)
11: {
12: // Loop through the array, drawing each object
13: for (liPos = 0; liPos < liCount; liPos++)
14: ((CLine*)poaLines[liPos])->Draw(pDC);
15: }
16: }
</PRE>
<H4>LISTING 17.9. THE ModArtSerialize FUNCTION.</H4>
<PRE>1: extern "C" void PASCAL EXPORT ModArtSerialize(CArchive &ar,
ÂCObArray *poaLines)
2: {
3: AFX_MANAGE_STATE(AfxGetStaticModuleState());
4: // normal function body here
5: // Pass the archive object on to the array
6: poaLines.Serialize(ar);
7: }
</PRE>
<H4>Listing 17.10. The MODARTCLEARDRAWING function.</H4>
<PRE>1: extern "C" void PASCAL EXPORT ModArtClearDrawing(CObArray *poaLines)
2: {
3: AFX_MANAGE_STATE(AfxGetStaticModuleState());
4: // Normal function body here
5: // Get the number of lines in the object array
6: int liCount = poaLines.GetSize();
7: int liPos;
8:
9: // Are there any objects in the array?
10: if (liCount)
11: {
12: // Loop through the array, deleting each object
13: for (liPos = 0; liPos < liCount; liPos++)
14: delete poaLines[liPos];
15: // Reset the array
16: poaLines.RemoveAll();
17: }
18: }
</PRE>
<P>Once you make the changes to these functions, the only thing remaining is to remove
all code for the class constructor and destructor, along with the code for the SetRect
function.</P>
<P>
<H4>Building the Module Definition File</H4>
<P>Before you compile the DLL, you need to add all the function names to the module
definition file. You can find this file in the list of source-code files in the File
View of the workspace pane. When you open this file, you'll find that it briefly
describes the module that you are building in generic terms. You'll see a place at
the bottom of the file where you can add the exports for the DLL. Edit this file,
adding the exportable function names, as in Listing 17.11.</P>
<P>
<H4>LISTING 17.11. THE DLL MODULE DEFINITION FILE.</H4>
<PRE>1: ; ModArtRDll.def : Declares the module parameters for the DLL
2:
3: LIBRARY "ModArtRDll"
4: DESCRIPTION `ModArtRDll Windows Dynamic Link Library'
5:
6: EXPORTS
7: ; Explicit exports can go here
8: ModArtNewDrawing
9: ModArtSerialize
10: ModArtDraw
11: ModArtClearDrawing
</PRE>
<P>You are now ready to compile your regular DLL. Once you compile the DLL, copy
it into the debug directory of the test application.</P>
<P>
<H3><A NAME="Heading10"></A>Adapting the Test Application</H3>
<P>To adapt the test application to use the new DLL that you have just created, you
need to make a number of changes. First, you need to change the member variable of
the document class from an instance of the drawing class to the object array. Next,
you need to change the include in the document and view source code to include the
header from the new DLL instead of the header from the old DLL. (You can completely
remove the include in the application source-code file.) Drop the DLL LIB file and
add the LIB file for the new DLL to the project. Change all of the drawing class
function calls to call functions in the new DLL instead. Finally, change the GetDrawing
function in the document class so that it returns a pointer to the object array,
instead of the drawing object.</P>
<P>You can start making these changes by deleting the LIB file from the test application
project. Once you delete the file, add the LIB file for the new DLL to the project
by selecting Project | Add To Project | Files from the main menu.</P>
<P>Once you switch the LIB files in the project, edit the source code for the document
and view classes to change the include statement, changing the project directory
to the new DLL project directory. You can edit the application class source-code
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -