<?xml version="1.0" encoding="gb2312"?>

<!-- RSS generated by oioj.net on 4/16/2004 ; 感谢LeXRus提供 RSS 2.0 文档; 此文件可自由使用，但请保留此行信息 --> 
<!-- Source download URL: http://blogger.org.cn/blog/rss2.asp       -->
<rss version="2.0">

<channel>
<title>codebee的博客</title>
<link>http://blogger.org.cn/blog/blog.asp?name=codebee</link>
<description>codebee的博客</description>
<copyright>blogger.org.cn</copyright>
<generator>W3CHINA Blog</generator>
<webMaster>webmaster@blogger.org.cn</webMaster>
<item>
<title><![CDATA[我又来了：D（不是没有在学习，是在一直学习。）]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=34634</link>
<author>codebee</author>
<pubDate>2008/5/3 21:29:07</pubDate>
<description><![CDATA[<P>不是没有在学习，是在一直学习。</P>
<P>终于把糟糕的本科毕业了，现在在新加坡国立大学上研究生，主要研究方向是软件工程，知识工程。</P>
<P>以后会发一些英文自己翻译的文章。</P>]]></description>
</item><item>
<title><![CDATA[在 Internet Explorer 5.5 中创建可编辑的 Web 页]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=20084</link>
<author>codebee</author>
<pubDate>2006/11/15 21:36:13</pubDate>
<description><![CDATA[<EM>Peggi Goodwin<BR>Microsoft Corporation<BR>2000年5月</EM> 
<P><B>摘要：</B>本文讨论 MSHTML，这是对 Internet Explorer 中分析和展现引擎的 HTML 扩展，它允许直接在浏览器内编辑 Web 页。</P>
<HR>

<P>现在，您可以直接将 Microsoft(R) Internet Explorer 复杂的 HTML 编辑功能合并到 Web 页中！Microsoft 的 HTML 编辑器是对 Internet Explorer 中 HTML 分析和展现引擎的内置扩展。从 Internet Explorer 4.0 开始，MSHTML 编辑器已经为主机应用程序提供了开发基于 HTML 的文本编辑器和 Web 创作应用程序的 HTML 编辑平台。但是，在以前的版本中，只有当文档处在“设计”模式时，才能启用编辑器。使用 Internet Explorer 5.5，您可以将文档或文档中的单个元素声明为可以在运行时编辑，这就使得 Web 创作者能够完全支持浏览器内的 WYSIWYG（所见即所得）HTML 编辑权。</P>
<P>MSHTML 编辑器提供了简单而又功能强大的脚本编辑模式，该模式支持对文本和窗体的最常用的编辑功能。这样，就有可能开发出高级的联机编辑应用程序、创建允许用户输入格式化文本或图象等的统一窗体、或使 Web 站点上的页面成为每个用户都能用自己的内容对其定制。Web 创作者可能使用文本编辑功能来开发联机文本编辑器，或者使用窗体编辑功能来编写联机明信片应用程序。</P>
<P><B><FONT class=105v><A name=createwp_topic1></A>文本编辑功能</FONT></B> 
<P>下面的文本编辑功能已经在以前版本的 Internet Explorer 中得到支持，在 Internet Explorer 5.5 中同样支持这些功能。除键盘快捷键外（它们始终处于启用状态），所有这些功能都有可以在脚本中执行的对应命令。 
<UL type=disc>
<LI>文本格式： 
<UL type=disc><BR><BR>
<LI>字体（例如，Times Roman、Arial、Courier 等）<BR><BR>
<LI>字体大小<BR><BR>
<LI>文本样式和装饰（斜体、粗体、下划线、加删除线、上标、下标）<BR><BR>
<LI>文本颜色<BR><BR>
<LI>背景颜色 </LI></UL>
<LI>段落格式： 
<UL type=disc><BR><BR>
<LI>缩进<BR><BR>
<LI>伸出<BR><BR>
<LI>左、右、居中以及页边对齐 <BR><BR>
<LI>文本方向（右到左，或左到右） </LI></UL>
<LI>列表编辑：<BR><BR>
<UL type=disc>
<LI>带编号的列表<BR><BR>
<LI>带项目符号的列表<BR><BR>
<LI>嵌套到任何等级 </LI></UL>
<LI>选定服务： 
<UL type=disc><BR><BR>
<LI>通过拖动鼠标选定范围<BR><BR>
<LI>通过双击选定单词<BR><BR>
<LI>通过三次单击选定段落<BR><BR>
<LI>基于键盘的选定（Shift + 箭头、Home 和 End 键） </LI></UL>
<LI>自动检测超级链接和书签（使它们可以导航） <BR><BR>
<LI>无限等级的撤消和恢复<BR><BR>
<LI>文本输入模式：<BR><BR>
<UL type=disc>
<LI>插入<BR><BR>
<LI>改写 </LI></UL>
<LI>支持标准键盘快捷键： </LI></UL>
<TABLE class=clsRef cellSpacing=2 cellPadding=5 width="75%" border=0>
<TBODY>
<TR vAlign=top>
<TD width="33%" bgColor=#eeeee><FONT class=90v>剪切 (Ctrl + X)</FONT></TD>
<TD width="33%" bgColor=#eeeee><FONT class=90v>复制 (Ctrl + C)</FONT></TD>
<TD width="34%" bgColor=#eeeee><FONT class=90v>粘贴 (Ctrl + V)</FONT></TD></TR>
<TR vAlign=top>
<TD width="33%" bgColor=#eeeee><FONT class=90v>粗体 (Ctrl + B)</FONT></TD>
<TD width="33%" bgColor=#eeeee><FONT class=90v>斜体 (Ctrl + I)</FONT></TD>
<TD width="34%" bgColor=#eeeee><FONT class=90v>下划线 (Ctrl + U)</FONT></TD></TR>
<TR vAlign=top>
<TD width="33%" bgColor=#eeeee><FONT class=90v>撤消 (Ctrl + Z)</FONT></TD>
<TD width="33%" bgColor=#eeeee><FONT class=90v>恢复 (Ctrl + Y)</FONT></TD>
<TD width="34%" bgColor=#eeeee><FONT class=90v>超级链接 (Ctrl + K)</FONT></TD></TR>
<TR vAlign=top>
<TD width="33%" bgColor=#eeeee><FONT class=90v>查找 (Ctrl + F)</FONT></TD>
<TD width="33%" bgColor=#eeeee><FONT class=90v>全选 (Ctrl + A)</FONT></TD>
<TD width="34%" bgColor=#eeeee><FONT class=90v>选定段落 (Ctrl + 单击左键)</FONT></TD></TR></TBODY></TABLE><BR>
<P><B>Internet Explorer 5.5 中的新功能</B> 
<P>当然，Internet Explorer 5.5 中最棒的新编辑功能之一，就是能够在浏览器运行时启用编辑功能，但我们将在后面讨论它。现在我们讨论 Internet Explorer 5.5 中其它一些新的和经过改进的功能，尤其是文本编辑： 
<UL type=disc>
<LI>垂直文本编辑<BR><BR>
<LI>双向编辑<BR><BR>
<LI>批撤消和恢复<BR><BR>
<LI>自动检测的撤消<BR><BR>
<LI>在剪切、复制和粘贴操作中保持格式<BR><BR>
<LI>在空行中保持格式 </LI></UL>
<P>垂直编辑是 Internet Explorer 5.5 中首次出现的功能。该功能主要针对那些使用中文或日文进行编辑的用户，但它在纯 ASCII 文本中也能很好地工作。使用西文字体的字符可以向右旋转，这样，在显示文本时仿佛整段文本都被顺时针旋转。Internet Explorer 5.5 中，双向文本支持也得到极大改进。该功能主要用于希伯来和阿拉伯的文本。虽然经常会有一些英文的单词和词组，或者其他基于拉丁文的单词或词组，被插入到希伯来和阿拉伯的文本中。在 Internet Explorer 5.5 中，当遇到拉丁文字符集时，主要的定位方向将自动切换为从左到右，而当检测到希伯来文或阿拉伯文字符集时又会自动切换为从右到左。</P>
<P>批撤消和恢复使用户可以立刻删除和还原整个句子，而不是一次一个字符。现在，如果由于某些原因用户不想让某个链接处于活动状态，则可以使用 BACKSPACE 键撤消自动检测到的链接。</P>
<P>在复制和粘贴文本时，该编辑器现在可以很好地保持格式。例如，如果复制了格式为粗体、红色宋体格式的文本，然后将它粘贴到格式为粗体 Times Roman 的文本段中，那么所粘贴的文本将保持其粗体、红色宋体格式。现在，格式还能在空行上保持。如果将某行的格式设置为 16 点、斜体、Haettenschweiler，并数次点击 RETURN，当您返回这些空行并在其中键入字符时，文本将以 16 点、斜体、Haettenschweiler 格式输入，而不再是文档的默认字体。</P>
<P><B><FONT class=105v><A name=createwp_topic2></A>Web 创作功能</B></FONT> 
<P>Internet Explorer 中的 HTML 编辑器一贯支持下面这些基本的 Web 创作功能，未来仍将继续支持。 
<UL type=disc>
<LI>插入：<BR><BR>
<UL type=disc>
<LI>控件<BR><BR>
<LI>IFrames <BR><BR>
<LI>图象<BR><BR>
<LI>字幕 <BR><BR>
<LI>水平线<BR><BR></LI></UL>
<LI>控件选定<BR><BR>
<LI>UI 激活 </LI></UL>
<P>控件、IFrames、图象、字幕、水平线和表格全都有一些共同之处。每个元素都有各自的布局。所谓具有布局，基本上表示着对象呈矩形。（实际上，只要为任何元素指定宽度和高度，或使它 <B>contentEditable</B>，就可以使它具有布局。）如果布局元素包含有内容，则其内容的布局是由界定其范围的矩形来决定。</P>
<P>可以与选择文本一样，按住鼠标左键并在其上拖动鼠标，就可以选定具有布局的元素。但是，当布局元素位于可编辑容器内部时，也可以通过单击或按 TAB 键对它进行控制选定。当元素被控制选定时，将在框定它的矩形角和每个边的中点上显示“抓取手柄”。当元素被控制选定时，可以将其作为单个单位拖动（或删除），连带它的所有内容。还可以用鼠标拖动它的抓取手柄来调整其大小。元素被控制选定时，单击它或点击 ENTER 键将使它成为被激活的 UI。当元素成为活动的 UI 时，（除非它是不能有内容的元素，如图象或水平线，）将在它的周围出现晕线边框，并且可以编辑它的内容。</P>
<P><B>Internet Explorer 5.5 中的新功能</B> 
<P>Internet Explorer 5.5 拥有窗体编辑器的所有功能，此外，它还支持一些很棒的新功能，这些新功能使得创建窗体和 Web 页成为轻松并充满乐趣的工作。这些新功能包括： 
<UL type=disc>
<LI>2D 绝对定位<BR><BR>
<LI>现场调整大小<BR><BR>
<LI>多项选定<BR><BR>
<LI>不可选定的 UI 元素 </LI></UL>
<P>使用 2D 绝对定位，用户只需进行拖放操作，就可以把元素放到页面的任何位置上。（再也不用创建以前那些复杂的表格，就可以得到希望的准确布局了！）</P>
<P>现场调整大小功能让用户在调整元素大小时获得现场的 WYSIWYG 反馈。用户不用在拖动鼠标的同时描绘外边框，并在松开鼠标按钮时让元素自行调整大小，元素将随着用户拖动它的抓取手柄实时地调整大小。 </P>
<P>多项选定让用户能够一次选定多个元素，并同时拖动它们或调整其大小。</P>
<P>新的“不可选定”属性使您能够为 Web 页创建用户界面元素，它们不会在用户单击时使当前选定内容遭到破坏。这对创建更改当前选定内容格式的控件非常有用，这一点我们随后就会谈到。</P>
<P><B><FONT class=105v><A name=createwp_topic3></A>激活编辑器</B></FONT> 
<P>激活编辑器的方法有两种。第一种方法是将整个文档设置为设计模式。第二种方法可以在浏览模式中使用，来使各个元素可在运行时编辑。如果想让整个文档可在浏览时进行编辑，则可以在文档正文上设置 <B>contentEditable</B> 属性。</P>
<P><B>将文档设置为设计模式</B> 
<P>要将整个文档设置为设计模式，可以对文档对象本身设置 <B>designMode</B> 属性。当文档处于设计模式时，将不运行脚本。这样，似乎在文档内设置一个按钮来打开或关闭设计模式是个好注意，但这样做没有作用。当用户打开它后，它将保持在设计模式状态。当他们下次单击此按钮时，它将被选定而不是被单击，他们再次单击它，将能够编辑它的值。这就是为什么如果要使用设计模式最好对框架或 IFrame 中的文档设置 <B>designMode</B> 属性的原因。下例展示如何为 IFrame 中的文档打开设计模式：</P><PRE class=clsCode>&lt;script for="btnDesign" event="onclick"&gt;
  targetDoc = document.frames(0).document;
  if (targetDoc.designMode == "On")
    targetDoc.designMode = "Off";
  else
    targetDoc.designMode = "On";
&lt;/script&gt;
&lt;button id=btnDesign&gt;DesignMode&lt;/button&gt;
&lt;iframe src="blank.htm" style="border: black thin; width:100%; height:200px"&gt;&lt;/iframe&gt; 
</PRE>
<P><B>designMode</B> 属性的值始终以首字母大写格式存储，即时它最初是以全部小写设置的。请在测试它的值时一定记住这点。<B>designMode</B> 属性的默认值是“Inherit”。</P>
<P><B>在浏览模式中使元素可以编辑（或在设计模式中不可编辑）</B> 
<P>在 Internet Explorer 5.5 中，可以针对每个元素激活编辑器，而同时，文档本身处于浏览模式中。只要将 <B>contentEditable</B> 属性设置为 True，就能使元素在浏览时可被编辑。下例展示如何说明性地设置该属性，并创建行为类似文本框的跨距：</P><PRE class=clsCode>&lt;span contentEditable=true style="width:150; border:lightgrey 3px inset"&gt;&lt;/span&gt;
</PRE>
<P>要使元素在全部脚本过程中可被编辑是非常容易实现的。下面的范例显示如何在脚本中对 ID 为“foo”的元素设置 <B>contentEditable</B> 属性：</P><PRE class=clsCode>foo.contentEditable=True;
</PRE>
<P>要防止元素在设计模式中处于可编辑状态，可以将 <B>contentEditable</B> 属性设置为 False。但这将使元素具有布局，这样，当它在设计模式中时，用户将能够对它进行控制选定、拖动、调整大小等：</P><PRE class=clsCode>foo.contentEditable=False;
</PRE>
<P><B>contentEditable 元素的继承和嵌套</B> 
<P><B>contentEditable</B> 属性是被继承的，所以，如果您说明元素具有 contentEditable 属性，则默认情况下它的所有子元素都将是可编辑的。（<B>contentEditable</B> 属性的默认值是“Inherit”。 </P>
<P>通过将其 <B>contentEditable</B> 属性设置为 False，可以使 contentEditable 元素的后代成为不可编辑的，但这样之后，请记住设置元素的 <B>contentEditable</B> 属性将导致元素具有自己的布局。无论元素的 <B>contentEditable</B> 属性被设置为 True 或 False，都要发生这样的情况。还要记住，当有布局的元素处在可编辑的容器中时，一旦用户单击它的内部，它将被控制选定。当它被控制选定时，将显示抓取手柄，并且用户可以拖动该元素或调整其大小。这并不表示不应当在可编辑的元素内嵌套不可编辑的元素，只不过要加以注意罢了。</P>
<P><B>判断元素是否是可编辑的</B> 
<P>要判断元素是否是可编辑的，只检查 <B>contentEditable</B> 属性的值是不够的。元素可能根本没有 <B>contentEditable</B> 属性，但仍然可能已经从它的某个祖先那里继承了内容可编辑性。或者，它可能是默认时可编辑的元素，如文本框。或者，包含它的文档可能处于设计模式中。确定元素是否可编辑的唯一完全可靠的方法是检查 <B>isContentEditable</B> 属性。<B>isContentEditable</B> 属性综合了所有这些因素。该属性是只读的，其结果为布尔值。下例展示如何判断 ID 为“foo”的元素是否可以被编辑：</P><PRE class=clsCode>result=foo.isContentEditable;
</PRE>
<P><B><FONT class=105v><A name=createwp_topic4></A>执行编辑命令</B></FONT> 
<P>Internet Explorer 5.5 中的大多数基本编辑功能可通过发出命令来访问。MSDN Online 上的文档列出了可用的命令，并说明了要使用哪些参数。</P>
<P>要执行编辑命令，可调用 <B>document.execCommand</B>，并传递对应于命令 ID 的字符串。另外还有可选的第二个参数，该参数指定如果可以应用的话是否显示此命令的用户界面。传递整数 1 将显示用户界面，整数 0 将跳过它。这个参数通常不用于编辑命令。因为默认值为 0，所以假如您没有使用第三个参数（在这种情况下，还必须为第二个参数传递值），一般可以不管它。第三个参数也是可选的，在可应用的情况下，使用它来将任何所需参数传递给该命令。 </P>
<P>例如，要打开多项选择功能，应当调用 <B>document.execCommand("MultipleSelection")</B>。<CODE> </CODE>要打开现场调整大小功能，只需调用 <B>document.execCommand("LiveResize")</B>。要打开 2D 定位，请调用 <B>document.execCommand("2D-Position")</B>。</P>
<P class=indent><B><B>注意 </B></B>2D 定位只能对 CSS 样式已设置为 <B>position:absolute</B> 的元素有效。</P>
<P>下例（见图 1）使用了 <B>contentEditable</B> 属性、<B>unselectable</B> 属性和三个可执行的命令来创建一个可在 Web 页上使用的简单的小文本编辑器。很重要的一点是，div 语句在另一个 div 语句中，而外层 div 底部有三个按钮。按钮使用 <B>document.execCommand</B> 方法来格式化当前选定内容的样式。内部 div 具有 <B>contentEditable</B> 属性，而外部 div 和按钮是不可选定的。由于它们是不可选定的，所以用户可以单击它们而不会破坏当前的选定内容。这对按钮尤其有用，因为用户可以选定 contentEditable 区域中的一些文本，然后单击<B>粗体</B>按钮、<B>斜体</B>按钮和<B>下划线</B>按钮，而不必重新选定文本：</P><PRE class=clsCode>&lt;div align=center&gt;
&lt;div unselectable="on" align=center 
 style="height:300; width:400; background-color:powderblue; border:outset powderblue"&gt;  
  &lt;br&gt;  
  &lt;div id=foo contenteditable align=left    
   style="height:250; width:350;background-color:white; font-face:Arial; padding:3;    
   border:inset powderblue; scrollbar-base-color:powderblue; overflow=auto;"&gt;  
  &lt;/div&gt;  
  &lt;br&gt;  
  &lt;button unselectable="On" onclick='document.execCommand("Bold");foo.focus();'   
   style="width:80; background-color:powderblue; border-color:powderblue"&gt;   
   &lt;B&gt;粗体&lt;/B&gt;&lt;/button&gt;  
  &lt;button unselectable="On" onclick='document.execCommand("Italic");foo.focus();'    
   style="width:80; background-color:powderblue; border-color:powderblue"&gt;   
   &lt;B&gt;&lt;I&gt;斜体&lt;/I&gt;&lt;/B&gt;&lt;/button&gt;  
  &lt;button unselectable="On" onclick='document.execCommand("Underline");foo.focus();'    
   style="width:80; background-color:powderblue; border-color:powderblue;"&gt;   
   &lt;B&gt;&lt;U&gt;下划线&lt;/U&gt;&lt;/B&gt;&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
</PRE>
<P>图 1 中值得申明的另一点是，现在可以指定滚动条的颜色了！（这是 Internet Explorer 5.5 的另一个新功能）。</P>
<P><IMG alt="" src="http://www.microsoft.com/china/msdn/Archives/workshop/createwp01.gif" border=0></P>
<P class=label><B>图 1. 创建文本编辑器</B></P>
<P><B><FONT class=105v><A name=createwp_topic5></A>保持可编辑的内容</B></FONT> 
<P>如何保持可编辑的内容由您决定。如果您正在使用 Active Server Pages (ASP)，您可以在窗体中包括可编辑的元素，之后使用 <B>Post</B> 方法将它们张贴到 ASP 页，然后以任何方式将它们存储在服务器上。有关 ASP 页的内容包含在 ASP SDK 中，这里不作详细说明。另一个方法，也可能是更有趣的方法，是使用 UserData 行为将数据保持在客户端。</P>
<P><B>UserData 行为</B> 
<P>UserData 行为是将 contentEditable 元素中的内容保持在用户计算机的某个存储区中的最好方法。行为是 Internet Explorer 5.0 中引入的一种封装可重用脚本和/或 HTML 的方法。行为存在于它自己的、称为 HTC（HTML 组件）文件中，该文件被位于客户端文档的文件头中的 CSS 样式段加以引用。将行为应用到元素所用的方法与应用 CSS 样式相同。一旦行为与某个元素相关联，则属于该行为的所有方法都将被调用到该元素上。</P>
<P>UserData 是行为具有强大功能的极好范例。通过为在 <B>Save</B> 和 <B>Load</B> 方法中所指定的 UserData 存储指定不同的名称，可以使用 UserData 行为来将多个元素的内容保持在单个页面上。唯一的限制是每页不能存储超过 64KB，每个域的限制则为 640KB。下一个范例展示如何保持单个 contentEditable 元素中的内容。</P>
<P>该范例中的元素是一个名为“foo”的 contentEditable div 语句。注意，在文件头的样式说明中，说明了 UserData 行为。通过说明元素的类为“userData”，行为被附加到 contentEditable 元素上。这样，可以访问由 UserData 行为显露的方法，如 <B>setAttribute</B>、<B>getAttribute</B>、<B>Load</B> 和 <B>Save</B>，就好象它们是元素自身的方法一样。（只要属性名在 <B>getAttribute</B> 和 <B>setAttribute</B> 方法中是一致的，而存储名在 <B>Load</B> 和 <B>Save</B> 方法中是一致的，就可以以任何名称命名用来保持数据的存储和属性。）</P><PRE class=clsCode>&lt;html&gt;
&lt;head&gt;
&lt;style&gt; .userData {behavior:url(#default#userdata);} &lt;/style&gt;
&lt;script for=window event=onload&gt;
 DoLoad();
&lt;/script&gt;
&lt;script for=window event=onbeforeunload&gt;
  DoSave();
&lt;/script&gt;
&lt;script&gt;
function DoSave(){
  foo.setAttribute("content", foo.innerHTML);
  foo.save("EditContent");
}
function DoLoad(){
  foo.load("EditContent");
  content = foo.getAttribute("content");
  if (content != null) foo.innerHTML=content; 
}
function DoClear(){
  foo.innerHTML = "";
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p align=center&gt;
  &lt;button onClick='DoSave()'&gt;保存&lt;/button&gt;
  &lt;button onClick='DoClear()'&gt;清除&lt;/button&gt;
  &lt;button onClick='DoLoad()'&gt;加载&lt;/button&gt;
&lt;/p&gt;
&lt;div id=foo class=userData contentEditable=true style="width:100%;height:90%"&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</PRE>
<P>图 2 展示了一个 contentEditable div 语句和三个按钮，它们允许用户保存 div 的内容、加载所保存的内容和清除当前的内容。另一个好的技巧是，当用户转到其它页时，<B>window.onBeforeUnload</B><CODE> </CODE>事件处理程序将自动存储用户输入的内容。然后，当他们返回时，<B>window.onLoad</B><CODE> </CODE>事件处理程序将自动还原它。当用户返回您的 Web 页并发现他们上次留下的相同内容仍然存在，他们一定非常吃惊。</P>
<P><IMG alt="" src="http://www.microsoft.com/china/msdn/Archives/workshop/createwp02.gif" border=0></P>
<P class=label><B>图 2. 使用 UserData 行为保持数据</B></P>
<P><B><FONT class=105v><A name=createwp_topic6></A>元素行为和编辑</B></FONT> 
<P>元素行为是一个完全自我约束的自定义元素，可以将它当作固有的 HTML 控件。在前面有关保持的内容中，我们看到了 UserData 行为，该行为可以与任何元素关联。与标准行为相比，元素行为有其自己的元素标记，并且它不能应用到其它任何元素。行为不能脱离元素本身。</P>
<P>“viewlinked”元素行为：无需将生成该 UI 的 HTML 插入到调用它的文档中，其用户界面即可在浏览时显示。当用户查看 Web 的源文件时，他们只能看到代表该元素的标记，用户永远无法看见导致元素外观和动作的源文件。只有元素行为可以是 viewlinked。</P>
<P>有关元素行为的另一个重要情况是，无论元素标记什么时候可见于分析程序，行为都是可用的。永远不会出现元素在那里，而行为还没有加载的二者分离的情形。所有这些优点，使得元素行为成为创建可随时随地重复使用的、您自己的 HTML 控件的最好方法。</P>
<P><B>一个简单的例子</B> 
<P>在该范例中，将获得简单的小文本编辑器（图 1），另外添加几个按钮使它更有趣，将它封装在一个 HTC 文件中，并添加几条线以告诉分析程序将它当作 viewlinked 元素行为。之后，我们将看见如何在 HTML 文件中创建该组件的实例。</P>
<P><B>HTC 文件</B> 
<P>下面的代码是一个 HTC 文件，该文件包含了定义组件的源。注意，在顶部的 <B>public:component</B><CODE> </CODE>说明中包括了标记名称（在这里是“editBox”）。当新组件被插入 HTML 文件中时，这就是用来标识该新组件的名称。在 <B>public:component</B><CODE> </CODE>说明中的其它说明是 <B>public:defaults viewLinkContent</B> 说明，<CODE> </CODE>它指定该元素行为是 viewlinked 的。将这些说明添加到文件顶部，并用 .htc 扩展名保存该文件，这样就完成了把新创建的 DHTML 转换成元素行为的全部操作。在这里，我们将该文件命名为“editBox.htc”。（并不是一定要将文件命名为与元素本身相同的名称，这样做只是为了便于记忆。）</P><PRE class=clsCode>&lt;public:component tagName=editBox&gt;
&lt;public:defaults viewLinkContent/&gt; 
&lt;/public:component&gt;
 
&lt;div unselectable="on" align=center style="height:250; width:425;
<BR> background-color:powderblue; border:outset powderblue"&gt;
  &lt;br&gt;
  &lt;div id=foo contenteditable align=left 
   style="height:200; width:370;background-color:white; font-face:Arial; padding:3; 
   border:inset powderblue; scrollbar-base-color:powderblue; overflow=auto;"&gt;
  &lt;/div&gt;
  &lt;br&gt;
 
  &lt;button unselectable="On" onclick='document.execCommand("Bold");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="粗体"&gt;
   &lt;B&gt;B&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("Italic");foo.focus();'    
   style="background-color:powderblue; border-color:powderblue" title="斜体"&gt;
   &lt;B&gt;&lt;I&gt;I&lt;/I&gt;&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("Underline");foo.focus();'
   style="background-color:powderblue; border-color:powderblue;" title="下划线"&gt;
   &lt;B&gt;&lt;U&gt;U&lt;/U&gt;&lt;/B&gt;&lt;/button&gt;
&lt;button unselectable="On" onclick='document.execCommand("StrikeThrough");foo.focus();'
   style="background-color:powderblue; border-color:powderblue; text-decoration=line-through"
   title="删除线"&gt;
   &lt;B&gt;S&lt;/B&gt;&lt;/button&gt;
  &amp;nbsp;&amp;nbsp;
 
  &lt;button unselectable="On" onclick='document.execCommand("SuperScript");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="上标"&gt;
   &lt;B&gt;^&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("SubScript");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="下标"&gt;
   &lt;B&gt;_&lt;/B&gt;&lt;/button&gt;
  &amp;nbsp;&amp;nbsp;
 
  &lt;button unselectable="On" onclick='document.execCommand("InsertOrderedList");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="已排序列表"&gt;
   &lt;B&gt;OL&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("InsertUnorderedList");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="未排序列表"&gt;
   &lt;B&gt;UL&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("Outdent");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="突出"&gt;
   &lt;B&gt;&amp;lt;&amp;lt;&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("Indent");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="缩进"&gt;
   &lt;B&gt;&amp;gt;&amp;gt;&lt;/B&gt;&lt;/button&gt;
  &amp;nbsp;&amp;nbsp;
 
  &lt;button unselectable="On" onclick='document.execCommand("JustifyLeft");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="左对齐"&gt;
   &lt;B&gt;|&amp;lt;&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("JustifyRight");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="右对齐"&gt;
   &lt;B&gt;&amp;gt;|&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("JustifyCenter");foo.focus();'
   style="background-color:powderblue; border-color:powderblue" title="居中"&gt;
   &lt;B&gt;&amp;gt;|&amp;lt;&lt;/B&gt;&lt;/button&gt;
  &amp;nbsp;&amp;nbsp;
  &lt;br&gt;
 
  &lt;button unselectable="On" onclick='document.execCommand("Cut");foo.focus();'
   style="background-color:powderblue; border-color:powderblue"&gt;&lt;B&gt;剪切&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("Copy");foo.focus();'
   style="background-color:powderblue; border-color:powderblue"&gt;&lt;B&gt;复制&lt;/B&gt;&lt;/button&gt;
  &lt;button unselectable="On" onclick='document.execCommand("Paste")'
   style="background-color:powderblue; border-color:powderblue"&gt;&lt;B&gt;粘贴&lt;/B&gt;&lt;/button&gt;
  &amp;nbsp;&amp;nbsp;
  &lt;button unselectable="On" onclick='document.execCommand("Overwrite");foo.focus();'
   style="background-color:powderblue; border-color:powderblue"&gt;&lt;B&gt;覆盖&lt;/B&gt;&lt;/button&gt;
&lt;/div&gt;
</PRE>
<P><B>HTML 文件</B> 
<P>现在既然已经看过了 HTC 文件，接着让我们来看看 HTML 文件。在该文件中与任何其它 HTML 文件唯一不同的内容是位于文件顶部的 html 说明中的 <B>namespace </B>属性，另一个不同是处理指导 (PI)，它告诉分析程序在哪里找到 editBox 元素的执行文件。当碰巧名称相同的单独 HTC 文件中有两个不同的元素行为时，就必需要有 namespace 属性。namespace 提供了分辨它们的方法。导入语句简单地告诉分析程序当它看见标记名有前缀“x”时，它应当在指定的执行文件中查找该标记的定义。所以，无论什么时候使用用于新组件的标记，都必须用在 PI 中已经说明的 namespace 来给该标记加上前缀。（与在 XML 中的 namespaces 不同，这个 namespace 不是“统一资源名 (URN)”，并且它与标记本身没有固有关联。namespace 由 HTML 文件的创作者定义，并且对说明它的文件来说，它位于本地。它类似于在特殊 XML 文件中与 XML namespace 相关联的前缀。）</P>
<P><CODE>&lt;html xmlns:x&gt;</CODE></P>
<P><CODE>&lt;head&gt;</CODE></P>
<P><CODE>&lt; import namespace=x implementation="editBox.htc" /&gt;</CODE></P>
<P><CODE>&lt;/head&gt;</CODE></P>
<P><CODE></CODE></P>
<P><CODE>&lt;body&gt;</CODE></P>
<P><CODE>&lt;x:editbox&gt;</CODE></P>
<P><CODE>&lt;/body&gt;</CODE></P>
<P><CODE>&lt;/html&gt;</CODE></P>
<P><IMG alt="" src="http://www.microsoft.com/china/msdn/Archives/workshop/createwp03.gif" border=0></P>
<P class=label><B>图 3. Viewlinking 元素行为</B></P>
<P><B><FONT class=105v><A name=createwp_topic7></A>摘要</B></FONT> 
<P>在了解如何创建简单的文本编辑器作为元素行为后，您就可以轻松地对它进行扩展了，方法是添加持久性、使用前面介绍的 UserData 行为、添加用于选择字体和字体大小的控件。还可以对它进一步扩展，比如将菜单或下拉框添加到 UI 以便插入控件、图象和字幕，以及支持 2D 绝对定位、多项选定和现场调整大小。（无疑，还可以制作出更好看的用户界面！）通过合并使用浏览时编辑功能、UserData 持久性和元素行为，要想创建很棒的编辑组件几乎不受任何限制！</P>
<P>当然，并不是说您必须执行元素行为才能创建可编辑的 Web 页。Viewlinking 只是提供绝佳的方法来压缩及重复使用您所建立的行为（这样可以避免泄露您的 HTML 源文件）。</P>
<P>在了解 Internet Explorer 5.5 中所有最棒的新编辑功能之后，剩下的事就看您的了。相信您将会成为您公司中第一个提供实时、“所见即所得”可编辑 Web 页的人！（您的同事一定<I>非常</I>羡慕又嫉妒。）</P>
<P>&nbsp;</P>
<P>引用地址:<U><A href="http://www.microsoft.com/china/msdn/Archives/workshop/createwp.asp#createwp_topic6">http://www.microsoft.com/china/msdn/Archives/workshop/createwp.asp#createwp_topic6</A></U></P>]]></description>
</item><item>
<title><![CDATA[输入法编程相关资源汇集(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=14710</link>
<author>codebee</author>
<pubDate>2006/5/25 11:46:26</pubDate>
<description><![CDATA[<P>原始出处：<A href="http://realfun.cnblogs.com/archive/2005/03/28/127152.html">http://realfun.cnblogs.com/archive/2005/03/28/127152.html</A></P>
<P>输入法编程相关资源汇集－欢迎补充 <BR>本文可以任意转载，转载时请务必以超链接形式标明文章原始出处 <BR>在这里向一些付出工作的同志们和网站站长抱歉，有些资源是我直接保存的，</P>
<P>现在有些网站打不开让我不能够贴上链接了，如果发现有损你们的利益，</P>
<P>给我来信说明，我会及时改正 </P>
<P>IME输入法编程，关于函数，接口等等等等，偶入门时读的，后来还一直在查 <BR><A href="http://forum.mywuzhen.com......art=0&amp;trange=15">http://forum.mywuzhen.com......art=0&amp;trange=15</A> </P>
<P>输入法编程指南（貌似论文）： <BR><A href="http://www.cnblogs.com/Files/realfun/">http://www.cnblogs.com/Files/realfun/</A>输入法编程指南.rar </P>
<P>汉字输入法软件设计技术辅导站： <BR><A href="http://wwsys.51.net/">http://wwsys.51.net/</A> <BR>很多有用的内容，可惜很久不更新了，还有一些链接不可用 </P>
<P>输入法的安装： <BR><A href="http://www.cnblogs.com/Files/realfun/">http://www.cnblogs.com/Files/realfun/</A>输入法安装制作原理.rar </P>
<P>其他的资源有： </P>
<P>键盘扫描码：<A href="http://www.cnblogs.com/Files/realfun/">http://www.cnblogs.com/Files/realfun/</A>键盘扫描码.rar </P>
<P>Unicode：有人可能会编写可以在各个系统包括韩文、日文、英文系统下的输入法，参见： <BR>&nbsp;1、chedong的站点： <BR>&nbsp; 版权声明：可以任意转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明&nbsp; <BR>&nbsp; <A href="http://www.chedong.com/tech/hello_unicode.html">http://www.chedong.com/tech/hello_unicode.html</A> <BR>&nbsp;2、CharlezPetzold 那本 windows编程里面关于Unicode那章介绍 <BR>&nbsp;3、Unicode编程入门：<A href="http://www.vckbase.com/document/viewdoc/?id=642">http://www.vckbase.com/document/viewdoc/?id=642</A> <BR>繁体和简体：谈到Unicode，还有的是要考虑繁体和简体的转换问题： <BR>经典 用API作简繁体转换.rar </P>
<P>然后，就是freepy，几乎所有输入法编写者都要从此开始，感谢他的无私付出： <BR><A href="http://www.cnblogs.com/Files/realfun/freepydoc_cn.rar">http://www.cnblogs.com/Files/realfun/freepydoc_cn.rar</A> <BR><A href="http://www.cnblogs.com/Files/realfun/freepy31.zip">http://www.cnblogs.com/Files/realfun/freepy31.zip</A> </P>
<P>小键盘（软键盘）的编码： <BR><A href="http://www.cnblogs.com/re......hive/2005/03/28/127174.aspx">http://www.cnblogs.com/re......hive/2005/03/28/127174.aspx</A> </P>
<P>一些链接： <BR>输入法编程指南(根据msdn翻译)：<A href="http://wwsys.51.net/wwwboard/messages/253.html">http://wwsys.51.net/wwwboard/messages/253.html</A> <BR>Windows 输入法编程： <A href="http://blog.csdn.net/dengting/archive/2002/08/17/14638.aspx">http://blog.csdn.net/dengting/archive/2002/08/17/14638.aspx</A> <BR>中文输入法论坛：<A href="http://www.petrocn.com/cgi-bin/leoboard.cgi">http://www.petrocn.com/cgi-bin/leoboard.cgi</A> <BR>输入法单步跟踪调试：<A href="http://www.cnblogs.com/re......hive/2005/08/29/225153.aspx">http://www.cnblogs.com/re......hive/2005/08/29/225153.aspx</A></P>]]></description>
</item><item>
<title><![CDATA[输入法编程指南（根据msdn翻译）]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=14709</link>
<author>codebee</author>
<pubDate>2006/5/25 11:45:10</pubDate>
<description><![CDATA[<P>作者：李丽 更新时间： 2005-05-15</P>
<P>Windows 95输入法编辑器（IME） <BR>原著：Microsoft <BR>翻译：TBsoft Software Studio <BR>一、关于Windows 95混合语言IME <BR>&nbsp;&nbsp;&nbsp; 在Windows 95中，IME是一个动态链接库（DLL），与Windows 3.1远东版本IME不同的是，每一个运行的IME相当于混合语言键盘布局中的一种。与Windows 3.1 IME相比较，Windows 95混合语言IME提供下列增强功能： <BR>&nbsp;&nbsp;&nbsp; ●运行时相当于混合语言环境的一个部件 <BR>&nbsp;&nbsp;&nbsp; ●为每一个应用程序任务提供多重输入上下文 <BR>&nbsp;&nbsp;&nbsp; ●为每一个应用程序线程提供一个活动的IME <BR>&nbsp;&nbsp;&nbsp; ●通过应用程序消息循环给应用程序提供信息（消息顺序不能改变） <BR>&nbsp;&nbsp;&nbsp; ●为无IME支持应用程序和部分IME支持应用程序提供有力的支持 <BR>&nbsp;&nbsp;&nbsp; 要得到全部的增强功能，应用程序需要支持Windows 95 IME应用程序I／F。 <BR>&nbsp;&nbsp;&nbsp; 本文档描述了Windows 95 IME体系结构的应用程序I／F。 </P>
<P>1、IME的结构 <BR>&nbsp;&nbsp;&nbsp; Windows 95 IME必须提供两个部件：IME转换接口和IME用户接口。IME转换接口由一组IME模块引出函数提供，这些函数被IMM（输入法管理器——译者注）调用。 <BR>&nbsp;&nbsp;&nbsp; IME用户接口由一组窗口提供，这些窗口接收消息并提供IME的用户界面。</P>
<P>2、IME支持应用程序（IME感知应用程序——译者注） <BR>&nbsp;&nbsp;&nbsp; 应用程序有下列类型： <BR>●无IME支持应用程序：这种应用程序不控制IME，然而，如果应用程序接受DBCS字符，用户可以通过IME在应用程序中输入DBCS字符。 <BR>●部分IME支持应用程序：这种应用程序只控制不同的IME上下文，例如打开和关闭IME、写作窗口等等，但是不重新显示任何IME用户界面。 <BR>●完全IME支持应用程序：这种应用程序负责管理通过IME显示给应用程序的任何信息。 <BR>&nbsp;&nbsp;&nbsp; 在Windows 95中，一个无IME支持应用程序有一个缺省的IME窗口和一个缺省的输入上下文。 <BR>&nbsp;&nbsp;&nbsp; 部分IME支持应用程序使用预定义的“IME”类创建自己的IME窗口，可以管理或者不管理自己的输入上下文。 <BR>&nbsp;&nbsp;&nbsp; 完全IME支持应用程序自己管理输入上下文，显示输入上下文给出的任何需要的信息，不使用IME窗口。<BR>二、IME用户界面 <BR>&nbsp;&nbsp;&nbsp; IME用户界面包括IME窗口、用户界面（UI）窗口以及UI窗口的部件。</P>
<P>1、特征 <BR>&nbsp;&nbsp;&nbsp; IME类是实现IME用户界面部分的预定义全局窗口类。“IME”类与预定义的公共控制窗口类有许多相同的特点，IME窗口实例与静态控制一样通过CreateWindowEx函数创建，IME类窗口自己不响应用户输入，取而代之的是接收不同类型的控制消息实现全部IME用户接口。应用程序可以使用IME类创建自己的IME窗口，还可以使用ImmGetDefaultIMEWnd函数获取缺省IME窗口。创建自己的IME窗口或者使用缺省IME窗口的应用程序被称为IME支持应用程序，具有以下优点（与对应的Windows3.1应用程序比较）：</P>
<P>●包括候选字列表窗口（候选窗口），每一个应用程序可以有自己的用户界面窗口实例，使得用户可以在任何输入过程的中途停止并切换到另一个应用程序。在Windows 3.1日文版本中，用户切换到另一个应用程序是必须放弃当前输入过程。 <BR>●因为IME用户界面窗口包括应用程序窗口句柄，IME用户界面窗口可以为应用程序提供缺省行为。例如当应用程序移动时IME用户界面窗口自动移动，自动跟随窗口中的插入符号位置，为每一个应用程序标示模式等等。 <BR>&nbsp;&nbsp;&nbsp; 即使系统仅仅只提供一个IME类，IME窗口仍然有两种类型。一种类型是系统为无IME支持应用程序创建的IME窗口，DefWindowProc函数为该窗口处理消息，DefWindowProc函数的IME用户接口被线程的所有无IME支持窗口共享，在文档中，这种窗口称为缺省IME窗口。另一种类型是IME支持应用程序创建的IME窗口，在文档中，IME支持应用程序创建的IME窗口称作应用程序IME窗口。 </P>
<P>2、缺省和应用程序IME窗口 <BR>&nbsp;&nbsp;&nbsp; 当线程初始化时系统创建缺省IME窗口，这就是说，线程自动获取缺省IME窗口。缺省IME窗口为无IME支持应用程序提供IME用户界面，当IME或者IMM生成一个IME消息（WM_IME_*）时，无IME支持应用程序传递该消息到DefWindowProc函数，DefWindowProc函数发送需要的消息到为应用程序提供缺省IME用户界面的缺省IME窗口。IME支持应用程序当不从IME获取消息时也可以使用缺省IME窗口，需要时可以使用自身的IME窗口。</P>
<P>3、IME类 <BR>&nbsp;&nbsp;&nbsp; IME类是Windows 95远东版本预定义的窗口类，就像Edit是预定义的窗口类一样。预定义的IME类实现全部的IME用户接口，处理所有来自IME和包含IMM函数的应用程序的消息，应用程序使用IME类创建自己的IME窗口。系统IME类不能被被任何IME替换。 <BR>&nbsp;&nbsp;&nbsp; 窗口过程与IME类通过WM_IME_SELECT消息交互，该消息包括新选中的IME的键盘布局，IME类使用键盘布局查找到每一个IME定义的类名。使用类名，IME类为当前活动的IME创建IME用户界面窗口。 </P>
<P>4、IME UI类 <BR>&nbsp;&nbsp;&nbsp; 每一个IME必须向系统注册自己的用户界面（UI）类，UI类提供IME相关功能。当IME附加在进程上时IME注册自己的UI类，这就是说，当DLLEntry函数被调用DLL_PROCESS_ATTACH功能时，IME必须在对ImeInquire函数的调用过程中指定UI类名。UI类应该使用CS_IME窗口风格注册以使得每一个应用程序都可以使用UI类。 <BR>&nbsp;&nbsp;&nbsp; UI类名（包括空终结符）可以使用16位的TCHAR字符，这个限制可能延续到Windows的未来版本。 <BR>&nbsp;&nbsp;&nbsp; 当注册一个UI类时，应该指定8个字节的窗口附加数据（这就是说，设置WNDCLASSEX类的cbWndExtra成员的值为2*sizeof(LONG)），系统使用该窗口附加数据。 <BR>&nbsp;&nbsp;&nbsp; IME可以在为应用程序执行任务时注册任何类和创建任何窗口。 </P>
<P>&nbsp;&nbsp;&nbsp; 下面的实例显示了怎样注册IME窗口类： </P>
<P>BOOL WINAPI DLLEntry ( HINSTANCE hInstDLL, DWORD dwFunction, LPVOID lpNot) <BR>{ <BR>&nbsp;&nbsp;&nbsp; switch (dwFunction) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case DLL_PROCESS_ATTACH: <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hInst= hInstDLL; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.style = CS_MYCLASSFLAG | CS_IME; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.lpfnWndProc = MyUIServerWndProc; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.cbClsExtra = 0; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.cbWndExtra = 2 * sizeof(LONG); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hInstance = hInst; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hCursor = LoadCursor( NULL, IDC_ARROW); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hIcon = NULL; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.lpszMenuName = (LPSTR) NULL; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.lpszClassName = (LPSTR) szUIClassName; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hbrBackground = NULL; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!RegisterClass((LPWNDCLASS)&amp;wc)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.style = CS_MYCLASSFLAG | CS_IME; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.lpfnWndProc = MyCompStringWndProc; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.cbClsExtra = 0; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.cbWndExtra = cbMyWndExtra; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hInstance = hInst; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hCursor = LoadCursor(NULL, IDC_ARROW); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hIcon = NULL; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.lpszMenuName = (LPSTR) NULL; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.lpszClassName = (LPSTR) szUICompStringClassName; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wc.hbrBackground = NULL; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!RegisterClass((LPWNDCLASS)&amp;wc)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case DLL_PROCESS_DETACH: <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UnregisterClass(szUIClassName,hInst); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UnregisterClass(szUICompStringClassName,hInst); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; <BR>&nbsp;&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp; return TRUE; <BR>} </P>
<P>5、UI窗口 <BR>&nbsp;&nbsp;&nbsp; IME类对应的IME窗口被应用程序或者系统创建，当IME窗口被创建时，IME自身提供的UI窗口被创建并被IME窗口所拥有。每一个UI窗口有一个当前的输入上下文，当UI窗口接收到IME消息（WM_IME_*）时，可以通过调用GetWindowLong函数和指定IMMGWL_IMC索引值查找到输入上下文，UI窗口可以根据输入上下文处理消息，UI窗口可以在除响应WM_CREATE消息以外的任何时间查找到输入上下文。 <BR>&nbsp;&nbsp;&nbsp; IME不允许改变UI窗口的窗口附加数据，如果UI窗口的某个实例需要窗口附加数据，可以使用IMMGWL_PRIVATE参数值调用SetWindowLong和GetWindowLong函数，IMMGWL_PRIVATE参数值提供为UI窗口的某个实例存取附加数据中LONG类型值的能力，如果需要大于LONG类型值的附加数据，可以保存一个内存块的句柄到IMMGWL_PRIVATE域。 <BR>&nbsp;&nbsp;&nbsp; UI窗口过程可以使用DefWindowProc函数，但是UI窗口不允许传递IME消息给DefWindowProc函数，即使某个IME消息没有被处理，UI窗口也不允许传递该消息给DefWindowProc函数。 <BR>LRESULT UIWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) <BR>{ <BR>HIMC hIMC; <BR>HGLOBAL hMyExtra; <BR>switch(msg){ <BR>case WM_CREATE: <BR>// Allocate the memory bloack for the window instance. <BR>hMyExtra = GlobalAlloc(GHND,size_of_MyExtra); <BR>if (!hMyExtra) <BR>MyError(); <BR>// Set the memory handle into IMMGWL_PRIVATE <BR>SetWindowLong(hWnd, IMMGWL_PRIVATE, (LONG)hMyExtra); <BR>. <BR>. <BR>. <BR>break; <BR>case WM_IME_xxxx: <BR>// Get IMC; <BR>hIMC = GetWindowLong(hWnd,IMMGWL_IMC); <BR>// Get the memory handle for the window instance. <BR>hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE); <BR>lpMyExtra = GlobalLock(hMyExtra); <BR>. <BR>. <BR>. <BR>GlobalUnlock(hMyExtra); <BR>break; <BR>. <BR>. <BR>. <BR>case WM_DESTROY: <BR>// Get the memory handle for the window instance. <BR>hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE); <BR>// Free the memory block for the window instance. <BR>GlobalFree(hMyExtra); <BR>break; <BR>default: <BR>return DefWindowProc(hWnd, msg, wParam, lParam); <BR>} <BR>} <BR>&nbsp;&nbsp;&nbsp; UI窗口必须在当前选定的输入上下文中执行动作，当一个窗口被激活时，UI窗口接收到提供当前输入上下文的消息，此后，UI窗口运行在当前选中的输入上下文上。输入上下文必须包括UI窗口显示写作窗口、状态窗口等需要的所有信息。 <BR>&nbsp;&nbsp;&nbsp; UI窗口要求输入上下文，但是窗口不必自己更新输入上下文。当UI窗口需要更新输入上下文时，应该调用IMM函数，因为输入上下文由IMM函数管理，当输入上下文更新时，IMM和IME接收到通知消息。 <BR>&nbsp;&nbsp;&nbsp; 例如，有时UI窗口当鼠标单击时需要改变输入上下文的转换模式，为了设置转换模式，UI窗口调用ImmSetConversionMode函数，该函数为NotifyIME生成一个通知消息并发送WM_IME_NOTIFY消息到UI窗口，如果UI窗口改变转换模式的显示，UI窗口会等待处理WM_IME_NOTIFY消息。 </P>
<P>6、UI窗口的部件 <BR>&nbsp;&nbsp;&nbsp; UI窗口可以根据输入上下文注册和显示写作窗口和状态窗口，UI窗口的部件类的窗口风格必须包括CS_IME。UI窗口的一个窗口实例从当前输入上下文接收例如写作字符串、字体、位置等信息，当应用程序的一个窗口获得焦点时，系统获取该窗口自己的输入上下文并将当前输入上下文传递给UI窗口，系统发送WM_IME_SETCONTEXT消息和输入上下文的句柄给应用程序，应用程序传递该消息给UI窗口。如果当前输入上下文被更新，UI窗口应该重新绘制写作窗口，无论何时输入上下文改变，UI窗口都应该显示正确的写作窗口，可以保证IME的状态。 <BR>&nbsp;&nbsp;&nbsp; UI窗口可以创建子窗口或者弹出式窗口显示状态、写作字符串或者候选字列表，这些窗口必须是UI窗口的附属窗口，而且必须创建为不可接收输入（Disable）窗口，任何IME创建的窗口都不应该获取焦点。 </P>
<P>三、输入上下文 </P>
<P>1、缺省输入上下文 <BR>&nbsp;&nbsp;&nbsp; 缺省情况下系统给每个线程一个输入上下文，该输入上下文被线程的所有无IME支持窗口共享。 </P>
<P>2、输入上下文与窗口的交互 <BR>&nbsp;&nbsp;&nbsp; 应用程序的一个窗口可以使用窗口句柄与输入上下文交互以维护任何IME状态，包括中间写作字符串。一旦应用程序使得输入上下文与窗口句柄交互，无论何时窗口被激活，系统自动选中输入上下文。使用这个特点，应用程序可以轻松地完成Windows 3.1下必须的复杂切换处理。 </P>
<P>3、使用输入上下文 <BR>&nbsp;&nbsp;&nbsp; 当应用程序或者系统创建新的输入上下文时，系统准备新的输入上下文，新的输入上下文已经包括IMCC，这个IMC的部件由hCompStr、hCandInfo、hGuideLine、hPrivate和hMsgBuf组成。IME基本上不需要创建输入上下文和输入上下文的部件，不过IME可以改变它们的大小，可以通过锁定它们查找到部件的指针。 <BR>　<BR>⑴存取HIMC <BR>&nbsp;&nbsp;&nbsp; 为了存取输入上下文，IME必须调用ImmLockIMC函数以查找到输入上下文的指针，ImmLockIMC函数给IMC增加imm锁定计数，ImmUnlockIMC函数减少之。</P>
<P>⑵存取HIMCC <BR>&nbsp;&nbsp;&nbsp; 为了存取输入上下文中的一个部件，IME必须调用ImmLockIMCC函数获取IMCC的指针，ImmLockIMCC函数给IMCC增加imm锁定计数，ImmUnlockIMCC函数减少之，ImmReSizeIMCC函数可以修改IMCC的大小以指定新的大小。 <BR>&nbsp;&nbsp;&nbsp; 某些情况下，IME可能需要自己创建输入上下文的一个部件，这种情况下，IME可以调用ImmCreateIMCC函数获取IMCC的句柄，这个IMCC可以是INPUTCONTEXT结构的成员（hCompStr、hCandInfo、hGuideLine、hPrivate或者hMsgBuf）。 <BR>&nbsp;&nbsp;&nbsp; ImmDestroyIMCC清除输入上下文的一个部件。 </P>
<P>⑶怎样使用输入上下文 <BR>&nbsp;&nbsp;&nbsp; 下面的实例显示了怎样使用输入上下文 <BR>LPINPUTCONTEXT lpIMC; <BR>LPCOMOSITIONSTRING lpCompStr; <BR>HIMCC hMyCompStr; <BR>if (hIMC) { // It is not NULL context. <BR>lpIMC = ImmLockIMC(hIMC); <BR>if (!lpIMC) { <BR>MyError( "Can not lock hIMC"); <BR>return FALSE; <BR>} <BR>// Use lpIMC-&gt;hCompStr. <BR>lpCompStr = (LPCOMPOSITIONSTRING) ImmLockIMCC(lpIMC-&gt;hCompStr); <BR>// Access lpCompStr. <BR>ImmUnlockIMCC(lpIMC-&gt;hCompStr); <BR>// ReSize lpIMC-&gt;hCompStr. <BR>if (!(hMyCompStr = ImmReSizeIMCC(lpIMC-&gt;hCompStr,dwNewSize)) { <BR>MyError("Can not resize hCompStr"); <BR>ImmUnlockIMC(hIMC); <BR>return FALSE; <BR>} <BR>lpIMC-&gt;hCompStr = hMyCompStr; <BR>ImmUnlockIMC(hIMC); <BR>} </P>
<P>四、生成消息 <BR>&nbsp;&nbsp;&nbsp; IME需要生成IME消息。当IME开始转换时，IME必须生成WM_IME_STARTCOMPOSITION消息，如果IME改变了写作字符串，IME必须生成WM_IME_COMPOSITION消息，IME引发的事件导致生成消息给与输入上下文进行交互的窗口。IME基本上使用ImeToAsciiEx函数参数提供的lpdwTransKey缓冲区生成消息，当ImeToAsciiEx函数被调用时IME存储消息到lpdwTransKey缓冲区中，不过即使ImeToAsciiEx函数没有 <BR>被调用，IME也可以生成消息给使用输入上下文的消息缓冲区与输入上下文交互的窗口。输入上下文有一个内存块的句柄作为消息缓冲区，IME存储消息到被消息缓冲区句柄提供的内存块中，以后IME调用ImmGenerateMessage函数，ImmGenerateMessage函数发送保存在消息缓冲区中的消息到适当的窗口。</P>
<P>1、在ImeToAsciiEx函数中使用消息缓冲区 <BR>&nbsp;&nbsp;&nbsp; 下面的实例显示了怎样通过传递缓冲区到ImeToAsciiEx函数生成消息： <BR>UINT ImeToAsciiEx(uVirKey, uScanCode, lpbKeyState, lpdwTransBuf, <BR>fuState , hIMC ) <BR>{ <BR>DWORD dwMyNumMsg = 0; <BR>. <BR>. <BR>. <BR>// Set the messages that the IME needs to generate. <BR>*lpdwTransBuf++ = (DWORD) msg; <BR>*lpdwTransBuf++ = (DWORD) wParam; <BR>*lpdwTransBuf++ = (DWORD) lParam; <BR>// Count the number of the messages that the IME needs to generate. <BR>dwMyNumMsg++; <BR>. <BR>. <BR>. <BR>return dwMyNumMsg; <BR>} <BR>&nbsp;&nbsp;&nbsp; 系统提供lpdwTransBuf参数指定的缓冲区，IMEToAsciiEx函数可以一次存储所有的消息到该缓冲区中，缓冲区的第一个双字给出存储在缓冲区中的消息个数。如果ImeToAsciiEx函数需要生成比这个给定的个数更多的消息，函数可以存储所有的消息到输入上下文的hMsgBuf域中，然后函数ImeToAsciiEx返回消息个数。当ImeToAsciiEx函数的返回值大于lpdwTransBuf中指定的值时，系统不从lpdwTransBuf中取出消息，系统查找作为ImeToAsciiEx函数参数传递的输入上下文中的hMsgBuf域。 </P>
<P>2、使用消息缓冲区 <BR>&nbsp;&nbsp;&nbsp; 下面的实例显示了怎样使用消息缓冲区： <BR>MyGenerateMesage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAMlParam) <BR>{ <BR>LPINPUTCONTEXT lpIMC; <BR>HGLOBAL hTemp; <BR>LPDWORD lpdwMsgBuf; <BR>DWORD dwMyNumMsg = 1; <BR>// Lock the input context. <BR>lpIMC = ImmLockIMC(hIMC); <BR>if (!lpIMC) <BR>// Error! <BR>// re-allocate the memory bloack for the message buffer. <BR>hTemp = ImmReSizeIMCC(lpIMC-&gt;hMsgBuf, <BR>(lpIMC-&gt;dwNumMsgBuf + dwMyNumMsg) * sizeof(DWORD) * 3); <BR>if (!hTemp) <BR>// Error! <BR>lpIMC-&gt;hMsgBuf = hTemp; <BR>// Lock the memory for the message buffer. <BR>lpdwMsgBuf = ImmLockIMCC(lpIMC-&gt;hMsgBuf); <BR>if (!lpdwMsgBuf) <BR>// Error! <BR>lpdwNumMsgBuf += 3 * lpIMC-&gt;dwNumMsgBuf. <BR>// Set the number of the messages. <BR>lpIMC-&gt;dwNumMsgBuf += dwMyNumMsg; <BR>// Set the messages that the IME needs to generate. <BR>*lpdwMsgBuf++ = (DWORD) msg; <BR>*lpdwMsgBuf++ = (DWORD) wParam; <BR>*lpdwMsgBuf++ = (DWORD) lParam; <BR>// Unlock the memory for the message buffer and the input context. <BR>ImmUnlockIMCC(lpIMC-&gt;hMsgBuf); <BR>ImmLockIMC(hIMC); <BR>// Call ImmGenerateMessage function. <BR>ImmGenerateMessage(hIMC); <BR>} </P>
<P>3、WM_IME_COMPOSITION消息 <BR>&nbsp;&nbsp;&nbsp; 当IME生成WM_IME_COMPOSITION消息时，IME指定lParam参数为GCS位。GCS位的意义是COMPOSITIONSTRING结构中的有效成员，即使IME没有更新，成员目前仍然有效，IME也会设置GCS位。 <BR>&nbsp;&nbsp;&nbsp; 为IME定义服务 <BR>&nbsp;&nbsp;&nbsp; 当IME生成WM_IME_COMPOSITION消息时，IME可能会立刻改变字符串、属性以及子句信息。IME使用下列定义： <BR>GCS_COMP <BR>GCS_COMPREAD <BR>GCS_RESULT <BR>GCS_RESULTREAD</P>
<P>五、关于ImeSetCompositionString函数 </P>
<P>1、ImeSetCompositionString函数能力 <BR>&nbsp;&nbsp;&nbsp; 如果IME没有ImeSetCompositionString函数能力，IME将不能在IMEINFO结构中指定任何SCS能力。如果IME可以处理ImeSetCompositionString函数，IME设置SCS_COMPSTR位。如果IME可以通过写作字符串生成解释（本文中的“解释”是单词“reading”的直译，真正意义可能是“原始输入的”，例如输入的汉语拼音字母字符串，下同）字符串，IME可以设置SCS_CAP_MAKEREAD位。 <BR>&nbsp;&nbsp;&nbsp; 如果IME有SCS_CAP_COMPSTR能力，ImeSetCompositionString函数将被调用，IME从应用程序获取新的写作字符串并生成WM_IME_COMPOSITION消息。 <BR>&nbsp;&nbsp;&nbsp; 如果IME有SCS_CAP_MAKEREAD能力，IME可以通过写作字符串建立解释字符串。 </P>
<P>2、关于SCS_SETSTR <BR>&nbsp;&nbsp;&nbsp; 如果ImeSetCompositionString函数的dwIndex参数值为SCS_SETSTR，IME可以清除hIMC中的COMPOSITIONSTR结构中所有的域。 <BR>如果IME需要，IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、IMN_CHANGECANDIDATE或者IMN_CLOSECANDIDATE。 <BR>&nbsp;&nbsp;&nbsp; 如果ImeSetCompositionString函数的lpRead参数有效，IME应该通过lpRead参数中的解释字符串建立写作字符串，另外IME为新的写作字符串和lpRead参数中的解释字符串建立属性和子句信息，IME生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息。有时IME需要自动确定建立上述信息，这种情况下，IME可以生成lParam参数以（GCS_RESULT|GCS_RESULTREAD）代替GCS_COMPxxx的消息。 <BR>&nbsp;&nbsp;&nbsp; 如果ImeSetCompositionString函数的lpComp参数有效，IME应该通过lpComp参数中的写作字符串建立写作属性和子句信息，IME生成lParam参数为GCS_COMP的WM_IME_COMPOSITON消息。如果IME有SCS_CAP_MAKEREAD能力，IME应该同时建立解释字符串，IME生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息。有时IME需要自动确定建立上述信息，这种情况下，IME可以生成lParam参数以（GCS_RESULT|GCS_RESULTREAD）代替GCS_COMPxxx的消息。 <BR>&nbsp;&nbsp;&nbsp; 如果lpRead参数和lpComp参数同时有效，IME应该建立写作字符串和解释字符串，这时IME不需要完全按照lpRead参数和lpComp参数。如果IME不能建立应用程序指定的lpRead参数和lpComp参数之间的关系，IME应该修正写作字符串，IME为新的写作字符串和lpRead参数指定的解释字符串建立属性和子句信息，IME生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息。有时IME需要自动完成建立上述信息，这种情况下，IME可以生成lParam参数以（GCS_RESULT|GCS_RESULTREAD）代替GCS_COMPxxx的消息。 </P>
<P>3、关于SCS_CHANGEATTR <BR>&nbsp;&nbsp;&nbsp; SCS_CHANGEATTR只影响属性信息，IME不应该更新写作字符串、写作字符串的子句信息、写作字符串的解释以及写作字符串的解释子句信息。 <BR>首先IME检查新的属性并判断新的属性是否可用，然后IME设置属性到hIMC中的COMPOSITIONSTRING结构中，最后IME生成WM_IME_COMPOSITION消息。 <BR>&nbsp;&nbsp;&nbsp; 如果需要，IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、IMN_CHANGECANDIDATA、IMN_CLOSECANDIDATE。IME不能确定写作字符串。 <BR>&nbsp;&nbsp;&nbsp; 如果ImeSetCompositionString函数的lpRead参数有效，IME使用lpRead参数中的新属性。IME也应该为当前写作字符串建立写作字符串的新属性，这时子句信息不被修改。 <BR>&nbsp;&nbsp;&nbsp; 写作字符串、属性、子句信息、解释字符串、解释属性和解释子句信息必须有效。IME生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息，如果IME不能接受lpComp参数中的新属性，IME不需要生成任何消息并返回FALSE。 <BR>&nbsp;&nbsp;&nbsp; 如果ImeSetCompositionString函数的lpComp参数有效，IME使用lpComp参数中的新属性，这时子句信息不被修改。 <BR>&nbsp;&nbsp;&nbsp; 如果IME有SCS_CAP_MAKEREAD能力，并且解释字符串有效，IME应该为当前写作字符串的解释建立写作字符串的解释的新属性。 <BR>&nbsp;&nbsp;&nbsp; 如果lpRead参数和lpComp参数同时有效，并且如果IME能够接受新的信息，IME设置新的信息到hIMC中的COMPOSITION结构中并生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息。 </P>
<P>4、关于SCS_CHANGECLAUSE <BR>&nbsp;&nbsp;&nbsp; SCS_CHANGECLAUSE影响写作字符串和写作字符串的解释的字符串和属性。 <BR>&nbsp;&nbsp;&nbsp; 如果需要，IME可以更新候选信息并生成候选消息IMN_OPENCANDIDATE、IMN_CHANGECANDIDATA、IMN_CLOSECANDIDATE。IME不能确定写作字符串。 <BR>&nbsp;&nbsp;&nbsp; 如果ImeSetCompositionString函数的lpRead参数有效，IME使用lpRead参数中的解释子句信息。IME必须修正写作字符串的解释的属性，IME可以更新写作字符串、属性和写作字符串的子句信息，IME生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息。 <BR>&nbsp;&nbsp;&nbsp; 如果ImeSetCompositionString函数的lpComp参数有效，IME使用新的子句信息。IME必须修正写作字符串和写作字符串的属性，IME可以更新解释属性和解释的子句信息，IME生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息。 <BR>&nbsp;&nbsp;&nbsp; 如果lpRead参数和lpComp参数同时有效，并且如果IME能够接受新的信息，IME设置新的信息到hIMC中的COMPOSITION结构中并生成lParam参数为（GCS_COMP|GCS_COMPREAD）的WM_IME_COMPOSITION消息。 </P>
<P>六、软键盘 </P>
<P>1、关于软键盘 <BR>&nbsp;&nbsp;&nbsp; 一些IME有特殊的解释字符，例如一个IME可能使用注音符号作为解释字符（这里指台湾中文版Windows 95，即CWin95中的注音符号，PWin95中可能指汉语拼音字母或者音调符号——译者注），另一个IME使用了一些字根符号（原文单词是“radials”，但实际可能是“radicals”——译者注）作为解释字符，IME可以提供一个软键盘显示这些特殊解释字符使得用户不必逐键记忆解释字符。 <BR>&nbsp;&nbsp;&nbsp; IME需要根据不同的变换状态改变键表示的解释字符，使用软键盘可以通知用户键的改变。在选择候选字时，IME可以只显示那些选择键给用户。 </P>
<P>2、使用软键盘 <BR>&nbsp;&nbsp;&nbsp; IME可能需要为软键盘创建一个更好的用户界面，或者可能需要系统预定义的软键盘，如果IME需要使用系统预定义的软键盘，IME需要在调用ImeInquire函数时将IMEINFO结构的fdwUICaps成员指定为UI_CAP_SOFTKBD。 <BR>&nbsp;&nbsp;&nbsp; IME可以调用ImmCreateSoftKeyboard函数为软键盘创建窗口，还可以调用ImmShowSoftKeyboard函数显示或者隐藏软键盘。软键盘窗口是UI窗口的一个组件，所以软键盘窗口应该附属于UI窗口。 <BR>&nbsp;&nbsp;&nbsp; IME可能需要决定是否在无论何时焦点移走的情况下删除窗口，软键盘可能占有一些系统资源（可能需要释放——译者注） <BR>&nbsp;&nbsp;&nbsp; 软键盘有不同的类型，一种类型可能是为特定的国家或者特定的目的设计的。为每一种类型的软键盘改变解释字符的方式可能不同，有两种改变解释字符的方式：使用IMC_SETSOFKBDSUBTYPE或者IMC_SETSOFKBDDATA。不同类型的软键盘有不同的窗口过程并存在不同的用户界面给用户。 <BR>　<BR>七、IME接口 <BR>&nbsp;&nbsp;&nbsp; 在Windows 95中，IME与设备驱动程序一样是动态链接库（DLL），输入法管理器（IMM）应该处理所有安装的IME。因为IME在运行时是可以改变的，不需要重新启动系统，IMM有一个结构用于维护每一个IME的所有入口点。IME函数列表是所有远东版本Windows 95公共IME功能函数的描述，这些函数不应该在应用程序中直接调用。 <BR>　<BR>&nbsp;&nbsp;&nbsp; UI窗口中的IMM函数 <BR>&nbsp;&nbsp;&nbsp; 下面是可以在UI窗口中调用的IMM函数： <BR>ImmGetCompositionWindow <BR>ImmSetCompositionWindow <BR>ImmGetCandidateWindow <BR>ImmSetCandidateWindow <BR>ImmGetCompositionString <BR>ImmSetCompositionString <BR>ImmGetCompositionFont <BR>ImmSetCompositionFont <BR>ImmGetNumCandidateList <BR>ImmGetCandidateList <BR>ImmGetGuideLine <BR>ImmGetConversionStatus <BR>ImmGetConversionList <BR>ImmGetOpenStatus <BR>ImmSetConversionStatus <BR>ImmSetOpenStatus <BR>ImmNotifyIME <BR>ImmCreateSoftKeyboard <BR>ImmDestroySoftKeyboard <BR>ImmShowSoftKeyboard</P>]]></description>
</item><item>
<title><![CDATA[输入法编程(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=14708</link>
<author>codebee</author>
<pubDate>2006/5/25 11:44:11</pubDate>
<description><![CDATA[<P>输入法编辑器篇<BR>输入法编辑器（IME）是允许用户使用标准键盘输入复杂字母与符号，如日文汉字的程式。本文描述创建及管理IME（input method editor）视窗的方法。<BR>1、输入法编辑器简介<BR>IME 不是检索用户可能用到的所字符值，而是监控用户的按键，来预料用户可能需要的字符，并提供一张备择字符列表以供用户从中选出所需字符。<BR>&nbsp; 默认情况下，IME为用户提供一个可以键入并选择备择字符的IME视窗。通过使用IME变换功能提供的定制接口，Win32程式可以利用输入法管理器 (Input method manager),IMM，函式和消息创建自己的IME视窗。<BR>IMM仅在远东地区的Windows95/98和WindowsNT4.0/3.5/平台上可被激活。在这些系统上用SM_DBCSENABLED调用GetSystemMetrics来判定IMM是否被激活。WINDOWS2000为所有地区的语言均提供全部特征的IME支持。然而须注意，仅当安装了亚洲语言包时，IMM方可被激活,一个可激活IMM的程序用SM_IMMENABLED调用GetSystemMetrics来决定当前IMM是否活动。<BR>1.1 状态、录字和备择视窗<BR>用户接口为IME提供状态、录字和备择视窗。状态视窗指示IME被打开，并向用户提供设置转换模式的方法；在用户输入文本时，录字视窗弹出来，依赖转换模式显示输入文本或转换后的文本。备择视窗同录字视窗也一同出现，包含待选的备择字符或录字视窗中的字符，用户可以滚动备择列表来选择所需的字符，然后返回至录字视窗。用户可用此方法录入所需文本，直至录入字符串结束且视窗关闭。以WM_IME_CHAR或WM_IME_COMPOSITION/GCS_RESULT消息的形式，IME向程式送入录入字符。若程序不处理这些消息，DefWindowProc函式将它们转译成一个或多个WM_CHAR消息。<BR>默认时，系统自动地为所有需要文本输入的视窗创建和管理状态、录字及备择视窗。对许多程式而言，这一默认处理是高效的。这些程式完全依赖于系统对IME的支持并被称为“无觉察IME”（ IME-unaware）。这是因为他们忽略许多系统管理IME视窗的任务。<BR>相对应，一个“IME察觉”（IME-aware）程序，必参与IME视窗的创建与管理工作。此类程序通过传递、截取和处理送往默认视窗的消息，来控制视窗的操作、位置以及外观。在有些情况下，程序可以创建自己的IME视窗，并对自己定制的状态、录字和备择视窗提供完整处理方法。<BR>1.2 IME视窗类<BR>"IME" 视窗类是预定义的定义标准IME视窗行为和外观系统全局类。视窗类与通用控件类相似，在该类中，可以用CreateWindowEx函数创建该类的视窗，如同静态控件IME视窗不自身响应用户输入，相反，它通知用户输入行为IME和用IME或响应用户行为的程式给它传送进程控制消息。<BR>IME-aware 程序有时用IME类创建自己的IME视窗。这就允许程序利用默认的IME视窗进程以及视窗位置控件。<BR>1．3&nbsp; IME消息<BR>当某个事件发生时，系统送出IME视窗消息到程序视窗程序来影响IME视窗。例如，当激活一个视窗，系统给应用程序送出WM_IME_SETCONTEXT消息。IME-Unaware程序传送这些消息给DefWindowProc函数，后者再把消息送到相应默认的IME视窗。<BR>可以使用WM_IME_CONTROL消息指导IME视窗执行命令，如改变录字视窗的位置；IME使用WM_IME_COMPOSITION消息通知程序录入字串的改变；送出WM_IME_NOTIFY消息通知程序IME视窗状态的通用变化。<BR>1．4 输入上下文<BR>输入上下文是IME支持的内部结构，包括IME状态及IME视窗使用的信息。默认情况下，系统为每个线程创建和指派一个输入上下文，在该线程内，此默认输入上下文是共享资源并被连接到每个新建视窗。<BR>要在IME中检索或设置信息，应用程式须首先检索，连接到指定视窗输入上下文的句柄，可调用ImmGetContext函数来完成检索。随后，可用检索到的句柄调用输入法管理器函数检索和设置IME值，如录字视窗风格，录字的风格和状态视窗位置。一旦使用完上下文必须用ImmReleaseContext函数释放它。<BR>由于默认的上下文是共享资源，故它的任何变化均会反应到线程的所有视窗中。然而可以由创建和关联自己的输入上下文到一个或多个线程的视窗，来越过此默认行为。此后只有与自己的输入上下文关联的视窗才会改变。<BR>由使用ImmCreateContext函数，可以创建输入上下文。为给视窗指派上下文，可调用ImmAssociateContext函数来给先前的关联输入上下文返回一个句柄。若先前没有将输入上下文与视窗关联，则返回句柄是默认输入上下文的。典型情况下，可保存此句柄，并在后面不再使用自己的输入上下文时，将该句柄与视窗重新连接。<BR>一旦输入上下文与视窗连接，系统自动选择何时视窗被激活和被输入焦点的上下文。输入上下文的风格和其它信息会影响该视窗后面的键盘输入，并决定如何和是否进行IME操作。<BR>在结束应用程序前，必须消除任何用户自己创建的输入上下文。首先必须移除在线程中由使用ImmAssociateContext函数关联到视窗的任何输入上下文。随后，调用ImmDestroyContext函数。<BR>1.5、 录入字符串<BR>录入字符串是录入视窗的当前文本。即IME转换到最终字符的文本。每个录入字符串由一个或多个Clauses组成，这里Clauses是IME能转换到最终字符的字符最小组合。可以调用ImmSetCompositionString和ImmGetCompositionString函数来获取和设置录入字符串。<BR>用户在录入视窗输入文本时，IME跟踪录入视窗的状态，包括属性信息，clause信息，键入信息和光标位置。可以用ImmGetCompositionString函数检索录入状态。<BR>在属性信息数组中，一个Clause中的所有字符，必须有相同的属性。属性信息是一个8位值数组，用来指定字符在录入字符串中的状态。串中的每字节对应一个值，如串中的任何双字节字符分别用一个字节来表示前导字节和第二字节。对于数组中的每个值，可按下表来组合1位到3位值。<BR>值 含&nbsp;&nbsp;&nbsp;&nbsp; 义<BR>ATTR_INPUT 将由IME转换的用户输入字符。 <BR>ATTR_INPUT_ERROR 字符错误且不能由IME 转换。如, 一些不能放在一起的辅音。<BR>ATTR_TARGET_CONVERTED 已被转换的字符， 用户已选择此字符且IME业已转换了它。<BR>ATTR_CONVERTED 已被转换的字符。<BR>ATTR_TARGET_NOTCONVERTED 正被转换的字符，用户已选择此字符但IME还未转换它。 <BR>ATTR_FIXEDCONVERTED 将不被转换的字符， IME 不会转换这些字符。<BR>所有其它值被保留。日文中，任何有ATTR_INPUT属性的未转换字符是平假名、片假名或字母数字字符。韩文中，此字符为不被IME转换的Hangeul字符。在繁简中文中，每个IME在某个范围均有限制的字符。Clause信息是32位值数组，来指定录入视窗中Clause的位置。每个Clause有一个值，且最后一个值用来指定字符串的长度。数组的每个值指定从串开始到Clause的字节数偏移量。由于第一个Clause总从串头起始，故第一个值总为零。如：一个串有两个Clause，则Clause信息有3个值：第一个值为零，第二个值为第二个Clause的偏移量，第三个值为串的长度。对Unicode，Clause的长度是Unicode字符中的大小。<BR>键入信息（typing information）是一个null结束的字符串，代表键盘的键入字符。<BR>光标位置（cursor position）是指示与录入串中字符相关的光标位置的值。该值用字节表示从串头的偏移量。若此值为零，则光标在串中第一个字符的正前方。若值为串的长度，则光标紧挨在串中最后一个字符后边。若值为-1，则无光标。对Unicode位置和长度在Unicode字符中度量，可利用ImmSetCompositionString函数来设定录入串或录入状态元素。为确保录入视窗更新基于这些变化的外观，函数允许给视窗传送通知消息，设定录入状态元素组合的应用程序，可以为该函数的除了最后一次调用的所有调用设定Notify参数为FALSE，故对录入视窗仅产生一个通知消息。最后，编辑控件支持两个消息来改变IME的录入串句柄。<BR>1．6 备择列表<BR>备择列表是一个CANDIDATELIST结构。该结构由指定字符串的数组成或用户可以从中选择的字符串组成，可以用ImmGetCandidateListCount和ImmGetCandidateList函数来检索备择列素。<BR>1．7 热键<BR>热键使用户可以快迅地改变IME输入模式或切换到其它IME。尽管程序无法给系统增加热键，但使用ImmSimulateHotKey函数，可使启动同一行作为热键。Hex To Unicode IME 也允许十六进制字符和Unicode字符的互转。<BR>1．8&nbsp; Hex To Unicode IME <BR>Rich Edit 3.0支持Hex To Unicode IME，允许用户采用一种或两种热键方式在十六进制字符和Unicode字符间互换。<BR>在第一种方法中，用户键入十六进制字符码，而且按下Alt+x。则IME在插入点前用Unicode字符代替十六进制数字。若当前字体不支持字符码，则支持的适当字体被选择。由Unicode变到十六进制，则按下Shift+Alt+x。特殊地，允许确定由“丢失符号”指示器指示的字符。若十六进制字符码紧跟在合法（非字符）十六进制字符后，在按Alt+x前须选择想去变换的特定数字。此种方法的例题是，Alt+x有时被用作“退出”命令的组合键，如在微软的office中，作为“文件”菜单的选项而发生。<BR>第二种方法涉及数字Pad。这里，用户输入Alt+Num Pad（大于255的值）数字来用十进制值输入Unicode字符。此法不如第一种方法有用，因为无法看到输入的十六进制数。同时除了重新输入一遍否则无法订正错误。</P>
<P><BR>2、输入法编辑器应用<BR>2．1 处理WM-IME-COMPOSITION消息<BR>处理WM_IME_COMPOSITION消息的程序测试lParam参数的位数和调用ImmGetCompositionString函数检索指示串或数据。下例检查结果串，为串指派足够的内存，并从IME中检索结果串。<BR>HIMC hIMC;<BR>HWND hWnd;<BR>DWORD dwSize;<BR>HGLOBAL hstr;<BR>LPSTR lpstr;</P>
<P>case WM_IME_COMPOSITION:<BR>&nbsp;&nbsp;&nbsp; if (lParam &amp; GCS_RESULTSTR) <BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hIMC = ImmGetContext(hWnd);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If (!hIMC)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyError(ERROR_NULLCONTEXT);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get the size of the result string.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwSize = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // increase buffer size for NULL terminator, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp; maybe it is in UNICODE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwSize += sizeof(WCHAR);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hstr = GlobalAlloc(GHND,dwSize);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hstr == NULL)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyError(ERROR_GLOBALALLOC);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpstr = GlobalLock(hstr);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lpstr == NULL)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyError(ERROR_GLOBALLOCK);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get the result strings that is generated by IME into lpstr.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImmReleaseContext(hWnd, hIMC);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // add this string into text buffer of application</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GlobalUnlock(hstr);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GlobalFree(hstr);<BR>&nbsp;&nbsp;&nbsp; }<BR>2．2 输入法编辑器和Unicode<BR>微软&reg; Windows NT &reg;/2000 和微软&reg; Windows&reg; 98两种平台均为IME支持Unicode接口，当然还有从Windows95起，就支持的ANSI接口。Windows98支持除ImmIsUIMessage以外的所有Unicode函数。此外Windows98中的所有消息均是基于ANSI的。既然Windows98不支持Unicode消息，程序可以利用ImmGetCompositionString从Win98中基于IME的Unicode中检索Unicode字符。<BR>有两个问题涉及Unicode句柄和IME。一个是IME例行程序的Unicode版本返回缓存字节的大小，而不是16位Unicode字符；另一个是IME通常在WM_CHAR 和WM_IME_CHAR消息中返回Unicode字符（不是DBCS）。<BR>用RegisterClassW使WM_CHAR和 WM_IME_CHAR消息在wParam参数中返回Unicode字符而不是DBCS字符。此法仅在Windows NT/2000中可用。在win95/98中不可用。<BR>2．3&nbsp; 复原IME<BR>在Windows 98/2000中，IME具有复原的新特征。通常情况下，IME仅限于由键入来决定备择列表。复原允许IME依照其所在的句子（上下文）来决定备择的字符（或仅一个备择字符）。复原有三种类型：简单，正常和高级。<BR>当用户在文件中发现录入错误时，复原是很有用的。此时，用户选出错误，并在菜单中选择复原，则IME用上下文来确定最佳替代。ImmSetCompositionString可用来支持复原的使用。<BR>2．4 开发IME-aware多线程应用程序。<BR>当前的输入法管理器（IMM）结构不支持访问IMM句柄的异步工具。<BR>Windows 2000的IMM包含线程确认检查，用来确认调用的线程是否是指定输入法上下文句柄（hIMc）或视窗句柄（hWnd）的创建者。若不是，则函数调用失败并从GetLastError函数中返回ERROR_INVALID_ACCESS<BR>这一过程须要开发者遵循以下原则：<BR>⑴一个线程不应该同由其它线程创建的输入上下文。<BR>⑵一个线程不应连接输入上下文和其它线程创建的视窗，或反之。<BR>2．5、Windows 2000中的IME<BR>Windows 2000为任何地方的语言版本均提供IME的所有特性。因此，可以在Windows 2000的任何版本中安装和使用IME，而不仅是仅为亚洲语言设计的Windows 2000。<BR>然而，仅当用户在Win 2000上安装了亚洲语言包，IMM方可被激活。基于IME的程序， 用SM_IMMENABLED调用GetSystemMetrics函数来判定IMM是否被激活。</P>]]></description>
</item><item>
<title><![CDATA[Visual C++编程控制输入法(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=14704</link>
<author>codebee</author>
<pubDate>2006/5/25 11:28:04</pubDate>
<description><![CDATA[<P>在Windows系统中一般都安装了至少三种输入法,在输入数据时常常会切换输入法，虽然Windows系统提供了切换快捷健，但对输入工作还是带来了不少麻烦。如果在应用程序中为用户提供智能输入法自动切换，那么这样的应用程序就显得更加专业、更加具有竞争力。不知你可用过Access，在表数据输入时Access自动切换输入法，如某字段需要输入英文时自动切换到En输入状态，如另一字段需要输入中文自动切换到某中文输入状态。</P>
<P>　　本文将对如何在Windows应用程序中动态的控制输入法的技术进行探讨。在DELPHI中许多控件都有控制输入法的属性，用户在设计时只要设置好这个属性就可以了，但在VC中并不直接提供对输入法的控制，要在VC应用中实现这种功能必须调用Windows API。在本文中我将用一个类将与输入法操作有关的Windows API函数进行封装，读者可以直接将这个类导入项目工程中，通过操作这个类来实现对输入法的控制，这样更适合于面向对象的开发。</P>
<P>　　要想控制输入法，首先要解决的问题是如果获得系统已安装的输入法信息。在Windows平台下，每个安装的输入法都在注册表中注册了相关信息。在“HKEY_CURRENT_USER\keyboard layout\preload”键下就可以找到这些信息，键下由以1为基的递增数字做为值名（暂取名为数字号），其值的内容是一个由八个数字组成的字符串（暂取名为代号，如"e0040804"）,其中左4位是设备代码(device identifier)，右4位是语言代码(language identifier)。例如上面：左e004指智能ABC,右0804指大陆中文。在MSDN中对所有代码做了详细的说明，如感兴趣请浏览MSDN相关内容。另外要说明一点的是在Windows98版本中输入法注册信息与上面说明略有不同，它是将已安装的输入法的数字号做为…\Preload下面的子键，而Windows2000将数字号做为…\Preload键下的值。</P>
<P>　　　通过读取注册表中的输入法信息，可以列出所有已安装的输入法，但得到的输入法信息只是一些让人难懂的数字串，如何将这些数字串翻译成易懂的文字说明呢？同样，　在HKEY_LOCAL_MACHINE:"System\CurrentControlSet\Control\Keyboard Layouts\"键下注册了这些信息，它的子键名为输入法代号(keyboard layout)，内容为该输入法的ime文件，名称等信息。到此，我们已经了解了Windows系统控制输入法的原理知识，下面我们开始着手创建一个控制输入法的C++类，主要步骤如下：</P>
<P>　　1． 创建一个新类，新类名为：CInputLanguage</P>
<P>　　2． 新建一个保存输入法信息的结构。当加载系统已安装的输入法信息时，用一个此结构的链表来保存输入法信息。</P>
<P><BR>struct IL{<BR>　char ilID[15]; //输入法代号。<BR>　char szName[100];//输入法的说明文字。<BR>　IL* pNext;<BR>};&nbsp;</P>
<P>　　3． 加入一个私有的成员变量</P>
<P>　　　IL* m_pILHead;</P>
<P>　　4． 加入加载输入法列表信息的成员函数</P>
<P><BR>//此函数只针对Windows2000以上版本，如要在Windows98版本的代码请与笔者联系。</P>
<P>BOOL CInputLanguage::LoadInputLanguage()<BR>{<BR>　HKEY hKey,hKey1;<BR>　DWORD cp=16;<BR>　char lp[15];<BR>　CString szID;<BR>　CString szKeyName,szKeyName1;<BR>　szKeyName = "Keyboard Layout\\Preload";<BR>　szKeyName1 = "System\\CurrentControlSet\\Control\\Keyboard Layouts\\";</P>
<P>　int i=1;<BR>　szID.Format("%d",i);</P>
<P>　DWORD lpT=REG_SZ;<BR>　if(::RegOpenKey(HKEY_CURRENT_USER,szKeyName,&amp;hKey)==ERROR_SUCCESS )<BR>　{ <BR>　　While( ::RegQueryValueEx(hKey,szID,NULL,&amp;lpT,(LPBYTE)lp,&amp;cp) == ERROR_SUCCESS )<BR>　　{ <BR>　　　CString szTempName;<BR>　　　szTempName = szKeyName1 + (LPCTSTR)(LPTSTR)lp;<BR>　　　if(RegOpenKey(HKEY_LOCAL_MACHINE,szTempName,&amp;hKey1)==ERROR_SUCCESS )<BR>　　　{<BR>　　　　char lpD[100];<BR>　　　　DWORD lpS=100; //DataSize<BR>　　　　if(RegQueryValueEx(hKey1,"Layout text",NULL,&amp;lpT,(LPBYTE)lpD,&amp;lpS)==ERROR_SUCCESS)<BR>　　　　{<BR>　　　　　IL* p1,*p2;<BR>　　　　　p1 = m_pILHead;<BR>　　　　　p2 = new(IL);<BR>　　　　　strcpy(p2-&gt;ilID,lp);<BR>　　　　　strcpy(p2-&gt;szName,lpD);<BR>　　　　　p2-&gt;pNext = NULL;<BR>　　　　　if( p1 )<BR>　　　　　{<BR>　　　　　　while( p1-&gt;pNext ){ p1 = p1-&gt;pNext ; }<BR>　　　　　　p1-&gt;pNext = p2;<BR>　　　　　}<BR>　　　　　else<BR>　　　　　{<BR>　　　　　　m_pILHead = p2;<BR>　　　　　}<BR>　　　　}<BR>　　　}<BR>　　　::RegCloseKey(hKey1);<BR>　　　i++;<BR>　　　szID.Format("%d",i); <BR>　　} <BR>　}</P>
<P>　::RegCloseKey(hKey);<BR>　return (m_pILHead != NULL );</P>
<P>}<BR>&nbsp;</P>
<P>　　5． 加入选择输入法成员函数</P>
<P><BR>BOOL CInputLanguage::SelectInputLanguage(IL *pIL)</P>
<P>{<BR>　if( !pIL ) return FALSE;<BR>　　HKL hkl;<BR>　　hkl=LoadKeyboardLayout(pIL-&gt;ilID,KLF_ACTIVATE);//装载输入法<BR>　　if(hkl==NULL) return FALSE;<BR>　　else{<BR>　　　ActivateKeyboardLayout(hkl,KLF_SETFORPROCESS);//激活输入法<BR>　　}<BR>　　return TRUE;</P>
<P>}<BR>&nbsp;</P>
<P>　　6． 其它部分</P>
<P>&nbsp;</P>
<P>CInputLanguage::CInputLanguage()</P>
<P>{<BR>　m_pILHead = NULL;<BR>　LoadInputLanguage();</P>
<P>}</P>
<P>CInputLanguage::~CInputLanguage()</P>
<P>{<BR>　Clear();<BR>}</P>
<P>//消除链表内存。</P>
<P>void CInputLanguage::Clear()</P>
<P>{<BR>　IL* p1,*p2;<BR>　p1 = m_pILHead;</P>
<P>　while( p1 )<BR>　{<BR>　　p2 = p1;<BR>　　p1 = p1-&gt;pNext;<BR>　　delete(p2);<BR>　}<BR>　m_pILHead = NULL;</P>
<P>}</P>
<P>//获得输入法信息链表头结点指针。</P>
<P>IL* CInputLanguage::GetInputLanguageList()</P>
<P>{<BR>　return m_pILHead;<BR>} </P>
<P><BR>　　使用此类时，只要将其头文件包括到要调用的文件中，调用GetInputLanguageList函数可以得到输入法信息链表的头结点指针，通过遍历此链表得到所有已安装的输入法的信息；通过SelectInputLanguage函数可以自由的控制输入法了</P>]]></description>
</item><item>
<title><![CDATA[C#编写最小化时隐藏为任务栏图标的Window appllication (转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=13235</link>
<author>codebee</author>
<pubDate>2006/4/6 14:38:47</pubDate>
<description><![CDATA[<P><FONT face="Times New Roman" color=#000000 size=3>1.设置窗体属性showinTask=false</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>2.加notifyicon控件notifyIcon1，为控件notifyIcon1的属性Icon添加一个icon图标。</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>3.添加窗体最小化事件(首先需要添加事件引用)：</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>// this.SizeChanged += new System.EventHandler(this.Form1_SizeChanged);</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>//上面一行是主窗体InitializeComponent()方法中需要添加的引用</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>private void Form1_SizeChanged(object sender, EventArgs e)<BR>{<BR>if (this.WindowState==FormWindowState.Minimized)<BR>{<BR>this.Hide();<BR>this.notifyIcon1.Visible=true;<BR>}</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>}<BR>4.添加点击图标事件(首先需要添加事件引用)：</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>private void notifyIcon1_Click(object sender, EventArgs e)<BR>{<BR>this.Visible = true;</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>this.WindowState = FormWindowState.Normal;</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>this.notifyIcon1.Visible = false;<BR>}</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3></FONT>&nbsp;</P>
<P><FONT face="Times New Roman" color=#000000 size=3>5.可以给notifyIcon添加右键菜单：</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>主窗体中拖入一个ContextMenu控件contextMenu1，点中控件，在上下文菜单中添加菜单，notifyIcon1的ContextMenu行为中选中contextMenu1作为上下文菜单。</FONT></P>
<P><FONT face="Times New Roman" color=#000000 size=3>(可以在子菜单中添加行为)<BR></FONT></P>]]></description>
</item><item>
<title><![CDATA[C 语言下的鼠标编程控制]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=12154</link>
<author>codebee</author>
<pubDate>2006/3/2 16:15:19</pubDate>
<description><![CDATA[
<P><A><FONT size=3>　</FONT></A></P>
<P><FONT size=3><FONT face=黑体>鼠标的控制可以应用于图形模式和文本模式。在初始图形模型时,首先调用</FONT>initgraph(),<FONT face=黑体>从文本模式切换到图形模式。在初始时，将用到<FONT size=4>DETECT 宏，它将令initgraph()函数自动选择最高的图形支持模式。关于图形模式请参考其它书籍，这里不是重点。</FONT></FONT></FONT></P>
<P><FONT face=黑体 size=4>鼠标的调用是通过调用中断51实现的，而它的状态控制是通过AX寄存器实现的。</FONT></P>
<P>
<TABLE id=AutoNumber1 style="BORDER-COLLAPSE: collapse" borderColor=#111111 height=228 cellSpacing=0 cellPadding=0 width="95%" align=left bgColor=#ffff00 border=1>
<TBODY>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=55><FONT style="FONT-SIZE: 16pt" color=#0000ff>中断码</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=55><FONT style="FONT-SIZE: 16pt" color=#0000ff>控制字</FONT></TD>
<TD align=middle width="358%" bgColor=#ffffcc height=55><FONT style="FONT-SIZE: 16pt" color=#0000ff>行为</FONT></TD></TR>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=89><FONT size=4>51<BR>&nbsp;</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=89><FONT size=4>0</FONT><BR>&nbsp;</TD>
<TD align=middle width="358%" bgColor=#ffffcc height=89>
<P align=justify><FONT size=4>&nbsp;初始化鼠标获得其状态<BR>&nbsp;调用：AX = 0<BR>&nbsp;返回：&nbsp;AX = FFFFh&nbsp;不支持&nbsp;鼠标&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></P>
<P align=justify><FONT size=4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</FONT><FONT size=4>Ax = 0&nbsp; 支持鼠标</FONT></P></TD></TR>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=73><FONT size=4>51</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=73><FONT size=4>1</FONT></TD>
<TD align=middle width="358%" bgColor=#ffffcc height=73>
<P align=left><FONT size=4>&nbsp;显示鼠标箭头<BR>&nbsp;调用：AX = 1&nbsp;&nbsp;<BR>&nbsp;返回：空</FONT></P></TD></TR>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=76><FONT size=4>51</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=76><FONT size=4>2</FONT></TD>
<TD align=middle width="358%" bgColor=#ffffcc height=76>
<P align=left><FONT size=4>&nbsp;隐藏鼠标箭头<BR>&nbsp;调用： AX = 2 <BR>&nbsp;返回： 空</FONT></P></TD></TR>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=193><FONT size=4>51</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=193><FONT size=4>3</FONT></TD>
<TD align=middle width="358%" bgColor=#ffffcc height=193>
<P align=left><FONT size=4>&nbsp;获取鼠标位置和状态&nbsp;<BR>&nbsp;调用：AX = 3&nbsp;<BR>&nbsp;返回： BX =&nbsp;鼠标状态</FONT><FONT size=4>&nbsp;</FONT></P>
<P align=left><FONT size=4>&nbsp; 值&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 状态</FONT></P>
<P align=left><FONT size=4>&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;没有按键按下</FONT></P>
<P align=left><FONT size=4>&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;左键按下</FONT></P>
<P align=left><FONT size=4>&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;右键按下</FONT></P>
<P align=left><FONT size=4>&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;中键按下<BR>&nbsp;CX = x&nbsp;坐标</FONT></P>
<P align=left><FONT size=4>&nbsp;DX = y 坐标</FONT></P></TD></TR>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=114><FONT size=4>51</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=114><FONT size=4>4</FONT></TD>
<TD align=middle width="358%" bgColor=#ffffcc height=114>
<P align=left><FONT size=4>&nbsp;设置鼠标位置</FONT></P>
<P align=left><FONT size=4>&nbsp;调用： AX = 4<BR>&nbsp;CX = x&nbsp;坐标</FONT></P>
<P align=left><FONT size=4>&nbsp;DX = y&nbsp;坐标</FONT></P>
<P align=left><FONT size=4>&nbsp;返回： 空</FONT></P></TD></TR>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=113><FONT size=4>51</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=113><FONT size=4>7</FONT></TD>
<TD align=middle width="358%" bgColor=#ffffcc height=113>
<P align=left><FONT size=4>&nbsp;设定x轴移动范围<BR>&nbsp;调用： AX = 7<BR>&nbsp;CX =&nbsp;最小 x&nbsp;坐标</FONT></P>
<P align=left><FONT size=4>&nbsp;DX =&nbsp;最大 x&nbsp;坐标</FONT></P>
<P align=left><FONT size=4>&nbsp;返回: 空</FONT></P></TD></TR>
<TR>
<TD align=middle width="14%" bgColor=#ffffcc height=113><FONT size=4>51</FONT></TD>
<TD align=middle width="14%" bgColor=#ffffcc height=113><FONT size=4>8</FONT></TD>
<TD align=middle width="358%" bgColor=#ffffcc height=113>
<P align=left><FONT size=4>&nbsp;设定y轴移动范围<BR>&nbsp;&nbsp;调用： AX = 8<BR>&nbsp;CX =&nbsp;最小 y&nbsp;坐标</FONT></P>
<P align=left><FONT size=4>&nbsp;DX =&nbsp;最大 y&nbsp;坐标</FONT></P>
<P align=left><FONT size=4>&nbsp;返回： 空</FONT></P></TD></TR></TBODY></TABLE></P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4></FONT>&nbsp;</P>
<P><FONT face=黑体 size=4>给出两个例子：</FONT></P>
<P><FONT face=黑体 size=4>例一：</FONT></P>
<P><FONT size=4>&nbsp;#include&lt;graphics.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include&lt;stdio.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include&lt;conio.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include&lt;dos.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union REGS in,out;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int callmouse()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.ax=1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int86(51,&amp;in,&amp;out);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void mouseposi(int &amp;xpos,int &amp;ypos,int &amp;click)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.ax=3;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int86(51,&amp;in,&amp;out);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; click=out.x.bx;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xpos=out.x.cx;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ypos=out.x.dx;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int mousehide()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.ax=2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int86(51,&amp;in,&amp;out);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void setposi(int &amp;xpos,int &amp;ypos)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.ax=4;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.cx=xpos;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.dx=ypos;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int86(51,&amp;in,&amp;out);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp; int main()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int x,y,cl,a,b;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clrscr();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int g=DETECT,m;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; initgraph(&amp;g,&amp;m,"c:\tc\bgi");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a=100;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b=400;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setposi(a,b);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; callmouse();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mouseposi(x,y,cl);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gotoxy(10,9);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("\n\tMouse Position is: %d,%d",x,y);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("\n\tClick: %d",cl);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("\n\tPress any key to hide the mouse");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }while(!kbhit());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getch();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mousehide();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("\n\n\tPress any key to Exit");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getch();<BR>&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face=黑体 size=4>例二</FONT></P>
<P><FONT size=4>#include&lt;graphics.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include&lt;stdio.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include&lt;conio.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include&lt;dos.h&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union REGS in,out;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int callmouse()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.ax=1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int86(51,&amp;in,&amp;out);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void restrictmouseptr(int x1,int y1,int x2,int y2)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.ax=7;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.cx=x1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.dx=x2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int86(51,&amp;in,&amp;out);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.ax=8;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.cx=y1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in.x.dx=y2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int86(51,&amp;in,&amp;out);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int main()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int x,y,cl,a,b;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clrscr();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int g=DETECT,m;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; initgraph(&amp;g,&amp;m,"c:\tc\bgi");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rectangle(100,100,550,400);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; callmouse();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; restrictmouseptr(100,100,550,400);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getch();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT size=4></FONT>&nbsp;</P>
<P><FONT size=4></FONT>&nbsp;</P>
<P><FONT size=4></FONT>&nbsp;</P>]]></description>
</item><item>
<title><![CDATA[隐藏桌面和屏蔽系统热键编程]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=11075</link>
<author>codebee</author>
<pubDate>2006/1/8 17:12:38</pubDate>
<description><![CDATA[<A><FONT size=3>　</FONT></A><FONT size=3> </FONT>
<P><FONT color=#445cbb size=3>-Codebee</FONT></P>
<P><FONT face=仿宋_GB2312 size=3>隐藏桌面</FONT></P>
<P><FONT size=3>在隐藏桌面，任务栏，开始按钮，都可以通过windows API 函数 FindWindow() 和 <BR>ShowWindow()实现。</FONT></P>
<P><FONT size=3>隐藏任务栏，你可以使用下面的代码：</FONT></P>
<P><FONT size=3>ShowWindow(FindWindow("Shell_TrayWnd", NULL), SW_HIDE);</FONT></P>
<P><FONT size=3>隐藏开始菜单按钮，你首先要获得按钮的ID,然后使用下面的代码：</FONT></P>
<P><FONT size=3>ShowWindow(GetDlgItem(FindWindow("Shell_TrayWnd", NULL),0x130), SW_HIDE);</FONT></P>
<P><FONT size=3>Shell_TrayWnd 是任务栏的类<BR>0x130 是开始按钮的ID</FONT></P>
<P><FONT size=3>这些都是通过VC++6.0 下面的Spy++ 工具捕获到的。同理，你可以捕获任何一个你想要的窗口或者按钮。</FONT></P>
<P><FONT size=3>屏蔽窗口不想隐藏，可以把ShowWindow() 函数换为 EnableWindow()。</FONT></P>
<P><FONT size=3>如此，当你按下Win键仍然会弹出开始菜单，下面我们来屏蔽热键。</FONT></P>
<P><FONT size=3>屏蔽系统热键</FONT></P>
<P><FONT size=3>在Win9x/ME 可以用下面的代码：</FONT></P>
<P><FONT size=3>SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &amp;bOldState, 0);</FONT></P>
<P><FONT size=3>当然Windows2000 和 Windows XP 是不适合这种方法的。</FONT></P>
<P><FONT size=3>屏蔽系统热键，在Windows2000 和 Windows XP 是用钩子函数来实现的</FONT></P>
<P><BR><FONT size=3>首先，在程序中安装一个钩子：<BR>SetWindowsHookEx():</FONT></P>
<P><FONT size=3>hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hInstance, 0);</FONT></P>
<P><FONT size=3>KeyboardProc() 函数是一个CallBack类型的，也就是说一旦有按键按下系统都会调用此函数。</FONT></P>
<P><FONT size=3>&nbsp;LRESULT KeyboardProc(...)<BR>&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp; if (Key == VK_SOMEKEY)<BR>&nbsp;&nbsp;&nbsp; return 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 屏蔽热键</FONT></P>
<P><FONT size=3>&nbsp;&nbsp;&nbsp; return CallNextHookEx(...); // 返回<BR>&nbsp; }</FONT></P>
<P><FONT size=3>释放钩子时：</FONT></P>
<P><FONT size=3>UnhookWindowsHookEx(hKeyboardHook);</FONT></P>
<P><FONT size=3>当然这里是安装的系统级的钩子(关于钩子可以参看Blog里的另外一篇转的文章[C++与WIN32与MFC]利用钩子函数来捕捉键盘响应的windows应用程序.(转))。<BR></FONT></P>
<P><BR><FONT size=3>Ctrl+Alt+Del&nbsp; 的屏蔽</FONT></P>
<P><FONT size=3>Ctrl+Alt+Del Windows 不会把它放入键盘钩子的消息中(关于键盘钩子也请参看上面的文章) </FONT></P>
<P><FONT size=3>在这里说说我的方法，主要是屏蔽任务管理。<BR>首先获得系统所以的进程(请参考Blog里的 通过Toolhelp API 查看本地进程的程序(VC 6.0 编译通过）)。</FONT></P>
<P><FONT size=3>然后使用 Bool TerminateProcess (HANDLE hProcess,UINT fuExitCode);完成。</FONT></P>
<P><FONT size=3>如果大家有更好的方法可以和我交流。 </FONT></P>]]></description>
</item><item>
<title><![CDATA[Windows XP 嵌入版开发系统(Microsoft Windows Embedded Studio)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=10949</link>
<author>codebee</author>
<pubDate>2006/1/1 21:12:49</pubDate>
<description><![CDATA[Windows XP Embedded是一种嵌入式操作系统，可以以组件化的形式提供 Windows 操作系统的功能。Windows XP Embedded 与 Windows XP Professional 一样基于二进制，包含 10,000 多个独立的功能组件，因此开发人员在自定义设备映像中管理或降低内存占用量时可以选择并获得最佳功能。<BR>Windows XP Embedded不同于Windows XP的其他版本——本身没有现成的安装文件，必须通过开发环境定制系统的组件。这一点又不同于XPLite或nLite，XPLite或nLite生成的只是简化版的Windows XP，而Windows XP Embedded则最大限度的限制系统体积，主要应用在机顶盒、POS机和手持机等嵌入式设备上。<BR>&nbsp;&nbsp;&nbsp;&nbsp; 这几天在下这个版本,不知道到底怎么样。打算好好用寒假的时间尝试，到时再给大家汇报了~:)]]></description>
</item><item>
<title><![CDATA[苏格拉底与失恋者的对话]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=9925</link>
<author>codebee</author>
<pubDate>2005/11/16 21:22:27</pubDate>
<description><![CDATA[苏(苏格拉底)：孩子，为什么悲伤？ <BR>失（失恋者）：我失恋了。 <BR>苏：哦 ，这很正常。如果失恋了没有悲伤，恋爱大概也就没有什么味道。可是，年轻人，我怎么发现你对失恋的投入甚至比对恋爱的投入还要倾心呢。 <BR>失：到收的葡萄给丢了，这份遗憾，这份失落，您非个中人，怎知其中的酸楚。 <BR>苏：丢就丢了，何不继续向前走去，鲜美的葡萄还有很多。 <BR>失：我要等到海枯石烂，直到她回心转意向我走来。 <BR>苏：但这一天也许永远不会到来。 <BR>失：那我就用自杀来表示我的诚心。 <BR>苏：如果这样，你不但失去了你的恋人，同时还失去了你自己，你会蒙受双倍的损失。 <BR>失：踩上她一脚如何？我得不到的别人也别想得到。 <BR>苏：可这只能使你离她更远，而你本来是想与她更接近的。 <BR>失：您说我该怎么办？ <BR>苏：真的很爱？那你当然希望你所爱的人幸福？ <BR>失：那是当然。 <BR>苏：如果她认为离开你是一种幸福呢？ <BR>失：不会的！她曾经跟我说过，只有跟我在一起的时候她才感到幸福！ <BR>苏：那是曾经，是过去，可她现在并不这么认为。 <BR>失：这就是说她一直在骗我？ <BR>苏：不，她一直对你很忠诚。当她爱你的时候，她和你在一起，现在她不爱你，她就离去了，世界上再没有比着更大的忠诚。如果她不再爱你，却还装得对你很有情意，甚至跟你结婚、生子，那才是真正的欺骗呢。 <BR>失：可我为她所投入的感情不是白白浪费了吗？谁来补偿我？ <BR>苏：不，你的感情从来没有浪费。因为在你付出感情的同时，她也对你付出了感情，在你给她快乐的时候，她也给了你快乐。 <BR>失：可是，她现在不爱我了，我却还苦苦的爱着她，这多不公平啊！ <BR>苏：的确不公平，我是说你对所爱的那个人不公平。本来，爱她是你的权利，但爱不爱你则是她的权力，而你却想在自己行使权力的时候剥夺别人行使权力的。这是何等的不公平！ <BR>失：可是您看得明白，现在痛苦的是我而不是她，是我在为她痛苦！ <BR>苏：为她而痛苦？她的日子可能过得很好，不如说是你为自己而痛苦吧。明明是为自己，却还打着为别人的旗号。 <BR>失：依您的说法，这一切倒成了我的错？ <BR>苏：是的，从一开始你就犯了错。如果你能给她带来幸福，她是不会从你的生活中离开的，要知道，没有人会逃避幸福。 <BR>失：可她连机会都不给我，你说可恶不可恶？ <BR>苏：当然可恶。好在你现在已经摆脱了这个可恶的人，你应该感到高兴，孩子。 <BR>失：高兴？怎么可能呢，不管怎么说，我是被人给抛弃了。 <BR>苏：被抛弃的并不是就是不好的。 <BR>失：此话怎讲？ <BR>苏：有一次，我在商店看中一套高贵的西服，爱不释手，营业员问我要不要。你猜我怎么说，我说质地太差了，不要！其实，我口袋了没有钱。年轻人，也许你就是被遗弃的西服。 <BR>失：您真会安慰人，可惜您还是不能把我从失恋的痛苦中引出。 <BR>苏：时间会抚平你心灵的创伤。 <BR>失：但愿我也有这一天，可我的第一步该从哪里做起呢？ <BR>苏：去感谢那个抛弃你的人，为她祝福。 <BR>失：为什么？ <BR>苏：因为她给了你忠诚，给了你寻找幸福的新的机会]]></description>
</item><item>
<title><![CDATA[（转）爱迪生欺骗了世界-]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=8935</link>
<author>codebee</author>
<pubDate>2005/10/1 11:35:13</pubDate>
<description><![CDATA[<FONT size=2><FONT size=3>&nbsp;&nbsp;&nbsp; “今天是我第一次和雅虎的朋友们面对面交流。我希望把我成功的经验和大家分享，尽 <BR>管我认为你们其中的绝大多数勤劳聪明的人都无法从中获益，但我坚信，一定有个别懒 <BR>的去判断我讲的是否正确就效仿的人，可以获益匪浅。<BR><BR>让我们开启今天的话题吧！<BR><BR>世界上很多非常聪明并且受过高等教育的人，无法成功。就是因为他们从小就受到了错 <BR>误的教育，他们养成了勤劳的恶习。很多人都记得爱迪生说的那句话吧：天才就是99％ <BR>的汗水加上1％的灵感。并且被这句话误导了一生。勤勤恳恳的奋斗，最终却碌碌无 <BR>为。其实爱迪生是因为懒的想他成功的真正原因，所以就编了这句话来误导我们。<BR><BR>很多人可能认为我是在胡说八道，好，让我用100个例子来证实你们的错误吧！事实胜 <BR>于雄辩。<BR><BR>世界上最富有的人，比尔盖茨，他是个程序员，懒的读书，他就退学了。他又懒的记那 <BR>些复杂的dos命令，于是，他就编了个图形的界面程序，叫什么来着？我忘了，懒的记 <BR>这些东西。于是，全世界的电脑都长着相同的脸，而他也成了世界首富。<BR><BR>世界上最值钱的品牌，可口可乐。他的老板更懒，尽管中国的茶文化历史悠久，巴西的 <BR>咖啡香味浓郁，但他实在太懒了。弄点糖精加上凉水，装瓶就卖。于是全世界有人的地 <BR>方，大家都在喝那种像血一样的液体。<BR><BR>世界上最好的足球运动员，罗纳耳朵，他在场上连动都懒的动，就在对方的门前站着。 <BR>等球砸到他的时候，踢一脚。这就是全世界身价最高的运动员了。有的人说，他带球的 <BR>速度惊人，那是废话，别人一场跑90分钟，他就跑15秒，当然要快些了。<BR><BR>世界上最厉害的餐饮企业，麦当劳。他的老板也是懒的出奇，懒的学习法国大餐的精 <BR>美，懒的掌握中餐的复杂技巧。弄两片破面包夹块牛肉就卖，结果全世界都能看到那个 <BR>M的标志。必胜客的老板，懒的把馅饼的馅装进去，直接撒在发面饼上边就卖，结果大 <BR>家管那叫PIZZA,比10张馅饼还贵。<BR><BR>还有更聪明的懒人：<BR><BR>懒的爬楼，于是他们发明了电梯；<BR><BR>懒的走路，于是他们制造出汽车，火车，和飞机；<BR><BR>懒的一个一个的杀人，于是他们发明了原子弹；<BR><BR>懒的每次去计算，于是他们发明了数学公式；<BR><BR>懒的出去听音乐会，于是他们发明了唱片，磁带和CD<BR><BR>这样的例子太多了，我都懒的再说了。<BR><BR>还有那句废话也要提一下，生命在于运动，你见过哪个运动员长寿了？世界上最长寿的 <BR>人还不是那些连肉都懒的吃的和尚？<BR><BR>如果没有这些懒人，我们现在生活在什么样的环境里，我都懒的想！人是这样，动物也 <BR>如此。世界上最长寿的动物叫乌龟，他们一辈子几乎不怎么动，就趴在那里，结果能活 <BR>一千年。他们懒的走，但和勤劳好动的兔子赛跑，谁赢了？牛最勤劳，结果人们给它吃 <BR>草，却还要挤它的奶。熊猫傻了吧唧的，什么也不干，抱着根竹子能啃一天，人们亲昵 <BR>的称它为“国宝“。<BR><BR>我以上所举的例子，只是想说明一个问题，这个世界实际上是靠懒人来支撑的。世界如 <BR>此的精彩都是拜懒人所赐。现在你应该知道你不成功的主要原因了吧！<BR><BR>懒不是傻懒，如果你想少干，就要想出懒的方法。要懒出风格，懒出境界。像我从小就 <BR>懒，连长肉都懒的长，这就是境界。<BR><BR>再次感谢大家！” </FONT><BR></FONT>]]></description>
</item><item>
<title><![CDATA[通过Toolhelp API 查看本地进程的程序(VC 6.0 编译通过）]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=8934</link>
<author>codebee</author>
<pubDate>2005/10/1 11:28:10</pubDate>
<description><![CDATA[<P>#include &lt;windows.h&gt;<BR>#include &lt;tlhelp32.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;//toolhelp API 头文件<BR>#include "stdio.h"</P>
<P>int main()<BR>{<BR>&nbsp;HANDLE hSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //建立进程快照<BR>&nbsp;PROCESSENTRY32 pe;&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; //定义一个PROCESSENTRY32结构<BR>&nbsp;pe.dwSize = sizeof(pe);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//初始化<BR>&nbsp;BOOL bNext=Process32First(hSnap, &amp;pe);&nbsp;&nbsp;&nbsp;&nbsp;//得到第一个进程</P>
<P>&nbsp;while (bNext)<BR>&nbsp;{<BR>&nbsp;printf("\n%-20s%d",pe.szExeFile,pe.th32ProcessID);&nbsp;//显示<BR>&nbsp;bNext= Process32Next(hSnap, &amp;pe);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//得到下一个进程<BR>&nbsp;}<BR>&nbsp;return 0;<BR>&nbsp;}</P>]]></description>
</item><item>
<title><![CDATA[论坛的十个基本礼节!(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=8845</link>
<author>codebee</author>
<pubDate>2005/9/28 11:56:28</pubDate>
<description><![CDATA[
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>转载自: <A href="http://bbs.berryz.cn/viewthread.php?tid=11586&amp;fpage=1" target=_blank>http://bbs.berryz.cn/viewthread.php?tid=11586&amp;fpage=1</A><BR><BR><B>礼节一：记住别人的存在 </B><BR>　 <BR>互联网给予来自五湖四海人们一个共同的地方聚集， <BR><BR>这是高科技的优点但往往也使得我们面对着电脑银屏忘了我们是在跟其他人打交道， <BR><BR>我们的行为也因此容易变得更粗劣和无礼。 <BR><BR>因此《网络礼节》第一条就是“记住人的存在”。如果你当着面不会说的话在网上也不要说。 <BR><BR><B>礼节二：网上网下行为一致 </B><BR><BR>在现实生活中大多数人都是尊法守纪，同样地在网上也同样如此。 <BR><BR>网上的道德和法律与现实生活是相同的，不要以为在网上与电脑交易就可以降低道德标准。 <BR><BR><B>礼节三：入乡随俗</B> <BR><BR>同样是网站，不同的论坛有不同的规则。 <BR><BR>在一个论坛可以做的事情在另一个论坛可能不宜做。 <BR><BR>最好的建议：先爬一会儿墙头再发言，这样你可以知道坛子的气氛和可以接受的行为。 <BR><BR><B>礼节四：尊重别人的时间和带宽</B> <BR><BR>在提问题以前，先自己花些时间去搜索和研究。 <BR><BR>很有可能同样问题以前已经问过多次，现成的答案随手可及。 <BR><BR>不要以自我为中心，别人为你寻找答案需要消耗时间和资源。 <BR><BR><B>礼节五：给自己网上留个好印象</B> <BR>　 <BR>因为网络的匿名性质，别人无法从你的外观来判断，因此你一言一语成为别人对你印象的唯一判断。 <BR><BR>如果你对某个方面不是很熟悉，找几本书看看再开口，无的放矢只能落个灌水王帽子。 <BR><BR>同样地，发帖以前仔细检查语法和用词。不要故意挑衅和使用脏话。 <BR><BR><B>礼节六：分享你的知识</B> <BR><BR>除了回答问题以外，这还包括当你提了一个有意思的问题而得到很多回答， <BR><BR>特别是通过电子邮件得到的以后你应该写份总结与大家分享。 <BR><BR><B>礼节七：平心静气地争论</B> <BR><BR>争论与大战是正常的现象。要以理服人，不要人身攻击。 <BR><BR><B>礼节八：尊重他人的隐私</B> <BR><BR>别人与你用电子邮件或私聊(MSN/QQ)的记录应该是隐私一部分。 <BR><BR>如果你认识某个人用笔名上网，在论坛未经同意将他的真名公开也不是一个好的行为。 <BR><BR>如果不小心看到别人打开电脑上的电子邮件或秘密，你不应该到处广播。 <BR><BR><B>礼节九：不要滥用权利</B> <BR><BR>管理员版主比其他用户有更多权利，应该珍惜使用这些权利。 <BR><BR><B>礼节十：宽容</B> <BR><BR>我们都曾经是新手，都会有犯错误的时候。 <BR><BR>当看到别人写错字，用错词，问一个低级问题或者写篇没必要的长篇大论时，你不要在意。 <BR><BR>如果你真的想给他建议，最好用电子邮件私下提议。 <BR></TD></TR></TBODY></TABLE>]]></description>
</item><item>
<title><![CDATA[利用钩子函数来捕捉键盘响应的windows应用程序.(转)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=8844</link>
<author>codebee</author>
<pubDate>2005/9/28 11:53:00</pubDate>
<description><![CDATA[一：引言： 
<P></P>
<P>你也许一直对金山词霸的屏幕抓词的实现原理感到困惑，你也许希望将你的键盘，鼠标的活动适时的记录下来，甚至你想知道木马在windows操作系统是怎样进行木马dll的加载的…..其实这些都是用到了windows的钩子函数。因此本文将对钩子函数的相关知识进行阐述。当然，本文的目的并不是想通过此程序让读者去窃取别人的密码，只是由于钩子函数在windows系统中是一个非常重要的系统接口函数，所以想和大家共同的探讨，当然本文也对怎样建立动态连结库（DLL）作了一些简单的描述。（本文的程序为vc6.0的开发环境，语言是：C和win32&nbsp;api）。</P>
<P>二：钩子概述：</P>
<P>微软的windowsX操作系统是建立在事件驱动的机制上的，也就是通过消息传递来实现。而钩子在windows操作系统中，是一种能在事件（比如：消息、鼠标激活、键盘响应）到达应用程序前中途接获事件的机制。而且，钩子函数还可以通过修改、丢弃等手段来对事件起作用。<BR>Windows&nbsp;有两种钩子，一种是特定线程钩子（Thread&nbsp;specific&nbsp;hooks），一种是全局系统钩子(Systemwide&nbsp;hooks)。特定线程钩子只是监视指定的线程，而全局系统钩子则可以监视系统中所有的线程。无论是特定线程钩子，还是全局系统钩子，都是通过SetWindowsHookEx&nbsp;()来设置钩子的。对于特定线程钩子，钩子的函数既可以是包含在一个.exe也可以是一个.dll。但是对于一个全局系统钩子，钩子函数必须包含在独立的dll中，因此，当我们要捕捉键盘响应时，我们必须创建一个动态链接库。但是当钩子函数在得到了控制权，并对相关的事件处理完后，如果想要该消息得以继续的传递，那么则必须调用另一个函数：CallNextHookEx。由于系统必须对每个消息处理，钩子程序因此增加了处理的负担，因此也降低了系统的性能。鉴于这一点，在windows&nbsp;ce中对钩子程序并不支持。所以当程序完成并退出时，应当释放钩子，调用函数：UnhookWindowsHookEx。<BR>下面我们将举一个例子（捕捉键盘）来详细的讲解钩子函数的程序设计。</P>
<P>三：程序的设计：</P>
<P>I:设置钩子</P>
<P>设置钩子是通过SetWindowsHookEx&nbsp;()的API函数.<BR>原形:&nbsp;HHOOK&nbsp;SetWindowsHookEx(int&nbsp;idHook,HOOKPROC&nbsp;lpfn,HINSTANCE&nbsp;hMod,DWORD&nbsp;dwThreadId)<BR>idhook:装入钩子的类型.<BR>lpfn:&nbsp;钩子进程的入口地址<BR>hMod:&nbsp;应用程序的事件句柄<BR>dwThreadId:&nbsp;装入钩子的线程标示</P>
<P>参数：<BR>idHook:<BR>这个参数可以是以下值：<BR>WH_CALLWNDPROC、WH_CALLWNDPROCRET、WH_CBT、WH_DEBUG、WH_FOREGROUNDIDLE、WH_GETMESSAGE、WH_JOURNALPLAYBACK、WH_JOURNALRECORD、WH_KEYBOARD、WH_KEYBOARD_LL、WH_MOUSE、WH_MOUSE_LL、WH_MSGFILTER、WH_SHELL、WH_SYSMSGFILTER。<BR>对于这些参数，我不想一一加以解释，因为MSDN中有关于他们的详细注解。我只挑选其中的几个加以中文说明。<BR>WH_KEYBOARD：一旦有键盘敲打消息（键盘的按下、键盘的弹起），在这个消息被放在应用程序的消息队列前，WINDOWS将会调用你的钩子函数。钩子函数可以改变和丢弃键盘敲打消息。<BR>WH_MOUSE：每个鼠标消息在被放在应用程序的消息队列前，WINDOWS将会调用你的钩子函数。钩子函数可以改变和丢弃鼠标消息。</P>
<P>WH_GETMESSAGE：每次当你的应用程序调用一个GetMessage()或者一个PeekMessage()为了去从应用程序的消息队列中要求一个消息时，WINDOWS都会调用你的钩子函数。而钩子函数可以改变和丢弃这个消息。</P>
<P>II:释放钩子</P>
<P>钩子的释放使用的是UnhookWindowsHookEx（）函数<BR>原形：BOOL&nbsp;UnhookWindowsHookEx(&nbsp;HHOOK&nbsp;hhk&nbsp;)<BR>UnhookWindowsHookEx（）函数将释放的是钩子链中函数SetWindowsHookEx所装入的钩子进程。<BR>hhk:&nbsp;将要释放的钩子进程的句柄。</P>
<P>III：钩子进程</P>
<P>钩子进程使用函数HookProc;其实HookProc仅仅只是应用程序定义的符号。比如你可以写成KeyBoardHook.但是参数是不变的。Win32&nbsp;API提供了诸如：CallWndProc、GetMsgProc、DebugProc、CBTProc、MouseProc、KeyboardProc、MessageProc等函数，对于他们的详细讲解，可以看MSDN我在此只讲解一下KeyBoardHook的含义。<BR>原形：LRESULT&nbsp;CALLBACK&nbsp;KeyBoardHook&nbsp;(int&nbsp;nCode,&nbsp;WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam)<BR>说明：钩子进程是一些依附在一个钩子上的一些函数，因此钩子进程只被WINDOWS调用而不被应用程序调用，他们有时就需要作为一个回调函数（CALLBACK）。</P>
<P>参数说明：<BR>nCode:钩子代码，钩子进程使用钩子代码去决定是否执行。而钩子代码的值是依靠钩子的种类来定的。每种钩子种类都有他们自己一系列特性的代码。比如对于WH_KEYBOARD，钩子代码的参数有：HC_ACTION，HC_NOREMOVE。HC_ACTION的意义：参数wParam&nbsp;和lParam&nbsp;包含了键盘敲打消息的信息，HC_NOREMOVE的意义：参数wParam&nbsp;和lParam包含了键盘敲打消息的信息，并且，键盘敲打消息一直没有从消息队列中删除。(应用程序调用PeekMessage函数，并且设置PM_NOREMOVE标志)。也就是说当nCode等于HC_ACTION时，钩子进程必须处理消息。而为HC_NOREMOVE时，钩子进程必须传递消息给CallNextHookEx函数，而不能做进一步的处理，而且必须有CallNextHookEx函数的返回值。&nbsp;<BR>wParam:键盘敲打所产生的键盘消息，键盘按键的虚拟代码。<BR>lParam:包含了消息细节。</P>
<P>注意:如果钩子进程中nCode小于零，钩子进程必须返回(return)&nbsp;CallNextHookEx(nCode,wParam,lParam);而钩子进程中的nCode大于零，但是钩子进程并不处理消息，作者推荐你调用CallNextHookEx并且返回该函数的返回值。否则，如果另一个应用程序也装入WH_KEYBOARD&nbsp;钩子，那么该钩子将不接受钩子通知并且返回一个不正确的值。如果钩子进程处理了消息，它可能返回一个非零值去阻止系统传递该信息到其它剩下的钩子或者windows进程。所以最好在钩子进程的最后都返回CallNextHookEx的返回值。&nbsp;</P>
<P>IV:调用下一个钩子函数</P>
<P>调用下一个钩子函数时使用CallNexHookEx函数。<BR>原形：LRESULT&nbsp;CallNextHookEx(&nbsp;HHOOK&nbsp;hhk,&nbsp;int&nbsp;nCode,&nbsp;WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam&nbsp;)<BR>CallNexHookEx()函数用于对当前钩子链中的下一个钩子进程传递钩子信息，一个钩子进程既可以在钩子信息处理前，也可以在钩子信息处理后调用该函数。为什么使用该函数已在iii钩子进程中的“注意”中，加以了详细的说明。<BR>hhk:&nbsp;当前钩子的句柄<BR>nCode:&nbsp;传送到钩子进程的钩子代码。<BR>wParam:传送到钩子进程的值。<BR>lParam:传送到钩子进程的值。<BR>参数：<BR>hhk:&nbsp;当前钩子的句柄.&nbsp;应用程序接受这个句柄，作为先前调用SetWindowsHookE函数的结果&nbsp;<BR>nCode:&nbsp;传送到钩子进程的钩子代码，下一个钩子进程使用这个代码以此决定如何处理钩子信息&nbsp;<BR>wParam:传送给钩子进程的wParam&nbsp;参数值&nbsp;，参数值的具体含义与当前钩子链的挂接的钩子类型有关<BR>lParam&nbsp;:&nbsp;传送给钩子进程的wParam&nbsp;参数值&nbsp;，参数值的具体含义与当前钩子链的挂接的钩子类型有关&nbsp;<BR>返回值：返回值是链中下一个钩子进程返回的值，当前钩子进程必须返回这个值，返回值的具体含义与挂接的钩子类型有关，详细信息请参看具体的钩子进程描述。</P>
<P>V&nbsp;建立一个动态连接库（DLL）</P>
<P>当我们熟悉了以上的各个函数后，现在我们开始编写一个动态连接库（DLL）。在这儿我采用的是WIN32&nbsp;DLL,而不是MFC&nbsp;DLL。而且以下所有的程序也都是采用C语言去编写。这主要是因为使用WIN32&nbsp;API能够更详细、更全面的控制程序的如何执行，而使用MFC，一些低级的控制是不可能实现的(当然，仅对该程序来说，也是可以使用MFC的)。</P>
<P>1：建立一个动态连接库的.cpp文件。比如我们现在建立一个名为hookdll.cpp的文件。在hookdll.cpp的文件中加上如下内容：<BR>#include&nbsp;&lt;windows.h&gt;<BR>#include&nbsp;"string.h"<BR>#include&nbsp;"stdio.h"&nbsp;</P>
<P>HINSTANCE&nbsp;hInst;</P>
<P>#pragma&nbsp;data_seg("hookdata")<BR>HHOOK&nbsp;oldkeyhook=0;<BR>#pragma&nbsp;data_seg()</P>
<P>#pragma&nbsp;comment(linker,"/SECTION:hookdata,RWS")</P>
<P>#define&nbsp;DllExport&nbsp;extern&nbsp;"C"__declspec(dllexport)</P>
<P>DllExport&nbsp;LRESULT&nbsp;CALLBACK&nbsp;KeyBoardProc(int&nbsp;nCode,WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam&nbsp;);<BR>DllExport&nbsp;void&nbsp;InstallHook(int&nbsp;nCode);<BR>DllExport&nbsp;void&nbsp;EndHook(void);</P>
<P>BOOL&nbsp;WINAPI&nbsp;DllMain(HINSTANCE&nbsp;hInstance,ULONG&nbsp;What,LPVOID&nbsp;NotUsed)<BR>{<BR>switch(What)<BR>{<BR>case&nbsp;DLL_PROCESS_ATTACH:<BR>hInst&nbsp;=&nbsp;hInstance;<BR>break;<BR>case&nbsp;DLL_PROCESS_DETACH:<BR>break;<BR>case&nbsp;DLL_THREAD_ATTACH:<BR>break;<BR>case&nbsp;DLL_THREAD_DETACH:<BR>break;&nbsp;</P>
<P>}<BR>return&nbsp;1;<BR>}</P>
<P>void&nbsp;InstallHook(int&nbsp;nCode)<BR>{<BR>oldkeyhook&nbsp;=&nbsp;SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyBoardProc,hInst,0);<BR>}</P>
<P>DllExport&nbsp;LRESULT&nbsp;CALLBACK&nbsp;KeyBoardProc(int&nbsp;nCode,WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam&nbsp;)<BR>{<BR>WPARAM&nbsp;j;<BR>FILE&nbsp;*fp;<BR>if(lParam&amp;0x80000000)<BR>{<BR>j&nbsp;=&nbsp;wParam;<BR>fp=fopen("c:\\hook\\key.txt","a");&nbsp;<BR>fprintf(fp,"%4d",j);<BR>fclose(fp);<BR>}<BR>return&nbsp;CallNextHookEx(oldkeyhook,nCode,wParam,lParam);<BR>}<BR>void&nbsp;EndHook(void)<BR>{<BR>UnhookWindowsHookEx(oldkeyhook);<BR>}<BR>这个动态连接库的源代码hookdll.cpp包含了键盘处理函数，设置钩子，退出钩子函数。并将键盘敲下的键以值的格式存入到c:\hook\key.txt文件中。以下是对该文件的详细的解释。<BR>使用包含在DLL的函数，必须将其导入。导入操作时通过dllimport来完成的，dllexport和dllimport都是vc（visual&nbsp;C++）和bc（Borland&nbsp;C++）所支持的扩展的关键字。但是dllexport和dllimport关键字不能被自身所使用，因此它的前面必须有另一个扩展关键字__declspec。通用格式如下：__declspec(specifier)其中specifier是存储类标示符。对于DLL，specifier将是dllexport和dllimport。而且为了简化说明导入和导出函数的语句，用一个宏名来代替__declspec.在此程序中，使用的是DllExport。如果用户的DLL被编译成一个C++程序，而且希望C程序也能使用它，就需要增加“C”的连接说明。#define&nbsp;DllExport&nbsp;extern&nbsp;"C"__declspec(dllexport)，这样就避免了标准C++命名损坏。（当然，如果读者正在编译的是C程序，就不要加入extern&nbsp;“C”,因为不需要它，而且编译器也不接受它）。有了宏定义，现在就可以用一个简单的语句就可以导出函数了，比如：DllExport&nbsp;LRESULT&nbsp;CALLBACK&nbsp;KeyBoardProc(int&nbsp;nCode,WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam&nbsp;)；DllExport&nbsp;void&nbsp;InstallHook(int&nbsp;nCode);DllExport&nbsp;void&nbsp;EndHook(void);<BR>第一个#pragma&nbsp;语句创造数据段，这里命名为hookdata。其实也可以命名为您喜欢的任意的一个名称。#pragma&nbsp;语句之后的所有初始化的变量都进入hookdata段中。第二个#pragma语句是数据段的结束标志。对变量进行专门的初始化是很重要的，否则编译程序将把它们放在普通的未初始化的段中而不是放在hookdata中。<BR>但是链接程序必须直到有一个hookdata段。我们可以在Project&nbsp;Setting（vc6.0）&nbsp;对话框中选择Link选项，选中HOOKDLL时在Project&nbsp;Options域（在Release&nbsp;和Debug配置中均可），包含下面的连接语句：/SECTION:hookdata,RWS字母RWS是表明该段具有读、写、和共享属性。当然，您也可以直接用DLL源代码指定链接程序就像HOOKDLL.c那样：#pragma&nbsp;comment(linker,"/SECTION:hookdata,RWS")。<BR>由于有些DLL需要特殊的启动和终止代码。为此，所有的DLL都有一个名为DllMain()的函数，当初始化或终止DLL时调用该函数。一般在动态连结库的资源文件中定义此函数。不过如果没有定义它，则编译器会自动提供缺省的形式。<BR>原型为：BOOL&nbsp;WINAPI&nbsp;DllMain(HINSTANCE&nbsp;hInstance,ULONG&nbsp;What,LPVOID&nbsp;NotUsed)<BR>参数：<BR>hInstance：DLL实例句柄<BR>What:指定所发生的操作<BR>NotUsed:保留参数<BR>其中What的值可以为以下值：<BR>DLL_PROCESS_ATTACH:进程开始使用DLL<BR>DLL_PROCESS_DETACH:进程正在释放DLL<BR>DLL_THREAD_ATTACH:进程已创建一个新的线程<BR>DLL_THREAD_DETACH:进程已舍弃了一个线程<BR>总的来说，无论何时调用DllMain()函数，都必须根据What的内容来采取适当的动作。这种适当的动作可以什么都不做，但不是返回非零值。&nbsp;<BR>DllMain()接下来的便是设置钩子，键盘处理，和释放钩子。</P>
<P>2：建立头文件<BR>正如应用程序所使用的其它任何库函数一样，程序也必须包含dll内的函数的原型。所有得Windows程序都必须包含windows.h的原因。所以我们现在建立一个头文件hookdll.h如下：<BR>#define&nbsp;DllImport&nbsp;extern"C"__declspec(dllimport)<BR>DllImport&nbsp;void&nbsp;InstallHook(int&nbsp;nCode);<BR>DllImport&nbsp;LRESULT&nbsp;CALLBACK&nbsp;KeyBoardProc&nbsp;(int&nbsp;nCode,WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam&nbsp;);<BR>DllImport&nbsp;void&nbsp;EndHook(void);<BR>使用dllimport主要是为了使代码更高效，因此推荐使用它。但是在导入数据时是需要dllimport的。当完成了上面的程序后，建一个项目工程，不妨为hookdll，然后将hookdll.c插入导项目工程中，编译，则可以生成了hookdll.dll和hookdll.lib。</P>
<P>3：建立程序主文件<BR>我们在上面作的所有得工作都是为现在的主程序打得基础。其实当我们完成了Dll文件后，剩下的就是调用设置钩子函数：InstallHook&nbsp;。如果你对windows编程十分的熟悉，那么你可以在你任何需要的时候来调用InstallHook。但是在你必须记住在你退出程序的时候你需要调EndHook以便释放你所装入的钩子函数。现在我在建立了一个hookspy.cpp，并将生成好的hookdll.dll和hookdll.lib拷贝到从一个目录下，并建立一个hookspy的项目工程。将hookspy.cpp,hookdll.dll,hookdll.lib,hookdll.h插入到项目工程中去。然后在建立windows窗口时就将钩子设置，在退出程序时退出钩子函数。比如：<BR>case&nbsp;WM_CREATE:<BR>InstallHook(TRUE);<BR>break;<BR>case&nbsp;WM_DESTROY:&nbsp;//terminate&nbsp;the&nbsp;program<BR>EndHook();<BR>PostQuitMessage(0);<BR>break;</P>]]></description>
</item><item>
<title><![CDATA[关于学习...]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=codebee&amp;id=8842</link>
<author>codebee</author>
<pubDate>2005/9/28 11:43:14</pubDate>
<description><![CDATA[
<P>开始学习编程序，可能入门了吧。</P>
<P>刚上大学学习了c，小试牛刀的得了学院c程序设计的第一名。幸哉~！</P>
<P>到了大二，学了c++，这次参加学校比赛又得了第一，进入了学校的程序训练队。</P>
<P>进入已后，发现意思不大，毅然退出。错误？？</P>
<P>现在，在学Win32API,MFC,头都大了，不是难，是熟练很难。</P>
<P>这几天在做钩子程序，写了WIN32API的，又要写基于MFC。</P>
<P>我相信熟能生巧这个道理。</P>
<P>现在缺的，是时间...</P>
<P>&nbsp;</P>]]></description>
</item>
</channel>
</rss>