📄 ch15.htm
字号:
<P>This means that the call to <font color="#008000">UpdateRegistry()</font> did not change these two keys. There is a way to provide parameters to <font color="#008000">UpdateRegistry()</font> to insist that the keys be updated, but it's even more
complicated than the route you will follow. Because no code has been changed from that provided by AppWizard, it's much quicker just to delete the ShowString directory and create it again, this time setting the long file type to ShowString Document.</P>
<blockquote><p><img src="caution.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/caution.gif">
<P>Always test AppWizard-generated code before you add changes of your own. Until you are familiar with every default you are accepting, it is worth a few moments to see what you have before moving on. Rerunning AppWizard is easy, but if you've made
several hours worth of changes and then decide to rerun it, it's not such a simple thing.</P>
<p><img src="bottom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/bottom.gif"></blockquote>
<P>Delete the ShowString folder entirely and generate a new application with AppWizard as before. This time, in Step 4, click the Advanced button and change the file type names as shown in Figure 15.6. After you click Finish, AppWizard asks whether you
wish to reuse the existing CLSID, as shown in Figure 15.7. Click Yes and then OK to create the project. This makes a new showstring.reg file for you with the correct Registry values.</P>
<A HREF="Qfigs06.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch15/Qfigs06.gif"><b>Fig. 15.6</b></A>
<P><I>The Advanced options dialog box of Step 4 of AppWizard is the place to improve the file type names.</I></P>
<A HREF="Qfigs07.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch15/Qfigs07.gif"><b>Fig. 15.7</b></A>
<P><I>AppWizard makes sure that you don't accidentally reuse a CLSID.</I></P>
<P>This changes the string table as well as the showstring.reg file, so you might be tempted to build and run the application to make this fix complete. And it's true, when you run the application, it will update the Registry for you, using the values
from the new string table. Alas, the registration update will fail yet again. If you were to try it, these messages would appear in the output window:</P>
<pre><font color="#008000">Warning: Leaving value 'ShowSt Document' for key </font></pre>
<pre><font color="#008000"> 'ShowString.Document' in registry</font></pre>
<pre><font color="#008000"> intended value was 'ShowString Document'.</font></pre>
<pre><font color="#008000">Warning: Leaving value 'ShowSt Document' for key </font></pre>
<pre><font color="#008000"> 'CLSID\{0B1DEE40-C373-11CF-870C-00201801DDD6}' in registry</font></pre>
<pre><font color="#008000"> intended value was 'ShowString Document'.</font></pre>
<pre><font color="#008000">Warning: Leaving value 'ShowSt' for key </font></pre>
<pre><font color="#008000"> 'CLSID\{0B1DEE40-C373-11CF-870C-00201801DDD6}\AuxUserType\2' </font></pre>
<pre><font color="#008000"> in registry</font></pre>
<pre><font color="#008000"> intended value was 'ShowString'.</font></pre>
<P>So, how do you get out of this mess? You have to edit the Registry. If that sounds intimidating, it should be. Messing with the Registry can leave your system unusable. But you are not going to go in by hand and change keys; instead, you are going to
use the registry file that AppWizard generated for you. Here's what to do:</P>
<ol>
<li><P> Choose Start, Run</P>
<li><P> Type <B>regedit</B> and press Enter.</P>
<li><P> Choose <U>R</U>egistry, <U>I</U>mport Registry File from the Registry Editor menu.</P>
<li><P> Using the Import Registry File dialog box, move through your folders until you reach the one where the replacement ShowString server was just generated by AppWizard, as shown in Figure 15.8. Click Open.</P>
<li><P> A success message is shown. Click OK.</P>
<li><P> Close the Registry Editor.</P>
</ol>
<A HREF="Qfigs08.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch15/Qfigs08.gif"><b>Fig. 15.8</b></A>
<P><I>Registry files generated by AppWizard have the extension .reg.</I></P>
<P>Now if you run ShowString again, those error messages do not appear. Run Word again, and choose Insert Object. The Object dialog box now has a more meaningful ShowString entry, as shown in Figure 15.9.</P>
<A HREF="Qfigs09.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch15/Qfigs09.gif"><b>Fig. 15.9</b></A>
<P><I>The updated long file type name appears in the Insert Object dialog box of other applications.</I></P>
<blockquote><p><img src="note.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/note.gif">
<P>There are three morals to this side trip. The first is that you should think really carefully before clicking Finish on the AppWizard dialog box. The second is that you cannot ignore the Registry if you are an ActiveX programmer. The third is that
anything can be changed if you have the nerve for it.</P>
<p><img src="bottom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/bottom.gif"></blockquote>
<P>Click OK on the Object dialog box to insert a ShowString object into the Word document. You can immediately edit it in place, as shown in Figure 15.10. You can see that the combined server and container in-place menus are being used. There's not much
you can do to the embedded object at this point, because the ShowString code that actually shows a string has not been added. Press Esc to finish editing in place and the menus return to the usual Word menus, as shown in Figure 15.11.</P>
<A HREF="Qfigs10.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch15/Qfigs10.gif"><b>Fig. 15.10</b></A>
<P><I>While editing in place, the in-place menus replace the Word menus.</I></P>
<A HREF="Qfigs11.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/figs/ch15/Qfigs11.gif"><b>Fig. 15.11</b></A>
<P><I>When the object is inactive, Word reminds the user of the object type.</I></P>
<P>Although this server doesn't do anything, it is a perfectly good server. You can resize and move the embedded item while it is active or inactive, and everything operates exactly as you expect. All that remains is to restore the ShowString
functionality.</P>
<P><B>Showing a String Again</B></P>
<P>As you did in <A HREF="index14.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index14.htm" target="text">Chapter 14</A>, "Building an ActiveX Container," it is time to add the ShowString functionality to this version of the program. If you went through this process before, it will be even quicker
this time. Remember to open the ShowString files from <A HREF="index09.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index09.htm" target="text">Chapter 9</A>, "Building a Complete Application: ShowString," so that you can copy code and resources from the functional ShowString to the do-nothing
ActiveX server you have just created and explored. Here's what to do:</P>
<ol>
<li><P> In ShowStringDoc.h, add the private member variables and public <font color="#008000">Get</font> functions to the class.</P>
<li><P> In <font color="#008000">CShowStringDoc::Serialize()</font>, paste in the code that saves or restores these member variables.</P>
<li><P> In <font color="#008000">CShowStringDoc::OnNewDocument()</font>, paste in the code that initializes the member variables.</P>
<li><P> Copy the entire <U>T</U>ools menu from the old ShowString to the new server ShowString: choose <U>F</U>ile, <U>O</U>pen to open the old ShowString.rc, open the <font color="#008000">IDR_SHOWSTTYPE</font> menu, click the Tools menu, and choose
<U>E</U>dit, <U>C</U>opy. Open the new ShowString's <font color="#008000">IDR_SHOWSTTYPE</font> menu, click the Window menu, and choose <U>E</U>dit, <U>P</U>aste.</P>
<li><P> Paste the <U>T</U>ools menu into the <font color="#008000">IDR_SHOWSTTYPE_SRVR_IP</font> (before the separator bars) and <font color="#008000">IDR_SHOWSTTYPE_SRVR_EMB</font> menus in the same way.</P>
<li><P> Add the accelerator Ctrl+T for ID_TOOLS_OPTIONS as described in <A HREF="index09.htm" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/index09.htm" target="text">Chapter 9</A>, "Building a Complete Application: ShowString." Add it to all three accelerators.</P>
<li><P> Delete the IDD_ABOUTBOX dialog box from the new ShowString. Copy IDD_ABOUTBOX and IDD_OPTIONS from the old ShowString to the new.</P>
<li><P> While IDD_OPTIONS has focus, choose <U>V</U>iew, ClassWizard. Create the <font color="#008000">COptionsDialog</font> class as in the original ShowString.</P>
<li><P> Use ClassWizard to arrange for <font color="#008000">CShowStringDoc</font> to catch the <font color="#008000">ID_TOOLS_OPTIONS</font> command.</P>
<li><P> In ShowStringDoc.cpp, replace the ClassWizard version of <font color="#008000">CShowStringDoc::OnToolsOptions()</font> with the one that puts up the dialog box.</P>
<li><P> In ShowStringDoc.cpp, add <B><font color="#008000">#include "OptionsDialog.h"</font></B> after the <font color="#008000">#include</font> statements already present.</P>
<li><P> Use ClassWizard to connect the dialog box controls to <font color="#008000">COptionsDialog</font> member variables as before.</P>
</ol>
<P>You haven't restored <font color="#008000">CShowStringView::OnDraw()</font> yet, because there are actually going to be two <font color="#008000">OnDraw()</font> functions. The first is in the view class, shown in Listing 15.13. It draws the string
when ShowString is running stand-alone and when the user is editing in place, and it's the same as in the old version of ShowString. Just copy it into the new one.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing 15.13—ShowStringView.cpp—CShowStringView::OnDraw</I><I><font color="#008000">()</font></I></P>
<pre><font color="#008000">void CShowStringView::OnDraw(CDC* pDC)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CShowStringDoc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> ASSERT_VALID(pDoc);</font></pre>
<pre><font color="#008000"> COLORREF oldcolor;</font></pre>
<pre><font color="#008000"> switch (pDoc->GetColor())</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> case 0:</font></pre>
<pre><font color="#008000"> oldcolor = pDC->SetTextColor(RGB(0,0,0)); //black</font></pre>
<pre><font color="#008000"> break;</font></pre>
<pre><font color="#008000"> case 1:</font></pre>
<pre><font color="#008000"> oldcolor = pDC->SetTextColor(RGB(0xFF,0,0)); //red</font></pre>
<pre><font color="#008000"> break;</font></pre>
<pre><font color="#008000"> case 2:</font></pre>
<pre><font color="#008000"> oldcolor = pDC->SetTextColor(RGB(0,0xFF,0)); //green</font></pre>
<pre><font color="#008000"> break;</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> int DTflags = 0;</font></pre>
<pre><font color="#008000"> if (pDoc->GetHorizcenter())</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> DTflags |= DT_CENTER;</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> if (pDoc->GetVertcenter())</font></pre>
<pre><font color="#008000"> {</font></pre>
<pre><font color="#008000"> DTflags |= (DT_VCENTER|DT_SINGLELINE);</font></pre>
<pre><font color="#008000"> }</font></pre>
<pre><font color="#008000"> </font></pre>
<pre><font color="#008000"> CRect rect;</font></pre>
<pre><font color="#008000"> GetClientRect(&rect);</font></pre>
<pre><font color="#008000"> pDC->DrawText(pDoc->GetString(), &rect, DTflags);</font></pre>
<pre><font color="#008000"> pDC->SetTextColor(oldcolor);</font></pre>
<pre><font color="#008000">}</font></pre>
<P>When the embedded ShowString item is inactive, <font color="#008000">CShowStringSrvrItem::OnDraw()</font> draws it. The code in here should be very like the view's <font color="#008000">OnDraw</font>, but because it is a member of <font
color="#008000">CShowStringSrvrItem</font> rather than <font color="#008000">CShowStringView</font>, it doesn't have access to the same member variables. So although there is still a <font color="#008000">GetDocument()</font> function you can call, <font
color="#008000">GetClientRect</font> doesn't work. It's a member of the view class but not of the server item class. You use a few CDC member functions instead. It's a nice touch to draw the item slightly differently, to help remind the user that it is not
active, as shown in Listing 15.14.</P>
<p><img src="cd_rom.gif" tppabs="http://www.mcp.com/814147200/0-7897/0-7897-1145-1/cd_rom.gif" hspace=10>
<P><I>Listing 15.14—SrvrItem.cpp—CShowStringSrvrItem::OnDraw</I><I><font color="#008000">()</font></I></P>
<pre><font color="#008000">BOOL CShowStringSrvrItem::OnDraw(CDC* pDC, CSize& rSize)</font></pre>
<pre><font color="#008000">{</font></pre>
<pre><font color="#008000"> CShowStringDoc* pDoc = GetDocument();</font></pre>
<pre><font color="#008000"> ASSERT_VALID(pDoc);</font></pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -