﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-挪威的森林</title><link>http://www.blogjava.net/kenneth/</link><description>不需要完美的可怕，太快乐如何招架！！！</description><language>zh-cn</language><lastBuildDate>Sun, 12 Apr 2026 06:01:06 GMT</lastBuildDate><pubDate>Sun, 12 Apr 2026 06:01:06 GMT</pubDate><ttl>60</ttl><item><title>推荐一个非常不错的娱乐社区</title><link>http://www.blogjava.net/kenneth/archive/2006/10/24/76854.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Mon, 23 Oct 2006 23:19:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2006/10/24/76854.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/76854.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2006/10/24/76854.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/76854.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/76854.html</trackback:ping><description><![CDATA[
		<p>快乐橙市<br /><a href="http://www.p2pfans.cn/forum/">http://www.p2pfans.cn/forum/</a></p>
<img src ="http://www.blogjava.net/kenneth/aggbug/76854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2006-10-24 07:19 <a href="http://www.blogjava.net/kenneth/archive/2006/10/24/76854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Creating Excel Spreadsheets with Office Web Components (OWC) By Scott Mitchell</title><link>http://www.blogjava.net/kenneth/archive/2005/09/07/12341.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Wed, 07 Sep 2005 13:46:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/07/12341.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/12341.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/07/12341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/12341.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/12341.html</trackback:ping><description><![CDATA[<P><B>Introduction</B><BR>One of the great things about running an ASP Web site where visitors regularly contribute articles is that, in reading/editing those article submissions, I end up learning a lot of new things! Last week Bret Hern submitted a beautiful article on using <A href="http://www.4guysfromrolla.com/webtech/022101-1.shtml">Charting with Office Web Components</A>. After poking around Microsoft's site some, I found rather terse, technical documentation on these nifty components and soon discovered that these components can also be used to create Excel spreadsheets via ASP code! These spreadsheets can then be saved as an Excel file for the user to download. 
<P>In this article we will look at using the Office Web Components (OWC) to create an Excel spreadsheet via ASP code based on the results from a database query! All of this complexity is encapsulated in a (rather basic) class. In the upcoming weeks I plan to expound on this class. Currently it just dumps the contents of a Recordset into a spreadsheet, but in future weeks I'd like to show how to add nifty formatting, apply formulas, pivot tables, and all that other jazzy stuff. 
<P>
<TABLE width="85%" align=center bgColor=#eeeeee border=0>
<TBODY>
<TR>
<TH>Licensing Issues</TH></TR>
<TR>
<TD>Microsoft has some <A href="http://support.microsoft.com/support/kb/articles/Q243/0/06.asp">pretty strict licensing</A> issues on using Office Web Components in the Internet-world (as well as on an intranet). Before you begin using Office Web Components on your Web site be sure to read <A href="http://support.microsoft.com/support/kb/articles/Q243/0/06.asp">Microsoft's Licensing Agreement for OWCs</A>. </TD></TR></TBODY></TABLE>
<P><B>Getting Started</B><BR>To get started using Office Web Components you must have (at minimum) the Office Web Components section of Office 2000 installed on the Web server. (If you are wanting to create Excel spreadsheets and graphs <I>without</I> requiring Excel's presence on the Web server be sure to check out SoftArtisan's <A href="http://www.4guysfromrolla.com/ASPScripts/Goto.asp?ID=8">ExcelWriter</A> component.) (For more on OWC requirements and installation information check out: <A href="http://www.microsoft.com/Office/ORK/2000/One/05t2_3.htm">Requirements for Office Web Components</A>!) 
<P><B>Creating a Spreadsheet</B><BR><I>In this article we will look only at the basics of creating a spreadsheet, setting various cell values, and saving the spreadsheet to disk. In future articles we will look at prettying up the display and working with some of the more advanced features...</I> 
<P>Since the spreadsheet aspect of the Office Web Components is a simple COM object, you can create an instance of the spreadsheet component through your ASP page just as you would create an instance of any other COM component: 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE>'Create an instance of the Spreadsheet component from OWC<BR>Dim objSpreadsheet<BR>Set objSpreadsheet = Server.CreateObject("<B>OWC.Spreadsheet</B>") </CODE></TD></TR></TBODY></TABLE>
<P>Simple enough. Once you have a <CODE>Spreadsheet</CODE> object to work with you can set the values of the spreadsheet's cells using the <CODE>Cells</CODE> property of the <CODE>Spreadsheet</CODE> object like so: 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE>objSpreadsheet.Cells(<I>Row</I>, <I>Column</I>).Value = <I>SomeValue</I> </CODE></TD></TR></TBODY></TABLE>
<P>Finally, to save the <CODE>Spreadsheet</CODE> as an Excel file you must use the <CODE>Export</CODE> method of the <CODE>Worksheet</CODE> object. (The <CODE>ActiveSheet</CODE> property of the <CODE>Spreadsheet</CODE> object returns a valid <CODE>Worksheet</CODE> object instance.) The <CODE>Export</CODE> method expects two parameters: a full physical file name and an <CODE>SheetExportActionEnum</CODE> constant. The file name parameter specifies the specific location to save the Excel spreadsheet; the export action indicates if the file should be saved to disk or piped directly to Excel. Since we are running all of this code on the server-side, if we try to pipe the spreadsheet contents directly to Excel, we will be trying to open Excel on the Web server - not what we want to do. In fact, this setting is only useful if you are using the <CODE>Spreadsheet</CODE> object as an ActiveX control, since then it will be executing on the client's machine as opposed to on the Web server. Therefore, when using the <CODE>Export</CODE> method in server-side script, always specify a value of <CODE>0</CODE> for the export action, which indicates to the <CODE>Export</CODE> method to simply save the spreadsheet to disk and to <B>not</B> try to pipe the contents straight to Excel. 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE>objSpreadsheet.ActiveSheet.Export("C:\Inetpub\wwwroot\FooBar.xls", 0) </CODE></TD></TR></TBODY></TABLE>
<P><I>Keep in mind that the <CODE>IUSR_machinename</CODE> account must have Write permissions on the directory that you wish to write the Excel file to. If the <CODE>IUSR_machinename</CODE> account has inadequate permissions you will receive an error when trying to use the <CODE>Export</CODE> method... (Check out <A href="http://www.aspfaqs.com/aspfaqs/ShowFAQ.asp?FAQID=23">this FAQ</A> for more information...)</I> 
<P>Now that we've covered the basics of creating / filling / saving an Excel spreadsheet through ASP, we're ready to look at a nifty Excel spreadsheet generation class I wrote that will help this process. In <A href="http://www.4guysfromrolla.com/webtech/022801-1.2.shtml">Part 2</A> we'll examine this class in detail! <BR><BR><BR></P>
<P>In <A href="http://www.4guysfromrolla.com/webtech/022801-1.shtml">Part 1</A> we looked at some very basic code for creating, populating, and saving an Excel spreadsheet all from an ASP page! In this part we'll look at the implementation of a class that will allow you to dump the results of a Recordset object to a spreadsheet!&nbsp;&nbsp;<NOSCRIPT>&nbsp<A href="http://63.236.18.118/RealMedia/ads/click_nx.ads/intm/win/www.4guysfromrolla.com@468x60-1,468x60-2,marketplace01,marketplace02,marketplace03,marketplace04,marketplace05,marketplace06,marketplace07,marketplace08,marketplace09,marketplace10,cp1,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,cp10,cp11,cp12,cp13,ciu,house_ribbon,flex,125x125-1!flex"></A> </NOSCRIPT><!-- /flex ad tag --> 
<P></P><A name=postadlink></A>
<P><B>Creating the Class</B><BR><I>I chose to encapsulate the complexity of creating/populating/saving a spreadsheet into a VBScript class. That means that you will need VBScript version 5.0 or higher installed on your Web server. To find out what version of VBScript you are currently using, check out: <A href="http://www.4guysfromrolla.com/webtech/122199-1.shtml">Determining the Server-Side Scripting Language and Version</A>. Also, for more information on the ins and outs of classes be sure to read Mark Lidstone's excellent article: <A href="http://www.4guysfromrolla.com/webtech/092399-1.shtml">Using Classes within VBScript</A>.</I> 
<P>Our class contains three private properties: <CODE>objSpreadsheet</CODE>, <CODE>iColOffset</CODE>, and <CODE>iRowOffset</CODE>. In the <CODE>Class_Initialize()</CODE> event handler, an instance of the <CODE>Spreadsheet</CODE> COM component is instantiated and referenced by <CODE>objSpreadsheet</CODE>; <CODE>iColOffset</CODE> and <CODE>iRowOffset</CODE>, which specify the how many columns over and rows down we should start inserting the database results, are initialized to values of <CODE>2</CODE>. 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE><PRE>Class ExcelGen

  Private objSpreadsheet
  Private iColOffset
  Private iRowOffset

  Sub Class_Initialize()
    Set objSpreadsheet = Server.CreateObject("OWC.Spreadsheet")

    iRowOffset = 2
    iColOffset = 2
  End Sub

  Sub Class_Terminate()
    Set objSpreadsheet = Nothing   'Clean up
  End Sub

  ...
End Class
</PRE></CODE></TD></TR></TBODY></TABLE>
<P>Next, two <CODE>Property Let</CODE> constructs are defined to allow users of this class to programmatically set the row and column offsets. These <CODE>Property Let</CODE> statements ensure that the offsets attempted to be set are greater than zero. 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE><PRE>Class ExcelGen
    ...

    Public Property Let ColumnOffset(iColOff)
      If iColOff &gt; 0 then
        iColOffset = iColOff
      Else
        iColOffset = 2
      End If
    End Property

    Public Property Let RowOffset(iRowOff)
      If iRowOff &gt; 0 then
        iRowOffset = iRowOff
      Else
        iRowOffset = 2
      End If
    End Property

    ...
End Class
</PRE></CODE></TD></TR></TBODY></TABLE>
<P>Our <CODE>ExcelGen</CODE> class contains only two methods: one to insert the contents of a Recordset into the spreadsheet and another to save the spreadsheet to an Excel file on the Web server's filesystem. We'll examine both of these methods, as well as how to use this class through an ASP page, in <A href="http://www.4guysfromrolla.com/webtech/022801-1.3.shtml">Part 3</A>. 
<P></P>
<LI>
<P>In <A href="http://www.4guysfromrolla.com/webtech/022801-1.2.shtml"><FONT color=#002c99>Part 2</FONT></A> we looked at the private member variables of our class as well as our <CODE>Class_Initialize()</CODE> and <CODE>Class_Terminate()</CODE> event handlers and our <CODE>Property Let</CODE> statements. In this final part we'll examine the two methods of the <CODE>ExcelGen</CODE> class and look at how to use this class through an ASP page! <!-- flex ad tag -->
<SCRIPT language=javascript>
<!--
OAS_AD('flex');
//-->
</SCRIPT>
<IMG height=1 src="http://mjxads.internet.com/RealMedia/ads/adstream_lx.cgi/intm/win/www.4guysfromrolla.com/webtech/022801-1.3.shtml/1164731913/flex/OasDefault/Nokia_NES1HSMCMS_EW_GEMS_1gg/Nokai_EW_350_A.html/64333930363634333433316563363630?_RM_EMPTY_" width=1>&nbsp;<NOSCRIPT><A href="http://63.236.18.118/RealMedia/ads/click_nx.ads/intm/win/www.4guysfromrolla.com@468x60-1,468x60-2,marketplace01,marketplace02,marketplace03,marketplace04,marketplace05,marketplace06,marketplace07,marketplace08,marketplace09,marketplace10,cp1,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,cp10,cp11,cp12,cp13,ciu,house_ribbon,flex,125x125-1!flex"></A> </NOSCRIPT><!-- /flex ad tag --> 
<P></P><A name=postadlink></A>
<P><B>Creating the Methods for the <CODE>ExcelGen</CODE> Class</B><BR>Only two methods are needed for our class. The first one, <CODE>GenerateWorksheet</CODE>, accepts a single parameter: a populated Recordset object. This method then loops through the Recordset, transferring its contents to <CODE>objSpreadsheet</CODE>'s <CODE>Cells</CODE>. Note that both the data from the Recordset <I>and</I> the names of the columns in the Recordset are outputted to the Excel spreadsheet. 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE><PRE>Class ExcelGen
    ...

    Sub GenerateWorksheet(objRS)
      'Populates the Excel worksheet based on a Recordset's
      'contents.  Check to make sure we have data to show
      If objRS.EOF then Exit Sub

      Dim objField, iCol, iRow
      
      'Set the iCol/iRow vars to the proper offsets
      iCol = iColOffset
      iRow = iRowOffset

      'Display the names of the columns in the Recordset
      For Each objField in objRS.Fields
        objSpreadsheet.Cells(iRow, iCol).Value = objField.Name
        iCol = iCol + 1
      Next 'objField

      'Display all of the data
      Do While Not objRS.EOF
        iRow = iRow + 1
        iCol = iColOffset

        For Each objField in objRS.Fields
          'If the column contains a null value, insert blank string
          If IsNull(objField.Value) then
            objSpreadsheet.Cells(iRow, iCol).Value = ""
          Else
            objSpreadsheet.Cells(iRow, iCol).Value = objField.Value
          End If

          iCol = iCol + 1
        Next 'objField

        objRS.MoveNext     
      Loop
    End Sub    

    ...
End Class
</PRE></CODE></TD></TR></TBODY></TABLE>
<P>Our last method, <CODE>SaveWorksheet</CODE>, accepts a single parameter, <CODE>strFileName</CODE>, which specifies the location to save the spreadsheet. This method returns a Boolean value: True if the file is saved successfully, False otherwise. Recall that exporting the <CODE>Spreadsheet</CODE> object to a physical Excel file can fail if the <CODE>IUSR_<I>machinename</I></CODE> account has inadequate permissions. 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE><PRE>Class ExcelGen
  ...

  Function SaveWorksheet(strFileName)
    'Save the worksheet to a specified filename
    On Error Resume Next
    Call objSpreadsheet.ActiveSheet.Export(strFileName, 0)

    'Return True if everthing went OK, False otherwise
    SaveWorksheet = (Err.Number = 0)
  End Function
End Class
</PRE></CODE></TD></TR></TBODY></TABLE>
<P><B>Using the <CODE>ExcelGen</CODE> Class from an ASP Page</B><BR>Now that we've looked at the contents of our class, let's examine how to use it through an ASP page to create a spreadsheet containing the contents of a Recordset! It is highly recommended that you place the <CODE>ExcelGen</CODE> class in an include file and then use a server-side include on those ASP pages that need to utilize the class's functionality. (To learn more about server-side includes be sure to read: <A href="http://www.4guysfromrolla.com/webtech/080199-1.shtml"><FONT color=#002c99>The Low-Down on <CODE>#include</CODE></FONT></A>.) For this example we'll assume that the <CODE>ExcelGen</CODE> class has been placed in the file <CODE>/scripts/ExcelGen.class.asp</CODE>. 
<P>To use this class, then, we'll use a server-side include to import the contents of <CODE>/scripts/ExcelGen.class.asp</CODE>. Next, we'll create an instance of the class using the <CODE>New</CODE> keyword. Once we've created and populated a Recordset, we can call the <CODE>.SaveWorksheet</CODE> method to dump the Recordset's contents into an Excel spreadsheet. Finally, we need to save the contents of the spreadsheet using the <CODE>.SaveWorksheet</CODE> method. 
<P>
<TABLE width="95%" border=0>
<TBODY>
<TR>
<TD width="100%" bgColor=#cccccc><CODE><PRE><!--#include virtual="/scripts/ExcelGen.class.asp"-->
<%
  Dim objRS
  Set objRS = Server.CreateObject("ADODB.Recordset")
  objRS.Open "SELECT * FROM titles", "DSN=FooBar"

  Dim objExcel
  Set objExcel = New ExcelGen

  objExcel.RowOffset = 4
  objExcel.ColumnOffset = 1

  objExcel.GenerateWorksheet(objRS)
  If objExcel.SaveWorksheet(Server.MapPath("foo.xls")) then
    Response.Write "Worksheet saved.  " & _
                   "<a href=""foo.xls"">Download</a>"
  Else
    Response.Write "Error in saving worksheet!"
  End If

  Set objExcel = Nothing

  objRS.Close
  Set objRS = Nothing
%>
</PRE></CODE></TD></TR></TBODY></TABLE>
<P>If the spreadsheet is saved successfully the user is presented with a hyperlink to download the Excel file. 
<P><B>Conclusion / Caveats</B><BR>One annoying thing with the <CODE>ExcelGen</CODE> class is that a user must go through a two-phase step to view the contents of a Recordset through an Excel file. First, he must visit an ASP page that creates the Recordset; next, he must click on the link to the Excel file. This is a pain and something I plan on fixing in the next article on this topic (which will serve, basically, as an enhancement to the <CODE>ExcelGen</CODE> class). 
<P>One major concern that should also be quickly apparent is that in the above example the Excel spreadsheet is always saved to the same file. Urg. This is bad since multiple users will be trying to access the same file and, most likely, they would be running different kinds of database queries producing varrying output. One approach is to create a unique file for every user visiting the page... but then how to we clean up old spreadsheets? We'll examine this topic in more detail in a future article... 
<P>In the mean time, play with the code here, create your own spreadsheets, and poke around the <A href="http://msdn.microsoft.com/library/officedev/off2000/ocobjSpreadsheet.htm"><FONT color=#002c99>Microsoft documentation</FONT></A>. Happy Programming! 
<P></P>
<LI>By <A href="http://www.4guysfromrolla.com/feedback.shtml"><FONT color=#002c99>Scott Mitchell</FONT></A> 
<P><B><U>Attachments:</U></B><BR></P></LI>
<P><A href="http://www.4guysfromrolla.com/webtech/code/owc.spreadsheet.asp.html">Download the <CODE>ExcelGen</CODE> class</A> (in text format) <BR>Visit the <A href="http://msdn.microsoft.com/library/officedev/off2000/ocobjSpreadsheet.htm">technical docs</A><BR>Read <A href="http://www.4guysfromrolla.com/webtech/030701-1.shtml">Enhancing the ExcelGen Class (for Creating Excel Spreadsheets)</A>&nbsp;<BR>&nbsp;</P><XMP><%
  Option Explicit

  Class ExcelGen

    Private objSpreadsheet
    Private iColOffset
    Private iRowOffset

    Sub Class_Initialize()
      Set objSpreadsheet = Server.CreateObject("OWC.Spreadsheet")

      iRowOffset = 2
      iColOffset = 2
    End Sub

    Sub Class_Terminate()
      Set objSpreadsheet = Nothing   'Clean up
    End Sub

    Public Property Let ColumnOffset(iColOff)
      If iColOff > 0 then
        iColOffset = iColOff
      Else
        iColOffset = 2
      End If
    End Property

    Public Property Let RowOffset(iRowOff)
      If iRowOff > 0 then
        iRowOffset = iRowOff
      Else
        iRowOffset = 2
      End If
    End Property


    Sub GenerateWorksheet(objRS)

      'Populates the Excel worksheet based on a Recordset's contents
      'Start by displaying the titles
      If objRS.EOF then Exit Sub

      Dim objField, iCol, iRow
      iCol = iColOffset
      iRow = iRowOffset

      For Each objField in objRS.Fields
        objSpreadsheet.Cells(iRow, iCol).Value = objField.Name
        iCol = iCol + 1
      Next 'objField

      'Display all of the data
      Do While Not objRS.EOF
        iRow = iRow + 1
        iCol = iColOffset

        For Each objField in objRS.Fields
          If IsNull(objField.Value) then
            objSpreadsheet.Cells(iRow, iCol).Value = ""
          Else
            objSpreadsheet.Cells(iRow, iCol).Value = objField.Value
          End If

          iCol = iCol + 1
        Next 'objField

        objRS.MoveNext     
      Loop

    End Sub    


    Function SaveWorksheet(strFileName)
      'Save the worksheet to a specified filename
      On Error Resume Next
      Call objSpreadsheet.ActiveSheet.Export(strFileName, 0)

      SaveWorksheet = (Err.Number = 0)
    End Function

  End Class
%>

<%
  Dim objRS
  Set objRS = Server.CreateObject("ADODB.Recordset")
  objRS.Open "SELECT * FROM titles", "DSN=FooBar"

  Dim objExcel
  Set objExcel = New ExcelGen

  objExcel.RowOffset = 4
  objExcel.ColumnOffset = 1

  objExcel.GenerateWorksheet(objRS)
  If objExcel.SaveWorksheet(Server.MapPath("foo.xls")) then
    Response.Write "Worksheet saved.  <a href=""foo.xls"">Download</a>"
  Else
    Response.Write "Error in saving worksheet!"
  End If

  Set objExcel = Nothing

  objRS.Close
  Set objRS = Nothing
%>
</XMP><img src ="http://www.blogjava.net/kenneth/aggbug/12341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-07 21:46 <a href="http://www.blogjava.net/kenneth/archive/2005/09/07/12341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>把Table的资料转到Excel [转]</title><link>http://www.blogjava.net/kenneth/archive/2005/09/07/12319.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Wed, 07 Sep 2005 07:55:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/07/12319.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/12319.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/07/12319.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/12319.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/12319.html</trackback:ping><description><![CDATA[<BR>经常看到有些人问怎么把Table的资料转到Excel里面去，很多人在碰到这个问题都先考虑用execl.appliction，使用不太好，首先必需要掌握它的一些内部用法，其次它在客户端使用时涉及安全性，以下介绍三种方法：&nbsp;<BR><BR><BR>方法一：用单纯的文本格式实现&nbsp;<BR>&nbsp;该方法相当简单，以下给出代码，各位就容易明白&nbsp;<BR>&nbsp;&lt;%&nbsp;set&nbsp;fso=server.createobject("scripting.filesystemobject")&nbsp;<BR>&nbsp;&nbsp;strExcelFile=server.MapPath("txtToExcel.xls")&nbsp;<BR>&nbsp;&nbsp;if&nbsp;fso.fileExists(strExcelFile)&nbsp;then&nbsp;fso.deletefile&nbsp;strExcelFile&nbsp;<BR>&nbsp;&nbsp;Set&nbsp;xslFile&nbsp;=&nbsp;fso.CreateTextFile(strExcelFile&nbsp;,&nbsp;True)&nbsp;<BR>&nbsp;&nbsp;xslFile.WriteLine("df"&nbsp;&amp;&nbsp;vbTab&nbsp;&amp;&nbsp;"345"&nbsp;&amp;&nbsp;vbLf&nbsp;&amp;&nbsp;"fe"&nbsp;&amp;&nbsp;vbTab&nbsp;&amp;&nbsp;"mon"&nbsp;&amp;vbLf)&nbsp;<BR>&nbsp;&nbsp;xslFile.Close&nbsp;<BR>&nbsp;&nbsp;set&nbsp;fso=nothing&nbsp;<BR>&nbsp;&nbsp;response.write&nbsp;"OK"&nbsp;<BR>&nbsp;%&gt;&nbsp;<BR><BR>原理：&nbsp;<BR>相信大家都知道，Excel是可以打开文本文件的，而对于里面的文本内容Excel则会这样处理：如果遇到[制表符]Tab键则跳下一列，如果遇到[换行符]则换下一行，所以根据这个规则我们整理一下就可以产生单一表格式Excel文件了，&nbsp;<BR><BR>优点：&nbsp;<BR>掌握简单，纯粹的文字整理而已。&nbsp;<BR>缺点：&nbsp;<BR>效率较低，把一个较多内容的table转成Excel档要则执行较长的循环（），而文档格式只能是规则的行列格式，对表格不能做更多的设置&nbsp;<BR><BR><BR>方法二：用OWC实现：&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;此方法也简单，只是少为人知而已，同样先给出代码：&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;script&nbsp;language="javascript"&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;exportExcel(atblData){&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(typeof(EXPORT_OBJECT)!="object"){&nbsp;<BR>&nbsp;document.body.insertAdjacentHTML("afterBegin","&lt;OBJECT&nbsp;style=’display:none’&nbsp;classid=clsid:0002E510-0000-0000-C000-000000000046&nbsp;id=EXPORT_OBJECT&gt;&lt;/Object&gt;");&nbsp;<BR>&nbsp;&nbsp;&nbsp;}&nbsp;<BR>&nbsp;with&nbsp;(EXPORT_OBJECT){&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DataType&nbsp;=&nbsp;"HTMLData";&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HTMLData&nbsp;=atblData.outerHTML;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveSheet.Export("C:\\owcToExcel.xls",&nbsp;0);&nbsp;<BR>&nbsp;&nbsp;alert(’汇出完毕’);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR>&nbsp;&nbsp;catch&nbsp;(e){&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(’汇出Excel表失败，请确定已安装Excel2000(或更高版本),并且没打开同名xls文件’);&nbsp;<BR>&nbsp;&nbsp;}&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR>&nbsp;}&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;table&nbsp;id="tblData"&gt;&nbsp;<BR>&nbsp;&nbsp;&lt;tr&gt;&lt;td&gt;gdsssa&lt;/td&gt;&lt;td&gt;445&lt;/td&gt;&lt;/tr&gt;&nbsp;<BR>&nbsp;&nbsp;&lt;tr&gt;&lt;td&gt;gdsssa&lt;/td&gt;&lt;td&gt;445&lt;/td&gt;&lt;/tr&gt;&nbsp;<BR>&nbsp;&lt;/table&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;input&nbsp;type="button"&nbsp;value="export"&nbsp;onclick="exportExcel(tblData)"&gt;&nbsp;<BR><BR>原理：&nbsp;<BR>大家应该看出这是前端脚本html实现，其实这是利用OWC的功能来转出Excel档，我们只需整理出一个Table档，基本上我们整理出的Table在网页上是什么样子，在Excel上就是什么样子，但要注意:网页里的&lt;style&gt;不会汇出到Excel中，所以网页里的样式表不会在Excel中看到.&nbsp;<BR>优点：&nbsp;<BR>掌握也很简单，而且可以在前台实现，并且不会设计权限问题，为前台产生Excel档存到客户端而伤透脑筋的兄弟姐妹们，这个方法.&nbsp;<BR>缺点：&nbsp;<BR>客户端必需安装Excel2000或更高版本（不过这个一般都不成问题的了），而且样式表的内容不能输出。&nbsp;<BR><BR>方法三：利用XML来产生&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先讲讲道理，先随便编一个Excel档，然后把它另存为*.htm文件，再用文本编辑器打开，是不是跟我们一般的网页内容非常相似，那么我们是不是只需要整理出这些文字出来就可以了，关键是怎样整理出这份文本文字档案呢&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们分析一下这些文字，第一部分是&lt;style&gt;样式表的定义，第二部分是Excel特有的定义内容，第三部分是则是最熟悉的Table数据了，那么对于这三部分，前两部分基本是固定了，我整理一下基本只需要这些：&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;html&nbsp;xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"&nbsp;xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"&nbsp;xmlns:rs="urn:schemas-microsoft-com:rowset"&nbsp;xmlns:z="#RowsetSchema"&nbsp;xmlns:o="urn:schemas-microsoft-com:office:office"&nbsp;xmlns:x="urn:schemas-microsoft-com:office:excel"&nbsp;xmlns="<IMG alt=::URL:: hspace=2 src="http://www.blogcn.com/images/aurl.gif" align=absBottom border=0><A href='http://www.w3.org/TR/REC-html40">' target=_blank>http://www.w3.org/TR/REC-html40"&gt;</A> &nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;meta&nbsp;http-equiv="Content-Type"&nbsp;content="text/html;"/&gt;&nbsp;<BR>&nbsp;&lt;style&gt;&nbsp;<BR>&nbsp;xl24{mso-style-parent:style0;mso-number-format:"\@";text-align:right;}&nbsp;<BR>&nbsp;&lt;/style&gt;&nbsp;<BR>&nbsp;&lt;xml&gt;&nbsp;<BR>&nbsp;&lt;x:ExcelWorkbook&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:ExcelWorksheets&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:ExcelWorksheet&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:Name&gt;Sheet1&lt;/x:Name&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:WorksheetOptions&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:ProtectContents&gt;False&lt;/x:ProtectContents&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:ProtectObjects&gt;False&lt;/x:ProtectObjects&gt;&nbsp;<BR>&nbsp;&nbsp;&lt;x:ProtectScenarios&gt;False&lt;/x:ProtectScenarios&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/x:WorksheetOptions&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/x:ExcelWorksheet&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/x:ExcelWorksheets&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/x:ExcelWorkbook&gt;&nbsp;<BR>&nbsp;&lt;/xml&gt;&nbsp;<BR>&nbsp;&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;然后是第三部分，我们可以通过recordset来读取数据的指定内容，而且可以通过save来直接把那些内容生成一个xml文件，所以我们只需要根据这个xml文件写一个xsl文件来转换就行了，那么这个方法是我认为最好的，因为我们可以任意设定Table的样式，同时不必诸多循环，有效解决Excel一些自做聪明的小动作&nbsp;<BR>&nbsp;&nbsp;&nbsp;这种方法的优点是你可以定制很好的格式的Excel文件，只要你xsl会写，包括统计都可以做出来，所以懂xsl的人估计来到这里比较明白了，而且效率很高，不用再慢慢循环了&nbsp;<BR>&nbsp;&nbsp;&nbsp;缺点嘛:就是技术要求高了一点，至于算有多高，各人不同了。&nbsp;<BR>&nbsp;&nbsp;&nbsp;最后附上代码：&nbsp;<BR>&nbsp;&nbsp;<BR>===========xmlToExcel.asp=============&nbsp;<BR>&lt;%&nbsp;Set&nbsp;Conn=Server.CreateObject("ADODB.Connection")&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Conn.Open&nbsp;"Provider&nbsp;=&nbsp;Microsoft.Jet.OLEDB.4.0;&nbsp;Data&nbsp;Source&nbsp;="&amp;&nbsp;Server.MapPath("comp_apply.mdb")&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;’strSelect="select&nbsp;dept_no,dept_name,dept_check&nbsp;from&nbsp;dept_data"&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strSelect="select&nbsp;*&nbsp;from&nbsp;user_data"&nbsp;&nbsp;’改变该SQL语句则可改变excel的内容&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set&nbsp;rs=server.createobject("adodb.recordset")&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rs.open&nbsp;strSelect,conn,1,1&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;fso=server.createobject("scripting.filesystemobject")&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strXmlFile=server.MapPath("xmlToExcelTmp.xml")&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strXslFile=server.MapPath("xmlToExcel.xsl")&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strExcelFile=server.MapPath("xmlToExcel.xls")&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;fso.fileExists(strXmlFile)&nbsp;then&nbsp;fso.deletefile&nbsp;strXmlFile&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rs.save&nbsp;strXmlFile,1&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rs.close&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Conn.close&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;Conn=nothing&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;set&nbsp;xmlDoc=server.createobject("microsoft.xmldom")&nbsp;<BR>&nbsp;set&nbsp;xslDoc=server.createobject("microsoft.xmldom")&nbsp;<BR>&nbsp;xslDoc.load(strXslFile)&nbsp;<BR>&nbsp;xmlDoc.load(strXmlFile)&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;xmlDoc.loadXml(xmlDoc.transformNode(xslDoc))&nbsp;<BR>&nbsp;if&nbsp;fso.fileExists(strExcelFile)&nbsp;then&nbsp;fso.deletefile&nbsp;strExcelFile&nbsp;<BR>&nbsp;Set&nbsp;xslFile&nbsp;=&nbsp;fso.CreateTextFile(strExcelFile&nbsp;,&nbsp;True)&nbsp;<BR>&nbsp;xslFile.WriteLine(xmlDoc.xml)&nbsp;<BR>&nbsp;xslFile.Close&nbsp;<BR>&nbsp;fso.deletefile&nbsp;strXmlFile&nbsp;<BR>&nbsp;set&nbsp;fso=nothing&nbsp;<BR>&nbsp;response.redirect&nbsp;"xmlToExcel.xls"&nbsp;<BR>&nbsp;%&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;==============xmlToExcel.xsl=============&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;xsl:stylesheet&nbsp;version="1.0"&nbsp;xmlns:xsl="<IMG alt=::URL:: hspace=2 src="http://www.blogcn.com/images/aurl.gif" align=absBottom border=0><A href='http://www.w3.org/1999/XSL/Transform"' target=_blank>http://www.w3.org/1999/XSL/Transform"</A> &nbsp;<BR>&nbsp;xmlns:s=’uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882’&nbsp;<BR>&nbsp;xmlns:dt=’uuid:C2F41010-65B3-11d1-A29F-00AA00C14882’&nbsp;<BR>&nbsp;xmlns:rs=’urn:schemas-microsoft-com:rowset’&nbsp;<BR>&nbsp;xmlns:z=’#RowsetSchema’&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;xsl:output&nbsp;method="html"&nbsp;indent="yes"&nbsp;/&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;xsl:template&nbsp;match="xml/rs:data"&gt;&nbsp;<BR>&nbsp;&lt;html&nbsp;xmlns:o="urn:schemas-microsoft-com:office:office"&nbsp;xmlns:x="urn:schemas-microsoft-com:office:excel"&nbsp;xmlns="<IMG alt=::URL:: hspace=2 src="http://www.blogcn.com/images/aurl.gif" align=absBottom border=0><A href='http://www.w3.org/TR/REC-html40">' target=_blank>http://www.w3.org/TR/REC-html40"&gt;</A> &nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;meta&nbsp;http-equiv="Content-Type"&nbsp;content="text/html;charset=gb2312"&nbsp;/&gt;&nbsp;<BR>&nbsp;&lt;style&gt;&nbsp;<BR>&nbsp;.xl24{mso-style-parent:style0;mso-number-format:"\@";text-align:right;}&nbsp;<BR>&nbsp;&lt;/style&gt;&nbsp;<BR>&nbsp;&lt;xml&gt;&nbsp;<BR>&nbsp;&lt;x:ExcelWorkbook&gt;&nbsp;<BR>&nbsp;&lt;x:ExcelWorksheets&gt;&nbsp;<BR>&nbsp;&lt;x:ExcelWorksheet&gt;&nbsp;<BR>&nbsp;&lt;x:Name&gt;Sheet1&lt;/x:Name&gt;&nbsp;<BR>&nbsp;&lt;x:WorksheetOptions&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:ProtectContents&gt;False&lt;/x:ProtectContents&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:ProtectObjects&gt;False&lt;/x:ProtectObjects&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;x:ProtectScenarios&gt;False&lt;/x:ProtectScenarios&gt;&nbsp;<BR>&nbsp;&lt;/x:WorksheetOptions&gt;&nbsp;<BR>&nbsp;&lt;/x:ExcelWorksheet&gt;&nbsp;<BR>&nbsp;&lt;/x:ExcelWorksheets&gt;&nbsp;<BR>&nbsp;&lt;/x:ExcelWorkbook&gt;&nbsp;<BR>&nbsp;&lt;/xml&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;table&nbsp;border="1"&nbsp;cellpadding="0"&nbsp;cellspacing="0"&gt;&nbsp;<BR>&nbsp;&lt;tr&gt;&lt;xsl:for-each&nbsp;select="/xml/s:Schema/s:ElementType/s:AttributeType"&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;th&gt;&lt;xsl:value-of&nbsp;select="@name"&nbsp;/&gt;&lt;/th&gt;&nbsp;<BR>&nbsp;&lt;/xsl:for-each&gt;&nbsp;<BR>&nbsp;&lt;/tr&gt;&nbsp;<BR>&nbsp;&lt;xsl:apply-templates&nbsp;select="z:row"&nbsp;/&gt;&nbsp;<BR>&nbsp;&lt;/table&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;/xsl:template&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;xsl:template&nbsp;match="z:row"&gt;&nbsp;<BR>&nbsp;&lt;xsl:variable&nbsp;name="position"&gt;&lt;xsl:value-of&nbsp;select="position()"&nbsp;/&gt;&lt;/xsl:variable&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;&lt;tr&gt;&lt;xsl:for-each&nbsp;select="/xml/s:Schema/s:ElementType/s:AttributeType"&gt;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;读取定义好的数据列名&nbsp;--&gt;&nbsp;<BR>&nbsp;&lt;xsl:variable&nbsp;name="strColumn"&gt;&lt;xsl:value-of&nbsp;select="@name"&nbsp;/&gt;&lt;/xsl:variable&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;xsl:variable&nbsp;name="strvalue"&gt;&lt;xsl:value-of&nbsp;select="/xml/rs:data/z:row[position()=$position]/@*[name()&nbsp;=&nbsp;$strColumn]"&nbsp;/&gt;&lt;/xsl:variable&gt;&nbsp;<BR>&nbsp;&lt;td&nbsp;class="xl24"&gt;&nbsp;<BR>&nbsp;&lt;xsl:value-of&nbsp;select="$strvalue"&nbsp;/&gt;&nbsp;<BR>&nbsp;&lt;/td&gt;&nbsp;<BR>&nbsp;&lt;/xsl:for-each&gt;&nbsp;<BR>&nbsp;&lt;/tr&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/xsl:template&gt;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;&lt;/xsl:stylesheet&gt;&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;补充一下：对于第三种方法因为Recordset&nbsp;用&nbsp;Save方法后有时对于那些null的字段在row中不会有它的字段名，所以我现在通过去ElementType那里读取字段名，以保证不造成到时的Excel的纵列方位出错，但这个问题在.net里的DataSet确很好解决，因为DataSet中如果碰到这种null的数据它也会有&lt;columnName&nbsp;/&gt;这样的空节点出现。&nbsp;<BR><BR>问题：&nbsp;<BR>能保証select出正確的數據后﹐如果仍沒看到需要的Excel內容的話﹐請確認以下情況:&nbsp;<BR>1.估計是你的msxml版本低了﹐試試去MS下載個msxmlsp2或更高的版本安裝再看看&nbsp;<BR>2.請確定你的FSO有足夠的讀寫權限&nbsp;<BR>3.請保証同名的Excel文件沒在使用中&nbsp;<BR><BR>怎樣修改標題名﹕&nbsp;<BR>這個可以在select&nbsp;時用別名來命名好標題名﹐但如果用中文的時候有時會出錯﹐我在簡繁體之間就飽受這點的困擾﹔如果不要做到通用的話也可以直接在xsl文件里修改&nbsp;<BR>B/S模式下实现EXCEL报表的生成与打印 [转]<BR><BR>1.&nbsp;前言&nbsp;<BR>报表打印通常是管理信息系统中的一个重要模块，而Excel凭借它功能强大、应用灵活、通用性强等的优势在报表打印中获得了广泛的应用。&nbsp;<BR>最初的管理信息系统基本上是采用客户机/服务器（C/S）模式开发的，但随着WWW的广泛应用，目前的管理信息系统已经逐渐开始从C/S模式向浏览器/服务器（B/S）模式转变。B/S模式具有传统C/S模式所不及的很多特点，如更加开放、与软硬件无关、应用扩充和系统维护升级方便等等，目前已成为企业网上首选的计算模式，原先在C/S下的很多软件都开始移植到B/S模式下。由于B/S模式的特殊性，在C/S下相对较易实现的Excel报表打印功能在B/S下却成为一个难点。本文根据在实际的项目中总结的经验，以ASP为例，给出了一个较好的通梅椒ā?nbsp;&nbsp;<BR>2.&nbsp;功能实现&nbsp;<BR>为了说明问题，这里举一个例子。系统平台是Windows&nbsp;2000+SQL&nbsp;Server&nbsp;2000+IIS&nbsp;5.0+ASP&nbsp;3，报表采用的是Excel，要求按照给定的报表格式生成图书销售统计的报表，并能够打印。&nbsp;<BR>2.1&nbsp;Excel报表模板的制作&nbsp;<BR>首先根据给定的报表格式，制作一个Excel模板（就是要打印的报表的表格），当然其中需要从数据库中动态统计生成的数据留着空白。这个报表先在Excel中画好，然后保存为模板，存放在起来，这里为\test\book1.xlt。&nbsp;<BR>2.2&nbsp;Excel报表的生成与打印&nbsp;<BR>这里采用了Excel的Application组件，该组件在安装Excel时安装到系统中。我们的操作也都是针对该组件。&nbsp;<BR>(1)&nbsp;建立Excel.Application对象&nbsp;<BR>set&nbsp;objExcel=CreateObject("Excel.Application")&nbsp;<BR>(2)&nbsp;打开Excel模板&nbsp;<BR>objExcel.Workbooks.Open(server.mappath("\test")&amp;"\book1.xlt")&nbsp;’打开Excel模板&nbsp;<BR>objExcel.Sheets(1).select&nbsp;’选中工作页&nbsp;<BR>set&nbsp;sheetActive=objExcel.ActiveWorkbook.ActiveSheet&nbsp;&nbsp;&nbsp;<BR>(3)&nbsp;Excel的常规添加操作&nbsp;<BR>例如sheetActive.range("g4").value=date()&nbsp;‘这里添加的是时间，当然也可以是你指定的任何数据&nbsp;<BR>(4)&nbsp;Excel中添加数据库中的纪录&nbsp;<BR>这里假设已有一个数据集adoRset，存放由Sql操作生成的统计数据。&nbsp;<BR>num=7&nbsp;‘从Excel的第七行开始&nbsp;<BR>do&nbsp;until&nbsp;adoRset.EOF&nbsp;‘循环直至数据集中的数据写完&nbsp;<BR>strRange="d"&amp;num&amp;":f"&amp;num&nbsp;‘设定要填写内容的单元区域&nbsp;<BR>sheetActive.range(strRange).font.size=10&nbsp;‘设定字体大小&nbsp;<BR>sheetActive.range(strRange).WrapText=false&nbsp;‘设定文字回卷&nbsp;<BR>sheetActive.range(strRange).ShrinkToFit=true&nbsp;‘设定是否自动适应表格单元大小&nbsp;<BR>sheetActive.range(strRange).value=array(adoRset("bookid"),adoRset("bookname"),adoRset("author"))&nbsp;‘把数据集中的数据填写到相应的单元中&nbsp;<BR>num=num+1&nbsp;<BR>adoRset.MoveNext&nbsp;<BR>loop&nbsp;<BR>(5)&nbsp;Excel临时报表文件的保存及处理&nbsp;<BR>实际运行中应该注意每次一个用户进行报表打印时都采用一个临时的Excel文件，而不是硬性规定文件名，因为如果用固定的文件名的话，只有第一次生成是成功的，后面的操作都会因为已存在同名文件而导致失败。所以我们需要每次都产生一个临时的而且不重复的文件名，这里可以采用自定义的getTemporaryFile()函数由来生成，然后存放在变量filename中,用变量filepos表示这些临时文件的路径。&nbsp;<BR>此外如果这些临时文件不处理的话久而久之会成为文件垃圾，因此在每个用户提交Excel报表打印请求时要先删除临时目录下所有原先产生的临时打印文件。&nbsp;<BR>临时文件的处理主要代码如下：&nbsp;<BR>function&nbsp;getTemporaryFile(myFileSystem)&nbsp;&nbsp;&nbsp;<BR>dim&nbsp;tempFile,dotPos&nbsp;<BR>tempFile=myFileSystem.getTempName&nbsp;<BR>dotPos=instr(1,tempFile,".")&nbsp;<BR>getTemporaryFile=mid(tempFile,1,dotPos)&amp;"xls"&nbsp;<BR>end&nbsp;function&nbsp;&nbsp;&nbsp;<BR>set&nbsp;myFs=createObject("scripting.FileSystemObject")&nbsp;<BR>filePos=server.mappath("\test")&nbsp;&amp;&nbsp;"\tmp\"&nbsp;’要存放打印临时文件的临时目录&nbsp;<BR>fileName=getTemporaryFile(myFs)&nbsp;’取得一个临时文件名&nbsp;<BR>myFs.DeleteFile&nbsp;filePos&amp;"*.xls"&nbsp;’删除该目录下所有原先产生的临时打印文件&nbsp;<BR>set&nbsp;myFs=nothing&nbsp;<BR>Excel临时文件的保存代码为：&nbsp;<BR>objExcel.ActiveWorkbook.saveas&nbsp;filePos&amp;filename&nbsp;&nbsp;&nbsp;<BR>(6)&nbsp;退出Excel应用&nbsp;<BR>objExcel.quit&nbsp;<BR>set&nbsp;objExcel=Nothing&nbsp;<BR>(7)&nbsp;Excel报表的打印&nbsp;<BR>前面的步骤已经生成了Excel报表，下一步进行打印，采用的策略可以有两种：&nbsp;<BR>方案一：提供上面生成的Excel报表临时文件链接给用户，用户可以直接点击在浏览器中打开Excel报表并通过浏览器的打印功能进行打印，也可以点击右键然后另存到本地后再作打印等相关处理。&nbsp;<BR>方案二：生成Excel报表后直接在客户端加载到浏览器，当然在没有完全加载时应该提示“正在加载，请等待”等字样。&nbsp;<BR>2.3&nbsp;系统配置与注意事项&nbsp;<BR>虽然以上代码很简单，但实际应用不当经常会出现错误，所以下面要讲到的系统配置和注意事项非常关键。&nbsp;<BR>(1)&nbsp;千万要保证以上代码输入的正确性，否则一旦运行错误，Excel对象会滞留内存，难以消除，导致下一次调用时速度狂慢，并产生内存不可读写的Windows错误。这时的解决方法就是注销当前用户，如果还不行，就只能Reset了。&nbsp;<BR>(2)&nbsp;一定要设置好负责打印功能的asp文件的权限。方法是：在IIS管理中，选择该asp文件，右键然后选“属性”/“文件安全性”/"匿名访问和验证控制“，在这里IIS默认是匿名访问，应该选择验证访问（这里基本验证和集成Windows验证两种方式均可，但前者不够安全），这一点无比重要，否则应用当中会出错的。&nbsp;<BR>(3)&nbsp;有的时候报表分为多页，而且我们希望每一页有相同的表头，要求表头每页都自动打印，可以在Excel模板中进行设置。方法如下：选择菜单"文件"/"页面设置"/"工作表"，然后在"顶端标题行"输入你表头的行数(如：表头为1-3行即填入：：$3)。&nbsp;<BR><BR>3．总结&nbsp;<BR>以上我们给出了一个采用ASP写的在B/S模式下实现EXCEL报表的生成与打印的例子，在实际当中已经得到了良好的应用。事实也证明，这个例子的代码虽然不难写，但一定要注意系统的配置，这也是无数次失败后得出的经验。&nbsp;<BR>ASP操作Excel技术总结 [转]<BR><BR>目录&nbsp;<BR>一、　　环境配置&nbsp;<BR>二、　　ASP对Excel的基本操作&nbsp;<BR>三、　　ASP操作Excel生成数据表&nbsp;<BR>四、　　ASP操作Excel生成Chart图&nbsp;<BR>五、　　服务器端Excel文件浏览、下载、删除方案&nbsp;<BR>六、　　附录&nbsp;<BR><BR>正文&nbsp;<BR>一、　　环境配置&nbsp;<BR>服务器端的环境配置从参考资料上看，微软系列的配置应该都行，即：&nbsp;<BR>1．Win9x+PWS+Office&nbsp;<BR>2．Win2000&nbsp;Professional+PWS+Office&nbsp;<BR>3．Win2000&nbsp;Server+IIS+Office&nbsp;<BR>目前笔者测试成功的环境是后二者。Office的版本没有特殊要求，考虑到客户机配置的不确定性和下兼容特性，建议服务器端Office版本不要太高，以防止客户机下载后无法正确显示。&nbsp;<BR>服务器端环境配置还有两个偶然的发现是：&nbsp;<BR>1．　　笔者开发机器上原来装有金山的WPS2002，结果Excel对象创建始终出现问题，卸载WPS2002后，错误消失。&nbsp;<BR>2．　　笔者开发ASP代码喜欢用FrontPage，结果发现如果FrontPage打开（服务器端），对象创建出现不稳定现象，时而成功时而不成功。扩展考察后发现，Office系列的软件如果在服务器端运行，则Excel对象的创建很难成功。&nbsp;<BR>服务器端还必须要设置的一点是COM组件的操作权限。在命令行键入“DCOMCNFG”，则进入COM组件配置界面，选择Microsoft&nbsp;Excel后点击属性按钮，将三个单选项一律选择自定义，编辑中将Everyone加入所有权限。保存完毕后重新启动服务器。&nbsp;<BR>客户端的环境配置没发现什么特别讲究的地方，只要装有Office和IE即可，版本通用的好象都可以。&nbsp;<BR><BR>二、　　ASP对Excel的基本操作&nbsp;<BR>1、　　建立Excel对象&nbsp;<BR>set&nbsp;objExcelApp&nbsp;=&nbsp;CreateObject("Excel.Application")&nbsp;<BR>objExcelApp.DisplayAlerts&nbsp;=&nbsp;false　　　　不显示警告&nbsp;<BR>objExcelApp.Application.Visible&nbsp;=&nbsp;false　　　　不显示界面&nbsp;<BR>2、　　新建Excel文件&nbsp;<BR>objExcelApp.WorkBooks.add&nbsp;<BR>set&nbsp;objExcelBook&nbsp;=&nbsp;objExcelApp.ActiveWorkBook&nbsp;<BR>set&nbsp;objExcelSheets&nbsp;=&nbsp;objExcelBook.Worksheets&nbsp;<BR>set&nbsp;objExcelSheet&nbsp;=&nbsp;objExcelBook.Sheets(1)&nbsp;<BR>3、　　读取已有Excel文件&nbsp;<BR>strAddr&nbsp;=&nbsp;Server.MapPath(".")&nbsp;<BR>objExcelApp.WorkBooks.Open(strAddr&nbsp;&amp;&nbsp;"\Templet\Table.xls")&nbsp;<BR>set&nbsp;objExcelBook&nbsp;=&nbsp;objExcelApp.ActiveWorkBook&nbsp;<BR>set&nbsp;objExcelSheets&nbsp;=&nbsp;objExcelBook.Worksheets&nbsp;<BR>set&nbsp;objExcelSheet&nbsp;=&nbsp;objExcelBook.Sheets(1)&nbsp;<BR>4、　　另存Excel文件&nbsp;<BR>objExcelBook.SaveAs&nbsp;strAddr&nbsp;&amp;&nbsp;"\Temp\Table.xls"&nbsp;<BR>5、　　保存Excel文件&nbsp;<BR>objExcelBook.Save　　　　（笔者测试时保存成功，页面报错。）&nbsp;<BR>6、　　退出Excel操作&nbsp;<BR>objExcelApp.Quit　　一定要退出&nbsp;<BR>set&nbsp;objExcelApp&nbsp;=&nbsp;Nothing&nbsp;<BR><BR>三、　　ASP操作Excel生成数据表&nbsp;<BR>1、　　在一个范围内插入数据&nbsp;<BR>objExcelSheet.Range("B3:k3").＆#118alue&nbsp;=&nbsp;Array("67",&nbsp;"87",&nbsp;"5",&nbsp;"9",&nbsp;"7",&nbsp;"45",&nbsp;"45",&nbsp;"54",&nbsp;"54",&nbsp;"10")&nbsp;<BR>2、　　在一个单元格内插入数据&nbsp;<BR>objExcelSheet.Cells(3,1).＆#118alue="Internet&nbsp;Explorer"&nbsp;<BR>3、　　选中一个范围&nbsp;<BR>4、　　单元格左边画粗线条&nbsp;<BR>5、　　单元格右边画粗线条&nbsp;<BR>6、　　单元格上边画粗线条&nbsp;<BR>7、　　单元格下边画粗线条&nbsp;<BR>8、　　单元格设定背景色&nbsp;<BR>9、　　合并单元格&nbsp;<BR>10、　　插入行&nbsp;<BR>11、　　插入列&nbsp;<BR><BR>四、　　ASP操作Excel生成Chart图&nbsp;<BR>1、　　创建Chart图&nbsp;<BR>objExcelApp.Charts.Add&nbsp;<BR>2、　　设定Chart图种类&nbsp;<BR>objExcelApp.ActiveChart.ChartType&nbsp;=&nbsp;97&nbsp;<BR>注：二维折线图，4；二维饼图，5；二维柱形图，51&nbsp;<BR>3、　　设定Chart图标题&nbsp;<BR>objExcelApp.ActiveChart.HasTitle&nbsp;=&nbsp;True&nbsp;<BR>objExcelApp.ActiveChart.ChartTitle.Text&nbsp;=&nbsp;"A&nbsp;test&nbsp;Chart"&nbsp;<BR>4、　　通过表格数据设定图形&nbsp;<BR>objExcelApp.ActiveChart.SetSourceData&nbsp;objExcelSheet.Range("A1:k5"),1&nbsp;<BR>5、　　直接设定图形数据（推荐）&nbsp;<BR>objExcelApp.ActiveChart.SeriesCollection.NewSeries&nbsp;<BR>objExcelApp.ActiveChart.SeriesCollection(1).Name&nbsp;=&nbsp;"=""333"""&nbsp;<BR>objExcelApp.ActiveChart.SeriesCollection(1).＆#118alues&nbsp;=&nbsp;"={1,4,5,6,2}"&nbsp;<BR>6、　　绑定Chart图&nbsp;<BR>objExcelApp.ActiveChart.Location&nbsp;1&nbsp;<BR>7、　　显示数据表&nbsp;<BR>objExcelApp.ActiveChart.HasDataTable&nbsp;=&nbsp;True&nbsp;<BR>8、　　显示图例&nbsp;<BR>objExcelApp.ActiveChart.DataTable.ShowLegendKey&nbsp;=&nbsp;True&nbsp;<BR><BR>五、　　服务器端Excel文件浏览、下载、删除方案&nbsp;<BR>浏览的解决方法很多，“Location.href=”，“Navigate”，“Response.Redirect”都可以实现，建议用客户端的方法，原因是给服务器更多的时间生成Excel文件。&nbsp;<BR>下载的实现要麻烦一些。用网上现成的服务器端下载组件或自己定制开发一个组件是比较好的方案。另外一种方法是在客户端操作Excel组件，由客户端操作服务器端Excel文件另存至客户端。这种方法要求客户端开放不安全ActiveX控件的操作权限，考虑到通知每个客户将服务器设置为可信站点的麻烦程度建议还是用第一个方法比较省事。&nbsp;<BR>删除方案由三部分组成：&nbsp;<BR>A：　　同一用户生成的Excel文件用同一个文件名，文件名可用用户ID号或SessionID号等可确信不重复字符串组成。这样新文件生成时自动覆盖上一文件。&nbsp;<BR>B：　　在Global.asa文件中设置Session_onEnd事件激发时，删除这个用户的Excel暂存文件。&nbsp;<BR>C：　　在Global.asa文件中设置Application_onStart事件激发时，删除暂存目录下的所有文件。&nbsp;<BR>注：建议目录结构&nbsp;\Src&nbsp;代码目录&nbsp;\Templet&nbsp;模板目录&nbsp;\Temp&nbsp;暂存目录&nbsp;<BR><BR>六、　　附录&nbsp;<BR>出错时Excel出现的死进程出现是一件很头疼的事情。在每个文件前加上“On&nbsp;Error&nbsp;Resume&nbsp;Next”将有助于改善这种情况，因为它会不管文件是否产生错误都坚持执行到“Application.Quit”，保证每次程序执行完不留下死进程。 <img src ="http://www.blogjava.net/kenneth/aggbug/12319.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-07 15:55 <a href="http://www.blogjava.net/kenneth/archive/2005/09/07/12319.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HOW TO：在运行程序时启用和使用“运行方式”命令</title><link>http://www.blogjava.net/kenneth/archive/2005/09/06/12272.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Tue, 06 Sep 2005 15:37:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/06/12272.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/12272.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/06/12272.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/12272.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/12272.html</trackback:ping><description><![CDATA[<H1 class=title>HOW TO：在运行程序时启用和使用“运行方式”命令</H1>
<DIV class=appliesToLink><A href="http://support.microsoft.com/?id=294676#appliesto">察看本文应用于的产品</A></DIV>
<DIV class=articleProperty>
<TABLE>
<TBODY>
<TR>
<TD class=label>文章编号</TD>
<TD class=text>:</TD>
<TD class=text>294676</TD></TR>
<TR>
<TD class=label>最后修改</TD>
<TD class=text>:</TD>
<TD class=text>2003年10月24日</TD></TR>
<TR>
<TD class=label>修订</TD>
<TD class=text>:</TD>
<TD class=text>1.0</TD></TR></TBODY></TABLE></DIV>
<DIV class=notice>本文的发布号曾为 CHS294676</DIV>
<DIV class=notice></DIV>
<DIV class=toc>
<H5>本页</H5>
<TABLE class=tallTable>
<COLGROUP>
<COL>
<COL>
<COL>
<COL>
<COL>
<COL></COLGROUP>
<TBODY>
<TR>
<TD class=image><A href="http://support.microsoft.com/?id=294676#kb1"></A></TD>
<TD class=text colSpan=5><A href="http://support.microsoft.com/?id=294676#kb1">概要</A></TD></TR>
<TR>
<TD class=space>&nbsp;</TD>
<TD class=image><A href="http://support.microsoft.com/?id=294676#XSLTH3127121123120121120120"></A></TD>
<TD class=text colSpan=4><A href="http://support.microsoft.com/?id=294676#XSLTH3127121123120121120120">要求 </A></TD></TR>
<TR>
<TD class=space>&nbsp;</TD>
<TD class=image><A href="http://support.microsoft.com/?id=294676#XSLTH3131121123120121120120"></A></TD>
<TD class=text colSpan=4><A href="http://support.microsoft.com/?id=294676#XSLTH3131121123120121120120">在 Windows 2000 计算机上启用 RunAs 服务，或在 Windows XP 计算机上启用 Secondary Logon 服务 </A></TD></TR>
<TR>
<TD class=space>&nbsp;</TD>
<TD class=image><A href="http://support.microsoft.com/?id=294676#XSLTH3143121123120121120120"></A></TD>
<TD class=text colSpan=4><A href="http://support.microsoft.com/?id=294676#XSLTH3143121123120121120120">通过快捷方式使用“运行方式”命令 </A></TD></TR>
<TR>
<TD class=space>&nbsp;</TD>
<TD class=image><A href="http://support.microsoft.com/?id=294676#XSLTH3147121123120121120120"></A></TD>
<TD class=text colSpan=4><A href="http://support.microsoft.com/?id=294676#XSLTH3147121123120121120120">疑难解答 </A></TD></TR>
<TR>
<TD class=image><A href="http://support.microsoft.com/?id=294676#appliesto"></A></TD>
<TD class=text colSpan=5><A href="http://support.microsoft.com/?id=294676#appliesto">这篇文章中的信息适用于:</A></TD></TR></TBODY></TABLE></DIV>
<DIV class=section><A id=kb1></A>
<H2 class=subTitle>概要</H2>
<DIV class=sbody>在 Windows 2000 和 Windows XP 中，可通过当前登录用户以外的其他用户身份运行程序。 若要在 Windows 2000 中执行此操作，RunAs 服务必须正在运行；若要在 Windows XP 中执行此操作，Secondary Logon 服务必须正在运行。 RunAs 和 Secondary Logon 服务是具有不同名称的相同服务。 本分步指南介绍了如何在 Windows 2000 计算机或 Windows XP 计算机上启用和使用<B>运行方式</B>命令。 <BR><BR><SPAN><A id=Requirements></A></SPAN><A id=XSLTH3127121123120121120120></A>
<H3>要求 </H3>
<TABLE class="list ul">
<TBODY>
<TR>
<TD class=bullet>•</TD>
<TD class=text>运行 Windows 2000 或 Windows XP 版本的计算机。 </TD></TR>
<TR>
<TD class=bullet>•</TD>
<TD class=text>计算机的管理权限。 </TD></TR></TBODY></TABLE><SPAN><A id=Task1></A></SPAN><A id=XSLTH3131121123120121120120></A>
<H3>在 Windows 2000 计算机上启用 RunAs 服务，或在 Windows XP 计算机上启用 Secondary Logon 服务 </H3>该服务是运行<B>运行方式</B>命令所必需的，在默认情况下，它在安装 Windows 时自动启动。 但是，该服务可由管理员禁用。 如果该服务已被禁用，可使用下列步骤重新启用它： 
<TABLE class="list ol">
<TBODY>
<TR>
<TD class=number>1.</TD>
<TD class=text>以 Administrator（管理员）身份登录到计算机，或者以具有管理权限的用户身份登录。 </TD></TR>
<TR>
<TD class=number>2.</TD>
<TD class=text>右键单击<B>我的电脑</B>，然后单击<B>管理</B>。 </TD></TR>
<TR>
<TD class=number>3.</TD>
<TD class=text>在“计算机管理”中，展开“<STRONG class=uiterm>服务和应用程序</STRONG>”节点，然后单击<B>服务</B>。 </TD></TR>
<TR>
<TD class=number>4.</TD>
<TD class=text>根据您拥有的操作系统执行以下某个步骤： 
<TABLE class="list ul">
<TBODY>
<TR>
<TD class=bullet>•</TD>
<TD class=text>Windows 2000： 在“详细信息”窗格中，右键单击<B> RunAs Service</B>（RunAs 服务），然后单击<B>属性</B>。 </TD></TR>
<TR>
<TD class=bullet>•</TD>
<TD class=text>Windows XP： 在“详细信息”窗格中，右键单击<B> Secondary Logon </B>服务，然后单击<B>属性</B>。 </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD class=number>5.</TD>
<TD class=text>在<B>属性</B>对话框中，将<B>启动类型</B>设置为<B>自动</B>，然后单击<B>启动</B>。 </TD></TR>
<TR>
<TD class=number>6.</TD>
<TD class=text>在计算机启动该服务之后，单击<B>确定</B>以关闭<B>属性</B>对话框，然后关闭“计算机管理”。 </TD></TR></TBODY></TABLE>运行<B>运行方式</B>命令所必需的服务现在运行于计算机上。 <BR><BR><SPAN><A id=Task2></A></SPAN><A id=XSLTH3143121123120121120120></A>
<H3>通过快捷方式使用“运行方式”命令 </H3>
<TABLE class="list ol">
<TBODY>
<TR>
<TD class=number>1.</TD>
<TD class=text>导航到快捷方式项： 单击<B>开始</B>，指向<B>程序</B>，然后在<B>程序</B>菜单中查找快捷方式项。 <BR><BR>如果快捷方式不在<B>开始</B>菜单的“程序”文件夹中，请导航到快捷方式的正确位置。 </TD></TR>
<TR>
<TD class=number>2.</TD>
<TD class=text>按住 SHIFT 键同时右键单击快捷方式项，然后单击<B>运行方式</B>。 </TD></TR>
<TR>
<TD class=number>3.</TD>
<TD class=text>根据您拥有的操作系统执行以下某个步骤： 
<TABLE class="list ul">
<TBODY>
<TR>
<TD class=bullet>•</TD>
<TD class=text>Windows 2000： 在<B>以其他用户身份运行</B>中，键入<B>用户名</B>、<B>密码</B>和<B>域</B>，然后单击<B>确定</B>。 </TD></TR>
<TR>
<TD class=bullet>•</TD>
<TD class=text>Windows XP： 在<B>运行方式</B>中，单击<B>下列用户</B>选项，键入或选择<B>用户名</B>，键入<B>密码</B>，然后单击<B>确定</B>。 </TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><SPAN><A id=Troubleshooting></A></SPAN><A id=XSLTH3147121123120121120120></A>
<H3>疑难解答 </H3>
<TABLE class="list ul">
<TBODY>
<TR>
<TD class=bullet>•</TD>
<TD class=text>如果尝试使用<B>运行方式</B>命令，从网络位置启动诸如 MMC 控制台或控制面板项之类的程序，并且用于连接到网络共享的凭据不同于用于启动该程序的凭据，则可能会失败。 用于运行程序的凭据不能获得对相同网络共享的访问。 </TD></TR>
<TR>
<TD class=bullet>•</TD>
<TD class=text>RunAs 和 Secondary Logon 服务只接受密码身份验证。 如果策略要求智能卡登录，则<B>运行方式</B>命令将无法运行。 </TD></TR></TBODY></TABLE>
<DIV class=topOfPage>
<TABLE>
<TBODY>
<TR>
<TD class=image><A href="http://support.microsoft.com/?id=294676#top"><IMG title=回到顶端 alt=回到顶端 src="http://support.microsoft.com/library/images/support/en-us/uparrow.gif"></A></TD>
<TD class=text><A href="http://support.microsoft.com/?id=294676#top">回到顶端</A></TD></TR></TBODY></TABLE></DIV></DIV></DIV>
<DIV class=appliesTo>
<HR>
<A id=appliesto></A>
<H5>这篇文章中的信息适用于:</H5>
<TABLE class=list>
<TBODY>
<TR>
<TD class=bullet>•</TD>
<TD class=text>Microsoft Windows XP Professional Edition</TD></TR>
<TR>
<TD class=bullet>•</TD>
<TD class=text>Microsoft Windows 2000 Professional Edition</TD></TR></TBODY></TABLE></DIV>
<DIV class=topOfPage>
<TABLE>
<TBODY>
<TR>
<TD class=image><A href="http://support.microsoft.com/?id=294676#top"><IMG title=回到顶端 alt=回到顶端 src="http://support.microsoft.com/library/images/support/en-us/uparrow.gif"></A></TD>
<TD class=text><A href="http://support.microsoft.com/?id=294676#top">回到顶端</A></TD></TR></TBODY></TABLE></DIV>
<DIV class=keywords>
<TABLE>
<TBODY>
<TR>
<TD class=header>
<H5>关键字：&nbsp;</H5></TD>
<TD class=text>kbhowto kbhowtomaster kbtool kbui KB294676</TD></TR></TBODY></TABLE>
<DIV class=topOfPage>
<TABLE>
<TBODY>
<TR>
<TD class=image><A href="http://support.microsoft.com/?id=294676#top"><IMG title=回到顶端 alt=回到顶端 src="http://support.microsoft.com/library/images/support/en-us/uparrow.gif"></A></TD>
<TD class=text><A href="http://support.microsoft.com/?id=294676#top">回到顶端</A></TD></TR></TBODY></TABLE></DIV></DIV>
<DIV class="disclaimer text">Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性，不作任何声明。 所有该等文件及有关图形均"依样"提供，而不带任何性质的保证。Microsoft和/或其各供应商特此声明，对所有与该等信息有关的保证和条件不负任何责任，该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下，在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中，Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、</DIV><!-- - -KB 3 end- - --><img src ="http://www.blogjava.net/kenneth/aggbug/12272.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-06 23:37 <a href="http://www.blogjava.net/kenneth/archive/2005/09/06/12272.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Telnet服务攻防新手上路</title><link>http://www.blogjava.net/kenneth/archive/2005/09/06/12270.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Tue, 06 Sep 2005 15:22:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/06/12270.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/12270.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/06/12270.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/12270.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/12270.html</trackback:ping><description><![CDATA[<A class=bluekey href="http://www.yesky.com/key/4223/34223.html" target=_blank>Telnet</A>服务是最早的<A class=bluekey href="http://www.yesky.com/key/4965/239965.html" target=_blank>远程访问服务</A>。它是在网络发展的早期，所有的操作系统还基于命令模式控制时，为了解决用户远程维护主机、<A class=bluekey href="http://www.yesky.com/key/2378/147378.html" target=_blank>远程办公</A>等用户需求而特意开发的一个服务，被一直沿用到现在。
<P>　　当<A class=bluekey href="http://www.yesky.com/key/1626/176626.html" target=_blank>终端服务</A>这个基于图形界面访问的服务推出之后，现在已经很少有人利用Telnet服务进行<A class=bluekey href="http://www.yesky.com/key/4794/14794.html" target=_blank>远程访问</A>和远程办公了。但是Telnet服务却摇身一变成为了黑客的最爱。据统计，被黑客利用得最多的一个系统服务，就是Telnet服务。</P>
<P>　　黑客为什么不喜欢使用同样基于远程访问，并且更加方便直观的终端服务，而偏爱Telnet服务呢?难道因为黑客就喜欢在黑乎乎的命令窗口中操作吗?<A class=bluekey href="http://www.yesky.com/key/824/110824.html" target=_blank>NO</A>，当然不是这样。因为使用Telnet服务进行远程控制更加隐蔽，对系统的资源消耗也非常小，并且只需要一个命令即可开启和关闭它。所以对于网络安全来讲Telnet服务是一个非常危险的服务。</P>
<P>　　Telnet服务使用Telnet协议传输，在系统中使用的默认端口为TCP23端口。由于Telnet协议是集成在<A class=bluekey href="http://www.yesky.com/key/3363/158363.html" target=_blank>TCP/IP</A>协议中的，所以我们<A class=bluekey href="http://www.yesky.com/key/855/180855.html" target=_blank>无法使用</A>删除协议的办法来禁止Telnet服务。在我们讲防御Telnet服务之前，首先来看看黑客是如何利用Telnet服务的(笔者系统为<A class=bluekey href="http://www.yesky.com/key/3059/148059.html" target=_blank>Windows2000</A>)。</P>
<P>　　<FONT color=#a00000>攻 利用Telnet服务入侵</FONT></P>
<P>　　<STRONG>1.开启Telnet服务</STRONG></P>
<P>　　要想利用系统当中的Telnet服务必须先开启Telnet服务，因为在默认情况下Telnet服务是被系统所禁止的。所以当黑客使用缓冲溢出，<A class=bluekey href="http://www.yesky.com/key/2278/2278.html" target=_blank>IPC</A>等方法拿到远程主机的<A class=bluekey href="http://www.yesky.com/key/4709/34709.html" target=_blank>Shell</A>之后，必须开启Telnet服务。</P>
<P>　　在<A class=bluekey href="http://www.yesky.com/key/1061/71061.html" target=_blank>命令行</A>方式下开启Telnet服务的方法非常简单，只要在命令行当中键入“net start telnet”命令，即可开启系统中的Telnet服务。这是黑客使用得最多的一种开启Telnet服务的手法(图1)。</P>
<P align=center><IMG src="http://biz.chinabyte.com/imagelist/05/05/3bd9749e8oug.gif" border=0><BR>图</P>
<P>　　<STRONG>2.利用Telnet服务</STRONG></P>
<P>　　那么是不是启动了Telnet服务，黑客就可以利用Telnet服务连接到远程主机中去了呢?在命令行窗口中键入“telnet IP”命令，如telnet 192.168.0.3，这时命令行窗口会出现如图2所示的情况。</P>
<P align=center><IMG src="http://biz.chinabyte.com/imagelist/05/05/w92q2j843w69.jpg" border=0><BR>图</P>
<P>　　在这个窗口中，无论用户选择“Y”还是“N”都会出现“失去了跟主机的连接”提示。</P>
<P>　　这是因为用户<A class=bluekey href="http://www.yesky.com/key/2551/72551.html" target=_blank>没有通过</A>远程主机的NTLM验证。正是利用NTLM这个基于<A class=bluekey href="http://www.yesky.com/key/1194/96194.html" target=_blank>WorkGroup</A>网络当中的<A class=bluekey href="http://www.yesky.com/key/1483/161483.html" target=_blank>身份验证</A>协议，使得黑客不能轻易地利用到Telnet服务，这时即使黑客知道了Telnet<A class=bluekey href="http://www.yesky.com/key/4384/84384.html" target=_blank>服务器的管理</A>员用户名和密码，他仍然通不过NTLM验证，这无疑给系统带给了一定的安全性。<BR><STRONG>3.突破NTLM验证</STRONG></P>
<P>　　既然入侵者无法通过NTLM验证，那么Telnet服务就安全了?其实黑客有非常多的方法可以突破NTLM验证。</P>
<P>　　比如黑客知道了Telnet服务器上的一个管理员组的用户名和密码(如用户名为xiewe<A class=bluekey href="http://www.yesky.com/key/497/160497.html" target=_blank><FONT color=#002c99>i,</FONT></A>密码为12345)，那么黑客可以在自己的系统中建立一个用户名和密码与之相同的管理员组用户。然后按住“Shift”键不放，找到“开始→程序→附件”中的“<A class=bluekey href="http://www.yesky.com/key/4282/9282.html" target=_blank><FONT color=#002c99>命令提示符</FONT></A>”，<A class=bluekey href="http://www.yesky.com/key/1043/46043.html" target=_blank><FONT color=#002c99>右击</FONT></A>“命令提示符”<A class=bluekey href="http://www.yesky.com/key/4113/49113.html" target=_blank><FONT color=#002c99>选项</FONT></A>，可以在<A class=bluekey href="http://www.yesky.com/key/4819/14819.html" target=_blank><FONT color=#002c99>右键菜单</FONT></A>中看到一个“运行方式”选项，打开它就可以看到一个选择用户打开程序的选项，勾上“下列用户”，黑客就可以在选项中填入刚刚建立的与Telnet服务器上等同的管理员组用户(图3)， 确定之后在打开的命令行窗口中，连接Telnet服务器，就可以非常顺利地通过NTLM验证。</P>
<P align=center><IMG src="http://biz.chinabyte.com/imagelist/05/05/99nj0o4n16bm.jpg" border=0><BR>图3</P>
<P>　　这只是突破NTLM验证方法中的一种，黑客如果拿到了<A class=bluekey href="http://www.yesky.com/key/1320/176320.html" target=_blank><FONT color=#002c99>远程系统</FONT></A>的CmdShell，可以<A class=bluekey href="http://www.yesky.com/key/2785/62785.html" target=_blank><FONT color=#002c99>上传</FONT></A>一些第三方的工具，如Ntlm.exe，然后执行这一工具也可以删除NTLM验证。</P>
<P>　　在系统中用户其实也可以手动地更改NTLM验证的设置，在“Telnet服务管理器”中就提供了修改NTLM验证的选项。用户可以在“程序→<A class=bluekey href="http://www.yesky.com/key/382/75382.html" target=_blank><FONT color=#002c99>控制面板</FONT></A>→管理工具”中找到“Telnet服务管理”选项，单击就可以打开。或者用在命令行窗口下键入“tlntadmn.exe”也可以打开“Telnet服务管理器”。用户可以看到“Telnet服务管理器”是以命令行的方式出现的。选择当中的选项3“显示 / 更改注册表设置” (图4)，用户可以看到会出现一个选项的列表，总共有八个选项。</P>
<P align=center><IMG src="http://biz.chinabyte.com/imagelist/05/05/6gj0414c2zm9.jpg" border=0><BR>图4</P>
<P>　　大家可以发现，选项7是针对NTLM验证的，它的默认值是“2”，其中还有两个值可以选择，分别是“0”和“1”。“0”的意思是不使用 NTLM 身份验证;“1”则表示先尝试 NTLM 身份验证，如果失败，再使用用户名和密码;“2”的意思是只使用 NTLM 身份验证。</P>
<P>　　如果把NTLM的值改为“0”或者“1”，在Telnet连接的时候，我们都可以顺利地通过NTLM验证。所以接下来的步骤，选择列表中的“(7)NTML”，并且选择“Y”更改默认值，最后把NTLM验证的值改为“0”或者“1”即可(图5)。从图5中可以看到“Telnet服务管理器”提示，只有当Telnet服务<A class=bluekey href="http://www.yesky.com/key/3276/43276.html" target=_blank><FONT color=#002c99>重新启动</FONT></A>之后配置才能够生效。用户可以在命令行窗口下键入“net stop telnet”和“net start telnet”即可重新启动Telnet服务。</P>
<P align=center><IMG src="http://biz.chinabyte.com/imagelist/05/05/57rw532j784f.gif" border=0><BR>图5</P>
<P>　　接下来<A class=bluekey href="http://www.yesky.com/key/3085/168085.html" target=_blank><FONT color=#002c99>远程用户</FONT></A>就可以使用“telnet IP”连接到Telnet服务器上了，虽然没有了NTLM验证的限制，但是访问用户必须键入Telnet服务器的管理员组用户名和密码方能访问到。当访问到时，用户就可以执行Windows <A class=bluekey href="http://www.yesky.com/key/4805/134805.html" target=_blank><FONT color=#002c99>SHELL</FONT></A>命令来管理远程主机了。<BR><FONT color=#a00000>防 全面封锁Telnet服务</FONT></P>
<P>　　知道了黑客利用Telnet服务的手法，那么针对Telnet服务的防御办法自然也就有了。根据黑客利用Telnet服务的思路，笔者总结了防御Telnet服务四种方法。</P>
<P>　　<STRONG>1.管理好用户的密码</STRONG></P>
<P>　　最简单的方法，管理好本机系统当中的用户名和密码，如果用户名和密码无法被黑客取得，那么黑客将很难利用到Telnet服务。</P>
<P>　　<STRONG>2.修改服务端口</STRONG></P>
<P>　　从前面的内容中大家可以了解到Telnet服务使用的是系统的23端口，如果我们修改了Telnet服务的默认端口，无疑隐藏了Telnet服务的入口点，给系统带来了一定的安全保障。修改方法非常简单，首先打开“Telnet服务管理器”，同样选择当中的选项3“显示 / 更改注册表设置”，打开Telnet服务管理列表，选择当中的选项8“TelnetPort”，选择“Y”更改Telnet服务的默认端口23，把Telnet服务的端口改为1024或1024以上的端口，确定即可。接着重新启动Telnet服务，配置即可生效。以后用户只要键入“telnet IP 1024”即可访问到Telnet服务器。</P>
<P>　　<STRONG>3.禁用Telnet服务</STRONG></P>
<P>　　大家知道要想使用Telnet服务必须开启Telnet服务，假如黑客利用缓冲溢出或者其它方法拿到了用户的CmdShell，那么他只要在中CmdShell下键入“net start telnet”即可启动Telnet服务，并且可以利用Telnet服务作为用户系统中的后门使用。有什么办法才能够阻止黑客开启Telnet服务呢?其实办法非常简单，禁用Telnet服务即可实现。用户打开“控制面板→管理工具→服务”在当中找到Telnet服务选项，<A class=bluekey href="http://www.yesky.com/key/4243/59243.html" target=_blank><FONT color=#002c99>双击</FONT></A>就可以进入“Telnet服务属性”对话框，在“启动类型”中选择“已禁用”，单击“确定”按钮即可。</P>
<P>　　<STRONG>4.终极Telnet服务防御</STRONG></P>
<P>　　禁用服务并不是防御Telnet服务的终极办法，针对这一限制，黑客专门有一些第三方工具，只要拿到了远程主机的CmdShell，他只须上传该工具到远程主机并运行它就可以突破禁用服务这一限制，开启Telnet服务。</P>
<P>　　所以针对这个问题，笔者最后给大家介绍一种<A class=bluekey href="http://www.yesky.com/key/4009/194009.html" target=_blank><FONT color=#002c99>最完美的</FONT></A>防御方法。</P>
<P>　　首先打开“Telnet服务管理器”，同样选择选项3“显示 / 更改注册表设置”，进入Telnet服务管理列表，大家可以看到其中的选项4“DefaultShell”，前面我们已经介绍过这个选项的具体含义，“显示Telnet服务所对应的程序。默认值是: %<A class=bluekey href="http://www.yesky.com/key/2097/102097.html" target=_blank><FONT color=#002c99>Systemroot</FONT></A>%\System32\<A class=bluekey href="http://www.yesky.com/key/730/125730.html" target=_blank><FONT color=#002c99>Cmd.exe</FONT></A> /q /k”，这个含义的具体意思是什么呢?为什么当我们通过Telnet验证的时候能够取得远程主机的命令控制权限呢?</P>
<P>　　因为我们可以看到Telnet服务对应的默认程序是“%Systemroot%\System32\Cmd.exe /q /k”也就是系统根目录<A class=bluekey href="http://www.yesky.com/key/1782/96782.html" target=_blank><FONT color=#002c99>WinNT</FONT></A>(或Windows)下System32目录下的Cmd.exe，我们都知道Cmd.exe是系统中的命令行窗口，那么当远程用户通过了Telnet验证的话，远程系统就会把自己的Cmd.exe调给远程用户使用，这就是为什么使用Telnet能够拿到远程主机命令控制权限的最根本原因。</P>
<P>　　讲到这里似乎防御方法也出来了，其实思路很简单，我们把Telnet服务所对应的默认程序改为一个未知的程序，这样即使黑客知道了远程主机的管理员用户和密码，突破了NTLM验证对方仍然无法拿到对主机的命令控制权，因为Telnet服务对应的默认程序已经不再是Cmd.exe。有了好思路我们就来具体使用这个方法。</P>
<P>　　选择Telnet服务管理列表中的选项4“DefaultShell”，就会提示我们是否更改Telnet服务的默认设置，选择“Y”，并且把Telnet服务对应的默认程序改为一个未知的文件，如:%SystemRoot%\system32\xiewei.exe，我的系统中根目录下根本不存在xiewei.exe文件，设置好之后重新启动服务。</P>
<P>　　设置好之后，我们来看一下它的效果。假如现在黑客知道这<A class=bluekey href="http://www.yesky.com/key/3999/153999.html" target=_blank><FONT color=#002c99>台系</FONT></A>统的管理员用户Administrator，密码为12345，并且这台系统开启了Telnet服务，NTLM验证也被突破，那么使用 “Telnet IP”连接到这台系统，这时会提示键入远程系统的用户名和密码，证明已经通过了NTLM验证，在正确地输入用户名密码之后，系统仍然提示“失去了跟主机的连接”。</P>
<P>　　通过对这种方法，用户可以全面禁止系统中的Telnet服务。</P><img src ="http://www.blogjava.net/kenneth/aggbug/12270.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-06 23:22 <a href="http://www.blogjava.net/kenneth/archive/2005/09/06/12270.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windows编程通用的Win32类型和常见的结构</title><link>http://www.blogjava.net/kenneth/archive/2005/09/02/11833.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Fri, 02 Sep 2005 05:52:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/02/11833.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/11833.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/02/11833.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/11833.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/11833.html</trackback:ping><description><![CDATA[CALLBACK 在应用程序的回调例程中取代FAR PASCAL<BR>HANDLE 一个32位的无符号整数，用作句柄<BR>HDC 设备描述句柄<BR>HWND 一个32位的无符号整数用作窗口句柄<BR>LONG 一个32位的带符号整数<BR>LPARAM 用于声明lParam的类型<BR>LPCSTR 与LPSTR类似，但用于只读字符串指针<BR>LPSTR 一个32位的指针<BR>LPVIOD 一个普通指针类型等价于（viod *）<BR>LRESULT 子窗口过程的返回值<BR>NULL 一个整型的0值，常常用于激活函数的缺省动作和参数<BR>UINT 一种无符号的整数类型，其大小取决于主机环境；在NT下是32位<BR>WCHAR 一种16位的UNICODE字符，用于表示世界上所有语言的符号。<BR>WINAPI 在API的定义中取代FAR PASCAL<BR>WPARAM 关于wParam的声明<BR><BR><B>Win32应用程序中常见的结构</B><BR><BR>结构 描述<BR>-----------------------------------------------<BR>MSG 定义了输入消息域<BR>PAINTSTRUCT 定义了在窗口内绘图时使用的绘图结构<BR>RECT 定义一个矩形<BR>WNDCLASS 定义一个窗口类<img src ="http://www.blogjava.net/kenneth/aggbug/11833.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-02 13:52 <a href="http://www.blogjava.net/kenneth/archive/2005/09/02/11833.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC实用小知识总结</title><link>http://www.blogjava.net/kenneth/archive/2005/09/02/11832.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Fri, 02 Sep 2005 05:25:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/02/11832.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/11832.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/02/11832.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/11832.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/11832.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （1） 如何通过代码获得应用程序主窗口的指针?<BR>　　&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　AfxGetMainWnd() -&gt;ShowWindow(SW_SHOWMAXMIZED)<BR>　　//使程序最大化.</P></TD></TR></TBODY></TABLE>
<P>　　（2） 确定应用程序的路径<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　Use GetModuleFileName 获得应用程序的路径，然后去掉可执行文件名。<BR>　　Example:<BR>　　TCHAR<BR>　　exeFullPath[MAX_PATH] // MAX_PATH在API中定义了吧，好象是<BR>　　128<BR>　　GetModuleFileName(NULL,exeFullPath,MAX_PATH)</P></TD></TR></TBODY></TABLE></P>
<P>　　（3） 如何在程序中获得其他程序的图标?<BR>　　两种方法:<BR>　　(1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle,<BR>　　(2) SDK函数 SHGetFileInfo 获得有关文件的很多信息,如大小图标,属性, 类型等.<BR>　　Example(1):<BR>　　在程序窗口左上角显示 NotePad图标.<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　void CSampleView:<BR>　　OnDraw(CDC * pDC)<BR>　　{<BR>　　if( :: SHGetFileInfo(_T("c:\\pwin95\\notepad.exe"),0,<BR>　　&amp;stFileInfo,sizeof(stFileInfo),SHGFI_ICON))<BR>　　{<BR>　　pDC -&gt;DrawIcon(10,10,stFileInfo.hIcon)<BR>　　}<BR>　　}<BR>　　Example(2):同样功能,Use ExtractIcon Function<BR>　　void CSampleView:: OnDraw(CDC *pDC)<BR>　　{<BR>　　HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T<BR>　　("NotePad.exe"),0)<BR>　　if (hIcon &amp;&amp;hIcon!=(HICON)-1)<BR>　　pDC-&gt;DrawIcon(10,10,hIcon)<BR>　　}</P></TD></TR></TBODY></TABLE><BR>　　说明: 获得notepad.exe的路径正规上来说用GetWindowsDirectory函数得到, 如果是调用 win95下的画笔，应该用访问注册表的方法获得其路径，要作成一个比较考究的程序，考虑应该全面点.</P>
<P>　　（4）获得各种目录信息<BR>　　Windows目录: Use "GetWindowsDirectory"<BR>　　Windows下的system目录: Use "GetSystemDirectory"<BR>　　temp目录: Use "GetTempPath"<BR>　　当前目录: Use "GetCurrentDirectory"</P>
<P>　　请注意前两个函数的第一个参数为目录变量名，后一个为缓冲区后两个相反.</P>
<P>　　（5）如何自定义消息<BR>　　(1) 手工定义消息，可以这么写<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　#define WM_MY_MESSAGE(WM_USER+100),</P></TD></TR></TBODY></TABLE><BR>　　MS 推荐的至少是 WM_USER+100</P>
<P>　　(2)写消息处理函数,用<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　WPARAM,LPARAM返回LRESULT.<BR>　　LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam)</P>
<P>　　{<BR>　　temp目录: Use "GetTempPath"<BR>　　//加入你的处理函数 irectory"<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（6） 如何改变窗口的图标?<BR>　　向窗口发送 WM_SECTION消息。<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　Example:<BR>　　HICON hIcon=AfxGetApp() -&gt;LoadIcon(IDI_ICON)<BR>　　ASSERT(hIcon)<BR>　　AfxGetMainWnd() -&gt;SendMessage(WM_SECTION,TRUE,(LPARAM)hIcon)</P></TD></TR></TBODY></TABLE></P>
<P>　　（7） 如何改变窗口的缺省风格?<BR>　　重载 CWnd:: PreCreateWindow 并修改CREATESTRUCT结构来指定窗口风格和其他创建信息.<BR></P>
<P>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　Example: Delete "Max" Button and Set Original<BR>　　Window's Position and Size</P>
<P>　　BOOL CMainFrame:: PreCreateWindow<BR>　　(CREATESTRUCT &amp;cs)<BR>　　{<BR>　　cs.style &amp;=~WS_MAXINIZEMOX</P>
<P>　　cs.x=cs.y=0<BR>　　cs.cx=GetSystemMetrics(SM_CXSCREEN/2)<BR>　　cs.cy=GetSystemMetrics(SM_CYSCREEN/2)</P>
<P>　　return CMDIFramewnd ::PreCreateWindow(cs)<BR>　　}</P></TD></TR></TBODY></TABLE></P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （8） 如何将窗口居中显示?<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　Call Function CWnd::<BR>　　Center Windows</P>
<P>　　Example(1):<BR>　　Center Window( ) //Relative to it's parent<BR>　　// Relative<BR>　　to Screen<BR>　　Example(2):<BR>　　Center Window(CWnd:: GetDesktopWindow( ))<BR>　　//Relative to<BR>　　Application's MainWindow<BR>　　AfxGetMainWnd( ) -&gt;<BR>　　Center Window( )</P></TD></TR></TBODY></TABLE>
<P>　　（9） 如何让窗口和 MDI窗口一启动就最大化和最小化?<BR>　　先说窗口。<BR>　　在 InitStance 函数中设定 m_nCmdShow的取值.<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　m_nCmdShow=SW_SHOWMAXMIZED //最大化<BR>　　m_nCmdShow=SW_SHOWMINMIZED //最小化<BR>　　m_nCmdShow=SW_SHOWNORMAL //正常方式</P></TD></TR></TBODY></TABLE></P>
<P>　　MDI窗口:<BR>　　如果是创建新的应用程序,可以用MFC AppWizard 的Advanced 按钮并在MDI子窗口风格组中检测最大化或最小化还可以重载 MDI Window 的PreCreateWindow函数，设置WS_MAXMIZE or WS_MINMIZE</P>
<P>　　如果从 CMDIChildWnd派生,调用 OnInitialUpdate函数中的 CWnd::Show Window来指定 MDI Child Window的风格。</P>
<P>　　（10） 如何限制窗口的大小?<BR>　　也就是 FixedDialog形式。 Windows发送 WM_GETMAXMININFO消息来跟踪, 响应它,在 OnGetMAXMININFO 中写代码:</P>
<P>　　（11） 如何使窗口不可见？<BR>　　很简单,用SW_HIDE 隐藏窗口，可以结合 FindWindow,ShowWindow控制.</P>
<P>　　（12） 如何创建一个字回绕的CEditView<BR>　　重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构，关闭CEditView对象的ES_AUTOHSCROLL和WS_HSCROLL风格位， 由于CEditView : : PreCreateWindow显示设置cs. style，调用基类函数后要修改cs . style。</P>
<P>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&amp;cs)<BR>　　{<BR>　　//First call basse class function .<BR>　　BOOL bResutl =CEditView : : PreCreateWindow (cs)</P>
<P>　　// Now specify the new window style .<BR>　　cs.style &amp;= ~ (ES_AUTOHSCROLL ｜WS_HSCROLL)<BR>　　return bResult<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（13） 如何使程序保持极小状态?<BR>　　这么办: 在恢复程序窗体大小时，Windows会发送WM_QUERY-OPEN消息，用 ClassWizard设置成员函数<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　OnQueryOpen() ,add following code:</P>
<P>　　Bool CMainFrame:: OnQueryOpen( )<BR>　　{<BR>　　Return false<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（14） 移动窗口<BR>　　调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口有关（顶层窗口与屏幕有关）。调用CWnd : : MoveWindow时必须要指定窗口的大小。<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　//Move window to positoin 100 , 100 of its parent window .<BR>　　SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE ｜SWP_NOAORDER)</P></TD></TR></TBODY></TABLE></P>
<P>　　（15） 通用控件的显示窗口<BR>　　MFC提供了几个CView派生的视窗类， 封装了通用控件的功能，但仍然使用工作框文档显示窗口体系结构：CEditView封装了编辑控件，CTreeView保持了树列表控件，CListView封装了列表显示窗口控件，CRichEditView可以处理多种编辑控件。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （16） 重置窗口的大小<BR>　　调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志， 也可调用CWnd : : MoveWindow 但必须指定窗口的位置。<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　// Get the size of the window .<BR>　　Crect reWindow<BR>　　GetWindowRect (reWindow )</P>
<P>　　//Make the window twice as wide and twice as tall .<BR>　　SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2,</P>
<P>　　reWindow . Height () * 2,<BR>　　SWP_NOMOVE ｜SWP_NOZORDER )</P></TD></TR></TBODY></TABLE></P>
<P>　　（17） 如何单击除了窗口标题栏以外的区域使窗口移动<BR>　　当窗口需要确定鼠标位置时Windows向窗口发送WM_NCHITTEST信息，可以处理该信息使Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序，可以使用ClassWizard处理该信息并调用基类函数， 如果函数返回HTCLIENT 则表明鼠标在客房区域，返回HTCAPTION表明鼠标在Windows的标题栏中。<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　UINT CSampleDialog : : OnNcHitTest (Cpoint point )<BR>　　{<BR>　　UINT nHitTest =Cdialog: : OnNcHitTest (point )<BR>　　return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　上述技术有两点不利之处，<BR>　　其一是在窗口的客户区域双击时，窗口将极大；<BR>　　其二， 它不适合包含几个视窗的主框窗口。<BR>　　还有一种方法，当用户按下鼠标左键使主框窗口认为鼠标在其窗口标题上，使用ClassWizard在视窗中处理WM_LBUTTODOWN信息并向主框窗口发送一个WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point<BR>　　)<BR>　　{<BR>　　CView : : OnLButtonDow (nFlags , pont )</P>
<P>　　//Fool frame window into thinking somene clicked<BR>　　on<BR>　　its caption bar .<BR>　　GetParentFrame ( ) —&gt; PostMessage (<BR>　　WM_NCLBUTTONDOWN ,<BR>　　HTCAPTION , MAKELPARAM (poitn .x , point .y) )</P>
<P>　　}</P></TD></TR></TBODY></TABLE><BR>　　该技术也适用于对话框和基于对的应用程序，只是不必调用<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　CWnd: :GetParentFrame 。<BR>　　void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point )<BR>　　{<BR>　　Cdialog : : OnLButtonDow (nFlags, goint )<BR>　　//Fool dialog into thinking simeone clicked on its<BR>　　caption bar .<BR>　　PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x<BR>　　, point. y<BR>　　) )<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（18） 如何改变视窗的背景颜色<BR>　　Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景，可以使用ClassWizard重载该消息的缺省处理程序来擦除背景（实际是画），并返回TRUE以防止Windows擦除窗口。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　//Paint area that needs to be erased.<BR>　　BOOL CSampleView : : OnEraseBkgnd (CDC* pDC)<BR>　　{<BR>　　// Create a pruple brush.<BR>　　CBrush Brush (RGB (128 , 0 , 128) )</P>
<P>　　// Select the brush into the device context .<BR>　　CBrush* pOldBrush = pDC—&gt;SelcetObject (&amp;brush)</P>
<P>　　// Get the area that needs to be erased .<BR>　　CRect reClip<BR>　　pDC—&gt;GetCilpBox (&amp;rcClip)<BR>　　//Paint the area.<BR>　　pDC—&gt; PatBlt (rcClip.left , rcClip.top , rcClip.Width ( ) , rcClip.Height( ) , PATCOPY )</P>
<P>　　//Unselect brush out of device context .<BR>　　pDC—&gt;SelectObject (pOldBrush )</P>
<P>　　// Return nonzero to half fruther processing .<BR>　　return TRUE<BR>　　}</P></TD></TR></TBODY></TABLE></P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （19） 如何改变窗口标题<BR>　　调用CWnd : : SetWindowText可以改变任何窗口（包括控件）的标题。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　//Set title for application's main frame window .<BR>　　AfxGetMainWnd ( ) —&gt; SetWindowText (_T("Application title") )</P>
<P>　　//Set title for View's MDI child frame window .<BR>　　GetParentFrame ( ) —&gt; SetWindowText ("_T ("MDI Child Frame new title")<BR>　　)</P>
<P>　　//Set title for dialog's push button control.<BR>　　GetDigitem (IDC_BUTTON) —&gt; SetWindowText (_T ("Button new title ") )</P></TD></TR></TBODY></TABLE><BR>　　如果需要经常修改窗口的标题（注：控件也是窗口），应该考虑使用半文档化的函数AfxSetWindowText。该函数在AFXPRIV.H中说明，在WINUTIL.CPP中实现，在联机帮助中找不到它，它在AFXPRIV.H中半文档化， 在以后发行的MFC中将文档化。<BR>　　AfxSetWindowText的实现如下：<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew )<BR>　　{<BR>　　itn nNewLen= Istrlen (Ipaznew)<BR>　　TCHAR szOld [256]<BR>　　//fast check to see if text really changes (reduces<BR>　　flash in the<BR>　　controls )<BR>　　if (nNewLen &gt;_contof (szOld)<BR>　　｜｜ : : GetWindowText (hWndCrtl, szOld , _countof (szOld) !=nNewLen<BR>　　｜｜ Istrcmp (szOld , IpszNew)! = 0<BR>　　{<BR>　　//change it<BR>　　: : SetWindowText(hWndCtrl , IpszNew )<BR>　　}<BR>　　}</P></TD></TR></TBODY></TABLE>
<P></P>
<P>　　（20） 如何防止主框窗口在其说明中显示活动的文档名<BR>　　创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位，如果不希望在说明中自动添加文档名， 必须禁止该风格位， 可以使用ClassWizard重置<BR>　　CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&amp;cs)<BR>　　{<BR>　　//Turn off FWS_ADDTOTITLE in main frame .<BR>　　cs.styel &amp; = ~FWS_ADDTOTITLE 　<BR>　　return CMDIFrameWnd : : PreCreateWindow (cs )<BR>　　}</P></TD></TR></TBODY></TABLE><BR>　　关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口，可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。</P>
<P>　　（21） 如何获取有关窗口正在处理的当前消息的信息<BR>　　调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如，可以使用ClassWizard将几个菜单项处理程序映射到一个函数中，然后调用GetCurrentMessage来确定所选中的菜单项。<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　viod CMainFrame : : OnCommmonMenuHandler ( )<BR>　　{<BR>　　//Display selected menu item in debug window .<BR>　　TRACE ("Menu item %u was selected . \n" ,</P></TD></TR></TBODY></TABLE></P>
<P>　　（22） 如何在代码中获取工具条和状态条的指针<BR>　　缺省时， 工作框创建状态条和工具条时将它们作为主框窗口的子窗口，状态条有一个AFX_IDW_STATUS_BAR标识符，工具条有一个AFX_IDW_TOOLBAR标识符，下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针：<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　//Get pointer to status bar .<BR>　　CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( )<BR>　　—&gt; GetDescendantWindow(AFX_IDW_STUTUS_BAR)</P>
<P>　　//Get pointer to toolbar .<BR>　　CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( )<BR>　　—&gt; GetDescendantWindow(AFX_IDW_TOOLBAR)</P></TD></TR></TBODY></TABLE></P>
<P>　　（23） 如何使能和禁止工具条的工具提示<BR>　　如果设置了CBRS_TOOLTIPS风格位，工具条将显示工具提示，要使能或者禁止工具提示，需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数：<BR><BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　void CMainFrame : : EnableToolTips ( BOOL bDisplayTips )<BR>　　{<BR>　　ASSERT_VALID (m_wndToolBar)</P>
<P>　　DWORD dwStyle = m _wndToolBar.GetBarStyle ( )</P>
<P>　　if (bDisplayTips) dwStyle ｜=CBRS_TOOLTIPS</P>
<P>　　else<BR>　　dwStyle &amp; = ~CBRS_TOOLTIPS</P>
<P>　　m_wndToolBar.SetBarStyle (dwStyle )<BR>　　}</P></TD></TR></TBODY></TABLE></P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （24） 如何创建一个不规则形状的窗口<BR>　　可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定的区域，实际上使窗口成为指定的不规则形状。 使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删除所在的缺省控件、标题以及边界。<BR>　　给对话类增加一个CRgn数据成员，以后要使用该数据成员建立窗口区域。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　Class CRoundDlg : public CDialog<BR>　　{<BR>　　…<BR>　　private :<BR>　　Crgn m_rgn : // window region<BR>　　…<BR>　　}<BR>　　修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给窗口：<BR>　　BOOL CRoundDlg : : OnInitDialog ( )<BR>　　{<BR>　　CDialog : : OnInitDialog ( )</P>
<P>　　//Get size of dialog .<BR>　　CRect rcDialog<BR>　　GetClientRect (rcDialog )</P>
<P>　　// Create region and assign to window .<BR>　　m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width( ) , rcDialog.Height ( ) )<BR>　　SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn ,TRUE )</P>
<P>　　return TRUE<BR>　　}</P></TD></TR></TBODY></TABLE>
<P>　　通过建立区域和调用SetWindowRgn，已经建立一个不规则形状的窗口，下面的例子程序是修改OnPaint函数使窗口形状看起来象一个球形体。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　voik CRoundDlg : : OnPaint ( )<BR>　　{<BR>　　CPaintDC de (this) // device context for painting<BR>　　.<BR>　　//draw ellipse with out any border<BR>　　dc. SelecStockObject (NULL_PEN)<BR>　　//get the RGB colour components of the sphere color<BR>　　COLORREF color= RGB( 0 , 0 , 255)<BR>　　BYTE byRed =GetRValue (color)<BR>　　BYTE byGreen = GetGValue (color)<BR>　　BYTE byBlue = GetBValue (color)</P>
<P>　　// get the size of the view window<BR>　　Crect rect<BR>　　GetClientRect (rect)</P>
<P>　　// get minimun number of units<BR>　　int nUnits =min (rect.right , rect.bottom )</P>
<P>　　//calculate he horiaontal and vertical step size<BR>　　float fltStepHorz = (float) rect.right /nUnits<BR>　　float fltStepVert = (float) rect.bottom /nUnits</P>
<P><BR>　　int nEllipse = nUnits/3 // calculate how many to<BR>　　draw<BR>　　int nIndex<BR>　　// current ellipse that is being draw</P>
<P>　　CBrush brush<BR>　　// bursh used for ellipse fill color<BR>　　CBrush *pBrushOld // previous<BR>　　brush that was selected into dc<BR>　　//draw ellipse , gradually moving towards upper-right<BR>　　corner<BR>　　for (nIndex = 0 nIndes &lt; + nEllipse nIndes++)<BR>　　{<BR>　　//creat solid brush<BR>　　brush . CreatSolidBrush (RGB ( ( (nIndex*byRed ) /nEllipse ).<BR>　　( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue)<BR>　　/nEllipse ) ) )</P>
<P>　　//select brush into dc<BR>　　pBrushOld= dc .SelectObject (&amp;brhsh)</P>
<P>　　//draw ellipse<BR>　　dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,<BR>　　rect. right -( (int) fltStepHorz * nIndex )+ 1,<BR>　　rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1)</P>
<P>　　//delete the brush<BR>　　brush.DelecteObject ( )<BR>　　}<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　最后，处理WM_NCHITTEST消息，使当击打窗口的任何位置时能移动窗口。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　UINT CRoundDlg : : OnNchitTest (Cpoint point )<BR>　　{<BR>　　//Let user move window by clickign anywhere on thewindow .<BR>　　UINT nHitTest = CDialog : : OnNcHitTest (point)<BR>　　rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest</P>
<P>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（25） 如何获取应用程序的 实例句柄?<BR>　　应用程序的实例句柄保存在CWinApp m_hInstance 中,可以这么调用AfxGetInstancdHandle获得句柄.<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>
<P>　　Example: HANDLE hInstance=AfxGetInstanceHandle()</P></TD></TR></TBODY></TABLE></P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（26） 如何编程结束应用程序?<BR>　　这是个很简单又是编程中经常要遇到的问题.<BR>　　向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示是否保存修改过的数据.<BR>　　<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><FONT color=#002c99><BR></FONT></TD>
<TD>　　Example: AfxGetMainWindow()-&gt;SendMessage(WM_CLOSE)</TD></TR></TBODY></TABLE>
<P>　　还可以创建一个自定义的函数 Terminate Window<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　void Terminate Window(LPCSTR pCaption)<BR>　　{<BR>　　CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption) 
<P>　　if (pWnd)</P>
<P>　　pWnd -&gt;SendMessage(WM_CLOSE)<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　说明: FindWindow函数不是提倡的做法，因为它无法处理标题栏自动改变，比如我们要检测 Notepad是不是已运行而事先不知道Notepad的标题栏,这时FindWindow就无能为力了，可以通过枚举 windows任务列表的办法来实现。在机械出版社"Windows 95 API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。</P>
<P>　　（27） 如何创建和使用无模式对话框<BR>　　MFC将模式和无模式对话封装在同一个类中，但是使用无模式对话需要几个对话需要几个额处的步骤。首先，使用资源编辑器建立对话资源并使用ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的：模式对话通过调用CDialog : : EndDialog 来中止，无模式对话则是调用CWnd: : DestroyWindow来中止的，函数CDialog : : OnOK和CDialog : : OnCancel调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　void CSampleDialog : : OnOK ( )<BR>　　{<BR>　　// Retrieve and validate dialog data .<BR>　　if (! UpdateData (TRUE) )<BR>　　{<BR>　　// the UpdateData rountine<BR>　　will set focus to correct item TRACEO (" UpdateData failed during dialog termination .\n")<BR>　　return<BR>　　} 
<P>　　//Call DestroyWindow instead of EndDialog .<BR>　　DestroyWindow ( )<BR>　　}</P>
<P>　　void CSampleDialog : : OnCancel ( )<BR>　　{<BR>　　//Call DestroyWindow instead of EndDialog .<BR>　　DestroyWindow ( )<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　其次，需要正确删除表示对话的C++对象。对于模式对来说，这很容易，需要创建函数返回后即可删除C++对象；无模式对话不是同步的，创建函数调用后立即返回，因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy，可以重置该函数并执行清除操作，诸如删除this指针。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　void CSampleDialog : : PostNcDestroy ( )<BR>　　{<BR>　　// Declete the C++ object that represents this dialog.<BR>　　delete this</TD></TR></TBODY></TABLE></P>
<P>　　最后，要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放，要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明 了应用程序是如何创建无模式对话的： 象；无模式对话不是同步的，创建函数调用后立即返回，<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　void CMainFrame : : OnSampleDialog ( )<BR>　　{<BR>　　//Allocate a modeless dialog object .<BR>　　CSampleDilog * pDialog =new CSampleDialog<BR>　　ASSERT_VALID (pDialog) Destroy ( ) 
<P>　　//Create the modeless dialog . represents this dialog.<BR>　　BOOL bResult = pDialog —&gt; Creste (IDD_IDALOG)<BR>　　ASSERT (bResult )<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（28） 如何防止主框窗口在其说明中显示活动的文档名<BR>　　创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位，如果不希望在说明中自动添加文档名， 必须禁止该风格位， 可以使用ClassWizard重置<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。<BR>　　BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&amp;cs)<BR>　　{<BR>　　//Turn off FWS_ADDTOTITLE in main frame .<BR>　　cs.styel &amp; = ~FWS_ADDTOTITLE 　<BR>　　return CMDIFrameWnd : : PreCreateWindow (cs )<BR>　　}</TD></TR></TBODY></TABLE><BR>　　关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口，可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （29） 如何在代码中获取工具条和状态条的指针<BR>　　缺省时， 工作框创建状态条和工具条时将它们作为主框窗口的子窗口，状态条有一个AFX_IDW_STATUS_BAR标识符，工具条有一个AFX_IDW_TOOLBAR标识符，下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//Get pointer to status bar .<BR>　　CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( )<BR>　　—&gt; GetDescendantWindow(AFX_IDW_STUTUS_BAR) 
<P>　　//Get pointer to toolbar .<BR>　　CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( )<BR>　　—&gt; GetDescendantWindow(AFX_IDW_TOOLBAR)</P></TD></TR></TBODY></TABLE></P>
<P>　　（30） 怎样加载其他的应用程序?<BR>　　三个SDK函数 winexec, shellexecute,createprocess可以使用。<BR>　　WinExec最简单，两个参数，前一个指定路径，后一个指定显示方式.后一个参数值得说一下，比如泥用 SW_SHOWMAXMIZED方式去加载一个无最大化按钮的程序，就是Neterm,calc等等，就不会出现正常的窗体，但是已经被加到任务列表里了。</P>
<P>　　ShellExecute较 WinExex灵活一点，可以指定工作目录,下面的Example就是直接打开 c:\temp\1.txt,而不用加载与 txt文件关联的应用程序,很多安装程序完成后都会打开一个窗口，来显示Readme or Faq,我猜就是这么作的啦.</P>
<P>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:\\temp"),SW_SHOWMAXMIZED)</TD></TR></TBODY></TABLE></P>
<P>　　CreateProcess最复杂，一共有十个参数，不过大部分都可以用NULL代替，它可以指定进程的安全属性，继承信息，类的优先级等等.来看个很简单的Example:<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　STARTUPINFO stinfo<BR>　　//启动窗口的信息<BR>　　PROCESSINFO procinfo //进程的信息 
<P>　　CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE,<BR>　　NORMAL_PRIORITY_</P>
<P>　　CLASS,NULL,NULL, &amp;stinfo,&amp;procinfo)</P></TD></TR></TBODY></TABLE></P>
<P>　　（31） 如何在代码中获取工具条和状态条的指针<BR>　　缺省时， 工作框创建状态条和工具条时将它们作为主框窗口的子窗口，状态条有一个AFX_IDW_STATUS_BAR标识符，工具条有一个AFX_IDW_TOOLBAR标识符，下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//Get pointer to status bar .<BR>　　CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( )<BR>　　—&gt; GetDescendantWindow(AFX_IDW_STUTUS_BAR)</TD></TR></TBODY></TABLE></P>
<P>　　（32） 如何使能和禁止工具条的工具提示<BR>　　如果设置了CBRS_TOOLTIPS风格位，工具条将显示工具提示，要使能或者禁止工具提示，需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　void CMainFrame : : EnableToolTips ( BOOL bDisplayTips )<BR>　　{<BR>　　ASSERT_VALID (m_wndToolBar) 
<P>　　DWORD dwStyle = m _wndToolBar.GetBarStyle ( )</P>
<P>　　if (bDisplayTips) dwStyle ｜=CBRS_TOOLTIPS</P>
<P>　　else<BR>　　dwStyle &amp; = ~CBRS_TOOLTIPS</P>
<P>　　m_wndToolBar.SetBarStyle (dwStyle )<BR>　　}</P>
<P>　　//Get pointer to toolbar .<BR>　　CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( )<BR>　　—&gt; GetDescendantWindow(AFX_IDW_TOOLBAR)</P></TD></TR></TBODY></TABLE></P>
<P>　　（33） 如何设置工具条标题<BR>　　工具条是一个窗口，所以可以在调用CWnd : : SetWindowText来设置标题，例子如下：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct )<BR>　　{<BR>　　…<BR>　　// Set the caption of the toolbar .<BR>　　m_wndToolBar.SetWindowText (_T "Standdard")</TD></TR></TBODY></TABLE></P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （34） 如何使窗口始终在最前方?<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　BringWindowToTop(Handle)</TD></TR></TBODY></TABLE><BR>　　SetWindowPos函数，指定窗口的 最顶风格,用WS_EX_TOPMOST扩展窗口的风格 
<P>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　Example:<BR>　　void ToggleTopMost(<BR>　　CWnd *pWnd)<BR>　　{<BR>　　ASSERT_VALID(pWnd) 
<P>　　pWnd -&gt;SetWindowPos(pWnd-&gt; GetStyle( ) &amp;WS_EX_TOPMOST)?</P>
<P>　　&amp;wndNoTopMOST: &amp;wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE)<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（35） 如何在对话框中显示一个位图<BR>　　这要归功于Win 32先进的静态控件和Microsoft的资源编辑器，在对话框中显示位图是很容易的， 只需将图形控件拖到对话中并选择适当属性即可，用户也可以显示图标、位图以及增强型元文件。</P>
<P>　　（36） 如何改变对话或窗体视窗的背景颜色<BR>　　调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第一个参数指定了背景颜色，第二个参数指定了文本颜色。下例将应用程序对话设置为蓝色背景和黄色文本。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　BOOL CSampleApp : : InitInstance ( )<BR>　　{<BR>　　… 
<P>　　//use blue dialog with yellow text .<BR>　　SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 ,255 , 0 ) )</P>
<P>　　…<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　需要重画对话（或对话的子控件）时，Windows向对话发送消息WM_CTLCOLOR，通常用户可以让Windows选择绘画背景的刷子，也可重置该消息指定刷子。下例说明了创建一个红色背景对话的步骤。</P>
<P>　　首先，给对话基类增加一人成员变量<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　CBursh :class CMyFormView : public CFormView<BR>　　{<BR>　　… 
<P>　　private :<BR>　　CBrush m_ brush // background brush</P>
<P>　　…<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　其次， 在类的构造函数中将刷子初始化为所需要的背景颜色。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　CMyFormView : : CMyFormView ( )<BR>　　{<BR>　　// Initialize background brush .<BR>　　m_brush .CreateSolidBrush (RGB ( 0, 0, 255) )<BR>　　}</TD></TR></TBODY></TABLE></P>
<P>　　最后，使用ClassWizard处理WM_CTLCOLOR消息并返回一个用来绘画对话背景的刷子句柄。注意：由于当重画对话控件时也要调用该函数，所以要检测nCtlColor参量。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　HBRUSH CMyFormView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor<BR>　　) 
<P>　　{<BR>　　// Determine if drawing a dialog box . If we are, return +handle to<BR>　　//our own background brush . Otherwise let windows handle it .<BR>　　if (nCtlColor = = CTLCOLOR _ DLG )<BR>　　return (HBRUSH) m_brush.GetSafeHandle ( )<BR>　　return CFormView : : OnCtlColor (pDC, pWnd , nCtlColor<BR>　　)<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（37） 如何获取一个对话控件的指针<BR>　　有两种方法。其一，调用CWnd: : GetDlgItem，获取一个CWnd*指针调用成员函数。下例调用GetDlgItem，将返回值传给一个CSpinButtonCtrl*以便调用CSpinButtonCtrl : : SetPos 函数：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　BOOL CSampleDialog : : OnInitDialog ( )<BR>　　{<BR>　　CDialog : : OnInitDialog ( ) 
<P>　　//Get pointer to spin button .<BR>　　CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem(IDC_SPIN)<BR>　　ASSERT _ VALID (pSpin)<BR>　　//Set spin button's default position .<BR>　　pSpin —&gt; SetPos (10)</P>
<P>　　return TRUE<BR>　　}</P></TD></TR></TBODY></TABLE></P>其二， 可以使用ClassWizard将控件和成员变量联系起来。在ClassWizard中简单地选择Member Variables标签，然后选择Add Variable …按钮。如果在对话资源编辑器中，按下Ctrl键并双击控件即可转到Add Member Variable对话。 
<P>　　（38） 如何禁止和使能控件<BR>　　控件也是窗口，所以可以调用CWnd : : EnableWindow使能和禁止控件。<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//Disable button controls .<BR>　　m_wndOK.EnableWindow (FALSE )<BR>　　m_wndApply.EnableWindow (FALSE )</TD></TR></TBODY></TABLE></P>
<P>　　（39） 如何改变控件的字体<BR>　　由于控件是也是窗口，用户可以调用CWnd: : SetFont指定新字体。该函数用一个Cfont指针，要保证在控件撤消之前不能撤消字体对象。下例将下压按钮的字体改为8点Arial字体：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//Declare font object in class declaration (.H file ).<BR>　　private : Cfont m_font<BR>　　// Set font in class implementation (.Cpp file ). Note m_wndButton is a<BR>　　//member variable added by ClassWizard.DDX routines hook the member<BR>　　//variable to a dialog button contrlo.<BR>　　BOOL CSampleDialog : : OnInitDialog ( )<BR>　　{<BR>　　…<BR>　　//Create an 8-point Arial font<BR>　　m_font . CreateFont (MulDiv (8 , -pDC<BR>　　—&gt; GetDeviceCaps(LOGPIXELSY) ,72). 0 , 0 , 0 , FW_NORMAL , 0 , 0,0, ANSI_CHARSER, OUT_STROKE_PRECIS , 
<P>　　CLIP_STROKE _PRECIS , DRAFT _QUALITY<BR>　　VARIABLE_PITCH ｜FF_SWISS, _T("Arial") )</P>
<P>　　//Set font for push button .<BR>　　m_wndButton . SetFont (&amp;m _font )</P>
<P>　　…<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（40） 如何在OLE控件中使用OLE_COLOR数据类型<BR>　　诸如COleControl : : GetFortColor和COleControl : : GetBackColor等函数返回OLE _COLOR数据类型的颜色，而GDI对象诸如笔和刷子使用的是COLORREF数据类型，调用COleControl : : TranslateColor可以很容易地将OLE_COLOR类型改为COLORREF类型。下例创建了一个当前背景颜色的刷子：</P>
<P>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　void CSampleControl : : OnDraw (CDC* pdc<BR>　　const Crect&amp; rcBounds , const Crect&amp; rcInvalid<BR>　　)<BR>　　{<BR>　　//Create a brush of the cuttent background color.<BR>　　CBrush brushBack (TranslateColor (GetBackColor () ) ) 
<P>　　//Paint the background using the current backgroundcolor .<BR>　　pdc—&gt; FilllRect (rcBounds , &amp;brushBack)</P>
<P>　　//other drawign commands</P>
<P>　　…<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　（41） 在不使用通用文件打开对话的情况下如何显示一个文件列表<BR>　　调用CWnd: : DlgDirList或者CWnd: : DlgDirListComboBox，Windows 将自动地向列表框或组合框填充可用的驱动器名或者指定目录中的文件，下例将Windows目录中的文件填充在组合框中：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　BOOL CSampleDig : : OnInitDialog ( )<BR>　　{<BR>　　CDialog : : OnInitDialog ( )<BR>　　TCHAR szPath [MAX_PATH] = {"c:\\windows"}<BR>　　int nReslt = DlgDirListComboBox (szPath, IDC_COMBO , IDC_CURIDIR, DDL_READWRITE ｜DDL_READONLY｜DDL_HIDDEN｜ DDL_SYSTEM｜DDL_ARCHIVE)<BR>　　return TRUE<BR>　　}</TD></TR></TBODY></TABLE></P>
<P>　　（42） 为什么旋转按钮控件看起来倒转<BR>　　需要调用CSpinCtrl : : SetRange 设置旋转按钮控件的范围，旋转按钮控件的缺省上限为0，缺省下限为100，这意味着增加时旋转按控件的值由100变为0。下例将旋转按钮控件的范围设置为0到100：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　BOOL CAboutDlg : : OnInitDialog ( )<BR>　　{<BR>　　CDialog : : OnInitDialog ( ) 
<P>　　//set the lower and upper limit of the spin button<BR>　　m_wndSpin . SetRange ( 0 ,100 )</P>
<P>　　return TRUE<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　Visual C++ 4.0 Print对话中的Copise旋转按钮控件也有同样的问题：按下Up按钮时拷贝的数目减少，而按下Down 按钮时拷贝的数目增加。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （43） 为什么旋转按钮控件不能自动地更新它下面的编辑控件<BR>　　如果使用旋转按钮的autu buddy特性， 则必须保证在对话的标记顺序中buddy窗口优先于旋转按钮控件。从Layout菜单中选择Tab Order菜单项（或者按下Crtl+D）可以设置对话的标签顺序。</P>
<P>　　（44） 如何用位图显示下压按钮<BR>　　Windows 95按钮有几处新的创建风格，尤其是BS_BITMAP和BS_ICON，要想具有位图按钮，创建按钮和调用CButton : : SetBitmap或CButton : : SetIcon时要指定BS_BITMAP或BS_ICON风格。</P>
<P>　　首先，设置按钮的图标属性。然后，当对话初始化时调用CButton: : SetIcon。注意：下例用图标代替位图，使用位图时要小心，因为不知道背景所有的颜色——并非每个人都使用浅灰色。</P>
<P>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　BOOL CSampleDlg : : OnInitDialog ( )<BR>　　{<BR>　　CDialog : : OnInitDialog ( ) 
<P>　　//set the images for the push buttons .<BR>　　BOOL CSampleDlg : : OnInitDialog ( )<BR>　　{<BR>　　CDialog : : OnInitDialog ( )</P>
<P>　　//set the images for the push buttons .<BR>　　m_wndButton1.SetIcon (AfxGetApp ( ) —&gt; LoadIcon (IDI _ IPTION1))<BR>　　m_wndButton2.SetIcon (AfxGetApp ( ) —&gt; LoadIcon (IDI _ IPTION2))<BR>　　m_wndButton3.SetIcon (AfxGetApp ( ) —&gt; LoadIcon (IDI _ IPTION3))</P>
<P>　　return TRUE<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P><BR>　　（45） 如何一个创建三态下压按钮<BR>　　可以使用新的BS_PUSHBUTTON 风格位和检测框以及按钮来创建一个三态下压按钮。这很容易，只需将检测框和按钮拖拉到对话中并指定属性Push—like即可。不用任何附加程序就可以成为三态下压按钮。</P>
<P>　　（46） 如何动态创建控件<BR>　　分配一个控件对象的实例并调用其Create成员函数。开发者最容易忽略两件事：忘记指定WS_VISBLE标签和在栈中分配控件对象。下例动态地创建一个下压按钮控件：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//In class declaration (.H file ).<BR>　　private : CButton* m _pButton 
<P>　　//In class implementation (.cpp file ) .<BR>　　m_pButton =new CButton<BR>　　ASSERT_VALID (m_pButton)<BR>　　m_pButton —&gt;Create (_T ("Button Title ") , WS_CHILD ｜WS_VISIBLE ｜BS_PUSHBUTTON. Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )</P></TD></TR></TBODY></TABLE></P>
<P>　　（47） 如何限制编辑框中的准许字符<BR>　　如果用户在编辑控件中只允许接收数字，可以使用一个标准的编辑控件并指定新的创建标志ES_NUMBERS,它是Windows 95新增加的标志，该标志限制 编辑控件只按收数字字符。如果用户需要复杂的编辑控件，可以使用Microsoft 的屏蔽编辑控件，它是一个很有用的OLE定制控件。<BR>如果希望不使用OLE 定制控件自己处理字符，可以派生一个CEdit类并处理WM_CHAR消息，然后从编辑控件中过滤出特定的字符。首先，使用ClassWizard建立一个 CEdit的派生类，其次，在对话类中指定一个成员变量将编辑控件分类在OnInitdialog 中调用CWnd: : SubclassDlgItem . </P>
<P></P>
<P>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//In your dialog class declaration (.H file )<BR>　　private : CMyEdit m_wndEdit // Instance of your new edit control . 
<P>　　//In you dialog class implementation (.CPP file )<BR>　　BOOL CSampleDialog : : OnInitDialog ( )<BR>　　{<BR>　　…</P>
<P>　　//Subclass the edit lontrod .<BR>　　m_wndEdit .SubclassDlgItem (IDC_EDIT,this)</P>
<P>　　…<BR>　　}</P></TD></TR></TBODY></TABLE></P>
<P>　　使用ClassWizard处理WM_CHAR消息，计算nChar参量并决定所执行的操作，用户可以确定是否修改、传送字符。下例说明了如何显示字母字符，如果字符是字母字符，则调用CWnd OnChar，否则不调用OnChar.<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//Only display alphabetic dharacters .<BR>　　void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags )<BR>　　{<BR>　　//Determine if nChar is an alphabetic character.<BR>　　if (: : IsCharAlpha ( ( TCHAR) nChar ) )<BR>　　CEdit : : OnChar (nChar, nRepCnt , nFlags )<BR>　　}</TD></TR></TBODY></TABLE></P>
<P>　　如果要修改字符，则不能仅仅简单地用修改过的nChar调用CEdit: : OnChar，然后CEdit: : OnChar调用CWnd: : Default获取原来的wParam 和lParam 的值，这样是不行的。要修改一个字符，需要首先修改nChar，然后用修改过的nChar调用CWnd: : DefWindowProc。下例说明了如何将字符转变为大写：<BR>
<TABLE borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
<TBODY>
<TR>
<TD width=10><BR></TD>
<TD>　　//Make all characters uppercase<BR>　　void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags )<BR>　　{<BR>　　//Make sure character is uppercase .<BR>　　if (: : IsCharAlpha ( .( TCHAR) nChar)<BR>　　nChar=: : CharUpper(nChar ) 
<P>　　//Bypass default OnChar processing and directly call<BR>　　//default window proc.<BR>　　DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt, nFlags ))<BR>　　}</P></TD></TR></TBODY></TABLE></P><img src ="http://www.blogjava.net/kenneth/aggbug/11832.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-02 13:25 <a href="http://www.blogjava.net/kenneth/archive/2005/09/02/11832.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中的常用的20个方法</title><link>http://www.blogjava.net/kenneth/archive/2005/09/02/11831.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Fri, 02 Sep 2005 05:21:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/02/11831.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/11831.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/02/11831.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/11831.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/11831.html</trackback:ping><description><![CDATA[<H4 clear=all>一、打开CD-ROM</H4>
<P class=code>mciSendString("Set cdAudio door open wait",NULL,0,NULL);</P>
<H4>二、关闭CD_ROM</H4>
<P class=code>mciSendString("Set cdAudio door closed wait",NULL,0,NULL);</P>
<H4>三、关闭计算机</H4>
<P class=code>OSVERSIONINFO OsVersionInfo; //包含操作系统版本信息的数据结构<BR>OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);<BR>GetVersionEx(&amp;OsVersionInfo); //获取操作系统版本信息<BR>if(OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)<BR>{<BR>&nbsp;&nbsp;&nbsp; //Windows98,饔肊xitWindowsEx()函数重新启动计算机<BR>&nbsp;&nbsp;&nbsp; DWORD dwReserved;<BR>&nbsp;&nbsp;&nbsp; ExitWindowsEx(EWX_REBOOT,dwReserved); //可以改变第一个参数，实现注销用户、<BR>&nbsp;&nbsp;&nbsp; //关机、关闭电源等操作<BR>&nbsp;&nbsp;&nbsp; // 退出前的一些处理程序<BR>}</P>
<H4>四、重启计算机</H4>
<P class=code>typedef int (CALLBACK *SHUTDOWNDLG)(int); //显示关机对话框函数的指针<BR>HINSTANCE hInst = LoadLibrary("shell32.dll"); //装入shell32.dll<BR>SHUTDOWNDLG ShutDownDialog; //指向shell32.dll库中显示关机对话框函数的指针<BR>if(hInst != NULL)<BR>{<BR>&nbsp;&nbsp;&nbsp; //获得函数的地址并调用之<BR>&nbsp;&nbsp;&nbsp; ShutDownDialog = (SHUTDOWNDLG)GetProcAddress(hInst,(LPSTR)60);<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; (*ShutDownDialog)(0);<BR>}</P>
<H4>五、枚举所有字体</H4>
<P class=code>LOGFONT lf;<BR>lf.lfCharSet = DEFAULT_CHARSET; // Initialize the LOGFONT structure<BR>strcpy(lf.lfFaceName,"");<BR>CClientDC dc (this);<BR>// Enumerate the font families<BR>::EnumFontFamiliesEx((HDC) dc,&amp;lf, (FONTENUMPROC) EnumFontFamProc,(LPARAM) this,0);<BR>//枚举函数<BR>int CALLBACK EnumFontFamProc(LPENUMLOGFONT lpelf,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPNEWTEXTMETRIC lpntm,DWORD nFontType,long lparam)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>{<BR>&nbsp;&nbsp;&nbsp; // Create a pointer to the dialog window<BR>&nbsp;&nbsp;&nbsp; CDay7Dlg* pWnd = (CDay7Dlg*) lparam;<BR>&nbsp;&nbsp;&nbsp; // add the font name to the list box<BR>&nbsp;&nbsp;&nbsp; pWnd -&gt;m_ctlFontList.AddString(lpelf -&gt;elfLogFont.lfFaceName);<BR>&nbsp;&nbsp;&nbsp; // Return 1 to continue font enumeration<BR>&nbsp;&nbsp;&nbsp; return 1;<BR>}<BR>//其中m_ctlFontList是一个列表控件变量</P>
<H4>六、一次只运行一个程序实例，如果已运行则退出</H4>
<P class=code>if( FindWindow(NULL,"程序标题")) exit(0);</P>
<H4>七、得到当前鼠标所在位置</H4>
<P class=code>CPoint pt;<BR>GetCursorPos(&amp;pt); //得到位置</P>
<H4>八、上下文菜单事件触发事件</H4>
<P class=code>OnContextMenu事件</P>
<H4>九、显示和隐藏程序菜单</H4>
<P class=code>CWnd *pWnd=AfxGetMainWnd();<BR>if(b_m) //隐藏菜单<BR>{<BR>&nbsp;&nbsp;&nbsp; pWnd-&gt;SetMenu(NULL);<BR>&nbsp;&nbsp;&nbsp; pWnd-&gt;DrawMenuBar();<BR>&nbsp;&nbsp;&nbsp; b_m=false;<BR>}<BR>else<BR>{<BR>&nbsp;&nbsp;&nbsp; CMenu menu;<BR>&nbsp;&nbsp;&nbsp; menu.LoadMenu(IDR_MAINFRAME); ////显示菜单 也可改变菜单项<BR>&nbsp;&nbsp;&nbsp; pWnd-&gt;SetMenu(&amp;menu);<BR>&nbsp;&nbsp;&nbsp; pWnd-&gt;DrawMenuBar();<BR>&nbsp;&nbsp;&nbsp; b_m=true;<BR>&nbsp;&nbsp;&nbsp; menu.Detach();<BR>}</P>
<H4>十、获取可执行文件的图标</H4>
<P class=code>HICON hIcon=::ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0);<BR>if (hIcon &amp;&amp;hIcon!=(HICON)-1)<BR>{<BR>&nbsp;&nbsp;&nbsp; pDC-&gt;DrawIcon(10,10,hIcon);<BR>&nbsp;&nbsp;&nbsp; <BR>}<BR>DestroyIcon(hIcon);</P>
<H4>十一、窗口自动靠边程序演示</H4>
<P class=code>BOOL AdjustPos(CRect* lpRect)<BR>{//自动靠边<BR>&nbsp;&nbsp;&nbsp; int iSX=GetSystemMetrics(SM_CXFULLSCREEN);<BR>&nbsp;&nbsp;&nbsp; int iSY=GetSystemMetrics(SM_CYFULLSCREEN);<BR>&nbsp;&nbsp;&nbsp; RECT rWorkArea;<BR>&nbsp;&nbsp;&nbsp; BOOL bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT), &amp;rWorkAre<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a, 0);<BR>&nbsp;&nbsp;&nbsp; CRect rcWA;<BR>&nbsp;&nbsp;&nbsp; if(!bResult)<BR>&nbsp;&nbsp;&nbsp; {//如果调用不成功就利用GetSystemMetrics获取屏幕面积<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rcWA=CRect(0,0,iSX,iSY);<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rcWA=rWorkArea;<BR>&nbsp;&nbsp;&nbsp; int iX=lpRect-&gt;left;<BR>&nbsp;&nbsp;&nbsp; int iY=lpRect-&gt;top;<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; if(iX &lt; rcWA.left + DETASTEP &amp;&amp; iX!=rcWA.left)<BR>&nbsp;&nbsp;&nbsp; {//调整左<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //pWnd-&gt;SetWindowPos(NULL,rcWA.left,iY,0,0,SWP_NOSIZE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpRect-&gt;OffsetRect(rcWA.left-iX,0);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AdjustPos(lpRect);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; if(iY &lt; rcWA.top + DETASTEP &amp;&amp; iY!=rcWA.top)<BR>&nbsp;&nbsp;&nbsp; {//调整上<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //pWnd-&gt;SetWindowPos(NULL ,iX,rcWA.top,0,0,SWP_NOSIZE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpRect-&gt;OffsetRect(0,rcWA.top-iY);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AdjustPos(lpRect);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; if(iX + lpRect-&gt;Width() &gt; rcWA.right - DETASTEP &amp;&amp; iX !=rcWA.right-lpRect-&gt;Width())<BR>&nbsp;&nbsp;&nbsp; {//调整右<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //pWnd-&gt;SetWindowPos(NULL ,rcWA.right-rcW.Width(),iY,0,0,SWP_NOSIZE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpRect-&gt;OffsetRect(rcWA.right-lpRect-&gt;right,0);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AdjustPos(lpRect);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; if(iY + lpRect-&gt;Height() &gt; rcWA.bottom - DETASTEP &amp;&amp; iY !=rcWA.bottom-lpRect<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;Height())<BR>&nbsp;&nbsp;&nbsp; {//调整下<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //pWnd-&gt;SetWindowPos(NULL ,iX,rcWA.bottom-rcW.Height(),0,0,SWP_NOSIZE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpRect-&gt;OffsetRect(0,rcWA.bottom-lpRect-&gt;bottom);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; return FALSE;<BR>}<BR>//然后在ONMOVEING事件中使用所下过程调用<BR>CRect r=*pRect;<BR>AdjustPos(&amp;r);<BR>*pRect=(RECT)r;</P>
<H4>十二、给系统菜单添加一个菜单项</H4>
<P>　　给系统菜单添加一个菜单项需要进行下述三个步骤：</P>
<P>　　首先，使用Resource Symbols对话（在View菜单中选择Resource Symbols．．．可以显示该对话）定义菜单项ID，该ID应大于0x0F而小于0xF000；<BR>　　其次，调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单项添加到菜单中。下例给系统菜单添加两个新的</P>
<P class=code>int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct)<BR>{<BR>&nbsp;&nbsp;&nbsp; //…<BR>&nbsp;&nbsp;&nbsp; //Make sure system menu item is in the right range.<BR>&nbsp;&nbsp;&nbsp; ASSERT(IDM_MYSYSITEM&lt;0xF000);<BR>&nbsp;&nbsp;&nbsp; //Get pointer to system menu.<BR>&nbsp;&nbsp;&nbsp; CMenu* pSysMenu=GetSystemMenu(FALSE);<BR>&nbsp;&nbsp;&nbsp; ASSERT_VALID(pSysMenu);<BR>&nbsp;&nbsp;&nbsp; //Add a separator and our menu item to system menu.<BR>&nbsp;&nbsp;&nbsp; CString StrMenuItem(_T ("New menu item"));<BR>&nbsp;&nbsp;&nbsp; pSysMenu-&gt;AppendMenu(MF_SEPARATOR);<BR>&nbsp;&nbsp;&nbsp; pSysMenu-&gt;AppendMenu(MF_STRING, IDM_MYSYSITEM, StrMenuItem);<BR>&nbsp;&nbsp;&nbsp; //…<BR>}<BR></P>
<H4>十三、运行其它程序</H4>
<P>　　1、运行EMAIL或网址</P>
<P class=code>char szMailAddress[80];<BR>strcpy(szMailAddress,"mailto:netvc@21cn.com");<BR>ShellExecute(NULL, "open", szMailAddress, NULL, NULL, SW_SHOWNORMAL);</P>
<P>　　2、运行可执行程序</P>
<P class=code>WinExec("notepad.exe",SW_SHOW); //运行计事本</P>
<H4>十四、动态增加或删除菜单</H4>
<P>1、 增加菜单<BR>添加</P>
<P class=code>CMenu *mainmenu;<BR>mainmenu=AfxGetMainWnd()-&gt;GetMenu(); //得到主菜单<BR>(mainmenu-&gt;GetSubMenu (0))-&gt;AppendMenu (MF_SEPARATOR);//添加分隔符<BR>(mainmenu-&gt;GetSubMenu (0))-&gt;AppendMenu(MF_STRING,ID_APP_ABOUT,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _T("Always on &amp;Top")); //添加新的菜单项<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DrawMenuBar(); //重画菜单</P>
<P>2、 删除菜单</P>
<P>删除</P>
<P class=code>CMenu *mainmenu;<BR>mainmenu=AfxGetMainWnd()-&gt;GetMenu(); //得到主菜单<BR><BR>CString str ;<BR>for(int i=(mainmenu-&gt;GetSubMenu (0))-&gt;GetMenuItemCount()-1;i&gt;=0;i--) //取得菜单的项数。<BR>{<BR>&nbsp;&nbsp;&nbsp; (mainmenu-&gt;GetSubMenu (0))-&gt;GetMenuString(i,str,MF_BYPOSITION);<BR>&nbsp;&nbsp;&nbsp; //将指定菜单项的标签拷贝到指定的缓冲区。MF_BYPOSITION的解释见上。<BR>&nbsp;&nbsp;&nbsp; if(str=="Always on &amp;Top") //如果是刚才我们增加的菜单项，则删除。<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (mainmenu-&gt;GetSubMenu (0))-&gt;DeleteMenu(i,MF_BYPOSITION);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<H4>十五、改变应用程序的图标静态更改：</H4>
<P>　　修改图标资源IDR_MAINFRAME。它有两个图标，一个是16*16的，另一个是32*32的，注意要一起修改。</P>
<P>　　动态更改： 向主窗口发送WM_SETICON消息.代码如下：</P>
<P class=code>HICON hIcon=AfxGetApp()-&gt;LoadIcon(IDI_ICON);<BR>ASSERT(hIcon);<BR>AfxGetMainWnd()-&gt;SendMessage(WM_SETICON,TRUE,(LPARAM)hIcon);</P>
<H4>十六、另一种改变窗口标题的方法</H4>
<P>　　使用语句 CWnd* m_pCWnd = AfxGetMainWnd( )，然后，再以如下形式调用SetWindowText()函数：</P>
<P class=code>SetWindowText( *m_pCWnd,(LPCTSTR)m_WindowText);// m_WindowText可以是一个CString类的变量。</P>
<H4>十七、剪切板上通过增强元文件拷贝图像数据</H4>
<P>　　下面代码拷贝通过元文件拷贝图像数据到任何应用程序，</P>
<P>//其可以放置在CView派生类的函数中。</P>
<P class=code>CMetaFileDC * m_pMetaDC = new CMetaFileDC();<BR>m_pMetaDC-&gt;CreateEnhanced(GetDC(),NULL,NULL,"whatever");<BR>//draw meta file<BR>//do what ever you want to do: bitmaps, lines, text...<BR>//close meta file dc and prepare for clipboard;<BR>HENHMETAFILE hMF = m_pMetaDC-&gt;CloseEnhanced();<BR>//copy to clipboard<BR>OpenClipboard();<BR>EmptyClipboard();<BR>::SetClipboardData(CF_ENHMETAFILE,hMF); <BR>CloseClipboard();<BR><BR>//DeleteMetaFile(hMF);<BR>delete m_pMetaDC;<BR></P>
<H4>十八、剪切板上文本数据的传送把文本放置到剪接板上：</H4>
<P class=code>CString source;<BR>//put your text in source<BR>if(OpenClipboard())<BR>{<BR>&nbsp;&nbsp;&nbsp; HGLOBAL clipbuffer;<BR>&nbsp;&nbsp;&nbsp; char * buffer;<BR>&nbsp;&nbsp;&nbsp; EmptyClipboard();<BR>&nbsp;&nbsp;&nbsp; clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength()+1);<BR>&nbsp;&nbsp;&nbsp; buffer = (char*)GlobalLock(clipbuffer);<BR>&nbsp;&nbsp;&nbsp; strcpy(buffer, LPCSTR(source));<BR>&nbsp;&nbsp;&nbsp; GlobalUnlock(clipbuffer);<BR>&nbsp;&nbsp;&nbsp; SetClipboardData(CF_TEXT,clipbuffer);<BR>&nbsp;&nbsp;&nbsp; CloseClipboard();<BR>}<BR><BR>//从剪接板上获取文本：<BR><BR>char * buffer;<BR>if(OpenClipboard())<BR>{<BR>&nbsp;&nbsp;&nbsp; buffer = (char*)GetClipboardData(CF_TEXT);<BR>&nbsp;&nbsp;&nbsp; //do something with buffer here<BR>&nbsp;&nbsp;&nbsp; //before it goes out of scope<BR>}<BR>CloseClipboard();</P>
<H4>十九、将捕捉屏幕图像到剪切版中</H4>
<P class=code>void CShowBmpInDlgDlg::OnCutScreen()<BR>{<BR>&nbsp;&nbsp;&nbsp; ShowWindow(SW_HIDE);<BR>&nbsp;&nbsp;&nbsp; RECT r_bmp={0,0,::GetSystemMetrics(SM_CXSCREEN),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::GetSystemMetrics(SM_CYSCREEN)}; <BR>&nbsp;&nbsp;&nbsp; HBITMAP hBitmap;<BR>&nbsp;&nbsp;&nbsp; hBitmap=CopyScreenToBitmap(&amp;r_bmp);<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; //hWnd为程序窗口句柄<BR>&nbsp;&nbsp;&nbsp; if (OpenClipboard())<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EmptyClipboard();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetClipboardData(CF_BITMAP, hBitmap);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CloseClipboard();<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; ShowWindow(SW_SHOW);<BR>}<BR>HBITMAP CShowBmpInDlgDlg::CopyScreenToBitmap(LPRECT lpRect)<BR>{<BR>&nbsp;&nbsp;&nbsp; //lpRect 代表选定区域<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HDC hScrDC, hMemDC;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 屏幕和内存设备描述表<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HBITMAP hBitmap, hOldBitmap;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 位图句柄<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nX, nY, nX2, nY2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 选定区域坐标<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nWidth, nHeight;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 位图宽度和高度<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int xScrn, yScrn;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 屏幕分辨率<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 确保选定区域不为空矩形<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (IsRectEmpty(lpRect))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //为屏幕创建设备描述表<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //为屏幕设备描述表创建兼容的内存设备描述表<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hMemDC = CreateCompatibleDC(hScrDC);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 获得选定区域坐标<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nX = lpRect-&gt;left;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nY = lpRect-&gt;top;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nX2 = lpRect-&gt;right;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nY2 = lpRect-&gt;bottom;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 获得屏幕分辨率<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xScrn = GetDeviceCaps(hScrDC, HORZRES);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; yScrn = GetDeviceCaps(hScrDC, VERTRES);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //确保选定区域是可见的<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nX&lt;0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nX = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nY&lt;0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nY = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nX2&gt;xScrn)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nX2 = xScrn;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nY2&gt;yScrn)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nY2 = yScrn;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nWidth = nX2 - nX;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nHeight = nY2 - nY;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 创建一个与屏幕设备描述表兼容的位图<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hBitmap = CreateCompatibleBitmap<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (hScrDC, nWidth, nHeight);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 把新位图选到内存设备描述表中<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hOldBitmap =(HBITMAP)SelectObject(hMemDC, hBitmap);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 把屏幕设备描述表拷贝到内存设备描述表中<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //得到屏幕位图的句柄<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //清除<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC(hScrDC);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DeleteDC(hMemDC);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 返回位图句柄<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return hBitmap;<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<H4>二十、如何将位图缩放显示在Static控件中</H4>
<P class=code>//在Staic控件内显示位图<BR>void CShowBmpInDlgDlg::ShowBmpInStaic()<BR>{<BR>&nbsp;&nbsp;&nbsp; CBitmap hbmp;<BR>&nbsp;&nbsp;&nbsp; HBITMAP hbitmap;<BR>&nbsp;&nbsp;&nbsp; //将pStatic指向要显示的地方<BR>&nbsp;&nbsp;&nbsp; CStatic *pStaic;<BR>&nbsp;&nbsp;&nbsp; pStaic=(CStatic*)GetDlgItem(IDC_IMAGE);<BR>&nbsp;&nbsp;&nbsp; //装载资源 MM.bmp是我的一个文件名，用你的替换<BR>&nbsp;&nbsp;&nbsp; hbitmap=(HBITMAP)::LoadImage (::AfxGetInstanceHandle(),"MM.bmp",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; hbmp.Attach(hbitmap);<BR>&nbsp;&nbsp;&nbsp; //获取图片格式<BR>&nbsp;&nbsp;&nbsp; BITMAP bm;<BR>&nbsp;&nbsp;&nbsp; hbmp.GetBitmap(&amp;bm);<BR>&nbsp;&nbsp;&nbsp; CDC dcMem;<BR>&nbsp;&nbsp;&nbsp; dcMem.CreateCompatibleDC(GetDC());<BR>&nbsp;&nbsp;&nbsp; CBitmap *poldBitmap=(CBitmap*)dcMem.SelectObject(hbmp);<BR>&nbsp;&nbsp;&nbsp; CRect lRect;<BR>&nbsp;&nbsp;&nbsp; pStaic-&gt;GetClientRect(&amp;lRect);<BR>&nbsp;&nbsp;&nbsp; //显示位图<BR>&nbsp;&nbsp;&nbsp; pStaic-&gt;GetDC()-&gt;StretchBlt(lRect.left ,lRect.top ,lRect.Width(),lRect.Height(),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;dcMem,0 ,0,bm.bmWidth,bm.bmHeight,SRCCOPY);<BR>&nbsp;&nbsp;&nbsp; dcMem.SelectObject(&amp;poldBitmap);<BR>}</P><img src ="http://www.blogjava.net/kenneth/aggbug/11831.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-02 13:21 <a href="http://www.blogjava.net/kenneth/archive/2005/09/02/11831.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用通用对话框</title><link>http://www.blogjava.net/kenneth/archive/2005/09/02/11815.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Fri, 02 Sep 2005 02:45:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/02/11815.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/11815.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/02/11815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/11815.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/11815.html</trackback:ping><description><![CDATA[<SPAN class=large><FONT color=#000000>&nbsp;
<P>在Windows系统中提供了一些通用对话框如：文件选择对话框<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/57_g1.gif" target=_blank><FONT color=#002c99>如图</FONT></A>，颜色选择对话框<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/57_g2.gif" target=_blank><FONT color=#002c99>如图</FONT></A>，字体选择对话框<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/57_g3.gif" target=_blank><FONT color=#002c99>如图</FONT></A>。在MFC中使用CFileDialog，CColorDialog，CFontDialog来表示。一般来讲你不需要派生新的类，因为基类已经提供了常用的功能。而且在创建并等待对话框结束后你可以通过成员函数得到用户在对话框中的选择。 </P>
<P><B>CFileDialog文件选择对话框的使用</B>：首先构造一个对象并提供相应的参数，构造函数原型如下：<BR>CFileDialog::CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL );参数意义如下： 
<UL>
<LI>bOpenFileDialog 为TRUE则显示打开对话框，为FALSE则显示保存对话文件对话框。 
<LI>lpszDefExt 指定默认的文件扩展名。 
<LI>lpszFileName 指定默认的文件名。 
<LI>dwFlags 指明一些特定风格。 
<LI>lpszFilter 是最重要的一个参数，它指明可供选择的文件类型和相应的扩展名。参数格式如： <BR>"Chart Files (*.xlc)|*.xlc|Worksheet Files (*.xls)|*.xls|Data Files (*.xlc;*.xls)|*.xlc; *.xls|All Files (*.*)|*.*||";文件类型说明和扩展名间用 | 分隔，同种类型文件的扩展名间可以用 ; 分割，每种文件类型间用 | 分隔，末尾用 || 指明。 
<LI>pParentWnd 为父窗口指针。 </LI></UL>创建文件对话框可以使用DoModal()，在返回后可以利用下面的函数得到用户选择： 
<UL>
<LI>CString CFileDialog::GetPathName( ) 得到完整的文件名，包括目录名和扩展名如：c:\test\test1.txt 
<LI>CString CFileDialog::GetFileName( ) 得到完整的文件名，包括扩展名如：test1.txt 
<LI>CString CFileDialog::GetExtName( ) 得到完整的文件扩展名，如：txt 
<LI>CString CFileDialog::GetFileTitle ( ) 得到完整的文件名，不包括目录名和扩展名如：test1 
<LI>POSITION CFileDialog::GetStartPosition( ) 对于选择了多个文件的情况得到第一个文件位置。 
<LI>CString CFileDialog::GetNextPathName( POSITION&amp; pos ) 对于选择了多个文件的情况得到下一个文件位置，并同时返回当前文件名。但必须已经调用过POSITION CFileDialog::GetStartPosition( )来得到最初的POSITION变量。 </LI></UL>
<P></P>
<P><B>CColorDialog颜色选择对话框的使用</B>：首先通过CColorDialog::CColorDialog( COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd* pParentWnd = NULL )构造一个对象，其中clrInit为初始颜色。通过调用DoModal()创建对话框，在返回后调用COLORREF CColorDialog::GetColor( )得到用户选择的颜色值。 </P>
<P><B>CFontDialog字体选择对话框的使用</B>：首先构造一个对象并提供相应的参数，构造函数原型如下： <BR>CFontDialog::CFontDialog( LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, CDC* pdcPrinter = NULL, CWnd* pParentWnd = NULL );构造一个对象，其中参数lplfInitial指向一个LOGFONG结构（该结构介绍请见<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/01_22.html" target=_blank><FONT color=#002c99>2.2 在窗口中输出文字</FONT></A>），如果该参数设置为NULL表示不设置初始字体。pdcPrinter指向一个代表打印机设备环境的DC对象，若设置该参数则选择的字体就为打印机所用。pParentWnd用于指定父窗口。通过调用DoModal()创建对话框，在返回后通过调用以下函数来得到用户选择： 
<UL>
<LI>void CFontDialog::GetCurrentFont( LPLOGFONT lplf );用来获得所选字体的属性。该函数有一个参数，该参数是指向LOGFONT结构的指针，函数将所选字体的各种属性写入这个LOGFONT结构中。 
<LI>CString CFontDialog::GetFaceName( ) 得到所选字体名字。 
<LI>int CFontDialog::GetSize( ) 得到所选字体的尺寸（以10个象素为单位）。 
<LI>COLORREF CFontDialog::GetColor( ) 得到所选字体的颜色。 
<LI>BOOL CFontDialog::IsStrikeOut( )<BR>BOOL CFontDialog::IsUnderline( )<BR>BOOL CFontDialog::IsBold( )<BR>BOOL CFontDialog::IsItalic( )<BR>得到所选字体的其他属性，是否有删除线，是否有下划线，是否为粗体，是否为斜体。 </LI></UL></FONT></SPAN><img src ="http://www.blogjava.net/kenneth/aggbug/11815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-02 10:45 <a href="http://www.blogjava.net/kenneth/archive/2005/09/02/11815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在对话框中进行数据交换和数据检查</title><link>http://www.blogjava.net/kenneth/archive/2005/09/02/11813.html</link><dc:creator>Kenneth Blog</dc:creator><author>Kenneth Blog</author><pubDate>Fri, 02 Sep 2005 02:42:00 GMT</pubDate><guid>http://www.blogjava.net/kenneth/archive/2005/09/02/11813.html</guid><wfw:comment>http://www.blogjava.net/kenneth/comments/11813.html</wfw:comment><comments>http://www.blogjava.net/kenneth/archive/2005/09/02/11813.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kenneth/comments/commentRss/11813.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kenneth/services/trackbacks/11813.html</trackback:ping><description><![CDATA[<SPAN class=large><FONT color=#000000>&nbsp;
<P>MFC提供两种方法在对话框中进行数据交换和数据检查（Dialog data exchange/Dialog data validation），数据交换和数据检查的思想是将某一变量和对话框中的一个子窗口进行关联，然后通过调用BOOL UpdateData( BOOL bSaveAndValidate = TRUE )来指示MFC将变量中数据放入子窗口还是将子窗口中数据取到变量中并进行合法性检查。</P>
<P>在进行数据交换时一个子窗口可以和两种类型的变量相关联，一种是控件（Control）对象，比如说按钮子窗口可以和一个CButton对象相关联，这种情况下你可以通过该对象直接控制子窗口，而不需要象上节中讲的一样使用GetDlgItem(IDC_CONTROL_ID)来得到窗口指针；一种是内容对象，比如说输入框可以和一个CString对象关联，也可以和一个UINT类型变量关联，这种情况下你可以直接设置/获取窗口中的输入内容。</P>
<P>而数据检查是在一个子窗口和一个内容对象相关联时在存取内容时对内容进行合法性检查，比如说当一个输入框和一个CString对象关联时，你可以设置检查CString的对象的最长/最小长度，当输入框和一个UINT变量相关联时你可以设置检查UINT变量的最大/最小值。在BOOL UpdateData( BOOL bSaveAndValidate = TRUE )被调用后，合法性检查会自动进行，如果无法通过检查MFC会弹出消息框进行提示，并返回FALSE。</P>
<P>设置DDX/DDV在VC中非常简单，ClassWizard可以替你完成所有的工作，你只需要打开ClassWizard并选中Member Variables页，<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/55_g1.gif" target=_blank><FONT color=#002c99>如图</FONT></A>，你可以看到所有可以进行关联的子窗口ID列表，双击一个ID会弹出一个添加变量的对话框，<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/55_g2.gif" target=_blank><FONT color=#002c99>如图</FONT></A>，填写相关的信息后按下确定按钮就可以了。然后选中你刚才添加的变量在底部的输入框中输入检查条件，<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/55_g3.gif" target=_blank><FONT color=#002c99>如图</FONT></A>。</P>
<P>下面我们看一个例子，对话框上的子窗口<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/55_g4.gif" target=_blank><FONT color=#002c99>如图</FONT></A>设置，各子窗口的ID和关联的变量如下表： 
<TABLE cellSpacing=0 cellPadding=3 width="100%" align=center border=1>
<TBODY>
<TR>
<TD><FONT color=#000000>ID</FONT></TD>
<TD><FONT color=#000000>关联的变量</FONT></TD>
<TD><FONT color=#000000>作用</FONT></TD></TR>
<TR>
<TD><FONT color=#000000>IDC_CHECK_TEST</FONT></TD>
<TD><FONT color=#000000>BOOL m_fCheck</FONT></TD>
<TD><FONT color=#000000>检查框是否被选中</FONT></TD></TR>
<TR>
<TD><FONT color=#000000>IDC_RADOI_TEST_1</FONT></TD>
<TD><FONT color=#000000>int m_iSel</FONT></TD>
<TD><FONT color=#000000>当前选择的圆形按钮的索引</FONT></TD></TR>
<TR>
<TD><FONT color=#000000>IDC_COMBO_TEST</FONT></TD>
<TD><FONT color=#000000>CString m_szCombo</FONT></TD>
<TD><FONT color=#000000>组合框中选中的文本或是输入的文本</FONT></TD></TR>
<TR>
<TD><FONT color=#000000>IDC_EDIT_TEST</FONT></TD>
<TD><FONT color=#000000>CString m_szEdit</FONT></TD>
<TD><FONT color=#000000>输入框中输入的文本，最大长度为5</FONT></TD></TR>
<TR>
<TD><FONT color=#000000>IDC_LIST_TEST</FONT></TD>
<TD><FONT color=#000000>CListBox m_lbTest</FONT></TD>
<TD><FONT color=#000000>列表框对象</FONT></TD></TR></TBODY></TABLE>这时候ClassWizard会自动生成变量定义和相关代码，在对话框的构造函数中可以对变量的初始值进行设置，此外在BOOL CDialog::OnInitDialog()中会调用UpdateData(FALSE)，即会将变量中的数据放入窗口中 。相关代码如下： <PRE>//头文件中的变量定义，ClassWizard自动产生
// Dialog Data
	//{{AFX_DATA(CMy55_s1Dlg)
	enum { IDD = IDD_MY55_S1_DIALOG };
	CListBox	m_lbTest;
	int		m_iSel;
	CString	m_szEdit;
	CString	m_szCombo;
	BOOL	m_fCheck;
	//}}AFX_DATA
//构造函数中赋初值
CMy55_s1Dlg::CMy55_s1Dlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMy55_s1Dlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CMy55_s1Dlg)
	m_iSel = -1;
	m_szEdit = _T("");
	m_szCombo = _T("");
	m_fCheck = FALSE;
	//}}AFX_DATA_INIT
.....
}
//ClassWizard产生的关联和检查代码
void CMy55_s1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMy55_s1Dlg)
	DDX_Control(pDX, IDC_LIST_TEST, m_lbTest);
	DDX_Radio(pDX, IDC_RADIO_TEST_1, m_iSel);
	DDX_Text(pDX, IDC_EDIT_TEST, m_szEdit);
	DDV_MaxChars(pDX, m_szEdit, 5);
	DDX_CBString(pDX, IDC_COMBO_TEST, m_szCombo);
	DDX_Check(pDX, IDC_CHECK_TEST, m_fCheck);
	//}}AFX_DATA_MAP
}
//在OnInitDialog中利用已经关联过的变量m_lbTest
BOOL CMy55_s1Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();
...	
	// TODO: Add extra initialization here
	//设置列表框中数据
	m_lbTest.AddString("String 1");
	m_lbTest.AddString("String 2");
	m_lbTest.AddString("String 3");
	m_lbTest.AddString("String 4");
	return TRUE;  // return TRUE  unless you set the focus to a control
}
//对两个按钮消息处理
//通过UpdateData(TRUE)得到窗口中数据
void CMy55_s1Dlg::OnGet() 
{
	if(UpdateData(TRUE))
	{
		//数据合法性检查通过，可以使用变量中存放的数据
		CString szOut;
		szOut.Format("radio =%d \ncheck is %d\nedit input is
 %s\ncomboBox input is %s\n",
	m_iSel,m_fCheck,m_szEdit,m_szCombo);
		AfxMessageBox(szOut);
	}
	//else 未通过检查
}
//通过UpdateData(FALSE)将数据放入窗口
void CMy55_s1Dlg::OnPut() 
{
	m_szEdit="onPut test";
	m_szCombo="onPut test";
	UpdateData(FALSE);
}	
</PRE>
<P></P>
<P>在上面的例子中我们看到利用DDX/DDV和UpdateData(BOOL)调用我们可以很方便的存取数据，而且也可以同时进行合法性检查。<A href="http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/55_s1.zip"><FONT color=#002c99>下载例子代码</FONT></A></P></FONT></SPAN><img src ="http://www.blogjava.net/kenneth/aggbug/11813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kenneth/" target="_blank">Kenneth Blog</a> 2005-09-02 10:42 <a href="http://www.blogjava.net/kenneth/archive/2005/09/02/11813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>