📄 ch17.htm
字号:
6: .7: .8: .9: // Implementation10: public:11: CObArray* GetDrawing();12: virtual ~CTestAppDoc();13: .14: .15: .16: private:17: CObArray m_oaLines;18: };</PRE><DL> <DT><B>Modifying the Document Functions</B></DT></DL><P>Now that you've made the general changes to the test application, it's time tostart making the functionality changes. All the calls to a class method of the drawingobject must be changed to the appropriate function call in the new DLL.</P><P>The changes necessary in the OnNewDocument function consist of dropping the functioncall to pass the CRect to the drawing object and replacing the NewDocument functioncall with the new DLL function--in this instance, ModArtNewDrawing, as shown in line19 in Listing 17.13.</P><P><H4>LISTING 17.13. THE CTestAppDoc OnNewDocument FUNCTION.</H4><PRE>1: BOOL CTestAppDoc::OnNewDocument()2: {3: if (!CDocument::OnNewDocument())4: return FALSE;5:6: // TODO: add reinitialization code here7: // (SDI documents will reuse this document)8:9: // Get the position of the view10: POSITION pos = GetFirstViewPosition();11: // Did we get a valid position?12: if (pos != NULL)13: {14: // Get a pointer to the view15: CView* pView = GetNextView(pos);16: RECT lWndRect;17: // Get the display area rectangle18: pView->GetClientRect(&lWndRect);19: // Create a new drawing20: ModArtNewDrawing(lWndRect, &m_oaLines);21: }22:23: return TRUE;24: }</PRE><P>In the Serialize function, change the drawing object Serialize function call tothe new DLL serialization function--in this case, ModArtSerialize, as in Listing17.14.</P><P><H4>LISTING 17.14. THE CTestAppDoc Serialize FUNCTION.</H4><PRE>1: void CTestAppDoc::Serialize(CArchive& ar)2: {3: // Serialize the drawing4: ModArtSerialize(ar, &m_oaLines);5: }</PRE><P>For the DeleteContents function, you need to change the call to the ClearDrawingfunction to the new DLL function, ModArtClearDrawing, as in line 5 of Listing 17.15.</P><P><H4>LISTING 17.15. THE CTestAppDoc DeleteContents FUNCTION.</H4><PRE>1: void CTestAppDoc::DeleteContents()2: {3: // TODO: Add your specialized code here and/or call the base class4: // Delete the drawing5: ModArtClearDrawing(&m_oaLines);6:7: CDocument::DeleteContents();8: }</PRE><P>Finally, for the GetDrawing function, you need to change the function declarationto designate that it's returning a pointer to an object array, just as you did inthe header file. Next, you need to change the variable that is being returned tothe object array variable that you added to the header file, as in Listing 17.16.</P><P><H4>LISTING 17.16. THE CTestAppDoc GetDrawing FUNCTION.</H4><PRE>1: CObArray* CTestAppDoc::GetDrawing()2: {3: // Return the drawing object4: return &m_oaLines;5: }</PRE><H4>Modifying the View Functions</H4><P>Switching to the view class, there's only one simple change to make to the OnDrawfunction. In this function, you need to change the type of pointer retrieved fromthe GetDrawing function from a drawing object to an object array object, as in line9 of Listing 17.17. Next, call the DLL function, ModArtDraw, to perform the drawingon the window, as shown in line 11.</P><P><H4>LISTING 17.17. THE CTestAppView OnDraw FUNCTION.</H4><PRE>1: void CTestAppView::OnDraw(CDC* pDC)2: {3: CModTestAppDoc* pDoc = GetDocument();4: ASSERT_VALID(pDoc);5:6: // TODO: add draw code for native data here7:8: // Get the drawing object9: CObArray* m_oaLines = pDoc->GetDrawing();10: // Draw the drawing11: ModArtDraw(pDC, m_oaLines);12: }</PRE><P>After making all these changes to the test application, you are ready to compileand test it. You should find that the application is working just as it did withthe previous DLL. You can also play around with it, going back and changing the DLL,copying the new DLL into the debug directory for the test application, and seeinghow the changes are reflected in the behavior of the test application.</P><BLOCKQUOTE> <P><HR><STRONG>CAUTION:</STRONG> The particular example of a regular DLL that you developed in this exercise is still not usable by other programming languages. The reason is that you are passing MFC classes as the arguments for each of the DLL's functions. This still limits the usage to other applications that are built using MFC. To make this DLL truly portable, you need to pass the bare-bones structures instead of the classes (such as the RECT structure instead of the CRect class) and then convert the structures to the classes inside the DLL.<HR></BLOCKQUOTE><H2><A NAME="Heading11"></A>Summary</H2><P>Today you learned about two more ways that you can package your functionalityfor other programmers. You learned how you can easily package your classes as anMFC extension DLL and how easily it can be used by a Visual C++ application. Yousaw how you can make changes to the DLL without having to recompile the applicationsthat use it. You also learned what's involved in creating a regular DLL that canbe used with other, non-Visual C++ applications. You saw how you needed to convertthe exported classes from the DLL into standard C-style functions and what's involvedin adapting an application to use this style of DLL.</P><P><H2><A NAME="Heading12"></A>Q&A</H2><DL> <DT></DT> <DD><B>Q How can I convert the regular DLL so that it can be used by non-Visual C++ applications?</B> <P> <DT><B></B></DT> <DD><B>A</B> First, you have to make all the arguments to the functions use the bare-bones structures, instead of the MFC classes. For instance, to convert the ModArtNewDrawing function, change it to receive the RECT structure instead of the CRect class and also to receive a generic pointer instead of a pointer to an object array. You have to make the conversions to the appropriate classes in the DLL, as in lines 4 through 9 in Listing 17.18. <P></DL><H4>LISTING 17.18. THE ModArtNewDrawing FUNCTION.</H4><PRE>1: extern "C" void PASCAL EXPORT ModArtNewDrawing(RECT spRect, ÂLPVOID lpoaLines)2: {3: AFX_MANAGE_STATE(AfxGetStaticModuleState());4: CRect pRect;5: pRect.top = spRect.top;6: pRect.left = spRect.left;7: pRect.right = spRect.right;8: pRect.bottom = spRect.bottom;9: CObArray* poaLines = (CObArray*)lpoaLines;10: // Normal function body here11: int m_lNumLines;12: int m_lCurLine;13:14: // Initialize the random number generator15: srand((unsigned)time(NULL));16: // Determine how many lines to create17: m_lNumLines = rand() % 50;18: // Are there any lines to create?19: if (m_lNumLines > 0)20: {21: // Loop through the number of lines22: for (m_lCurLine = 0; m_lCurLine < m_lNumLines; m_lCurLine++)23: {24: // Create the new line25: NewLine(pRect, poaLines);26: }27: }28: }</PRE><DL> <DT></DT> <DD>You also have to add functions to create and destroy the object array, with the application storing the object array as a generic pointer as in Listing 17.19. <P></DL><H4>LISTING 17.19. THE ModArtInit FUNCTION.</H4><PRE>1: extern "C" LPVOID PASCAL EXPORT ModArtInit()2: {3: AFX_MANAGE_STATE(AfxGetStaticModuleState());4: // Create the object array5: return (LPVOID)new CObArray;6: }</PRE><DL> <DT></DT> <DD><B>Q When do I need to recompile the applications that use my DLLs?</B> <P> <DT><B></B></DT> <DD><B>A</B> Whenever you change any of the exported function calls. Changing, adding, or removing arguments to any of these functions would mean recompiling the applications that use the DLL. If you are working with an MFC extension DLL, the applications that use the DLL need to be recompiled if the public interface for the exported classes change or a new function or variable is added or removed. It doesn't matter if the application isn't using any of the functions that were changed; it's still good practice to recompile the applications, just to be sure. <P></DL><H2><A NAME="Heading13"></A>Workshop</H2><P>The Workshop provides quiz questions to help you solidify your understanding ofthe material covered and exercises to provide you with experience in using what you'velearned. The answers to the quiz questions and exercises are provided in AppendixB, "Answers."</P><P><H3><A NAME="Heading14"></A>Quiz</H3><DL> <DT></DT> <DD><B>1. </B>What kind of DLL do you have to create to make classes in the DLL available to applications? <P> <DT></DT> <DD><B>2. </B>What do you have to add to the class to export it from a DLL? <P> <DT></DT> <DD><B>3. </B>What kind of DLL can be used with other programming languages? <P> <DT></DT> <DD><B>4. </B>If you make changes in a DLL, do you have to recompile the applications that use the DLL? <P> <DT></DT> <DD><B>5. </B>What function does the LIB file provide for a DLL? <P></DL><H3><A NAME="Heading15"></A>Exercises</H3><DL> <DT></DT> <DD><B>1. </B>Separate the line class into its own MFC extension DLL and use it with the second (regular) DLL. <P> <DT></DT> <DD><B>2. </B>Alter the line class DLL so that it uses a consistent line width for all lines.</DL><H1></H1><CENTER><P><HR><A HREF="../ch16/ch16.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch18/ch18.htm"><IMGSRC="../button/next.gif" WIDTH="128" HEIGHT="28" ALIGN="BOTTOM" ALT="Next chapter"BORDER="0"></A><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <BR><BR></P><P>© <A HREF="../copy.htm">Copyright</A>, Macmillan Computer Publishing. Allrights reserved.</CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -