<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Architecting Life &#187; Desktop</title>
	<atom:link href="http://xujiwei.com/blog/posts/develop/desktop/feed/" rel="self" type="application/rss+xml" />
	<link>http://xujiwei.com/blog</link>
	<description>Just do it</description>
	<lastBuildDate>Thu, 05 Apr 2012 17:19:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>在 Mac App 中支持全屏和文件版本控制</title>
		<link>http://xujiwei.com/blog/support-lion-fullscreen-and-versions-in-map-app/</link>
		<comments>http://xujiwei.com/blog/support-lion-fullscreen-and-versions-in-map-app/#comments</comments>
		<pubDate>Thu, 05 Apr 2012 17:19:13 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Mac OS & iOS]]></category>
		<category><![CDATA[Lion]]></category>
		<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Versions]]></category>

		<guid isPermaLink="false">http://xujiwei.com/blog/?p=545</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/support-lion-fullscreen-and-versions-in-map-app/" title="在 Mac App 中支持全屏和文件版本控制"></a>前言 在 Mac OS X 10.7 Lion 中，新增了两个特性对用户来说可能比较有用的特性，一个是全屏程序，一个是文件版本控制。 全屏程序可以使用户集中注意力到一个程序上，并且隐藏菜单栏、Dock 等不相关的界面元素，使得工作区最大化，更加有效地利用有限的屏幕空间。 文件版本控制可以让用户在不借助于 Time Machine、Git 或者 SVN 这些工具的时候，也可以轻松恢复文件到之前保存过的版本，防止一些误操作删除了重要内容。 全屏程序 全屏功能可以让程序以全屏方式显示，这样用户可以拥有最大的操作区域，并隐藏与程序无关的视觉元素。 在全屏方式下，Dock 和菜单栏都会自动隐藏，可以通过将鼠标移动到屏幕边缘的方式来重新显示 Dock 或者菜单栏。 目前全屏程序有一个问题是在使用双屏的情况下，有一个屏幕会无法使用，只能显示背景图片，而不能同时使用两个屏幕，或者将另外一个程序全屏在另一个屏幕。 另外，全屏程序切换是使用水平动画切换，对我来说可能动作太大，不是很习惯，这是题外话了。 要设置一个 App 支持全屏很简单，只需要设置对应 Window 的属性即可。 Full Screen 有两种模式，分别为 NSWindowCollectionBehaviorFullScreenPrimary 和 NSWindowCollectionBehaviorFullScreenAuxiliary，其中多数时候只需要使用 NSWindowCollectionBehaviorFullScreenPrimary 即可。 在设置 NSWindowCollectionBehaviorFullScreenPrimary 后，就会在相应的 &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/support-lion-fullscreen-and-versions-in-map-app/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/support-lion-fullscreen-and-versions-in-map-app/" title="在 Mac App 中支持全屏和文件版本控制"></a><h2>前言</h2>

<p>在 Mac OS X 10.7 Lion 中，新增了两个特性对用户来说可能比较有用的特性，一个是全屏程序，一个是文件版本控制。</p>

<p>全屏程序可以使用户集中注意力到一个程序上，并且隐藏菜单栏、Dock 等不相关的界面元素，使得工作区最大化，更加有效地利用有限的屏幕空间。</p>

<p>文件版本控制可以让用户在不借助于 Time Machine、Git 或者 SVN 这些工具的时候，也可以轻松恢复文件到之前保存过的版本，防止一些误操作删除了重要内容。</p>

<h2>全屏程序</h2>

<p>全屏功能可以让程序以全屏方式显示，这样用户可以拥有最大的操作区域，并隐藏与程序无关的视觉元素。</p>

<p>在全屏方式下，Dock 和菜单栏都会自动隐藏，可以通过将鼠标移动到屏幕边缘的方式来重新显示 Dock 或者菜单栏。</p>

<p>目前全屏程序有一个问题是在使用双屏的情况下，有一个屏幕会无法使用，只能显示背景图片，而不能同时使用两个屏幕，或者将另外一个程序全屏在另一个屏幕。</p>

<p>另外，全屏程序切换是使用水平动画切换，对我来说可能动作太大，不是很习惯，这是题外话了。</p>

<p>要设置一个 App 支持全屏很简单，只需要设置对应 Window 的属性即可。</p>

<p><a href="http://xujiwei.com/blog/wp-content/uploads/2012/04/Snip20120406_2.png"><img src="http://xujiwei.com/blog/wp-content/uploads/2012/04/Snip20120406_2.png" alt="" title="Snip20120406_2" width="392" height="476" class="alignnone size-full wp-image-550" /></a></p>

<p>Full Screen 有两种模式，分别为 <code>NSWindowCollectionBehaviorFullScreenPrimary</code> 和 <code>NSWindowCollectionBehaviorFullScreenAuxiliary</code>，其中多数时候只需要使用 <code>NSWindowCollectionBehaviorFullScreenPrimary</code> 即可。</p>

<p>在设置 <code>NSWindowCollectionBehaviorFullScreenPrimary</code> 后，就会在相应的 Window 右上角显示一个全屏按钮，用户通过这个按钮就可以切换程序到全屏方式使用。</p>

<h3>全屏模式切换菜单</h3>

<p>有些时候，为了用户使用方便，需要设置一个快捷键，或者菜单来供用户进行全屏模式的切换，这时，只需要添加一个 NSMenuItem 到主菜单的 View 菜单中，将 selector 连接到 First Responder 的 <code>toggleFullScreen:</code> 即可。</p>

<p><a href="http://xujiwei.com/blog/wp-content/uploads/2012/04/Snip20120406_3.png"><img src="http://xujiwei.com/blog/wp-content/uploads/2012/04/Snip20120406_3.png" alt="" title="Snip20120406_3" width="637" height="282" class="alignnone size-full wp-image-551" /></a></p>

<p>Cocoa 在运行时会自动寻找 View 菜单中 selector 为 <code>toggleFullScreen:</code> 的菜单项目，并根据当前窗体的显示情况来自动更新菜单标题为 Enter Full Screen 或 Exit Full Screen。</p>

<h2>文件版本控制</h2>

<p>在 Lion 中对普通用户来说，一个非常有用的特性就是文件版本控制了。在不需要 Time Machine，不需要 Git、SVN 等版本控制参与的情况下，只需要程序支持这个功能，就可以直接找回编辑过文件的以前版本。</p>

<p>在文件版本控制之后，其实是自动保存功能在起作用，要实现文件版本控制，只需要 Mac App 实现自动保存即可，文件版本的控制会有框架来做，不需要开发者过多参与。</p>

<p>对于 NSDocument based 的 Mac App 来说，要实现文件自动保存，一般情况下，只需要在 NSDocument 的子类中实现以下方法就行了：</p>

<pre><code>+ (BOOL)autosavesInPlace {
    return YES:
}
</code></pre>

<p>当然，这是在 Mac App 中，是以 NSDocument 提供的诸如 <code>- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError</code> 或者 <code>- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError</code> 来保存文件内容为基础，而不是自己去实现写文件内容到磁盘，那样的话就算有 autosaveInPlace 也是不行的。</p>

<p>另外，同样需要使用 <code>- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError</code> 等 NSDocument 提供的 API 来获取内容。</p>

<p><a href="http://xujiwei.com/blog/wp-content/uploads/2012/04/Snip20120406_4.png"><img src="http://xujiwei.com/blog/wp-content/uploads/2012/04/Snip20120406_4.png" alt="" title="Snip20120406_4" width="1192" height="592" class="alignnone size-full wp-image-552" /></a></p>

<p>另外，在 NSWindowDelegate 也有一些新的方法，可以控制程序在浏览文件的以往版本时，控制程序窗口的样式，例如大小，设置控件的状态等。例如，在默认情况下，浏览文件以往版本会改变当前文档窗口的大小，而如果不想修改文档窗口大小，只是缩放显示的话，可以在 <code>window:willResizeForVersionBrowserWithMaxPreferredSize:maxAllowedSize:</code> 方法中指定窗口要变化到的目标大小：</p>

<pre><code>- (NSSize)window:(NSWindow *)window willResizeForVersionBrowserWithMaxPreferredSize:(NSSize)maxPreferredFrameSize maxAllowedSize:(NSSize)maxAllowedFrameSize {
    NSSize winSize = [window frame].size;
    return winSize;
}
</code></pre>

<p>NSWindowDelegate 的 <strong>Managing Presentation in Version Browsers</strong> 一节中，还有另外一个 delegate 方法，可以得知当前文档窗口正在进入版本浏览，或者退出版本浏览等状态，从而可以设置界面控件，将一些无关的界面元素隐藏，使用户可以更加清晰的观察到文件不同版本之间的差别。</p>

<p>要实现文件版本控制的支持，开发者并没有很多工作需要做，多数功能已经由框架实现。</p>

<h2>参考资料</h2>

<ul>
<li><a href="http://developer.apple.com/library/mac/#documentation/General/Conceptual/MOSXAppProgrammingGuide/FullScreenApp/FullScreenApp.html">Implementing the Full-Screen Experience</a></li>
<li><a href="http://oleb.net/blog/2011/07/whats-new-for-developers-in-lion-part-1/">What&#8217;s New for Developers in Mac OS X Lion (Part 1)</a></li>
</ul>

<p>&#8211; EOF &#8211;</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/support-lion-fullscreen-and-versions-in-map-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>REALbasic 中使用结构体作为 Win32 API 的参数及使用 Win32 API 停止服务</title>
		<link>http://xujiwei.com/blog/using-win32-api-in-realbasic/</link>
		<comments>http://xujiwei.com/blog/using-win32-api-in-realbasic/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 15:47:42 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[REALbasic]]></category>
		<category><![CDATA[Win32]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=65</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/using-win32-api-in-realbasic/" title="REALbasic 中使用结构体作为 Win32 API 的参数及使用 Win32 API 停止服务"></a>在之前，我使用 ShellExecute 这个 API 来执行命令（《REALbasic 中使用 ShellExecute 执行命令》），然后通过这个方法来停止某个服务，但是今天想加服务运行状态检测，这样就可以在服务没有运行的情况下不再询问用户是否需要停止某个服务。 为了省事，我一开始决定同样使用 cmd 去执行一个命令，将服务状态输出到一个临时文件中，再通过读取这个临时文件，查找特征字符串来判断服务是否运行： // 伪代码 ShellExecute(&#34;cmd.exe /c sc query service_name &#38;gt; tmpfile&#34;) dim serviceStatus as string serviceStatus = TextInputStream.Open(tmpfile).ReadAll() if instr(serviceStatus, &#34;STOPPED&#34;) &#38;lt; 1 then // 提示用户是否停止服务 end if 但是这样做不太靠谱，因为 sc 这个命令执行是要时间的，而 &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/using-win32-api-in-realbasic/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/using-win32-api-in-realbasic/" title="REALbasic 中使用结构体作为 Win32 API 的参数及使用 Win32 API 停止服务"></a><p>在之前，我使用 ShellExecute 这个 API 来执行命令（《REALbasic 中使用 ShellExecute 执行命令》），然后通过这个方法来停止某个服务，但是今天想加服务运行状态检测，这样就可以在服务没有运行的情况下不再询问用户是否需要停止某个服务。</p>

<p>为了省事，我一开始决定同样使用 cmd 去执行一个命令，将服务状态输出到一个临时文件中，再通过读取这个临时文件，查找特征字符串来判断服务是否运行：</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">// 伪代码
ShellExecute(<span style="color: #800000;">&quot;cmd.exe /c sc query service_name &amp;gt; tmpfile&quot;</span>)
<span style="color: #151B8D; font-weight: bold;">dim</span> serviceStatus <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">string</span>
serviceStatus = TextInputStream.<span style="color: #151B8D; font-weight: bold;">Open</span>(tmpfile).ReadAll()
<span style="color: #8D38C9; font-weight: bold;">if</span> instr(serviceStatus, <span style="color: #800000;">&quot;STOPPED&quot;</span>) &amp;lt; 1 <span style="color: #8D38C9; font-weight: bold;">then</span>
  // 提示用户是否停止服务
<span style="color: #8D38C9; font-weight: bold;">end</span> <span style="color: #8D38C9; font-weight: bold;">if</span></pre></div></div>


<p>但是这样做不太靠谱，因为 sc 这个命令执行是要时间的，而 ShellExecute 是异步的，这就导致了在调用 ShellExecute 执行完 sc query 之后，临时文件 tmpfile 里并不是马上就有服务状态的内容了。</p>

<p>为了防止这个情况，我再加了一个临时文件内容的检测，如果为空的话，sleep 100ms，再继续读取，如果超过 10 次仍没有内容，直接当作服务正在运行来对待。</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">// 伪代码
ShellExecute(<span style="color: #800000;">&quot;cmd.exe /c sc query service_name &amp;gt; tmpfile&quot;</span>)
<span style="color: #151B8D; font-weight: bold;">dim</span> serviceStatus <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">string</span>
<span style="color: #151B8D; font-weight: bold;">dim</span> tryCount <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">integer</span>
<span style="color: #8D38C9; font-weight: bold;">while</span> tryCount &amp;lt; 10 <span style="color: #8D38C9; font-weight: bold;">and</span> serviceStatus = <span style="color: #800000;">&quot;&quot;</span>
  tryCount = tryCount + 1
  App.SleepCurrentThread(100)
  serviceStatus = TextInputStream.<span style="color: #151B8D; font-weight: bold;">Open</span>(tmpfile).ReadAll()
&nbsp;
wend
<span style="color: #8D38C9; font-weight: bold;">if</span> instr(serviceStatus, <span style="color: #800000;">&quot;STOPPED&quot;</span>) &amp;lt; 1 <span style="color: #8D38C9; font-weight: bold;">then</span>
  // 提示用户是否停止服务
<span style="color: #8D38C9; font-weight: bold;">end</span> <span style="color: #8D38C9; font-weight: bold;">if</span></pre></div></div>


<p>但是这样仍然不能百分百保证正确，于是想到可不可以继续用 win32 api 来做这些，Google 了一下，找到一篇博客[1]，看了之后发现如果只需要停止服务的话，还是蛮简单的，决定使用 win32 api 来实现我想要的功能了。</p>

<p>在停止服务这个过程中需要用到的 win32 api 有：OpenSCManagerW、OpenServiceW、QueryServiceStatus、ControlService，还有一个结构体：SERVICE_STATUS。</p>

<p>win32 api 的参数都很好对应，数值、句柄类型的参数直接使用 Integer 即可，字符串类型使用 CString，而 SERVICE_STATUS 这个结构体也可以直接通过工程菜单添加。</p>

<p>在传参的时候需要注意两点：</p>

<ol>
    <li><strong>如果是字符串类型的参数并且调用的接口是 Unicode 类型的，那么需要在传入参数之前，将参数值转换为 Unicode 编码。可以通过 ConvertEncoding(text, Encodings.UTF16) 来转换。</strong></li>
    <li><strong>如果参数是结构体，那么参数前的传参方式就要写 ByRef，也就是按引用传值，字符串和数值类型的参数可以不写或者写 ByVal。</strong></li>
</ol>

<p>以下是 4 个 win32 api 的 REALbasic 定义：</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">soft <span style="color: #151B8D; font-weight: bold;">declare</span> <span style="color: #E56717; font-weight: bold;">function</span> OpenSCManagerW Lib <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #151B8D; font-weight: bold;">ByVal</span> lpMachineName <span style="color: #151B8D; font-weight: bold;">As</span> CString, <span style="color: #151B8D; font-weight: bold;">ByVal</span> lpDatabaseName <span style="color: #151B8D; font-weight: bold;">As</span> CString, _
<span style="color: #151B8D; font-weight: bold;">ByVal</span> dwDesiredAccess <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>
&nbsp;
soft <span style="color: #151B8D; font-weight: bold;">declare</span> <span style="color: #E56717; font-weight: bold;">function</span> OpenServiceW lib <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #151B8D; font-weight: bold;">ByVal</span> hSCManager <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>, <span style="color: #151B8D; font-weight: bold;">ByVal</span> lpServiceName <span style="color: #151B8D; font-weight: bold;">As</span> CString, _
<span style="color: #151B8D; font-weight: bold;">ByVal</span> dwDesiredAccess <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>) <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>
&nbsp;
soft <span style="color: #151B8D; font-weight: bold;">declare</span> <span style="color: #E56717; font-weight: bold;">function</span> QueryServiceStatus lib <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #151B8D; font-weight: bold;">byval</span> hService <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">integer</span>, <span style="color: #151B8D; font-weight: bold;">byref</span> lpServiceStatus <span style="color: #151B8D; font-weight: bold;">as</span> SERVICE_STATUS) _
<span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">boolean</span>
&nbsp;
soft <span style="color: #151B8D; font-weight: bold;">declare</span> <span style="color: #E56717; font-weight: bold;">function</span> ControlService lib <span style="color: #800000;">&quot;advapi32.dll&quot;</span> _
(<span style="color: #151B8D; font-weight: bold;">byval</span> hService <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">integer</span>, <span style="color: #151B8D; font-weight: bold;">byval</span> dwControl <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">integer</span>, _
<span style="color: #151B8D; font-weight: bold;">byref</span> lpServiceStatus <span style="color: #151B8D; font-weight: bold;">as</span> SERVICE_STATUS) <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">boolean</span></pre></div></div>


<p>有了 api 定义之后，就可以直接根据上面提到的 vc++ 流程来停止某个服务了。</p>

<p>完整的服务操作 api 可以参阅微软的 MSDN。</p>

<p>这样看来，REALbasic 要写出支持 Windows 7 特性的应用程序也不是难事：）</p>

<p><strong>参数资料</strong></p>

<ol>
    <li><a rel="external" href="http://blog.csdn.net/huangchonghai/archive/2007/04/25/1583602.aspx">VC++启动和停止服务</a>, huangchonghai</li>
    <li><a rel="external" href="http://msdn.microsoft.com/en-us/library/ms684939(VS.85).aspx">QueryServiceStatus</a>, MSDN</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/using-win32-api-in-realbasic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于 REALbasic 中使用 AutoDiscovery 时发生错误 40 的问题</title>
		<link>http://xujiwei.com/blog/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/</link>
		<comments>http://xujiwei.com/blog/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 16:12:14 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[AutoDiscovery]]></category>
		<category><![CDATA[REALbasic]]></category>
		<category><![CDATA[UDP]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=70</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/" title="关于 REALbasic 中使用 AutoDiscovery 时发生错误 40 的问题"></a>今天在使用 AutoDiscovery 发送数据时，发生了错误码为 40 的错误，直接在 UDPSocket 的属性列表里找了一下，没有找到对应的错误码。 在网上搜了一下，找到这篇帖子，里面提到在发送大量数据时，UDPSocket 就会报错误，并且这个错误没有在文档中提到，因此这应该是一个系统级别的错误。 MonkeybreadSoftware 提到了 unix 的错误码定义： #define    EMSGSIZE    40     /* Message too long */ 联想到在程序中是在今天开始有问题的，而且今天添加了一大堆数据，看来的确是同于 UDP 消息过大造成的错误 40。 在网上找了找，使用 UDP 发送消息时，报文的大小最好不要超过 MTU，否则会就容易丢包。我在测试时是使用的 127.0.0.1，包大小为 12.5K，照理说应该是直接走 loopback 而不需要走路由的，就算超过 MTU 也应该能发送，不清楚是不是因为 OS 内部实现机制的问题。 为了彻底解决这个问题，最后还是采用了 TCP 来传递大量数据，只使用 UDP 来传递一些控制信息。]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/" title="关于 REALbasic 中使用 AutoDiscovery 时发生错误 40 的问题"></a><p>今天在使用 AutoDiscovery 发送数据时，发生了错误码为 40 的错误，直接在 UDPSocket 的属性列表里找了一下，没有找到对应的错误码。</p>

<p>在网上搜了一下，找到<a rel="external" href="http://forums.realsoftware.com/viewtopic.php?f=2&amp;t=25418">这篇帖子</a>，里面提到在发送大量数据时，UDPSocket 就会报错误，并且这个错误没有在文档中提到，因此这应该是一个系统级别的错误。</p>

<p>MonkeybreadSoftware 提到了 unix 的错误码定义：</p>

<blockquote>#define    EMSGSIZE    40     /* Message too long */</blockquote>

<p>联想到在程序中是在今天开始有问题的，而且今天添加了一大堆数据，看来的确是同于 UDP 消息过大造成的错误 40。</p>

<p>在网上找了找，使用 UDP 发送消息时，报文的大小最好不要超过 <a rel="external" href="http://en.wikipedia.org/wiki/Maximum_transmission_unit">MTU</a>，否则会就容易丢包。我在测试时是使用的 127.0.0.1，包大小为 12.5K，照理说应该是直接走 loopback 而不需要走路由的，就算超过 MTU 也应该能发送，不清楚是不是因为 OS 内部实现机制的问题。</p>

<p>为了彻底解决这个问题，最后还是采用了 TCP 来传递大量数据，只使用 UDP 来传递一些控制信息。</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/%e5%85%b3%e4%ba%8e-realbasic-%e4%b8%ad%e4%bd%bf%e7%94%a8-autodiscovery-%e6%97%b6%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af-40-%e7%9a%84%e9%97%ae%e9%a2%98/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 AIR 中突破同源策略访问 iframe 中的内容</title>
		<link>http://xujiwei.com/blog/access-iframe-in-air/</link>
		<comments>http://xujiwei.com/blog/access-iframe-in-air/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 12:20:15 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AIR]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[Sandbox]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=139</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/access-iframe-in-air/" title="在 AIR 中突破同源策略访问 iframe 中的内容"></a>本篇所讲关于 AIR 的内容是基本 HTML+JS，而不是 Flex 或其他。 在 AIR 中，如果当前页面有一个 iframe，并且我们需要获取这个 iframe 的内容，但是如果 iframe 里包含的是远程页面，在默认情况下，浏览器策略并不允许这种情况，这就是同源策略的限制。 在 Titanium 这个类似于 AIR 的平台中，默认情况下是可以直接从应用的页面中去读取 iframe 中的内容而没有任何限制，但是在 AIR 中不可以。在网上搜索了一番，再看了好几遍 AIR 的文档之后，终于找到解决问题的方法了。 在 AIR 中，iframe 标签拥有额外的几个属性：sandboxRoot、documentRoot、allowCrossDomainXHR 及 ondominitialize。这里为了解决读取 iframe 内容所用到的属性就是 sandboxRoot 及 documentRoot。 通过 sandboxRoot 及 documentRoot，可以将本地的页面映射为远程页面，并在沙盒中运行，另外，在沙盒中运行的页面就会拥有映射域名的域。例如，我们可以将本地的 proxy.html 映射为 http://example.com/local/proxy.html，这样，在实际运行时，proxy.html 中如果用 document.domain 获取页面所在的域，就会得到 example.com，这个时候如果在 proxy.html 中添加一个 iframe，这个 iframe 指向我们实际需要获取内容的地址，因为域相同，就可以直接获取 iframe 的内容了。 例如，我们要在 AIR 中获取 http://example.com/member/login.html 的内容，或者操作这个页面的元素，就可以先用一个 proxy.html，用来实现将本地文件运行在沙盒中，再用一个 login.html 来对实际网页进行操作。 &#60;!&#8211; proxy.html &#8211;&#62; &#60;iframe src=&#8221;http://example.com/local/login.html&#8221; id=&#8221;frame&#8221; width=&#8221;100%&#8221; sandboxRoot=&#8221;http://example.com/local/&#8221; documentRoot=&#8221;app:/&#8221; name=&#8221;frame&#8221; height=&#8221;100%&#8221;&#62;&#60;/iframe&#62; &#60;!&#8211; login.html &#8211;&#62; &#60;iframe id=&#8217;f' frameborder=&#8221;0&#8243; scrolling=&#8221;no&#8221; src=&#8221;http://example.com/member/login.html&#8221; width=&#8221;100%&#8221; height=&#8221;100%&#8221;&#62;&#60;/iframe&#62; &#60;script type=&#8221;text/javascript&#8221;&#62; alert(document.domain); var f = document.getElementById(&#8216;f&#8217;); f.onload = function() { alert(f.contentWindow.document.documentElement.innerHTML); }; &#60;/script&#62; 在 proxy.html 中，虽然 iframe 的 src 属性是 http://example.com/locale/login.html，但是由于这个 iframe 具有 sandboxRoot 属性，所以实际请求会被重定向到相对于 sandboxRoot，并且使用 documentRoot 进行定位的实际地址 app://login.html，但是这个时候 login.html 中具有  document.domain=&#8221;example.com&#8221; 这个属性，所有可以直接使用 iframe.contentWindow 来访问 iframe 中的内容。 虽然解决方法有些麻烦，但终归可以实现突破同源策略的限制来读取 iframe 的内容了。 当然，如果你有更好的方法，请不吝赐教：）]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/access-iframe-in-air/" title="在 AIR 中突破同源策略访问 iframe 中的内容"></a><div class="post-content">

本篇所讲关于 AIR 的内容是基本 HTML+JS，而不是 Flex 或其他。

在 <a rel="external" href="get.adobe.com/air/">AIR</a> 中，如果当前页面有一个 iframe，并且我们需要获取这个 iframe 的内容，但是如果 iframe 里包含的是远程页面，在默认情况下，浏览器策略并不允许这种情况，这就是同源策略的限制。

在 <a rel="external" href="http://www.appcelerator.com">Titanium</a> 这个类似于 AIR 的平台中，默认情况下是可以直接从应用的页面中去读取 iframe 中的内容而没有任何限制，但是在 AIR 中不可以。在网上搜索了一番，再看了好几遍 AIR 的文档之后，终于找到解决问题的方法了。

在 AIR 中，<a rel="external" href="http://help.adobe.com/en_US/AIR/1.5/devappsflex/WS5b3ccc516d4fbf351e63e3d118666ade46-7eb2.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7edb">iframe 标签拥有额外的几个属性</a>：sandboxRoot、documentRoot、allowCrossDomainXHR 及 ondominitialize。这里为了解决读取 iframe 内容所用到的属性就是 sandboxRoot 及 documentRoot。

通过 sandboxRoot 及 documentRoot，可以将本地的页面映射为远程页面，并在沙盒中运行，另外，在沙盒中运行的页面就会拥有映射域名的域。例如，我们可以将本地的 proxy.html 映射为 http://example.com/local/proxy.html，这样，在实际运行时，proxy.html 中如果用 document.domain 获取页面所在的域，就会得到 example.com，这个时候如果在 proxy.html 中添加一个 iframe，这个 iframe 指向我们实际需要获取内容的地址，因为域相同，就可以直接获取 iframe 的内容了。

例如，我们要在 AIR 中获取 http://example.com/member/login.html 的内容，或者操作这个页面的元素，就可以先用一个 proxy.html，用来实现将本地文件运行在沙盒中，再用一个 login.html 来对实际网页进行操作。
<blockquote>
<div id="CODE_6635" class="codeMain"><span style="font-style: normal;">&lt;!&#8211; proxy.html &#8211;&gt;
&lt;iframe src=&#8221;http://example.com/local/login.html&#8221; id=&#8221;frame&#8221; width=&#8221;100%&#8221;
sandboxRoot=&#8221;http://example.com/local/&#8221;
documentRoot=&#8221;app:/&#8221; name=&#8221;frame&#8221; height=&#8221;100%&#8221;&gt;&lt;/iframe&gt;</span></div></blockquote>
<blockquote>
<div id="CODE_4316" class="codeMain">
<ul></ul>
<em><span style="font-style: normal;">&lt;!&#8211; login.html &#8211;&gt;</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;">&lt;iframe id=&#8217;f' frameborder=&#8221;0&#8243; scrolling=&#8221;no&#8221;</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;"> src=&#8221;http://example.com/member/login.html&#8221; </span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;"> width=&#8221;100%&#8221; height=&#8221;100%&#8221;&gt;&lt;/iframe&gt;</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;">&lt;script type=&#8221;text/javascript&#8221;&gt;</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;">alert(document.domain);</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;">var f = document.getElementById(&#8216;f&#8217;);</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;">f.onload = function() {</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;"> alert(f.contentWindow.document.documentElement.innerHTML);</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;">};</span></em><span style="font-style: normal;">
</span><em><span style="font-style: normal;">&lt;/script&gt;</span></em></div></blockquote>
在 proxy.html 中，虽然 iframe 的 src 属性是 http://example.com/locale/login.html，但是由于这个 iframe 具有 sandboxRoot 属性，所以实际请求会被重定向到相对于 sandboxRoot，并且使用 documentRoot 进行定位的实际地址 app://login.html，但是这个时候 login.html 中具有  document.domain=&#8221;example.com&#8221; 这个属性，所有可以直接使用 iframe.contentWindow 来访问 iframe 中的内容。

虽然解决方法有些麻烦，但终归可以实现突破同源策略的限制来读取 iframe 的内容了。

当然，如果你有更好的方法，请不吝赐教：）

</div>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/access-iframe-in-air/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>REALbasic 中使用 ShellExecute 执行命令</title>
		<link>http://xujiwei.com/blog/using-shellexecute-in-realbasic/</link>
		<comments>http://xujiwei.com/blog/using-shellexecute-in-realbasic/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 13:50:40 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[REALbasic]]></category>
		<category><![CDATA[ShellExecute]]></category>
		<category><![CDATA[Win32]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=72</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/using-shellexecute-in-realbasic/" title="REALbasic 中使用 ShellExecute 执行命令"></a>在 REALbasic 中，如果需要执行 cmd 命令，可以直接使用 Shell 类，但是这样的话，编译成 Windows 程序时会额外需要一个 Shell.dll 的动态链接库，这对于我这样的 1exe 爱好者是不能忍受的。但是对于 Mac OS X 和 Linux 的生成目标来说，是不存在这个问题的，因为 Mac OS X 的应用程序本身就是一个文件夹，而 Linux 的目标不会生成额外的链接库。因此，需要针对 Windows 进行特殊处理。于是在网上搜索解决方案，找到了 VB 中执行程序的几种方法： 1. 使用 CreateProcess 通过 CreateProcess 以及使用管道，可以执行外部程序并获取输出，但是这个方法过于烦琐，并且我也不需要外部进程执行完毕后的输出结果，因此不采用。 2. 使用 Shell 方法 VB 里有一个 Shell 方法，但是在 RB 中并没有，所以此路不通。 3. 使用 ShellExecute 这个方法同样是一个系统 API，可以直接通过 RB 的 declare 声明并调用它，在测试之后，使用 declare 来使用系统 API 不会生成额外的 dll，正是我需要的。 首先在 RB 的某个模块中添加一个方法 ShellExecute，用来封装对系统 API 的请求： function ShellExecute(hWnd as Integer, lpOperation as String, _ lpFile as String, lpParameters as String, lpDirectory as String, nShowCmd as Integer) 注意，在 RB 中添加方法时，参数列表中的 _ 需要去掉，这里是为了排版的需要而加上的。 这个 API 是定义在 shell32.dll 中的，在 ShellExecute 方法中先需要声明： soft declare function ShellExecuteA Lib &#8221;shell32.dll&#8221; _ (ByVal hWnd As Integer, ByVal lpOperation As CString, _ ByVal lpFile As CString, ByVal lpParameters As CString, _ ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer soft declare function ShellExecuteW Lib &#8221;shell32.dll&#8221; _ (ByVal hWnd As Integer, ByVal lpOperation As CString, _ ByVal lpFile As CString, ByVal lpParameters As CString, _ ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer 然后来调用这个 API： dim ret as Integer Try ret = ShellExecuteW(hWnd, ConvertEncoding(lpOperation, Encodings.UTF16), _ ConvertEncoding(lpFile, Encodings.UTF16), _ ConvertEncoding(lpParameters, Encodings.UTF16), _ ConvertEncoding(lpDirectory, &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/using-shellexecute-in-realbasic/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/using-shellexecute-in-realbasic/" title="REALbasic 中使用 ShellExecute 执行命令"></a><p>在 REALbasic 中，如果需要执行 cmd 命令，可以直接使用 Shell 类，但是这样的话，编译成 Windows 程序时会额外需要一个 Shell.dll 的动态链接库，这对于我这样的 1exe 爱好者是不能忍受的。但是对于 Mac OS X 和 Linux 的生成目标来说，是不存在这个问题的，因为 Mac OS X 的应用程序本身就是一个文件夹，而 Linux 的目标不会生成额外的链接库。因此，需要针对 Windows 进行特殊处理。于是在网上搜索解决方案，找到了 VB 中执行程序的几种方法：</p>

<p><strong>1. 使用 CreateProcess</strong></p>

<p>通过 CreateProcess 以及使用管道，可以执行外部程序并获取输出，但是这个方法过于烦琐，并且我也不需要外部进程执行完毕后的输出结果，因此不采用。</p>

<p><strong>2. 使用 Shell 方法</strong></p>

<p>VB 里有一个 Shell 方法，但是在 RB 中并没有，所以此路不通。</p>

<p><strong>3. 使用 ShellExecute</strong></p>

<p>这个方法同样是一个系统 API，可以直接通过 RB 的 declare 声明并调用它，在测试之后，使用 declare 来使用系统 API 不会生成额外的 dll，正是我需要的。</p>

<p>首先在 RB 的某个模块中添加一个方法 ShellExecute，用来封装对系统 API 的请求：</p>

<blockquote>function ShellExecute(hWnd as Integer, lpOperation as String, _
lpFile as String, lpParameters as String, lpDirectory as String, nShowCmd as Integer)</blockquote>

<p>注意，在 RB 中添加方法时，参数列表中的 _ 需要去掉，这里是为了排版的需要而加上的。</p>

<p>这个 API 是定义在 shell32.dll 中的，在 ShellExecute 方法中先需要声明：</p>

<blockquote>soft declare function ShellExecuteA Lib &#8221;shell32.dll&#8221; _
(ByVal hWnd As Integer, ByVal lpOperation As CString, _
ByVal lpFile As CString, ByVal lpParameters As CString, _
ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer

soft declare function ShellExecuteW Lib &#8221;shell32.dll&#8221; _
(ByVal hWnd As Integer, ByVal lpOperation As CString, _
ByVal lpFile As CString, ByVal lpParameters As CString, _
ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer</blockquote>

<p>然后来调用这个 API：</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">  <span style="color: #151B8D; font-weight: bold;">dim</span> ret <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>
    Try
      ret = ShellExecuteW(hWnd, ConvertEncoding(lpOperation, Encodings.UTF16), _
      ConvertEncoding(lpFile, Encodings.UTF16), _
      ConvertEncoding(lpParameters, Encodings.UTF16), _
      ConvertEncoding(lpDirectory, Encodings.UTF16), nShowCmd)
    Catch
      ret = ShellExecuteA(hWnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd)
    <span style="color: #8D38C9; font-weight: bold;">End</span>
    return ret</pre></div></div>


<p>把 ShellExecuteW 放在 Try &#8230; Catch 中是为了兼容的需要，因为像 Windows 98 这样比较老的系统中，系统内部编码还不是 Unicode，还没有 ShellExecuteW 这样结尾是 W 的 API。</p>

<p>另外，因为 RB 内部是使用的 UTF-8 编码，而系统 API ShellExecuteW 使用的编码是 Unicode，所以参数在传递前需要进行转码，将字符串参数值转换为 Unicode 编码，否则在执行一个明明正确的命令时，会出现“找不到文件”的错误。</p>

<p>好了，这样就可以使用 ShellExecute 方法来执行外部程序了，例如：</p>


<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">  #if TargetWin32
    <span style="color: #151B8D; font-weight: bold;">dim</span> ret <span style="color: #151B8D; font-weight: bold;">as</span> <span style="color: #F660AB; font-weight: bold;">Integer</span>
    ret = Win32Helper.ShellExecute(hWnd, <span style="color: #800000;">&quot;open&quot;</span>, <span style="color: #800000;">&quot;cmd.exe&quot;</span>, _
    <span style="color: #800000;">&quot;/c shutdown -t 10&quot;</span>, <span style="color: #800000;">&quot;&quot;</span>, 0)
  #endif</pre></div></div>


<p>上面的代码就调用 cmd.exe 执行了命令 shutdown -s -t 10，也就是 10 秒后关机。</p>

<p>其实这个方法也可以用来打开文档或者网址，具体的用法可以去 MSDN 找一找。</p>

<p>当然，如果不在乎生成的 Windows 目标还有额外的 dll 的话，完全可以使用 RB 自带的 Shell 类，功能也强上不少。</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/using-shellexecute-in-realbasic/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>在VB中用PictureBox实现图片的缩略图浏览</title>
		<link>http://xujiwei.com/blog/thumbnail-in-vb-by-picturebox/</link>
		<comments>http://xujiwei.com/blog/thumbnail-in-vb-by-picturebox/#comments</comments>
		<pubDate>Sat, 09 Dec 2006 04:09:28 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[PictureBox]]></category>
		<category><![CDATA[Thumbnail]]></category>
		<category><![CDATA[VB]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=108</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/thumbnail-in-vb-by-picturebox/" title="在VB中用PictureBox实现图片的缩略图浏览"></a>要写一个程序，涉及到缩略图的问题，原先准备用StretchBlt来实现的，后来找了下发现PictureBox的PaintPicture方法 也可以把图像按规定大小进行缩放，试了一下感觉PaintPicture的速度比StretchBlt快一些。 PaintPicture的 函数定义为： Sub PaintPicture(Picture As IPictureDisp, X1 As Single, Y1 As Single, [Width1], [Height1], [X2], [Y2], [Width2], [Height2], [Opcode]) X1 和Y1是目标位置，Width1和Height1是目标大小，默认是PictureBox的大小，X2和Y2是源位置，Width2和Height2是源 大小，Opcode是操作方式，默认应该是vbSrcCopy，如果Width1、Height1和Width2、Height2的大小不一样则进行缩 放。 新建一个工程，设置Form1的ScaleMode为“3 - Pixel”，往窗体上放1个FileListBox控件名称为 File1，1个ImageList控件名称为ImageList1，2个PictureBox控件，一个名称为Picture1，AutoResize 为True，Visible为False，另外一个名称为Picture2，AutoRedraw为True，Visible为False，Width和 Height为128，1个ListView控件名称为ListView1，将图像列表中普通设置为ImageList1。 在窗体里添加如 下代码： &#8216; 窗体载入时载入图像列表 Private Sub Form_Load() Dim i As Long For i = 0 To File1.ListCount &#8211; 1 &#8216; 载入图像 Picture1.Picture = LoadPicture(File1.Path &#38; &#8220;\&#8221; &#38; &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/thumbnail-in-vb-by-picturebox/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/thumbnail-in-vb-by-picturebox/" title="在VB中用PictureBox实现图片的缩略图浏览"></a><p>要写一个程序，涉及到缩略图的问题，原先准备用StretchBlt来实现的，后来找了下发现PictureBox的PaintPicture方法 也可以把图像按规定大小进行缩放，试了一下感觉PaintPicture的速度比StretchBlt快一些。</p>

<p>PaintPicture的 函数定义为：</p>

<p>Sub PaintPicture(Picture As IPictureDisp, X1 As Single, Y1 As Single, [Width1], [Height1], [X2], [Y2], [Width2], [Height2], [Opcode])</p>

<p>X1 和Y1是目标位置，Width1和Height1是目标大小，默认是PictureBox的大小，X2和Y2是源位置，Width2和Height2是源 大小，Opcode是操作方式，默认应该是vbSrcCopy，如果Width1、Height1和Width2、Height2的大小不一样则进行缩 放。</p>

<p>新建一个工程，设置Form1的ScaleMode为“3 - Pixel”，往窗体上放1个FileListBox控件名称为 File1，1个ImageList控件名称为ImageList1，2个PictureBox控件，一个名称为Picture1，AutoResize 为True，Visible为False，另外一个名称为Picture2，AutoRedraw为True，Visible为False，Width和 Height为128，1个ListView控件名称为ListView1，将图像列表中普通设置为ImageList1。</p>

<p>在窗体里添加如 下代码：</p>

<blockquote>
<div id="_mcePaste">
<div id="_mcePaste"><span style="font-style: normal;">&#8216; 窗体载入时载入图像列表</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Sub Form_Load()</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Dim i As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> For i = 0 To File1.ListCount &#8211; 1</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216; 载入图像</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Picture1.Picture = LoadPicture(File1.Path &amp; &#8220;\&#8221; &amp; File1.List(i))</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216; 生成缩略图</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Picture2.PaintPicture Picture1.Picture, 0, 0</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216; 添加缩略图到ImageList</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> ImageList1.ListImages.Add , , Picture2.Image</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216; 添加缩略图到ListView</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> ListView1.ListItems.Add , , File1.List(i), i + 1</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> DoEvents</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Next</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Sub</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&#8216; 窗体改变大小时改变ListView的大小</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Sub Form_Resize()</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> With ListView1</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> .Top = 0</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> .Left = 0</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> .Width = Me.ScaleWidth</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> .Height = Me.ScaleHeight</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> End With</span></div>
<div><span style="font-style: normal;"><span style="color: #4e4e4e;">End Sub</span></span></div>
</div></blockquote>

<div><span style="font-style: normal;">这样就差不多可以实现图片的缩略图浏览了。</span></div>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/thumbnail-in-vb-by-picturebox/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用VB写一个你自己的Flash播放器</title>
		<link>http://xujiwei.com/blog/write-a-flashplayer-in-vb/</link>
		<comments>http://xujiwei.com/blog/write-a-flashplayer-in-vb/#comments</comments>
		<pubDate>Mon, 10 Jul 2006 02:43:52 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[VB]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=110</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/write-a-flashplayer-in-vb/" title="用VB写一个你自己的Flash播放器"></a>前天在PConline下了一个孙鑫的《Java从入门到精通》的视频教程，Flash格式，在看的时候感觉很不爽，每一课开始的时候有一大段广 告，而且前面的一部分颇为啰嗦，讲了乱七八糟的东西，不知道是不是因为“入门”的关系，然后就把以前做的一个Flash播放器找出来，直接跳到自己要看的 地方～ 要想用VB做一个自己的Flash播放器还是比较方便的，因为Macromedia已经提供了Shockwave Flash控件， 可以方便来的播放Flash影片。要想使用这个控件，首先要在工程里添加这个控件，选中菜单“工程-&#62;部件”，找到 Shockwave Flash，打上勾，确定就可以了。另外，因为要加载Flash影片，所以我们还需要加入对话框控件 Microsoft Common Dialog Control。 做这个Flash播放器之前，先用对象浏览器来看一下 Shockwave Flash控件有哪些我们需要的事件、方法和属性。 因为我们做的Flash播放器比较简单，所以没有可以利用的控件事 件。 方法： Sub Back() 跳 到前一帧，相当于Flash右键菜单中的快退 Function CurrentFrame() As Long 获 取当前播放的为第几帧 Sub Forward() 跳到后一帧，相当于Flash 右键菜单中的快进 Sub GotoFrame(FrameNum As Long) 跳 到指定帧，这是一个相当有用的方法，也是要做这个Flash播放器的理由之一了 Sub Play() 播 放，相当于Flash中的播放 Sub Stop() 停止，需要注意的是这个是停 止，而不是暂停，停止后再开始播放将从第1帧开始 Sub StopPlay() 暂 停，暂停后再播放是继续暂停之前的状态 属性： Property Movie As String 影 片路径，用来加载要播放的Flash影片 Property Playing As Boolean 是 否正在播放 &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/write-a-flashplayer-in-vb/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/write-a-flashplayer-in-vb/" title="用VB写一个你自己的Flash播放器"></a><p>前天在PConline下了一个孙鑫的《Java从入门到精通》的视频教程，Flash格式，在看的时候感觉很不爽，每一课开始的时候有一大段广 告，而且前面的一部分颇为啰嗦，讲了乱七八糟的东西，不知道是不是因为“入门”的关系，然后就把以前做的一个Flash播放器找出来，直接跳到自己要看的 地方～</p>

<p>要想用VB做一个自己的Flash播放器还是比较方便的，因为Macromedia已经提供了Shockwave Flash控件， 可以方便来的播放Flash影片。要想使用这个控件，首先要在工程里添加这个控件，选中菜单“工程-&gt;部件”，找到 Shockwave Flash，打上勾，确定就可以了。另外，因为要加载Flash影片，所以我们还需要加入对话框控件 Microsoft Common Dialog Control。</p>

<p>做这个Flash播放器之前，先用对象浏览器来看一下 Shockwave Flash控件有哪些我们需要的事件、方法和属性。</p>

<p>因为我们做的Flash播放器比较简单，所以没有可以利用的控件事 件。</p>

<p><strong>方法：</strong></p>

<p><strong>Sub Back()</strong></p>

<p>跳 到前一帧，相当于Flash右键菜单中的快退</p>

<p><strong>Function CurrentFrame() As Long</strong></p>

<p>获 取当前播放的为第几帧</p>

<p><strong>Sub Forward()</strong></p>

<p>跳到后一帧，相当于Flash 右键菜单中的快进</p>

<p><strong>Sub GotoFrame(FrameNum As Long)</strong></p>

<p>跳 到指定帧，这是一个相当有用的方法，也是要做这个Flash播放器的理由之一了</p>

<p><strong>Sub Play()</strong></p>

<p>播 放，相当于Flash中的播放</p>

<p><strong>Sub Stop()</strong></p>

<p>停止，需要注意的是这个是停 止，而不是暂停，停止后再开始播放将从第1帧开始</p>

<p><strong>Sub StopPlay()</strong></p>

<p>暂 停，暂停后再播放是继续暂停之前的状态</p>

<p><strong>属性：</strong></p>

<p><strong>Property Movie As String</strong></p>

<p>影 片路径，用来加载要播放的Flash影片</p>

<p><strong>Property Playing As Boolean</strong></p>

<p>是 否正在播放</p>

<p><strong>TotalFrames</strong></p>

<p>Flash影片的总帧数</p>

<p>好了， 有了这些资料就可以开始写自己的Flash播放了～</p>

<p>打开窗体编辑器，先在窗体添加5个按钮，名称和Caption分别 为：cmdOpen(&#8220;打开&#8221;)，cmdPlay(&#8220;播放&#8221;)，cmdStop(&#8220;停止&#8221;)，cmdPrev(&#8220;前一帧&#8221;)，cmdNext(&#8220;后一 帧&#8221;)。为了能快整跳转，再添加一个水平滚动条，名称为hslFrame。当然，最重要的，Shockwave Flash不能少了，也要添加，名称为 swf。再者要打开文件，所以添加一个Microsoft Common Dialog Control，名称为dlg。</p>

<p><a href="http://tmp.xujiwei.com/blog/wp-content/uploads/2010/01/sphw_step1.jpg"><img class="alignnone size-full wp-image-111" title="sphw_step1" src="http://tmp.xujiwei.com/blog/wp-content/uploads/2010/01/sphw_step1.jpg" alt="" width="409" height="359" /></a></p>

<p>完成窗体的设计，开始编写代码。</p>

<blockquote><span style="font-style: normal;">&#8216; 先给打开按钮添加过程</span>

<span style="font-style: normal;">Private Sub cmdOpen_Click()</span>

<span style="font-style: normal;">dlg.Filter = &#8221;Flash(*.swf)|*.swf&#8221;  &#8217; 设 置文件名过滤器，只显示Flash文件</span>

<span style="font-style: normal;">dlg.ShowOpen</span>

<span style="font-style: normal;">If dlg.FileName = &#8221;" Then Exit Sub &#8217; 如 果用户点了取消则退出处理</span>

<span style="font-style: normal;">swf.Movie = dlg.FileName           &#8217; 加载影片</span>

<span style="font-style: normal;">hslFrame.Max = swf.TotalFrames     &#8217; 获 取总帧数，并赋值给滚动条的最大值</span>

<span style="font-style: normal;">End Sub</span>

<span style="font-style: normal;">&#8216; 接着是播放按钮</span>

<span style="font-style: normal;">Private Sub cmdPlay_Click()</span>

<span style="font-style: normal;">If swf.Playing = True Then   &#8217; 如 果正在播放则暂停</span>

<span style="font-style: normal;">swf.StopPlay</span>

<span style="font-style: normal;">cmdPlay.Caption = &#8221;播 放&#8221; &#8217; 按钮文本设置为“播放”</span>

<span style="font-style: normal;">Else</span>

<span style="font-style: normal;">swf.Play                 &#8217; 否 则就继续播放</span>

<span style="font-style: normal;">cmdPlay.Caption = &#8221;暂停&#8221; &#8217; 按钮文本设置为“暂停”</span>

<span style="font-style: normal;">End If</span>

<span style="font-style: normal;">End Sub</span>

<span style="font-style: normal;">&#8216; 停 止按钮</span>

<span style="font-style: normal;">Private Sub cmdStop_Click()</span>

<span style="font-style: normal;">swf.Stop  &#8217; 停止</span>

<span style="font-style: normal;">End Sub</span>

<span style="font-style: normal;">&#8216; 前 一帧按钮</span>

<span style="font-style: normal;">Private Sub cmdPrev_Click()</span>

<span style="font-style: normal;">swf.Back</span>

<span style="font-style: normal;">End Sub</span>

<span style="font-style: normal;">&#8216; 后 一帧按钮</span>

<span style="font-style: normal;">Private Sub cmdNext_Click()</span>

<span style="font-style: normal;">swf.Forward</span>

<span style="font-style: normal;">End Sub</span>

<span style="font-style: normal;">&#8216; 为 了可以拖动滚动条来进行播放，下面处理hslFrame的OnChange事件</span>

<span style="font-style: normal;">Private Sub hslFrame_Change()</span>

<span style="font-style: normal;">swf.GotoFrame hslFrame.Value  &#8217; 跳 到滚动条值所在的帧</span>

<span style="font-style: normal;">End Sub</span></blockquote>

<p>好了，一个简单的Flahs播放器就做好了，当然你也可以在这个此基础上加上更多的功能。</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/write-a-flashplayer-in-vb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[ASM] 是男人就下100层，交出序列号来</title>
		<link>http://xujiwei.com/blog/get-serial-of-shinanrenjiuxia100cen/</link>
		<comments>http://xujiwei.com/blog/get-serial-of-shinanrenjiuxia100cen/#comments</comments>
		<pubDate>Sat, 17 Jun 2006 05:07:40 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[ASM]]></category>
		<category><![CDATA[Crack]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=113</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/get-serial-of-shinanrenjiuxia100cen/" title="[ASM] 是男人就下100层，交出序列号来"></a>某天（前天：），看了两个小时高数（具体不详：）之后，想放松一下，找到《是男人就下100层》，打开，玩了两把，突然发现今天怎么看那个“注册”的按钮特别不爽，OK，Crack it！ 常规步骤，用PEid侦壳，用VC4.x写的，这样方便了，脱壳都不用。接着祭出用户级调试法宝——Ollydbg，加载《是男人就下100层》，万事俱备，踏上征途！ 按F9运行程序，等程序窗口出来，点一下任务栏上按钮，结果竟然中断了，CPU窗口一看，原来是一条INT3指令，麻烦的东西，NOP掉。继续F9运行，好，这下可以把程序窗口调到前面了。切换到程序窗口，点注册，出现填写用户名和序列号的窗口。用户名填HotHeart，序列号填一个123456，确定，当然不会成功，要不我就可以去买彩票了^_^。弹出一个错误提示框，内容是日文的……意思大概是序列号无效。既然有提示框，那就好办，回到Ollydbg，下断点bp MessageBoxA，再次换到程序窗口点确定。YES！顺利中断，切回Ollydbg看看代码： ; 获取对话框中控件文本 00407A78  PUSH 100 00407A7D  LEA EAX,DWORD PTR SS:[EBP-204] 00407A83  PUSH EAX 00407A84  PUSH 3EB 00407A89  MOV EAX,DWORD PTR SS:[EBP+8] 00407A8C  PUSH EAX 00407A8D  CALL DWORD PTR DS:[&#60;&#38;USER32.GetDlgItemText&#62;] 00407A93  LEA EAX,DWORD PTR SS:[EBP-204] 00407A99  PUSH EAX 00407A9A  CALL 是男人就.00407C5F 00407A9F  ADD ESP,4 00407AA2  TEST EAX,EAX 00407AA4  JNZ 是男人就.00407AE1 ; 从资源中载入字符串，是注册失败的提示信息 00407AAA  PUSH 100 00407AAF  LEA EAX,DWORD PTR SS:[EBP-104] &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/get-serial-of-shinanrenjiuxia100cen/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/get-serial-of-shinanrenjiuxia100cen/" title="[ASM] 是男人就下100层，交出序列号来"></a><div class="post-content">

某天（前天：），看了两个小时高数（具体不详：）之后，想放松一下，找到《是男人就下100层》，打开，玩了两把，突然发现今天怎么看那个“注册”的按钮特别不爽，OK，Crack it！

常规步骤，用PEid侦壳，用VC4.x写的，这样方便了，脱壳都不用。接着祭出用户级调试法宝——Ollydbg，加载《是男人就下100层》，万事俱备，踏上征途！

按F9运行程序，等程序窗口出来，点一下任务栏上按钮，结果竟然中断了，CPU窗口一看，原来是一条INT3指令，麻烦的东西，NOP掉。继续F9运行，好，这下可以把程序窗口调到前面了。切换到程序窗口，点注册，出现填写用户名和序列号的窗口。用户名填HotHeart，序列号填一个123456，确定，当然不会成功，要不我就可以去买彩票了^_^。弹出一个错误提示框，内容是日文的……意思大概是序列号无效。既然有提示框，那就好办，回到Ollydbg，下断点bp MessageBoxA，再次换到程序窗口点确定。YES！顺利中断，切回Ollydbg看看代码：

<span style="color: #008000;">; 获取对话框中控件文本</span>

00407A78  <span style="color: #0000d0;">PUSH</span> 100

00407A7D  <span style="color: #0000d0;">LEA</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-204]

00407A83  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407A84  <span style="color: #0000d0;">PUSH</span> 3EB

00407A89  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407A8C  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407A8D  <span style="color: #0000d0;">CALL</span> <span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[&lt;&amp;USER32.GetDlgItemText&gt;]

00407A93  <span style="color: #0000d0;">LEA</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-204]

00407A99  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407A9A  <span style="color: #0000d0;">CALL</span> 是男人就.00407C5F

00407A9F  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407AA2  <span style="color: #0000d0;">TEST</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span>

00407AA4  <span style="color: #0000d0;">JNZ</span> 是男人就.00407AE1

<span style="color: #008000;">; 从资源中载入字符串，是注册失败的提示信息</span>

00407AAA  <span style="color: #0000d0;">PUSH</span> 100

00407AAF  <span style="color: #0000d0;">LEA</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-104]

00407AB5  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407AB6  <span style="color: #0000d0;">PUSH</span> 4

00407AB8  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[40E200]

00407ABD  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407ABE  <span style="color: #0000d0;">CALL</span> <span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[&lt;&amp;USER32.LoadStringA&gt;]

<span style="color: #008000;">; 下面就是弹出出错提示框的代码了</span>

00407AC4  <span style="color: #0000d0;">PUSH</span> 10

00407AC6  <span style="color: #0000d0;">PUSH</span> 是男人就.0040D270

00407ACB  <span style="color: #0000d0;">LEA</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-104]

00407AD1  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407AD2  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407AD5  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407AD6  <span style="color: #0000d0;">CALL</span> <span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[&lt;&amp;USER32.MessageBoxA&gt;]

00407ADC  <span style="color: #0000d0;">JMP</span> 是男人就.00407B22

看到407AD6这里调用了MessageBoxA，往上看，很舒服地看到这一句：

00407AA4  <span style="color: #0000d0;">JNZ</span> 是男人就.00407AE1

一个很值得注意的跳转，是不是关键跳转呢，把JNZ改成JZ，再试试，点确定，出错提示是没有了，不过那个注册按钮还是在的，也就是说这句不是关键跳转，没有涉及到序列号的部分。再往上看，发现看在这个跳转之前有获取对话框中数据：

00407A8D  <span style="color: #0000d0;">CALL</span> <span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[&lt;&amp;USER32.GetDlgItemText&gt;]

那么在这里中断看看它得到了什么。F2下断点，切到程序窗口，输入用户名和序列号，确定，预料之中断下来。接着F8单步运行，再来一个YES！它得到的是123456，也就是我填的序列号，接着把序列号所在的地址存到EAX中，再将EAX压入堆栈，紧接着又一个call，嗯，这个call很值得怀疑，跟进！下面就是整个call的函数的代码了，有点长：）

00407C5F  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EBP</span> <span style="color: #008000;">; C函数标准开头</span>

00407C60  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EBP</span>,<span style="color: #ff0000;">ESP</span>

00407C62  <span style="color: #0000d0;">SUB</span> <span style="color: #ff0000;">ESP</span>,4   <span style="color: #008000;">; 局部变量，分析后面的代码可知是用来作计数器的</span>

00407C65  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EBX</span> <span style="color: #008000;">; 保护寄存器</span>

00407C66  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">ESI</span>

00407C67  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EDI</span>

从代码开始可明显看出这是一个标准的C函数，接着往下看。碰到堆栈操作，这值得注意，因为call过来时有压入过一个参数，指向序列号起始地址：

00407C68  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]  <span style="color: #008000;">; 这句之后EAX指向序列号</span>

00407C6B  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span>

00407C6D  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+7]    <span style="color: #008000;">; 得到序列号第8位</span>

00407C70  <span style="color: #0000d0;">TEST</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span> <span style="color: #008000;">; 判断是否为0</span>

00407C72  <span style="color: #0000d0;">JE</span> 是男人就.00407C7F    <span style="color: #008000;">; 是刚跳转</span>

00407C78  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; EAX清零</span>

00407C7A  <span style="color: #0000d0;">JMP</span> 是男人就.00407DC4    <span style="color: #008000;">; 这里跳到函数结尾</span>

00407C7F  <span style="color: #0000d0;">MOV</span> <span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-4],0    <span style="color: #008000;">; 计数器清零</span>

00407C86  <span style="color: #0000d0;">JMP</span> 是男人就.00407C8E

上面的代码的作用是得到序列号第8位，并判断是否为0，学过C的人都知道在C里字符串是以0表示结束的，那么就知道这里三句是用来判断用户输入的序列号是否大于7位的了，如果大于7位，就会将EAX清零并跳到函数结束的地方，而前面已经知道，在调用这个函数之后，如果返回值为0则序列号验证失败，所以序列号是7位或7位以内的。我填的123456，是6位，所以没有跳到函数结束，接着往下分析：

00407C8B  <span style="color: #0000d0;">INC</span> <span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-4]    <span style="color: #008000;">; 计数器加1</span>

00407C8E  <span style="color: #0000d0;">CMP</span> <span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-4],7  <span style="color: #008000;">; 判断计数器是否大于7</span>

00407C92  <span style="color: #0000d0;">JGE</span> 是男人就.00407CC3       <span style="color: #008000;">; 大于等于就</span>

00407C98  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>-4] <span style="color: #008000;">; 取计数器值到EAX</span>

00407C9B  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8] <span style="color: #008000;">; 取序列号地址到ECX</span>

00407C9E  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+<span style="color: #ff0000;">ECX</span>] <span style="color: #008000;">; 取序列号第N位到AL，N为计数器值</span>

00407CA1  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; 压入堆栈，调用处理函数</span>

00407CA2  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9  <span style="color: #008000;">; 将1位序列号从ASCII转换成二进制值</span>

00407CA7  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4   <span style="color: #008000;">; 恢复堆栈</span>

00407CAA  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span> <span style="color: #008000;">; ECX清零</span>

00407CAC  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff0000;">AL</span> <span style="color: #008000;">; 将处理过的1位序列号存到CL</span>

00407CAE  <span style="color: #0000d0;">CMP</span> <span style="color: #ff0000;">ECX</span>,24  <span style="color: #008000;">; 判断是否大于0&#215;24</span>

00407CB1  <span style="color: #0000d0;">JLE</span> 是男人就.00407CBE  <span style="color: #008000;">; 大于就出错了</span>

00407CB7  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; 大于0&#215;24，跳到函数结束，返回0</span>

00407CB9  <span style="color: #0000d0;">JMP</span> 是男人就.00407DC4

00407CBE  <span style="color: #0000d0;">JMP</span> 是男人就.00407C8B  <span style="color: #008000;">; 继续处理下一位</span>

很清楚的，上面这段代码是用来判断序列号中每一位是否符合要求，是什么要求呢，看到在每取得1位序列号之后有一句call：

00407CA2  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9

这个调用得看看，F7跟进：

00407DC9  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EBP</span>

00407DCA  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EBP</span>,<span style="color: #ff0000;">ESP</span>

00407DCC  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EBX</span>

00407DCD  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">ESI</span>

00407DCE  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EDI</span>

00407DCF  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span>

00407DD1  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]    <span style="color: #008000;">; 取参数，即1位序列号</span>

00407DD4  <span style="color: #0000d0;">CMP</span> <span style="color: #ff0000;">EAX</span>,61

00407DD7  <span style="color: #0000d0;">JL</span> 是男人就.00407DE8

<span style="color: #008000;">; 判断是否大于0&#215;61，如果对ASCII码表熟悉的话可以知道0&#215;61对应的是a</span>

<span style="color: #008000;">; 小于则跳转，好，上面那个判断应该不是用来判断这个字符是否为小写字母了</span>

<span style="color: #008000;">; 不是则跳到后面继续处理，是则进行下面的处理过程</span>

00407DDD  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; EAX清零</span>

00407DDF  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]    <span style="color: #008000;">; 取字符</span>

00407DE2  <span style="color: #0000d0;">SUB</span> <span style="color: #ff0000;">EAX</span>,20     <span style="color: #008000;">; 减0&#215;20，变大写字母</span>

00407DE5  <span style="color: #0000d0;">MOV</span> <span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8],<span style="color: #ff0000;">AL</span> <span style="color: #008000;">; 保存</span>

<span style="color: #008000;">; 不管是否为小字字母，经过上面的判断和处理都会变成大写字母，继续进行处理</span>

00407DE8  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; EAX清零</span>

00407DEA  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]    <span style="color: #008000;">; 取字符</span>

00407DED  <span style="color: #0000d0;">CMP</span> <span style="color: #ff0000;">EAX</span>,41

00407DF0  <span style="color: #0000d0;">JL</span> 是男人就.00407E01

<span style="color: #008000;">; 判断是否大于，0&#215;41对应的ASCII字符为A</span>

<span style="color: #008000;">; 小于则跳转，说明这里是判断字符是否为大写字母</span>

<span style="color: #008000;">; 不是则跳到后面继续处理，是则进行下面的处理过程</span>

00407DF6  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; EAX清零</span>

00407DF8  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]    <span style="color: #008000;">; 取字符</span>

00407DFB  <span style="color: #0000d0;">SUB</span> <span style="color: #ff0000;">EAX</span>,7      <span style="color: #008000;">; 减去7</span>

00407DFE  <span style="color: #0000d0;">MOV</span> <span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8],<span style="color: #ff0000;">AL</span> <span style="color: #008000;">; 保存</span>

<span style="color: #008000;">; 如果不是大写字母就跳到这里了，当然如果是大写字母的话</span>

<span style="color: #008000;">; 经过上面的处理过程同样要进行下面的处理过程</span>

00407E01  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; EAX清零</span>

00407E03  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]    <span style="color: #008000;">; 取字符</span>

00407E06  <span style="color: #0000d0;">SUB</span> <span style="color: #ff0000;">EAX</span>,30     <span style="color: #008000;">; 减去0&#215;30</span>

00407E09  <span style="color: #0000d0;">JMP</span> 是男人就.00407E0E  <span style="color: #008000;">; 函数结束</span>

00407E0E  <span style="color: #0000d0;">POP</span> <span style="color: #ff0000;">EDI</span>

00407E0F  <span style="color: #0000d0;">POP</span> <span style="color: #ff0000;">ESI</span>

00407E10  <span style="color: #0000d0;">POP</span> <span style="color: #ff0000;">EBX</span>

00407E11  <span style="color: #0000d0;">LEAVE</span>

00407E12  <span style="color: #0000d0;">RETN</span>

连贯起来看可以知道这个处理函数的过程是这样的：

char是否为小写字母 -&gt; 是则减去0&#215;20变成大写字母，不是则保持不变 -&gt; char是否为大写字母 -&gt; 是则减去7，不是则保持不变 -&gt; char减0&#215;30

再联系数字和字母的ASCII码值，9为0&#215;39，A为0&#215;41，0&#215;41-0&#215;39=7，OK，可以知道这个函数是把1位序列号变成二进制值，字符0到9对应数值0到9，字母全部转换成大写字母，并且字母A对应10，B对应11，后面依次类推。

弄明白了字符到数字的函数，继续看序列号验证的代码，可以看到在得到二进制值之后，又来了一句：

00407CB1  <span style="color: #0000d0;">JLE</span> 是男人就.00407CBE  <span style="color: #008000;">; 大于就出错了</span>

00407CB7  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; 大于0&#215;24，跳到函数结束，返回0</span>

00407CB9  <span style="color: #0000d0;">JMP</span> 是男人就.00407DC4

00407CBE  <span style="color: #0000d0;">JMP</span> 是男人就.00407C8B  <span style="color: #008000;">; 继续处理下一位</span>

0&#215;24转换成十进制就是36，刚好是10个数字加26个字母，也就是说序列号只允许数字与字母，并且要7位，否则就通不过这个验证了。弄明白了这个，继续往下看：

00407CC3  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407CC6  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+5]  <span style="color: #008000;">; 取序列号第6位</span>

00407CC9  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407CCA  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9      <span style="color: #008000;">; 转换成数值</span>

00407CCF  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407CD2  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">EBX</span>

00407CD4  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">BL</span>,<span style="color: #ff0000;">AL</span> <span style="color: #008000;">; 序列号第6位值保存到EBX</span>

00407CD6  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407CD9  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+2]  <span style="color: #008000;">; 取序列号第3位</span>

00407CDC  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407CDD  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9      <span style="color: #008000;">; 转换成数值</span>

00407CE2  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407CE5  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span>

00407CE7  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff0000;">AL</span> <span style="color: #008000;">; 序列号第3位值保存到ECX</span>

00407CE9  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">ESI</span>,24   <span style="color: #008000;">; ESI=0&#215;24</span>

00407CEE  <span style="color: #0000d0;">LEA</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">ECX</span>+<span style="color: #ff0000;">EBX</span>*2+1D] <span style="color: #008000;">; EAX=ECX+EBX*2+1D</span>

00407CF2  <span style="color: #0000d0;">CDQ</span> <span style="color: #008000;">; 扩展成64位</span>

00407CF3  <span style="color: #0000d0;">IDIV</span> <span style="color: #ff0000;">ESI</span> <span style="color: #008000;">; 除以0&#215;24</span>

00407CF5  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">EDX</span> <span style="color: #008000;">; EDX为余数，存到EBX</span>

00407CF7  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407CFA  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>]  <span style="color: #008000;">; 取序列号第1位</span>

00407CFC  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407CFD  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9    <span style="color: #008000;">; 转换成数值</span>

00407D02  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407D05  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span>

00407D07  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff0000;">AL</span> <span style="color: #008000;">; 序列号第1位值存到ECX</span>

00407D09  <span style="color: #0000d0;">CMP</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">ECX</span> <span style="color: #008000;">; EBX=ECX?</span>

00407D0B  <span style="color: #0000d0;">JNZ</span> 是男人就.00407DBD  <span style="color: #008000;">; 不等，验证失败，跳到函数结束</span>

<span style="color: #008000;">; 头有些大了，用心看发现这里在判断序列号是否符合规则</span>

<span style="color: #008000;">; (第3位+第6位*2+0x1D)%0&#215;24==第1位</span>

<span style="color: #008000;">; 跟着又是两段代码类似的，不难发现也是判断，不过规则有小小的不同</span>

<span style="color: #008000;">; 下面这段的判断规则是</span>

<span style="color: #008000;">; (第2位+第5位*2+0x1D)%0&#215;24==第7位</span>

00407D11  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407D14  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+4]

00407D17  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407D18  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9

00407D1D  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407D20  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">EBX</span>

00407D22  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">BL</span>,<span style="color: #ff0000;">AL</span>

00407D24  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407D27  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+1]

00407D2A  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407D2B  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9

00407D30  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407D33  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span>

00407D35  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff0000;">AL</span>

00407D37  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">ESI</span>,24

00407D3C  <span style="color: #0000d0;">LEA</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">ECX</span>+<span style="color: #ff0000;">EBX</span>*2+1D]

00407D40  <span style="color: #0000d0;">CDQ</span>

00407D41  <span style="color: #0000d0;">IDIV</span> <span style="color: #ff0000;">ESI</span>

00407D43  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">EDX</span>

00407D45  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407D48  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+6]

00407D4B  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407D4C  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9

00407D51  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407D54  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span>

00407D56  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff0000;">AL</span>

00407D58  <span style="color: #0000d0;">CMP</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">ECX</span>

00407D5A  <span style="color: #0000d0;">JNZ</span> 是男人就.00407DBD

<span style="color: #008000;">; 下面这段的判断规则是</span>

<span style="color: #008000;">; (第1位+第7位*2+0x1D)%0&#215;24==第4位</span>

00407D60  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407D63  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+6]

00407D66  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407D67  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9

00407D6C  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407D6F  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">EBX</span>

00407D71  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">BL</span>,<span style="color: #ff0000;">AL</span>

00407D73  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407D76  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>]

00407D78  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407D79  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9

00407D7E  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407D81  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span>

00407D83  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff0000;">AL</span>

00407D85  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">ESI</span>,24

00407D8A  <span style="color: #0000d0;">LEA</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">ECX</span>+<span style="color: #ff0000;">EBX</span>*2+1D]

00407D8E  <span style="color: #0000d0;">CDQ</span>

00407D8F  <span style="color: #0000d0;">IDIV</span> <span style="color: #ff0000;">ESI</span>

00407D91  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">EDX</span>

00407D93  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff00ff;">DWORD</span> PTR <span style="color: #ff0000;">SS</span>:[<span style="color: #ff0000;">EBP</span>+8]

00407D96  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">AL</span>,<span style="color: #ff00ff;">BYTE</span> PTR <span style="color: #ff0000;">DS</span>:[<span style="color: #ff0000;">EAX</span>+3]

00407D99  <span style="color: #0000d0;">PUSH</span> <span style="color: #ff0000;">EAX</span>

00407D9A  <span style="color: #0000d0;">CALL</span> 是男人就.00407DC9

00407D9F  <span style="color: #0000d0;">ADD</span> <span style="color: #ff0000;">ESP</span>,4

00407DA2  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">ECX</span>,<span style="color: #ff0000;">ECX</span>

00407DA4  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">CL</span>,<span style="color: #ff0000;">AL</span>

00407DA6  <span style="color: #0000d0;">CMP</span> <span style="color: #ff0000;">EBX</span>,<span style="color: #ff0000;">ECX</span>

00407DA8  <span style="color: #0000d0;">JNZ</span> 是男人就.00407DBD

上面这三段就是序列号验证的主要部分了，写个示意表达式，用b1~b7表示序列号第1至7位转换后的数值，T为临时变量：

T = b3 + b6*2 + 1D

b1 = T mod 24 ?

T = b2 + b5*2 + 1D

b7 = T mod 24 ?

T = b1 + b7*2 + 1D

b4 = T mod 24 ?

如果三次判断均通过，那么整个序列号验证函数就回返回1，表示验证通过：

00407DAE  <span style="color: #0000d0;">MOV</span> <span style="color: #ff0000;">EAX</span>,1   <span style="color: #008000;">; EAX=1</span>

00407DB3  <span style="color: #0000d0;">JMP</span> 是男人就.00407DC4  <span style="color: #008000;">; 跳到返回</span>

00407DB8  <span style="color: #0000d0;">JMP</span> 是男人就.00407DC4

00407DBD  <span style="color: #0000d0;">XOR</span> <span style="color: #ff0000;">EAX</span>,<span style="color: #ff0000;">EAX</span> <span style="color: #008000;">; 任何验证的情况下均返回0</span>

00407DBF  <span style="color: #0000d0;">JMP</span> 是男人就.00407DC4

00407DC4  <span style="color: #0000d0;">POP</span> <span style="color: #ff0000;">EDI</span>

00407DC5  <span style="color: #0000d0;">POP</span> <span style="color: #ff0000;">ESI</span>

00407DC6  <span style="color: #0000d0;">POP</span> <span style="color: #ff0000;">EBX</span>

00407DC7  <span style="color: #0000d0;">LEAVE</span>

00407DC8  <span style="color: #0000d0;">RETN</span>

到这里就差不多了，序列号验证函数已经分析完成，它的验证规则也知道了，接着是写注册机了，不过我一开始没想到怎么随机产生一个序列号，只好把正确的序列号全列出来了，看了一下，有4万多个……我用C写了个列序列号的程序，用的穷举法，列出每一个序列号，判断是否可用，如果可用就打印出来，程序清单如下：

<span style="color: #0000d0;">#include</span> &lt;stdio.h&gt;

<span style="color: #0000d0;">int</span> main()

{

<span style="color: #0000d0;">char</span> bin2char(<span style="color: #0000d0;">int</span> bin);

<span style="color: #0000d0;">int</span> tmp,b1,b2,b3,b4,b5,b6,b7;

<span style="color: #ff0000;">printf</span>(<span style="color: #808080;">&#8220;register codes:\n&#8221;</span>);

<span style="color: #0000d0;">for</span>(b1=0;b1&lt;36;b1++)

<span style="color: #0000d0;">for</span>(b2=0;b2&lt;36;b2++)

<span style="color: #0000d0;">for</span>(b3=0;b3&lt;36;b3++)

<span style="color: #0000d0;">for</span>(b4=0;b4&lt;36;b4++)

<span style="color: #0000d0;">for</span>(b5=0;b5&lt;36;b5++)

<span style="color: #0000d0;">for</span>(b6=0;b6&lt;36;b6++)

<span style="color: #0000d0;">for</span>(b7=0;b7&lt;36;b7++)

{

tmp = b3 + b6*2 + 0x1D;

<span style="color: #0000d0;">if</span> (b1!=tmp%0&#215;24) <span style="color: #0000d0;">break</span>;

tmp = b2 + b5*2 + 0x1D;

<span style="color: #0000d0;">if</span> (b7!=tmp%0&#215;24) <span style="color: #0000d0;">break</span>;

tmp = b1 + b7*2 + 0x1D;

<span style="color: #0000d0;">if</span> (b4!=tmp%0&#215;24) <span style="color: #0000d0;">break</span>;

<span style="color: #ff0000;">printf</span>(<span style="color: #808080;">&#8220;%c%c%c%c%c%c%c\n&#8221;</span>,

bin2char(b1),bin2char(b2),bin2char(b3),bin2char(b4),bin2char(b5),bin2char(b6),bin2char(b7));

}

}

<span style="color: #0000d0;">char</span> bin2char(<span style="color: #0000d0;">int</span> bin)

{

<span style="color: #0000d0;">if</span>(bin&lt;10) <span style="color: #0000d0;">return</span>(bin+0&#215;30);

<span style="color: #0000d0;">else</span> <span style="color: #0000d0;">return</span>(bin-10+0&#215;41);

}

函数bin2char是序列号验证过程中字符转数值的逆过程。

是男人就下100层的破解就到此结束了，后来我又看了一下序列号的规律，发现第7位总是为0，而第4位决定第1位，而第3位与第6位，第2位与第5位分别为一组。这样，随机产生b2,b3,b4就可以生成一个序列号了。另外，也可用暴力破解的方式，在序列号验证函数中直接将EXA=1并返回，这样不论什么序列号都能通过验证了：）

OK，大功告成。写的有些啰嗦，第一次写破解的文章，有错误也是难免的，欢迎指正^_^，vipxjw#163.com。

</div>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/get-serial-of-shinanrenjiuxia100cen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[VB] 一个操作多线程的类</title>
		<link>http://xujiwei.com/blog/vb-multithread-class/</link>
		<comments>http://xujiwei.com/blog/vb-multithread-class/#comments</comments>
		<pubDate>Wed, 10 May 2006 13:19:25 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[MultiThread]]></category>
		<category><![CDATA[VB]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=124</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/vb-multithread-class/" title="[VB] 一个操作多线程的类"></a>根据点睛工作室的多线程类改写的，不过没有经过严格测试，好像工作不是很稳定，如果使用不当会出错的说。 Option Explicit Private Type SECURITY_ATTRIBUTES nLength As Long lpSecurityDescriptor As Long bInheritHandle As Long End Type Private Declare Function CreateThread Lib &#8220;kernel32&#8243; (lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/vb-multithread-class/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/vb-multithread-class/" title="[VB] 一个操作多线程的类"></a><p>根据点睛工作室的多线程类改写的，不过没有经过严格测试，好像工作不是很稳定，如果使用不当会出错的说。</p>

<blockquote>
<div id="_mcePaste">
<div id="_mcePaste"><span style="font-style: normal;">Option Explicit</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Type SECURITY_ATTRIBUTES</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> nLength As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> lpSecurityDescriptor As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> bInheritHandle As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Type</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function CreateThread Lib &#8220;kernel32&#8243; (lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function CreateThreadL Lib &#8220;kernel32&#8243; Alias &#8220;CreateThread&#8221; (ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function TerminateThread Lib &#8220;kernel32&#8243; (ByVal hThread As Long, ByVal dwExitCode As Long) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function SetThreadPriority Lib &#8220;kernel32&#8243; (ByVal hThread As Long, ByVal nPriority As Long) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function GetThreadPriority Lib &#8220;kernel32&#8243; (ByVal hThread As Long) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function ResumeThread Lib &#8220;kernel32&#8243; (ByVal hThread As Long) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function SuspendThread Lib &#8220;kernel32&#8243; (ByVal hThread As Long) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function GetCurrentThread Lib &#8220;kernel32&#8243; () As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function GetCurrentThreadId Lib &#8220;kernel32&#8243; () As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Sub ExitThread Lib &#8220;kernel32&#8243; (Optional ByVal dwExitCode As Long = 0)</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Declare Function GetLastError Lib &#8220;kernel32&#8243; () As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&#8216; 常数常量</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const MAXLONG = &amp;H7FFFFFFF</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&#8216; 线程优先级常量</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_BASE_PRIORITY_IDLE = -15</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_BASE_PRIORITY_LOWRT = 15</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_BASE_PRIORITY_MAX = 2</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_BASE_PRIORITY_MIN = -2</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_HIGHEST = THREAD_BASE_PRIORITY_MAX</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_IDLE = THREAD_BASE_PRIORITY_IDLE</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_LOWEST = THREAD_BASE_PRIORITY_MIN</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_NORMAL = 0</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_TIME_CRITICAL = THREAD_BASE_PRIORITY_LOWRT</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_ABOVE_NORMAL = (THREAD_PRIORITY_HIGHEST &#8211; 1)</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_BELOW_NORMAL = (THREAD_PRIORITY_LOWEST + 1)</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const THREAD_PRIORITY_ERROR_RETURN = (MAXLONG)</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&#8216; 线程创建标志</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_ALWAYS = 2</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_NEW = 1</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_NEW_CONSOLE = &amp;H10</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_NEW_PROCESS_GROUP = &amp;H200</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_NO_WINDOW = &amp;H8000000</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_PROCESS_DEBUG_EVENT = 3</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_SUSPENDED = &amp;H4</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Const CREATE_THREAD_DEBUG_EVENT = 2</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">&#8216; 线程优先级结构</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Public Enum ThreadPriority</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Lowest = THREAD_PRIORITY_LOWEST</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> BelowNormal = THREAD_PRIORITY_BELOW_NORMAL</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Normal = THREAD_PRIORITY_NORMAL</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> AboveNormal = THREAD_PRIORITY_ABOVE_NORMAL</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Highest = THREAD_PRIORITY_HIGHEST</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Enum</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private mAttrib As SECURITY_ATTRIBUTES</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private mEnabled As Boolean</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private mThreadHandle As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private mThreadID As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private mTerminate As Boolean</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Public Property Get ThreadID() As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> ThreadID = mThreadID</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Property</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Public Property Get ThreadHandle() As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> ThreadHandle = mThreadHandle</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Property</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Public Function Create(ByVal cFunction As Long, Optional ByVal cPriority As ThreadPriority, Optional ByVal cEnabled As Boolean = True) As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Dim CreateFlag As Long</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If mThreadHandle &lt;&gt; 0 Then TerminateMe</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> mEnabled = cEnabled</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If mEnabled Then</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> CreateFlag = CREATE_NEW</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Else</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> CreateFlag = CREATE_SUSPENDED</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> End If</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> mAttrib.nLength = Len(mAttrib)</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> mThreadHandle = CreateThreadL(0, 0, cFunction, 0&amp;, CreateFlag, mThreadID)</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If mThreadHandle = 0 Then</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> MsgBox &#8220;Create thread failed!Error code:&#8221; &amp; GetLastError, vbOKOnly Or vbCritical, &#8220;Error&#8221;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> End If</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Function</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Public Sub SuspendMe()</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If mThreadHandle = 0 Or mEnabled = False Then Exit Sub</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If SuspendThread(mThreadHandle) &lt;&gt; -1 Then</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> mEnabled = False</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Else</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> MsgBox &#8220;Suspend thread failed!Error code:&#8221; &amp; GetLastError, vbOKOnly Or vbCritical, &#8220;Error&#8221;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> End If</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Sub</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Public Sub ResumeMe()</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If mThreadHandle = 0 Or mEnabled = True Then Exit Sub</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If ResumeThread(mThreadHandle) &lt;&gt; -1 Then</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> mEnabled = True</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> Else</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> MsgBox &#8220;Resume thread failed!Error code:&#8221; &amp; GetLastError, vbOKOnly Or vbCritical, &#8220;Error&#8221;</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> End If</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Sub</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Public Sub TerminateMe()</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> If mThreadHandle = 0 Then Exit Sub</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> TerminateThread mThreadHandle, 0</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> mThreadHandle = 0</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216;mTerminate = True</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216;Do</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216;    DoEvents </span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216;Loop Until mTerminate</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Sub</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">Private Sub Class_Terminate()</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;"> &#8216;TerminateThread mThreadHandle, 0</span></div>
<div id="_mcePaste"><span style="font-style: normal;">
</span></div>
<div id="_mcePaste"><span style="font-style: normal;">End Sub</span></div>
</div></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/vb-multithread-class/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用汇编实现符串操作函数</title>
		<link>http://xujiwei.com/blog/string-operating-in-asm/</link>
		<comments>http://xujiwei.com/blog/string-operating-in-asm/#comments</comments>
		<pubDate>Mon, 29 Aug 2005 22:33:14 +0000</pubDate>
		<dc:creator>Xu Jiwei</dc:creator>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[ASM]]></category>
		<category><![CDATA[String]]></category>

		<guid isPermaLink="false">http://tmp.xujiwei.com/blog/?p=128</guid>
		<description><![CDATA[<a href="http://xujiwei.com/blog/string-operating-in-asm/" title="用汇编实现符串操作函数"></a>不管是在系统开发还是在平时的编程当中，字符串操作都是很重要的一部分。在C中，已经有库提供了strcpy、strcmp、strcat等函数， 而在开发用汇编开发自己的系统时，并没有现在的库可用，这就要求我们自己来实现字符串操作了。以下如果没有特别说明，字符串均以0为结束标志。 strcpy 字 符串复制 在字符串复制当中，为了简便，可以像在C中一样，不考虑边界问题，把这个问题交调用者，不过这样就有可能产生缓冲区溢出 了：）字符串复制还是比较容易实现的，只要在复制每一个字节之前判断是不是0，如果是就结束，不是则继续复制下一个字节。我给出一个简单的例子，当然，你 可以把它优化以产生更好的性能。 strcpy: ; in  si 源字符串起始地址 ;     di 目标地 址 ; out 无 push si push di  ; 保护寄存器 next: lodsb    ; 载 入一个字节 or al,al  ; 是0吗？ je end  ; 是则结束 stosb   ; 不 是则放入目标中 jmp next ; 继续下一个字节 end: mov [di],byte 0  ; 结 束标志 pop di  ; 恢复寄存器 pop si ret strlen 取 字符串长度 应该说，这一个比上一个容易，因为这个只需要考虑什么结束，而不需要去复制字节。 strlen: ; in si 源 字符串 ; out ax 字符串长度 push si push cx    ; 保护寄存器 xor cx,cx  ; 计 数器清零 next: &#8230;<p class="read-more"><a href="http://xujiwei.com/blog/string-operating-in-asm/">Read more &#187;</a>]]></description>
			<content:encoded><![CDATA[<a href="http://xujiwei.com/blog/string-operating-in-asm/" title="用汇编实现符串操作函数"></a><p>不管是在系统开发还是在平时的编程当中，字符串操作都是很重要的一部分。在C中，已经有库提供了strcpy、strcmp、strcat等函数， 而在开发用汇编开发自己的系统时，并没有现在的库可用，这就要求我们自己来实现字符串操作了。以下如果没有特别说明，字符串均以0为结束标志。</p>

<p>strcpy 字 符串复制</p>

<p>在字符串复制当中，为了简便，可以像在C中一样，不考虑边界问题，把这个问题交调用者，不过这样就有可能产生缓冲区溢出 了：）字符串复制还是比较容易实现的，只要在复制每一个字节之前判断是不是0，如果是就结束，不是则继续复制下一个字节。我给出一个简单的例子，当然，你 可以把它优化以产生更好的性能。</p>

<p>strcpy:</p>

<p>; in  si 源字符串起始地址</p>

<p>;     di 目标地 址</p>

<p>; out 无</p>

<p>push si</p>

<p>push di  ; 保护寄存器</p>

<p>next:</p>

<p>lodsb    ; 载 入一个字节</p>

<p>or al,al  ; 是0吗？</p>

<p>je end  ; 是则结束</p>

<p>stosb   ; 不 是则放入目标中</p>

<p>jmp next ; 继续下一个字节</p>

<p>end:</p>

<p>mov [di],byte 0  ; 结 束标志</p>

<p>pop di  ; 恢复寄存器</p>

<p>pop si</p>

<p>ret</p>

<p>strlen 取 字符串长度</p>

<p>应该说，这一个比上一个容易，因为这个只需要考虑什么结束，而不需要去复制字节。</p>

<p>strlen:</p>

<p>; in si 源 字符串</p>

<p>; out ax 字符串长度</p>

<p>push si</p>

<p>push cx    ; 保护寄存器</p>

<p>xor cx,cx  ; 计 数器清零</p>

<p>next:</p>

<p>lodsb       ; 载入一个字节</p>

<p>or al,al     ; 是0？</p>

<p>je end     ; 是 则结束</p>

<p>inc cx      ; 字符串长度＋1</p>

<p>jmp next ; 继续下一个字节</p>

<p>end:</p>

<p>mov ax,cx ; 将 字符串长度放到AX中作为返回值</p>

<p>pop bx     ; 恢复寄存器</p>

<p>pop si</p>

<p>ret</p>

<p>strcat 字 符串连接</p>

<p>就个人来说，字符串连接用得并不是很多，但既然在C中有这个函数，就必然有它存在的理由，所以我们还是有必要来实现它的。 同样的，在字符串连接时不考虑目标缓冲区是否足够的问题，把这个交给调用者。</p>

<p>要将一个字符串连接到另一个字符之后，就需要先找出目 标字符串的结尾，即0的地址，然后就可以把这个地址做为目标，把需要连接的字符串的首地址做为源，调用strcpy即可完成。而找出0的地址，原理和取字 符串长度一样，载入一个字节然后判断是否为0。这个留大家自己去实现。</p>

<p>上面的例子使用的寄存器都是16位的，所以只能用在16位的 程序当中，当然，如果是你自己写的，那么自己懂得它实现的原理，移植到32位就是件很容易的事。</p>

<p>今天这篇就到这里喽～～难得写教 程之类的文章，今天还算顺手^-^～～</p>
]]></content:encoded>
			<wfw:commentRss>http://xujiwei.com/blog/string-operating-in-asm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

