查看完整版本: [-- [ZT]我和电脑亲密接触的心路历程 --]

Bay Area Chinese--灣區華人 -> 乱讲 -> [ZT]我和电脑亲密接触的心路历程 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

<<  1   2   3  >>  Pages: ( 3 total )

伍胥之 08-29-2015 06:20

[ZT]我和电脑亲密接触的心路历程

[attachment=78335] b)r;a5"<5  
n"@){:{4?  
当年闲得无聊,用DEBUG跟踪出来FDISK居然有一个未公开的参数,就信手写了个小豆腐,发在来浪潮集团的一个小杂志上。 LyG`q3@  
Y3SV6""y/  
没想到,第二年有个专业人士居然在另一杂志上发表了一篇差不多一样一样的文章。 U6YHq2<  
7vc4 JO]  
这是不是叫所见略同呢?

伍胥之 08-29-2015 06:35
玩硬盘主引导记录,写动态分区表 8T Tj<T!N  
% pAbkb3m  
DOS玩了一阵,再玩点啥呢? |+qsO ;  
j' b0sve|?  
那就看看硬盘分区表吧! 35:RsL  
gJ>#HEkMB  
那个时代办公室用的电脑也就是PC-XT,好一点是286,毕竟不是专业用嘛!能打个字就差不多了。 z|zEsDh;  
U(%6ny  
没有杂志看,也没有攻略,没有目的,就是瞎琢磨。 ;Nd'GA+1;(  
 %\~U>3Q  
一般几十MB的硬盘,都是CHS模式,连LBA都没有。 0:c3aq&u  
sj6LrE=1  
0道0面一共有17个扇区,最多1023条磁道。 DL为驱动器,80h为第一硬盘, DS:BX为读写缓冲,AH=2(r)/3(w), CH为10位磁道的低8位,AL低6位是扇区号,高2位借给CH,所以最大为1023, DH是磁头号,最大倒是可以到255。CL是读写扇区数,缓冲区应该是不能超过64KB. 那个时候支持的最大磁盘为 1024道* 256面 /道* 63扇区/面.   ]2A2<Q_,  
0-/@-qV\  
Mov DL, 80h U U#tm  
Mov DH,00 n3$u9!|P  
mov BX, 1000h #+$ PD`j  
mov cx, 0001 ;s8\F]K  
mov ax,0201h -vc ,O77z"  
int 13h Tt,T6zs- <  
SH O&:2  
这就把主引导记录读入了地址为DS:1000h的内存。 uG-S$n"7K  
{`(MK6D8 c  

伍胥之 08-29-2015 06:44
U(nassembly) 1000 :NB.ib@*  
把它反汇编出来,就知道它在启动过程中在做什么了。 /[n]t  
5f2=`C0_  
不过,不能真正跟踪它,只在在脑子里或纸上跟踪,否则立马死机。 l8e)|MSh  
{Q @?CT  
因为,执行不了几步,它就把它自己搬到了一个固定的地方0000:0700H这个地方在有OS时是OS的核心地区。 $f >(TW  
nQ{~D5y,,  
BOIS是固定把这个主引导程序读到0:700H地方,检查这个块的最后一个字是否是0xAA55的。然后才将控制权给它。 7G0;_f{  
TV`sqKW  
它干得活很简单,它把自己复制到另一个地址,并跳过去,检查分区表,一共4*20h的个符,每一项用32个字节,标志了是否可引导,OS类型、分区大小、起始的CHS位置。然后找到一个标记为80h的可引导分区,从对应的CHS读出这个分区的引导记录,也是读 到0:700h,检查合格后就再交给它了。 zjzEmX  
 }ktK*4<k  
那个时候,我只用过DOS,别的系统从没有用过。 j3u!lZ}U  
9_ ~9?5PU  
_nSEp >]L  
但是,我突然发现这4个分区不够用的了。 N0N%~3  
xc7Rrh]}  
因为我需要隐藏点什么,当然,不是艳照,那时不仅没有DC,连扫描仪也没有。 n'%cO]nSx  
&-m}w:j=  
9WV8ZP  
T&}KUX~Q/  
uuL(BUGt-  
XV,ce~ro[  

伍胥之 08-29-2015 06:47
地址记错了,不是0:700h,而是0:7c00h

伍胥之 08-29-2015 06:55
0000:7C00 XOR AX,AX )19#g1rn5  
0000:7C02 MOV SS,AX <&bBE"U4  
0000:7C04 MOV SP,7C00 ~yA^6[a=  
0000:7C07 STI MPF({Pnx7  
0000:7C08 PUSH AX mP?}h  
0000:7C09 POP ES +fq \K]  
0000:7C0A PUSH AX   9#kk5 )J  
0000:7C0B POP DS yw1Xxwc  
0000:7C0C CLD PfGiJ]:V-u  
0000:7C0D MOV SI,7C1B 12: Q`   
0000:7C10 MOV DI,061B P/Y)Yx_(  
0000:7C13 PUSH AX  `YO&  
0000:7C14 PUSH DI y. (m#&T  
0000:7C15 MOV CX,01E5   p\Iy)Y2Lf!  
0000:7C18 REPZ   }9FWtXAU^1  
0000:7C19 MOVSB Nnoj6+b  
0000:7C1A RETF x'SIHV4M@Q  
K??jV&Xor  
;跳到这里来了。 I.`D BI#-f  
0000:061B MOV SI,07BE 5'%O]~  
0000:061E MOV CL,04 !(3[z>  
0000:0620 CMP [SI],CH ; Q5_,`r`  
0000:0622 JL 062D   Dj6^|R$z&  
0000:0624 JNZ 063B   '2rSX[$ tf  
0000:0626 ADD SI,+10 w{N8Y ~O  
0000:0629 LOOP 0620 n#B}p*G  
0000:062B INT 18  ‘ 如果没有可引导的分区,就直接执行一个软中断,这个玩艺,当年叫ROM BASIC 9fO E .  

伍胥之 08-29-2015 07:07
我想干什么呢? yh).1Q-D  
}G!'SZ$F 5  
办公室有很多人,我想把游戏、我的个人文件分别放到不同分区上,给每个人定义一个属于自己的分区。 WcpH= "vm  
C:f^&4 3  
那年头没有什么安全机制啊!所以只能是隐藏整个磁盘。 T7l,}G  
C IRMAX  
我用整整一个扇区做分区表,最多可以分成16个分区(我的硬盘才20MB!)。 LvU/,.$  
IoV"t,  
然后用另一个扇区做成一个用户表,反正第一个分区总是从0道的1柱面开始,有十几个扇区在DOS分区之前可用呢!用户表里面定义了用户名、密码和用户可以访问的分区,除大家共用的C盘有DOS外,其它的15个根据权限决定哪一个可以访问。如果在0-15分区中,0,1,5,6,7可被该用户访问,则把0分区变成DOS的主分区,把1567合成一个扩展分区,1为D盘567分别有EFG盘。而对另一用户而言,可能D代表了第9个分区。 +U?7 3cYN  
L x iN9  
在引导过程中,主引导记录不含分区表,除了有一个55AA标志外,其余是我自己的代码。加载我的全部代码后,要求用户输入一个用户名、密码,如果校验成功,则根据相应权限,重新合成一个用户对应的分区表,包括了主分区和扩展分区(以及逻辑卷的链表)。 ]I]G3 e  
Mgu9m8 `J  
然后,根据新生成的分区表,去引导主分区的DOS分区。 J?tnS6V  
4ywtE}mp  

伍胥之 08-29-2015 07:10
还需要一个安装程序,把我们东东直接写到CH0Head0Sect1中。 K1- RJj\L  
)Lk2tv r  
这些代码都是用汇编写的,不过,我已经会用C了,所以它的管理程序是用C写出来的。就是定义用户表、分区表这样的东东,把它写入一个Binary的文件中。 fd62m]X  
=l6W O*  
居然可以工作了!虽然长得很丑,而且一点也不温油。 o ,xy'  
Yq:/dpA_  
我不知道那个时候有没有多操作系统引导程序,所以,我这个也没有多OS,所以我自己给它起了一个名字,叫动态引导。

伍胥之 08-29-2015 07:12
很可惜,这些代码我已经找不到了。

伍胥之 08-29-2015 07:25
引用
引用第28楼newport93于01-21-2011 17:06发表的  : u{dkUG1ia  
老5从FORTRAN玩起的啊,那是相当的牛! A.YK=_J  
6.a>7-K}%  
现在玩什么了?   dkg+_V!  
CurU6x1  
[~;wCW,1  
现在只会玩VB6.0混合点Win32API了。 h,K&R8S  
YeB C6`7y  
不过ASP用得多一点,我的课基本上都自己弄个网站,让学生交作业或考试。 w[G-=>;  
R/6 v#9m7  
想学学ASPX, 但是我对.net的托管啥得不明白。 #kJ8 qN  
d[E= HN  

伍胥之 08-29-2015 07:27
引用
引用第39楼suehan234于01-22-2011 08:00发表的 回 38楼(伍胥之) 的帖子 : QqXaXx;  
佩服,玩也玩得这么专业! xx?0F tuq  
DnN+W  
#X6=`Xe#  
算不上专业,只是瞎捣鼓,或瞎鼓捣。

伍胥之 08-29-2015 07:46
初见中文版HTML类语言 K5(T7S  
7'`nTF-@v  
t=[/ L]!  
大约在93或94年的时候,四通MS2401已经在打字社用得不多了,学校印刷厂用华光激光照排系统。 77 ?TRC  
m 7+=w>o  
学校里有一个研究所出一个小杂志,自己有台电脑可以用这个华光/方正的排版系统,我不知道是华光[在山东潍坊]和北大方正是谁山寨谁,不过,反正都是王选他们搞出来的。 H 'nLC,  
[attachment=78336] TETfRnm  
够复杂吧? 3[~LmA  
[yRqSB  
但是它可以排出我们在中文书本上的所有格式,很神奇。直接就是一门语言。 dO-Zj#%7z8  
DG3Mcf@5  
确实, 人家就叫BD排版语言。我猜是代表北大吧!

伍胥之 08-29-2015 07:51
一般的文字还是比较简单的,就是如【HT4K】汉字4号楷体【HT5XBS】汉字5号小标宋  这样的东东。 GW9,%}l^;  
h^J :k  
8"u.GL.  
此为小样,可以用任何文字编辑器,然后经过一次扫描,生成一个文件,再经二次扫描生成一个可以由专门显示程序显示的实际格式,此为大样。 cc"<H}g>`  
h5^We"}+  
在没有所见即所得的年代,打字员完全在脑子里想像它最终的格式。结果不理想再回去重新编辑。 i_I`  
q"-Vh,8h  

伍胥之 08-29-2015 08:13
我也想玩玩它了。 "`w*-O  
9  I&[6}  
但是,它有一个硬件加密卡,插在电脑里面的ISA总线接口上。 F[fs^Q6S$  
R!rMrWX  
没有它,扫描1程序就不work. -{yG+1  
J,=^'K(  
肿么办呢?里面有啥秘密呢? V7+/|P_  
#O'g*]j  
一个假期里,人家不上班的时候,我找一个相熟的女打字员偷偷借出来了,她电脑坏了也常找我修修补补。 I."s&]FZ  
}5X.*wz  
\; "S>dg  
我家里那时候没有电脑啊! TI8E W  
T$V8 n_;  
带着它去了门口的LQ公司,自己组装了一台286兼容机。 @Z96902<t  
C{6m?6  
那个时候我连ISA总线接口规范也不懂,只是知道一点,它里面绝对没有通过DMA总线访问的存贮器。因为电脑开机后,从0-640KB RAM中没有它的地方,而从A000:0 - F000:0FFF的ROM中可以看到除了固有的BIOS外,没有别的。实模式下就这些东东。 -3XnUGK  
gX* &RsF  
先DEBUG找找有没有小虫再说吧! uYd_5 nw  
e JEcLK3u  
72小时!!!! 3V]psZS  
{|e7^_ke  
整 整 3天,我跟踪了它2天半! 店里给我准备了水和方便面,下班就把我关在里面。 4U[X-AIY&  
Mv7tK l  
发现它总是在扫描1时写入1个特定的端口,然后从另一端口读出点东东。 #;"lBqxY`  
% <h2^H\O  
然后,不管三七二十一,把pass1全部反汇编成一个巨大的文本文件,找出了所有IN 和 OUT 指令。这个好办,咱有DOS的FIND命令,那时叫管道或过滤操作。   O:dUzZR['  
gOaK7A  
type  pass1.txt | find "IN 7E" >in.txt     J!'IkC$>  
type  pass1.txt | find "OUT 7F" >out.txt zaE!=-U  
X0K Unxw  
再看看它们是不是真的 in 和 out 指令,因为许多字符也会被反汇编成莫名其妙的指令。debug比较笨,不会反汇编伪指令,所以它是不会给我反汇编成类似    db "this is a string other than a series of 8086 instruction$"这样的东东的。 g G|4+' t  
;47=x1j i  
其实,那个年代实际上是有专门的反汇编程序的,能根据内容反汇编出不同的段,类似于: pf3-  
I*(7(>zgyv  
Identfier1 segment \i)@"}  
   msg01 db "this is a data segment", 0dh,0ah c>C!vAg  
ends >rFM8P(  
\/r]Ra  
但是,俺不是圈内人,不知道有这好东东啊! vLCm,Bb2L  
4 @9cO)m  
A}1:fw\Fn3  
不管如何,我找到了它的读写端口的真实指令和地址。  <*p  
&7c#i  
再跟踪它就好办了,直接运行了所有读写 7E和7F端口的地方。看看它到底读出了什么东东。 `oE.$~'  
.O PBET(gv  
Ej`G(  
L_IvR 4:j~  
K%/g!t)  

伍胥之 08-29-2015 08:19
说白了就很简单了,它和接在LPT:口上的加密狗一样。向特定端口发送一个要读的字节地址,然后从另一端口读出来一个字节。 }5?|iUH|  
w/7vXz<  
发现它只是从加密卡出读出来32个字节而已。 f{'N O`G  
W#9LK Jj  
而且,每次运行读出来的字符序是完全一致的! hllb\Y)XL  
y<y9'tx  
把加密卡取出来,重新运行。在读端口时停下来,然后跳过去,但是把我记下的字符序列传给DX寄存器。当然把这个序列用完了以后,一个Go指令,它开始给我处理排版文件了,而PASS2 也是同样处理。 o* QZf *M  
B{1yMJA  
L_>LxF43  
哈哈哈!这个加密卡被我破解了!!! a$ G hb]  
cP0(Q+i7  
这三天,太TMD值了!比打任何游戏通关都兴奋,而且特别好玩!

伍胥之 08-29-2015 08:27
接下来的就比较简单了。 JOki4N  
-"xC\R  
把所有的IN DX, 7F指令变成一个 INT 80, 然后在华光的中文系统加载后,自己写一个简单的TSR程序,安装一个INT 80的软中断服务程序,在其中把这32个字节放在服务程序中,再用一个字节做个计数器。 每次有程序调用这个中断时,它返回一个序列中的字节,计数器加1,达到序列末尾时计数器复位。 C,{ Ekbg  
*(VwD)*  
完工!

伍胥之 08-29-2015 08:31
后来呢?没有什么后来了。 ?gXdi<2Qn  
9O:-q[K**  
我把这个盗版的东东,给好几个朋友装上了,其实我也不知道它值多少钱,反正学校门口的打字社我去了不论打字复印人家都不收钱。 4{" v  
f:9qId ;/M  
SN#N$] y5s  
中间出了一个插曲。 "l6Ob  
0#F<JsO|u  
上班以后,我给人家那个研究所的电脑上装上了我的解密版,而把加密卡自己留下来装到我自己的机器上了。不厚道吧? z'EphL7r   
Z0Qh7xWve  
过了两年,她突然找到我,问我那个卡是不是还用? 我都快忘了这事了,因为那个386SX被我扔到床底下去了,我已经免费换了一套386DX. dwm>! h  
1sfs!b&E  
而她的电脑也换了,再装上正版的方正不干活了。 77G4E ,]  
=&vRT;6  
赶紧从床底下扒拉出来那个破电脑。好在,加密卡还在。 mS]soYTQ  
P;e@<O  

伍胥之 08-29-2015 08:40
其实,我是做了很多无用功的。 #YLI"/Kn  
FFf ~Vmw  
因为那个时候,在386平台上已经有比DEBUG好5倍的调试器了。  c$)!02  
rrZ'Dz  
叫SoftICE, 因为ICE是一块硬件调试板,当然是专业级的。而Soft ICE只是一个软件,但是它利用了386 CPU的调试寄存器,所以有了条件中断。 例如,可以设置一个条件而不必逐条指令跟 踪,符合条件时程序会中断运行,回到SOFTICE控制台。比如当BX寄存器为1000h时则运行中断。 a+n?y)u  
&|Vzo@D(!  
那可是省事省时多了。 w)gMJX/0yw  
PMiG:bM  
]tEH`Kl  
不过,这个东东我还没用热乎,它就不能用了。因为有程序自己使用了调试寄存器,所以在监控条件下运行和非监控下运行结果可以完全不同,会把跟踪都引向歧路。 v1E(K09h2  
Ak2Vf0Eb  
从此,跟踪与反跟踪就变成了道和魔。 vu/P"?F  
zZ])G  

伍胥之 08-29-2015 08:59
那个时候,自己玩得不亦乐乎,已经开始把它当游戏玩了。 RD*.n1N1  
SwhArvS  
我自己写过一个反跟踪的小程序,只有几条指令,做成一个宏,可以插在任意地方。很有效,但也可能很危险。 R"QWap}  
vn96o] n  
那个年代对指令和数据没有什么严格区分的,只要把DS取成CS一样的值,就可以在运行过程中修改代码。现在,则有人会利用一此漏洞,在数据中插入代码,然后利用这些代码来窃取点什么。 1ka58_^  
X""}]@B9z  
这个反跟踪程序利用了CPU的指令预取(prefetch)特征,在绝大多数情况下,CPU在运行一条指令时,除非是跳转指令,下面的几条指令已经在CPU中排队了,并不需要从内存中读指令。 0U:9&j P,  
E%)3{# .z  
所以,如果正在运行的指令修改了下一条指令,在全速运行且不中断时,这个修改只改变了内存中的东东,而CPU指令流水线中的并不会改变。但是,如它在被跟踪进,这条指令修改后,下一条指令已经被上条修改,所以,运行结果就会完全不同了。 bw[K^/  
0"`|f0}c  
antitrace macro ) "^ )Nk  
`I5So-^&z  
pusha 'S; l"  
CLI ;3sJ7%`v  
mov dx, CS Vj_z"t7q  
mov DS,DX L$f:D2Ei  
nextInst: B{Lcx~  
lea BX, nextinst+8 )`m/vYKWL  
mov [bx],DX 2iWxx:e  
STI [JVU a2Sm  
POPA K.6xNQl{}  
Il<ezD{  
endm >zv}59M  
R6G%_,p$7  
我在8086-80486系统上试过,都没有问题,当然测试次数也没有像那些Benchmark程序那么多,反正只要插入这个宏,在所有有此宏的代码段,程序都不能被跟踪,因为一跟踪,在mov [bx],dx后,后面两条指令就变成随机的了(DX只是当前的DS段值,与程序加载内存位置有关)。所以,它到底可靠性多高,吃不准。不过,这东东一旦出错,后果也是完全不可预料的。 =]sM,E,n  
y1Yrf,E m=  

伍胥之 08-29-2015 09:04
年轻时玩的胆子不小,但是跳槽的勇气却没有。 g U v`G  
%XZdz =B  
现在老了,就只能YY了。 G~Fjla\?Q  
.BZ 3>]F3<  
如果当初跨专业读个CS硕士,我现在会做什么呢? Y; q['h  
OlYCw.Zu  
估计不如现在好玩。 qg8T}y>  
,wk %)^  
X!0m,  
因为分子生物学注定只能是个full time工作,而CS则是可以当作业余爱好玩的。 `~ R%}ID  
0bR})}a+Yg  
如果我转了CS, 难道能在半夜三更玩分子生物学? {>>Gc2UT  
M Y>o8A  
所以,命中如此吧!人老了就认命了。 (t-JGye>  

ostasia 08-29-2015 21:09
这是伍sir自传吗?那个唯一一次恋爱就修成正果了?

伍胥之 08-30-2015 07:00
引用
引用第69楼ostasia于08-29-2015 21:09发表的  : ?rv5Z^D'  
这是伍sir自传吗?那个唯一一次恋爱就修成正果了? e/V8lo  
 .t RWL!  
算是吧! 是成了正果,但是20年后又abortion了, 正在考虑: /9 soUt  
EX,)MU  
R U sure? [Ignore? Retry? Restart? ]

伍胥之 08-30-2015 07:02
10、DOS的Abort,Retry, Fail?错误 #5W-*?H  
85年以后出生的人可能不知道DOS是什么了,只有那老家伙还知道这是什么。 MIWI0bnf  
ngQ]  
我还记得当时的我对于Abort和Fail这两个选择还是比较清楚的,不过,今天完全忘记了Abort和Fail的差别是什么? -$_h]x* W  
4w0Y(y  
这个出是DOS下的经常出现,也相当的经典,以至于在Wikepedia上都有专门的业面 Abort, Retry, Fail?。 iY4FOt7\  
8{ J{)gF  
简称为ARF。当然,ARI – Abort, Retry, Ignore?

伍胥之 08-30-2015 07:10
这个SideKick是个好东东。 /s^O M`5  
{!7 ^ w  
下面的程序不是我写的。 !l1ycQM  
1\BQq  
用汇编编写DOS下的内存驻留程序(1) i^u5j\pfY*  
a$'= a09  
` Ui|T  
!3#*hL1fy  
-OV!56&  
ih/MW_t=m=  
GOhGSV#  
绪言 JGKiVBN  
>2?O-WXe  
3_+$x 4 %  
0.1 内存驻留与中断 BF>3CW7  
D<*#. >  
` SO"F,  
内存驻留程序英文叫Terminate and Stay Resident Program,缩写为TSR.这些程序加载进内存,执行完后,就驻留在内存里,当满足条件时,调到前台来执行。 &5F@u IA  
S,TK;g  
gdyP,zMD7  
内存驻留程序的常用形式有: R} aHo0r  
/I3>u  
X3;|h93.a  
>诸如Borland 的SideKick弹出式实用程序 MUU9IMFJ  
WD,iY_'7u^  
&B5@\Hd;  
>日历系统 Z2u5n`K  
!<xeAo%8  
g {?]a'?  
>网络服务器 Td>Lp=0rU  
3xGk@ 333  
F;^GhiQVS  
>通讯程序 ^8r4tX  
.ahYj n  
?-IjaDC}  
>本地的DOS扩展(如CCDOS,UCDOS等中文系统都属于这个范畴) :svRn9_8H  
wWR9dsB.;  
geRD2`3;  
>一些可恶的人利用TSR技术制作很多可恶的病毒程序,几乎所有的病毒程序都是TSR程序. :TzHI    
K\]ey;Bd  
_4jRUsvjY  
就象多任务系统调度一个进程有一个调度程序一样,在PC中从前台程序进入到一个TSR,也要有一个调度者,只是PC操作系统的调度不称为调度程序,而只称为触发机制.触发机制调度TSR执行在PC机上党称为激活一个TSR.触发机制主要有以下几种: 6P KH%  
s'|^6/  
bC@9 */i  
>硬件中断:党用的是键盘中断INT 9H,时钟中断INT 8H,通讯中断INT 14H,磁盘中断INT 13H等等. o Z#4<7K  
L0O},O  
{`vv-[j|  
>软件中断:党用的是键盘中断INT 16H,时钟中断INT 1CH,DOS中断INT 21H,等等. 8P'zQ:#RV  
8_@#5  
^}4=pkJ;s  
>以上各种的结合. i''[ u  
3<nd;@:-  
ngoAFb  
从以上的触发机制可以看出,TSR和PC机的中断系统有着密切的关系.每种激活方式实际上都是与中断有关的.常用特殊的击键序列的识别码是通过截获INT 9H和INT 16H来实现.实际上不管TSR程序的哪一个环节,都与中断有着密切的关系.因此在具体进行TSR和程序设计之前,先介绍PC中断系统.在此只作简单说明. #(G#O1+  
{qHf%y&[  
Q (Dp116  
在PC机内存的最低端(0000H开始)的1K字节中,存放着256个指针即常说的中为向量或中断矢量(Interrupt vertor),每个中断向量都指向一个子程序,该程序称为中断处理程序(Interrup handler).一个中断向量由四个字节组成,有一个字是中断处理程序的偏移量值,后一个字是中断处理程序的段值.256中断向量一起称为中断向量表. GY%48}7  
REvY`   
@4N@cM0   
手式计算中断向量的首址,可通过以下的公式来求得: l|P(S(ikh  
lIj2w;$v  
%l7|+%M.{  
X号中断向量的首址=0000H:X*4 [EETx-  
0*KU"J cXd  
1 ]uHaI(  
当产生一个中断时,处理器都按顺序执行以下步骤: Pe_iA_  
T};fy+iq  
/HmD/ E\  
>在堆栈上压入处理器的标志(相当于指令PUSHF). =c,m)\u/8  
r!vSYgee  
Zn`vL52_  
>在堆栈上压入当前CS和IP值(相当于指令PUSH CS和PUSH IP). J `8bh~7  
3tlA! e  
YI*Av+Z)  
>关闭中断(CLI) 3,cZ*4('d  
hDJ84$eVZ  
sKT GZA  
>从中断向量加载的CS和IP,执行中断处理程序. iCYo?>  
<|'C|J_!  
mw1|>*X&R  
当执行完中断处理程序后,一般用IRET返回,它的作用是: tOK lCc  
b^Xq(q>5  
L-lDvc?5c  
>从堆栈上取出保存的IP和CS(相当于指令POP CS和PUSH CS). C 4 &1M  
P]4C/UDS-~  
;-1yG@KG  
>同时恢复中断前的处理器标志(相当于指令POPF). P+Ta|-  
)wROPA\uA  
nRmZu\(Ow|  
中断有多种分类,由触发的原因和实现的性质来分,可分为硬件中断和软件中断,从操作系统分层实现来说,可以分成BIOS中断,BOS中断和用户中断. Q!<b"8V]  
dfBTx6/F  
tNI~<#+lg  
一方面,BIOS和DOS通过中断系统向用户提供一个操作系统功能界面.也就是说用户(一般来说是前台程序)的功能主要是通过调用DOS和BIOS的中断服务来实现的,具体来说就是通过INT指令来实现的.另一方面,BIOS和DOS由中断系统所构成,BIOS对硬件成为高层的功能,并通过中断的形式向用户提供. 'bpx  
U`es n?m!  
pZ,P_?  
如果在当前程序执行的同时,能将一块代码放在内存,把中断向量指向代码中的子程序,那么在当前程序执行中产生中断时,就有可能执行不属于当前程序和操作系统的代码,产生的中断可能是当前程序产生的软件中断,也可能是由硬件产生的硬件中断.这就是单任务的PC操作系统可能执行多于一个进程的简单说明. 9_mys}+  
l`s_ #3  
<-:gaA`KM  
在PC中断系统中有几个中断具有周期性,即INT 8H,INT 1CH和INT 28H.它们或者周期性被执行用于时间计时,或者周期性产生用于等待.它们是在实现TSR时进行轮询触发的基础.键盘中断(INT 9H和INT 16H)当用户击键时发生,利用它们是进行热键处理的基础.串行口通讯也是触发的一个重要机制.此外众多的软件中断也是触发的媒介. eh-/,vmRa  
lxpi   
e!67Na0X(  
+8 avA:o  
0.2 DOS的可重入性分析 }.x&}FqXE  
> T,^n {_v  
[C]u!\(IF  
一个多任务操作系统之所以能使多个进行并存,是因为操作系统的大部分代码是可以了重的,对于临界资源有相应的PV操作,使得当调度一个新的进程时,能完整地保存前一个里程的现场,当再一次调度被挂起的进程时能象没有被中断一样继续执行. ?-P]m&nh|  
n3t0Qc  
G#&R/Tc5N  
对于PC机来说,代码的重入性比较弱,对临界资源没有PC操作.当我们用中断程序启动用户的TSR时,如果只保存标志和寄存器,以及当前进程一些信息,那么只保存了当前程序的一部分现场,DOS的临界资源不会自动保存.在进行TSR设计时,一定要了解PC操作系统的重入性和临界资源. i(XcNnn6  
)r#^{{6[v  
%hzl3>().  
重入性总是体现在代码上,所谓可重入代码的指这样的代码,即该代码被执行时还没有从中退出,由于某种原因又一次或者多次进入相同的代码,该代码每次的执行结果都是正确的,就说该代码是可重入的.相反,如果结果不正确,那么就就该代码是不可重入的.下面是一个可重入的子程序的例子: 'W/E*O6BY  
lth t'|  
4$oX,Q`#  
Add proc near n)(E 0h  
h 4 s!VK1X  
`)[bu  
cmp DS:word ptr [si],0 p<\yp<g  
mRT`'f xK  
!dVth)UV  
je DonotAddTheValue (0Xgv3wd  
m 4Vh R_  
{U&*8Q(/  
add ax,DS:word ptr [si] h-Q3q:  
|7V:~MTkk&  
c:Tw.WA  
DonotAddTheValue: 4%TY` II  
NX^%a1D!  
 'mz _JM  
ret x>^r%<WbX  
VQ/<MY C  
7ZbnG@s7  
Add endp p2;-*D  
;=IGl:  
T=|oZ  
上面的例子不管在其中任何一处再一次执行该子程序,执行结果不变.为了说明,只举多种可能性中的一种. |5 sI=?p&t  
:66xrw  
\h DH81L  
mov ds,0100h ;ds=0100h 1)8;9 Ba:  
{"dU?/d  
gu[3L  
mov si,0010h ;si=0010h gQJy"f  
&>I4-D[  
|RBgJkS;8  
mov ax,0001h ;ax,=0001h k{3:$, b  
:_%  
#TLqo(/  
call Add ]e?cKC\"e  
gOpGwpYZ,  
lZ5 lm sCU  
cmp 0100h:word ptr [0010h],0 ;Call Add subroutine Y!C=0&p  
]:B|_| H  
w1-/U+0o  
push ds ;Interrupted M~Yho".  
H[ Dr G6GA  
Q Fv"!Ql  
push si ,[rh7 _  
1'dL8Y  
8m0GxgS  
push ax H1H+TTZr  
` k}   
15i8) 4h  
mov ds,0200h ;ds=0200h &}P{w  
G'/36M@  
URbu=U  
mov si,0200h ;si=0020h t0*JinK I  
oe$Y= `  
R&13P&:g  
mov ax,0003h ;ax=0003h D&f(h][hH?  
Nb2]}; O  
_e<3 g9bj  
call Add XY]|OZ7(  
f)p c$~B  
beyC't  
cmp 0200h:word ptr [0020h],0 ;0200:0020h=0004h 3"HpM\A{A=  
&<Bx1\ ~V  
/`YHPeXu  
jne >z*2Og#1  
)]"aa_20]  
%Y"@VcN  
add ax,0200h:word ptr [0020h] ;ax=0007h b$kCyOg  
I^pD=1Y]  
Tti]H9g_  
ret ;Return J+3PUfg>@R  
B1]dub9  
] Ma2*E !p  
pop ax ;ax=0001h \Lxsg! wtJ  
{c|=L@/  
t =ErJ  
pop si ;si=0010h .` z](s  
:zk69P3  
N`7) 88>w  
pop ds ;ds=0100h tkBp?Wl  
V 45\.V  
uUXvBA?l  
iret ;Return to Add subroutine ^Jb=&u$  
U$j*{`$4  
d^"<Tz!  
jne Hn%n>Bnl  
x j6-~<  
KXEDpr  
add ax,0100h:word ptr [0100h] ;ax= 0001h ,}i`1E1=  
$~xY6"_}!!  
XOQj?Q7)U  
;0100h:0010h= 0002h Z!Njfq5  
&BnK[Q8X  
Hf( d x\5  
;---------------------------------------- {O-,JCq/  
6$qn'K$  
kK2x';21  
;ax = 0003h w,(e,8#:  
9K*yds  
0GW(?7ZC  
ret F0O"rN{  
&CCp@" +  
%/17K2g  
mov bx,ax q| p6UL9  
eqK6`gHa6  
[bd fp a  
而下面的子程序是不可重入的: E 9_aNYD  
w) o^?9T  
tL68 u[  
Add proc near LMchNTL  
irSdqa/  
'./j<2|;U  
mov Temp,ax [,s{/OM  
!BD+H/A.{  
lg_X|yhL  
mov ax,DS:word ptr [si] md_9bq/w  
tSK{Abw1B  
gbOd(ugH  
cmp ax,0 =vx iqRm  
R9X* R3n B  
.l$ '%AG:~  
je DonotTheValue iX 0s4  
+Z0@z^6\  
$gm`}3C<  
add ax,Temp "V!y"yQ  
LFHV~>d  
&?\ h[3  
DonotTheValue: qy1$(3t$  
#wH<W5gSZ  
ngM>Tzirt  
ret {8Jr.&Y2  
5a1)`2V2M  
x/Pi#Xm  
Temp: Vk Cv`E  
*k:Sg*neVq  
M#II,z>q  
dw 0 "f|\":\  
trL:qD+{(  
ZSj^\JU  
Add endp GQXN1R   

伍胥之 08-30-2015 07:10
o:u *E  
可以利用检查可重入子程序的方法检查这个子程序的不可重入性,尝试一下在" mov ax,DS:word ptr [si]"指令后再次执行该子程序,那么就会出第一次调用返回的结果不对. "Gx(-NH+  
Y_n^6 ;  
2x-67_BHY=  
mov ds,0100h ;ds=0100h eIjn~2^  
g3@Qn?(j!  
b&s"/Y89  
mov si,0010h ;si=0010h p!<Y 'G  

伍胥之 09-05-2015 05:51
转战VB 6.0 )En*5-1  
$ BV4i$  

伍胥之 09-05-2015 05:57
等我用熟了Turbo C后,TC已经又面临淘汰了。 fMaUIJ:Q9  
s ^Lg*t 3I  
因为早已进入视窗时代了。 Windows 2.0被译为视窗,我觉得还是很贴切的。 ?9#}p  
`N%q^f~  
可是, Borland C++ for Windows 和 Visual C++ 的程度我都看不懂。 6T>e~<^  
$qk2!  
因为我错过了Windows编程,只对X86的实模式非常熟悉,对保护模式一窍不通。 oTj9/r  
PzThVeJ+  
所以,也没有学过事件、消息啥的,因为全系最好的电脑是联想的80286,386以上的机器我只能去家对门的电脑公司。那里从来不缺各种兼容机,但是都是新机器,没有一台相对固定的有全套开发系统的电脑,因为装出来都是卖的,要么是别人送修的。 T0xU}  
P#5&D*`}h  

伍胥之 09-05-2015 06:06
公司一个长期固定客户是济钢采购部的,常常没事过来聊天,到点一起吃饭,当然是公司请客,我作陪。 b]s.h8+v;  
)8Defuxk  
而我这个时候帮公司干了一个活,用Visual FoxPro帮他们写一个程序,是给济南电视台广告部的广告管理系统。 {S4^;Va1  
MY1 1 5%  
其实比较简单,就是客户、联系方式、广告、要求播出时间(每周的一个模式)、时长、每天执行播出的时间、和广告带子编号、在磁带上的位置。这样比较容易安排播出计划和便于查找磁带目录。 i9?$BZQ[R  
3*9<JHu  
连续用了48小时,算是搞定了。但最后是不是采用了,我就不得而知了,我只对公司负责。 y21zaQ  
Pl4$`Qw#y  
老板希望我在他们公司兼职,但是我不同意。因为拿了人家的钱就得受人家管,而我是自由惯了的人。如果遇事请我帮忙,我有兴趣有时间就做,没兴趣可以推掉。只要我想找台电脑试试时有电脑可用,钱对我不重要。我那时的状态是我没有什么钱,可是从不缺钱,因为我不需要花钱。 %;+Q0 e9  
 {f;]  
作完这个后,济南的这个人告诉我VB很好用,可以简单地定义按钮、窗口啥的。不过他用的VB是DOS版的,但是对鼠标支持不错。 X_Vj&{  
T/Q# V)Tp  
我去软件市场看了看,有Windows版的VB, 当然是D版的。5块钱买了再说吧! / $7E  
^nn3;  
W|_^Oe<  
.^BL7  
,TY&N-  

伍胥之 09-05-2015 06:11
在此之前我用过微软最传统的Basic,深恶而痛绝之,后来的Quick Basic 支持了结构化编程,基本可以避免使用Goto语句,感觉还不错。 #w3cImgp2  
Tl9KL%9  
再看VB, 原来语法是完全一样的并略有扩充,而且窗口、事件都有现成的。 AZ~= ]1  
.c~`{j}  
倒是很容易学习的。 g+Z~"O]$M  
?k)(~Y&@p  
公司有一本Windows 32位函数参考,发现VB可以直接利用。这样多数编码效率低的缺陷也可以基本弥补了。 d6ZJh xJ  
1:S75~b-`  

伍胥之 09-05-2015 06:17
在用DOS年代,教务处组织了一帮人写题库,除了计算机系的人外,只有我一个外行。 $CXKeWS=Q.  
4 %do.D*  
那个时候我们用FoxPro 2.5 for DOS,我的工作除了参与题库设计外,主要的活儿是将组卷结果加入BD排版语言指令,卷子可以直接送印刷厂印刷就可以,不用再排版。 c}K>#{YeB  
_h1n]@ d5  
换了VB以后,自然就把数据库换成了Access 97,那时不会用OLE DB,只好用ODBC数据库引擎,将组卷结果写成一个RTF文件,然后可以用Windows下的Word来打开并编辑了。因为我把想到的在所有试卷中出现在格式编出一个文件,再存成.rtf格式,就知道这个“HTML”的各种标记了。 !"{+|heU9p  
Jybx'vZj  

伍胥之 09-05-2015 06:41
其间给公司干了一个小活,但是虎头蛇尾没有做完。 Yhu 6QyRV  
cTf/B=yMi  
公司的另一个客户是黄台电厂,在电厂进煤的专用线上有一个运态轨道衡,也就是在火车以一定速度通过后,它可以称出每节车皮的重量,操 作人员记下车厢号后,就知道车厢自重。 4$D:<8B  
z7X[$T$V  
我不知道怎么实现的,他们说里面有很多猫腻,就是说可以多算煤净重,也可以少算。 J0@ ^h  
0#f;/ c0i  
所以,他们要求用CCD拍下车厢,自动识别出车号,另外测出车辆通过的速度。结果存入一个数据库。 #Pi}2RBRu  
wmh[yYWc  
就是一个我并不懂的模式识别问题。 >, 22@4  
S~auwY,<  
想拍下火车再说吧! umV5Y`  
V$O{s~@ti  
在铁路对面的柱子上,设置了一个标记,当检测到图像变化时,开始录像。居然没有与轨道衡联动,那是别的公司的东东,接口不明。 cl s-x@ Kd  
7XLz Ewa  
逐帧保存是一个问题,写盘数据量非常大,因为不能实时识别车号(事实上到最后我也没有学会),所以只能全存。就用BMP格式吧!我也只了解这一种格式。 ~Y^ UP  
c%,~1l  
但是不能将每帧保存为一个文件,这样太慢了。  w.kb/  
X2PQL"`  
我的办法是只存原始数据,图像的XY值是固定的,不必记入文件,所以也不用文件头了。将一列火车的所有图像写入一个文件,你想想会有多大吧!每秒大约20帧,单色的灰度CCD,每像素8位(1字节,256级灰度)。 jFYv4!\ju  
H2oAek(  
Win32API除了一个写文件的函数(writefile)外,还有一个特别的WriteDisk函数,它从内存中一个页面对齐的地址开始,将与扇区字节数(0x200)整数位的内存块,直接写入磁盘上的一个特殊方式打开的文件中。这个写操作速度特别快。 0^htwec!  
@&!HMl  
我猜想,Windows的交换文件pagefile.sys 就是用这种方式读写的。 )r _zM~jI  
qI,4 uGg  
所以,就需要除了变量声明外,需要用Win32API申请一块存贮区域作为读写的buffer(这个词在CS中叫缓冲区,后来我开始做分子生物学,才知道我天天用的缓冲溶液也叫buffer)。然后用Win32API 打开一个固定的文件,并且保证它是一个连续的磁盘区域(这在编程中是做不到的,需要用Defrag去优化)。 z>HeM Mei  
}lzUl mRTe  
如此,我写了一个监控程序,就是各种看守所里用的经常在需要的情况下损坏的摄像头记录仪。 |/B2Bm  
Dg]( ?^  
火车通过后的时间,就把图像再调出来分析,我最后只能把含有车厢编号的图像块分离出来,但是却不会识别出车号来。 -x i]~svg  
(~t/8!7N  
这个识别工作后来交给了别人,我知道黄台电厂用上了,但最后结果是否理想我并不清楚。 <a_Q1 l  
rdd%"u+  
公司好像给了我一笔挺多的钱,4或5K吧!在当时,算是我见到的最多的钱了,这时工资才1K多点嘛! ye Q6\yi  
~$7fU  
"Xq.b"N{*  
?rqU&my S  

伍胥之 09-05-2015 07:01
引用
引用第20楼newport93于06-14-2010 13:47发表的  :  =lIG#{`Q  
kae &,'@JF  
老五,I 服了U。 '{9 nQ DgT  
C FqteY"  
哪一天等俺退休了,也写一个The Non-Progamming career of an ex-programmer。哈哈哈。。。。。 fba QXM  
Y{~[N yE  
&_cMbFLBP  
新港妹妹,虽然你还没有退休,但是孩子读了大学你应该有些时间了嘛!就开帖写吧!我们很想看啊! 也特别想看看你的non-programming career中的恋爱史啊! 6BT o%  

伍胥之 09-05-2015 07:03
引用
引用第3楼阿散于03-19-2010 22:49发表的  : .H,v7L,~88  
Is that what you wanted to express yourself to us with the whole blank message but the very big title? *^]Hqf(`  
I8=p_Ie  
#kD8U#  
阿散这个家伙,已经被我全局禁言了,但是在他不犯错的时候,也还是个很好玩的同学。

伍胥之 09-05-2015 07:04
引用
引用第6楼沧桑于06-13-2010 14:39发表的  : "/v{B?~%!  
老伍在写交代材料啊,而且写在一个ZT的贴下,哈哈。 w#EP`aM2$=  
A|!u`^p  
u;$g1 3  
这不是怕您见笑嘛!现在露馅了,只得继续招供了。 ` /en&l  
 [wS~.  
可以从宽不?

伍胥之 09-05-2015 07:07
引用
引用第10楼卡拉于06-13-2010 21:49发表的  : xE+Nz5F  
老伍,对不住,我把你原来的英文标题改了,太不吸引人眼球了,有些人还当是英文的都不会去点击。我通篇读了一下,改成了现在的标题。如果你不喜欢,可以改回来。 HFV4S] U=  
zqqu7.`  
|L XYF$  
其实标题没有什么,卡总既然改了就不必再改回了。 d^5OB8t  
@k_xA-a  
主要是当初写的时候真是顶着锅盖写的。 ,'~8{,h5  
(+Ia: D  
阿散说得对。我就是把一堆鸡毛蒜皮的小事,用了一个big title.

伍胥之 09-05-2015 07:08
引用
引用第16楼阿平于06-13-2010 22:25发表的  : d@o1< Q  
哦, 打倒忽悠大家的家伙.      `~${fs{-`/  
v[S>   
\[m{&%^G  
阿平姐,这可不是忽悠,我可是认真交待经历呢!

伍胥之 09-05-2015 07:12
引用
引用第17楼阿散于06-13-2010 22:29发表的  : <B,z)c  
每个人的故事对其他人都是故事, [ArPoJt  
自己的故事也是其中之一. ko-:) z  
跳出来看, .2y2Qm  
不过是众人中的一个人的故事. @.JhL[f  
1 +P&O4>  
所以,接着听故事. wWaO"N]  
P)VysYb?  
女人们有兴趣的就等老伍开个新帖或者跟贴, P2lDi!q|  
听他痛说恋爱革命历史.... )_$F/ug  
zR)9]pJ-  
杂家接着听他自学程序员历史, xx^7  
高级程序员考了吗? ?OW!zE:  
3vs;ZBM  
37:\X5)z/  
这个恋爱革命史还是等你痛改前非换个新ID来讲吧! ^SdorPOq&  
Q& p'\6~  
我什么程度员也没有考过,连大学生的计算机应用等级证明都没有。 lO?dI=}]  
-ti nL(?3  
我唯一考过的计算机科目是职称评审时要求有证书,所以我用了半小时考了word, powerpoint,和internet基础。都是小儿科的东东。如果没有用VBA写个Word的宏,我都觉得对不起微软了。 HvhP9_MB  

伍胥之 09-05-2015 07:14
引用
引用第21楼阿散于06-14-2010 22:33发表的  : 3`V #ImV>  
引用第19楼伍胥之于06-14-2010 12:33发表的  : Xbm\"g \  
x  RV@ _  
(%` R{Y  
我平生唯一参加的计算机考试就是职称考试,任选4个模块。 )ad-p.Hus  
!1g2'  
我连一级也没有考过。 Gag=GHG  
.
hrLPy V:  
.i^aYbB$X  
引用
zkFx2(Hq-f  
矬子里拔将军... XMt5o&U1  
你们那里的俗语是吧? y81B3`@  
r-Nv<oH;  
我们这里说"矮子里拔长脚"..应该是同一个意思... W<W5ih,#  
uif1)y`Q$C  
有趣....各地有表达意思一样却方式不同的俗语.... RtE2%d$JT  
]{mz %\  
gO {XD.s  
你的文章写的有脸皮,没屁眼的, lwY2zX&%)/  
让看客大为不满... 5e> <i  
HY (|31  
你等着,,估计你以后接到的午夜凶铃就多了... l]pHj4`uv  
"mBX$t'gb  
c:%ll&Xtn  
我到现在也没有接到你的午夜凶铃呢! cjTV~(i'4A  

伍胥之 09-05-2015 07:17
引用
引用第25楼猪小秘于01-20-2011 20:51发表的  :  X`REhvT  
伍SIR,再次抱拳佩服  BKiyog  
5*Wo/%#q  
_{d0Nm  
小秘倒是好久不见了呢!宝贝几岁了?很健康活泼吧?

伍胥之 09-05-2015 07:18
引用
引用第39楼suehan234于01-22-2011 08:00发表的 回 38楼(伍胥之) 的帖子 : nPAVrDg O  
佩服,玩也玩得这么专业! SHc<`M'+  
7U:-zfq  
U$-;^=;  
只是票友而已,算不上专业的。

伍胥之 09-05-2015 07:20
引用
引用第46楼清水于03-03-2011 14:50发表的  : Py&DnG'H  
-AJ$-y  
介个真的看不懂。 XN*?<s3  
你说你老啦,喜欢怀旧了,才想起来填坑。 A,P_|  
提醒我也想想,是不是也老啦,是不是也有坑没填呢。 #u<^  
+Wr"c  
.Mn+Bd4f  
你肯定有许多坑没有填,但是我挖的坑更多,但同是我也在你的某个坑里等你填埋呢!

伍胥之 09-05-2015 23:50
//从指定扇区号dwSector开始,写dwLength长度的数据 fj/sN HU  
BOOL WriteDisk( HANDLE hpartition, DWORD dwSector, DWORD dwLength, char* lpBuffer){ r)9&'m.:  
DWORD dwCB; ]8Eci^i  
LARGE_INTEGER  offset;  .<0s?Q  
offset.QuadPart  =  UInt32x32To64(dwSector ,  512); *5kQ6#l  
SetFilePointer(hpartition,  offset.LowPart,  &offset.HighPart,  FILE_BEGIN); LjE@[@d  
if(!WriteFile(hpartition, lpBuffer, dwLength * 512, &dwCB, NULL)){ N2 vA/  
DWORD error = GetLastError(); 9;fyC =  
MessageBox(NULL,"写入文件失败!",NULL,IDOK); uQ}0hs  
return FALSE; E3p3DM0F$  
} AK7IPftlH  
return TRUE; Aqc Cb[1r  
} ;8?i  

伍胥之 09-06-2015 00:05
'VB 6.0 版 7wO0d/l_  
'这不是我写的,它更强悍了。因为可以直接读写物理扇区(CHS),而不是逻辑扇区。 Z~JX@s0v  
 D8w:c6b  
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long U}6F B =  
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long mKsTA;  
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Long) As Long '//declare has changed *@EItj`  
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long '//declare has changed $p(,Qz(.8  
Private Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long b1("(,r/`  
'如果用绝对扇区写,那么文件的建立打开都不能用VB的 open 语句了。 efK3{   
}I1A4=d  
%Ydzzr3  
Private Const GENERIC_READ = &H80000000 (%i)A$i6a  
Private Const GENERIC_WRITE = &H40000000 5|4=uoA<  
$O+e+Y  
Private Const FILE_SHARE_READ = &H1 ^KKU@ab9  
Private Const FILE_SHARE_WRITE = &H2 0<,Q7onDD:  
Private Const OPEN_EXISTING = 3  1#G(  
w6B'&   
Private Const INVALID_HANDLE_VALUE = -1 =LFrV9  
4 ^=qc99  
'//file seek * KDT0;/s  
Private Const FILE_BEGIN = 0 0v~Eu>Rg  
Private Const FILE_CURRENT = 1 FN25,Q8:*I  
Private Const FILE_END = 2 Oq7R^t`b  
J?Ed^B-  
Private Const ERROR_SUCCESS = 0&  -<R"  
JTK0#+?  
'//device io control Ca&p;K9FR  
Private Declare Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Long, ByVal dwIoControlCode As Long, lpInBuffer As Any, ByVal nInBufferSize As Long, lpOutBuffer As Any, ByVal nOutBufferSize As Long, lpBytesReturned As Long, ByVal lpOverlapped As Long) As Long e)(m0m\  
H1FD|Q3  
Private Const IOCTL_DISK_GET_DRIVE_GEOMETRY As Long = &H70000   '458752 shjq4# 9  
Private Const IOCTL_STORAGE_GET_MEDIA_TYPES_EX  As Long = &H2D0C04 1X5*V!u  
Private Const IOCTL_DISK_FORMAT_TRACKS As Long = &H7C018 zW,Nv>Ac5  
Private Const FSCTL_LOCK_VOLUME As Long = &H90018 o(2tRDT\_b  
Private Const FSCTL_UNLOCK_VOLUME As Long = &H9001C #6jdv|fu  
Private Const FSCTL_DISMOUNT_VOLUME As Long = &H90020 m]Sv>|  
Private Const FSCTL_GET_VOLUME_BITMAP = &H9006F T:/68b*H\:  
wRc=;f  
'//type &_DRrp0CN  
Private Type LARGE_INTEGER 3?}W0dZ$d  
    lowpart As Long +[=yLE#P%  
    highpart As Long ^m3[mY [a  
End Type 4f}:)M$5  
2u(v hJ F5  
Private Enum MEDIA_TYPE S$=e %c  
    Unknown \Mujx3Fmvx  
    F5_1Pt2_512 \z/_vzz4  
    F3_1Pt44_512 E(0(q#n  
    F3_2Pt88_512 DgJG: D{  
    F3_20Pt8_512 L>,j*a_[  
    F3_720_512 Cb{n4xKW6  
    F5_360_512 d%"?^ e  
    F5_320_512 |k # ~  
    F5_320_1024 MzF9 &{N  
    F5_180_512 f9Vxtd  
    F5_160_512 }G:5P3f  
    RemovableMedia Kb<^Wdy4T  
    FixedMedia LC!ZeW35  
End Enum k:+Bex$g  
FUq>+U!Qu  
Private Type DISK_GEOMETRY 0Hs\q!5Q  
    Cylinders           As LARGE_INTEGER Y ivWvV  
    MediaType           As MEDIA_TYPE 3\= iB&Gf|  
    TracksPerCylinder   As Long *jBn ^  
    SectorsPerTrack     As Long HjX!a29Wf  
    BytesPerSector      As Long nA!Xb'y&  
End Type _ li\b-  
:4{;^|RgU  
'//private vars 1j_ x51p  
Private hDisk           As Long             'disk handle +<^TyIJ0  
Private lpGeometry      As DISK_GEOMETRY    'disk info SO}$96  
Private lBufferSize     As Long             'the buffer size of read/write ]h Dy]  
Gk.;< d  
Public Function OpenDisk(ByVal FileName As String) As Boolean zF& >1y.$  
'// 打开磁盘 q}nL'KQ,n  
    hDisk = CreateFile(FileName, _ S`!MoIMsD  
                        GENERIC_READ Or GENERIC_WRITE, _ :6,qp?/  
                        FILE_SHARE_READ Or FILE_SHARE_WRITE, _ Oy @vh>RY  
                        ByVal 0&, _ Is87 9_Z  
                        OPEN_EXISTING, _ ]^>#?yEA3  
                        0, _ ";)SA,Z  
                        0) Ik92=' Z  
    OpenDisk = Not (hDisk = INVALID_HANDLE_VALUE) hhS]wM?B  
End Function L4)@lmd3  
7_AR()CM  
Public Function CloseDisk() As Boolean LPg1G+e  
'//关闭磁盘 !kPZuU `T  
    CloseDisk = CloseHandle(hDisk) }]qx "  
End Function -nC 5  
)$# Ku2X  
Public Function GetDiskGeometry() As Boolean R* C  
'//获取磁盘参数  ?~mw  
    Dim dwOutBytes      As Long [n53 eC  
    Dim bResult         As Boolean SqiLp!Y`  
     g{`rWKj  
    bResult = DeviceIoControl(hDisk, _ 2n9E:tc  
                                IOCTL_DISK_GET_DRIVE_GEOMETRY, _ v{R:F  
                                ByVal 0&, 0, _ )u. ut8![T  
                                lpGeometry, Len(lpGeometry), _ \"E-z.wW=  
                                dwOutBytes, _ `=]I -5#.W  
                                ByVal 0&) D]I]I!2c  
     ~MvLrg"i  
    If bResult Then lBufferSize = lpGeometry.BytesPerSector * lpGeometry.SectorsPerTrack F-^#EkEGe  
    GetDiskGeometry = bResult jY]hMQ/H  
End Function 8gA:s`ofJ  
 2Z ? N  
Public Sub GetDiskInfo(MediaType As Long, _ .ZK|%VGW  
                        Cylinders As Long, _ _ ]W }6?i  
                        TracksPerCylinder As Long, _ lS`hJ:  
                        SectorsPerTrack As Long, _ UUxDW3K  
                        BytesPerSector As Long) ;'\{T#5)  
'//返回磁盘的参数 e[3 rz%'Q  
    MediaType = lpGeometry.MediaType %H-(-v^T*  
    Cylinders = lpGeometry.Cylinders.lowpart @ =RH_NB  
    TracksPerCylinder = lpGeometry.TracksPerCylinder QU&b5!;&  
    SectorsPerTrack = lpGeometry.SectorsPerTrack w85PRruW  
    BytesPerSector = lpGeometry.BytesPerSector (I?CW~3#  
G1Qc\mp  
End Sub 7VP[U,  
lC/4CPKtV  
Public Property Get BufferSize() As Long u}Q@u!~e9  
'//返回每次读/写的缓冲大小 6j]pJ]F6  
    BufferSize = lBufferSize `.0QY<;  
End Property ]FJpe^ ua  
nDR)UR  
c8o $WyO  
Public Function LockVolume() As Boolean 94=aVM\>>  
'// 将卷锁定 y.zS?vv2g  
    Dim dwOutBytes  As Long a;Nj'M~U  
    Dim bResult     As Boolean [WOLUb  
     I|6wPV?  
    bResult = DeviceIoControl(hDisk, _ ~%6GF57gC  
                                FSCTL_LOCK_VOLUME, _ #+1*g4m~B  
                                ByVal 0&, 0, _ l!B)1  
                                ByVal 0&, 0, _ -L9I;]:KY  
                                dwOutBytes, _ ]M"l-A  
                                ByVal 0&) mUj=NRq  
    LockVolume = bResult # j_<iy  
End Function lP@/x+6tg  
*):xK;o  
D4:c)}  
Public Function UnlockVolume() As Boolean uT5sLpA|6  
'// 将卷解锁 |eEcEu?/b  
    Dim dwOutBytes As Long 4= VAJ  
    Dim bResult As Boolean 0NY2Kw;  
     [:HT=LX3  
    bResult = DeviceIoControl(hDisk, _ xh7#\m_U8  
                                FSCTL_UNLOCK_VOLUME, _ [Z3B~c  
                                ByVal 0&, 0, _ 49o5"M(  
                                ByVal 0&, 0, _ 9(%ptnya  
                                dwOutBytes, _ `-l, `7e'  
                                ByVal 0&) 2:(h17So  
    UnlockVolume = bResult DA[s k7  
End Function 7Y:~'&U|  
+4kBd<0Y  
=[O;/~J%:  
Public Function DismountVolume() As Boolean R<}Yf[TQ  
'// 将卷卸下,使系统重新辨识磁盘,等效于重新插盘 0Ey*ci^ue  
    Dim dwOutBytes As Long *siN#,5  
    Dim bResult As Boolean p;S<WJv k  
     t83n`LC  
    bResult = DeviceIoControl(hDisk, _ A7~~{9  
                                FSCTL_DISMOUNT_VOLUME, _ G22= 8V  
                                ByVal 0&, 0, _ cLN(yL  
                                ByVal 0&, 0, _ $-dz1}  
                                dwOutBytes, _ >Q0HqOq  
                                ByVal 0&) )~q@2^  
    DismountVolume = bResult : "[dr~.  
End Function \ 9T;-]  
%ZF6%m0S  
^cYm.EHI  
Public Function ReadDisk(ByVal Cylinders As Long, _ 4uU G0o  
                    ByVal Tracks As Long, _ L< MIl[z7  
                    db() As Byte) As Boolean )V!dmVQq{g  
'//按柱面和磁道来读取磁盘数据 [u_-x3`  
    Dim iPos    As Long .Dw^'p>  
    Dim lRead   As Long M(,npW  
     */B-%*#I.  
    iPos = Cylinders * Tracks * lBufferSize Kt,ENbF  
      C0\A  
    If SeekAbsolute(0, iPos) Then G)A5;u\P9  
        ReadDisk = ReadBytes(lBufferSize, db(), lRead) zt1Pu /e  
    End If EUv xil  
End Function SwESDo)  
fJ[(zjk  
Public Function WriteDisk(ByVal Cylinders As Long, _ mQQ5>0^m  
                     ByVal Tracks As Long, _ ,UFr??ZKm  
                     db() As Byte) As Boolean G S^U6Xef  
'//按柱面和磁道来写磁盘数据 \R >!HY  
    Dim iPos    As Long ^-3R+U- S  
    Dim lRead   As Long ?#F}mOVAa  
     Lb GyD;#_  
    iPos = Cylinders * Tracks * lBufferSize )'{:4MX  
     D`=hP( y^  
    If SeekAbsolute(0, iPos) Then @u./VK  
        WriteDisk = WriteBytes(lBufferSize, db()) W/O& (t  
    End If N?d4Pu1m  
End Function  6?U2Et  
Sm2 |I6  
d#@N2  
'///////////////////////////////////////////////////////////////////////////////////// Z3K~C_0Cnu  
'//file system p[*NekE6-  
;>o}/h  
Private Function SeekAbsolute(ByVal HighPos As Long, ByVal LowPos As Long) As Boolean 6x*u S~'  
'//seek file 9/LI[{  
    '//Notice: when you set LowPos=5, the read/write will begin with the 6th(LowPos+1) byte W s!N%%g  
    LowPos = SetFilePointer(hDisk, LowPos, HighPos, FILE_BEGIN) \-mz[ <ep  
    If LowPos = -1 Then ER:)Fk>_  
        SeekAbsolute = (Err.LastDllError = ERROR_SUCCESS) h"S+8Y:1{k  
    Else ~eH+*U|\|M  
        SeekAbsolute = True pZR KM<k  
    End If $7{V+>  
     M[ea!an  
End Function }.<%46_Z-  
IrU}%ZVV  
~Co7%e V  
Private Function ReadBytes(ByVal ByteCount As Long, ByRef DataBytes() As Byte, ByRef ActuallyReadByte As Long) As Boolean L0{ehpvM  
'//read data to array MtAD&+3$  
    Dim RetVal    As Long )-FQ_K%  
    RetVal = ReadFile(hDisk, DataBytes(0), ByteCount, ActuallyReadByte, 0) \2!v~&S  
    'ActuallyReadByte =>> if the bytesRead=0 mean EOF !BHIp7p  
    ReadBytes = Not (RetVal = 0) (ilU<Ht  
     RVmD&  
End Function .!kqIx*3  
N@UO8'"9K&  
Private Function WriteBytes(ByVal ByteCount As Long, ByRef DataBytes() As Byte) As Boolean W{\){fr6O  
'//write data from array U @$Kp>X  
    Dim RetVal As Long z T|]!',  
    Dim BytesToWrite As Long #`6A}/@.+  
    Dim BytesWritten As Long t 7D2k2x9  
     `;L0ax  
    RetVal = WriteFile(hDisk, DataBytes(0), ByteCount, BytesWritten, 0) C[$uf  
     Y?Yix   
    WriteBytes = Not (RetVal = 0) 1]r+$L3  
End Function :U`8s#  

伍胥之 09-06-2015 00:24
这才是我当年写出的一个比较烂的程序 a_5`9BL  
}Y(yDg;"  
Main2.bas zmI?p4,  
/IM5#M5~  
Attribute VB_Name = "SubMain" h5 Y3 v  
Option Explicit ` `o:N`  
2U6j?MyH2  
'采集文件与临时文件 t@-:e^ v  
Public Const TmpFile As String = "d:\30-0600.dat" =R)9_D6I  
'已有数据:30-0600.dat /30日早6点进车与6:30出车头 S5ofe]tS@  
K;2tY+I  
Public fStatus As Long, hFile As Long, bytesRW As Long, lptrFile As Long J;Az0[qMR  
Public hBCFile As Long  '记录采集参数的文件 gP*:>[lR  
Public Const TmpBMP As String = "d:\1.bmp" { U a19~'>  
Public hTmpFile As Long rm*Jo|eH`  
~:."BA  
6=]%Y  
'采集窗口参数常量 JcxhI]E  
Public Const FrameH As Long = 280& F kas*79  
Public Const FrameW As Long = 768& >a98 H4  
Public Const pFrameSize As Long = FrameW * FrameH {9KG06%+  
K,YKU? z6  
'标志区范围,用于识别车辆 xUE9%qO  
Public Const PilarC As Integer = 260   '识别标志立柱中线坐标X \M/XM6:UG4  
Public Const mkW As Integer = 28  '识别标志立柱宽度 -b-Pvw4  
Public Const mkH As Integer = 80 ''识别标志立柱高度(上白中黑下白) 7 \aLK#  
Public Const mkY As Integer = 4 ''识别标志立柱Y坐标(40-79白, 80-119黑,120-159白) Au'[|Pr r  
Public Const mkX As Integer = PilarC - mkW / 2 '识别标志立柱X坐标 O&93QN0  
'车缝检测位置常数 u]P0:)tS.  
Public Const sSize As Long = 32& 8Z>ZjNG  
Public Const sPos As Long = 310& %p?u ^rq  
Public Const sPosL As Long = 200& fG O.wb  
Public Const sPosR As Long = 500& Ml8'=KN_  
'车缝检测框位置 ~SkdP7 )  
Public Slice(1 To sSize, 1 To FrameH) As Byte Dqu1!f  
Public SliceL(1 To sSize, 1 To FrameH) As Byte i*j[j~2>C;  
Public SliceR(1 To sSize, 1 To FrameH) As Byte =)C}u6  
Public avSL As Integer, avSLR As Integer, avSLL As Integer EAq/Yw2$  
;p%a!Im_ <  
'j];tO6GfC  
Public MKpilar(1 To mkW * mkH) As Byte   '一维数组用于亮度对比度分析,比使用二维数组更便于VB编译优化 XA{ tVh  
'该数组用于亮度对比度调节、车辆通过识别与车皮间隔识别 j'i-XIs   
Public BsLine(1 To 4 * FrameW) As Byte, bsAV As Integer  '图像的前4行。用于确定标志区的亮度与对比度范围 dX0A(6  
Public PilarW As Long, PilarH As Long, PilarX As Long, PilarY As Long xz YvD{>  
Public LeftBK(1 To 1024, 0 To 1) As Byte, RightBK(1 To 1024, 0 To 1) As Byte hqVx%4s*J  
'前后帧左右上角128列*8行像素块,根据平均值差绝对值判断进车方向 @W|}|V5  
VmrW\rH@  
JZ&]"12]fR  
; pdW7  
'一次连续采集的帧数 FA\gz?h  
Public tFrames As Long `zAo IQ  
"V:B-q  
'在采集卡申请的缓存中,是按帧为单位的,每一帧包含奇偶场两场的数据 fRJSo%  
'而该卡的硬件设置是按场采集,只需要读第一场的数据即可。 Y;>0)eP  
'所以要设置的缓存帧的大小是frameW*frameH*2,而一场的数据量为pFrameSize v"Bv\5f,Ys  
5:SfPAx  
Public pFRAME(1 To FrameW, 1 To FrameH) As Byte _$"qC[.  
Public pBuffer(1 To FrameW * FrameH * 2) As Byte Y[x9c0  
Public pWorkSpace(1 To FrameW * FrameH) As Long Owalt4}C  
Public Const pBufferSize As Long = FrameW * FrameH * 2 P-ma~g>I  
Public pGray(0 To 255) As Long '整幅图像的灰度直方图 0V*L",9M  
_T^ ip.o  
Public hBoard As Long   '采集卡标识 &;7\/m*W1  
Public mBufferAddr As Long  '缓存地址 m*h d%1D  
Public BufferSize As Long  '缓存大小(字节) }9e4?7  
Public iCurrentCard As Long bh:;o vH  
Public CapStatus As Long  5I5~GH  
Public iFrames As Long Kx6_Vp  
Public currentBr As Byte, currentContr As Byte Dm6WSp1| b  
uj_u j!  
Public hMEM As Long, mStatus As Long ymybj  
Public Const hMemSize As Long = pFrameSize * 4 )Rla VAtM  
Public hMemWork As Long s,ZJ?[/  
Public Const hMemWorkSize As Long = pFrameSize * 5 M")v ph^  
elXY*nt8h  
7,ODh-?ez  
<1]# E@  
'串口接收轨道衡数据 &O(z|-&| x  
Public WeightFromCom As String !G3O!]  
Public bReceiveComplete As Boolean R% XbO~{u  
"2 (4?P  
cYdk,N  
Public Type GrayBMPHeader Ps0'WRJnx  
  Tag As Integer [Fe`}F}Co8  
  FileLength As Long    '文件大小 +2`RvQN  
  Reserve1 As Long 0Ep%&>@  
  DataOffset As Long    '图像数据偏移量 9 8bmia&H  
  BMPHeaderSize As Long  '文件头长 LOi5 ^Um|  
                        'length of the bitmap info header used to describe the bitmap colors, compression,… NvXds;EC  
                        'the following sizes are possible: j&) + qTV  
                        '28h - windows 3.1x, 95, nt, … 0*W=u-|s6  
                        '0ch - os/2 1.x \(jSkrrD  
                        'f0h - os/2 2.x YVZm^@ZVV  
oUR'gc :  
  ImageWidth As Long           '图像宽(像素数) EP7L5GZ-a  
  ImageHeight As Long          '图像高(像素数) N5[QQtQ  
  PlaneNumber As Integer  '图像层数 NMmk ,  
  bpp As Integer    'bits per pixels    '1 - monochrome bitmap o <8L, u(U  
                                        '4 - 16 color bitmap :<Y,^V(  
                                        '8 - 256 color bitmap dNG>:p  
                                        '16 - 16bit (high color) bitmap k2N[B(&4J  
                                        '24 - 24bit (true color) bitmap MsCY5g  
                                        '32 - 32bit (true color) bitmap & :x_  
  Compression As Long '压缩方法     '0 - none (also identified by bi_rgb) $+zev$f  
                                    '1 - rle 8-bit / pixel (also identified by bi_rle4) <9YRSE [Ed  
                                    '2 - rle 4-bit / pixel (also identified by bi_rle8) 9f;\fe  
                                    '3 - bitfields (also identified by bi_bitfields) WcAX/<Y>  
  IMAGESIZE As Long  '图像数据字节数 e.n&Os<|<  
  hResolution  As Long  '水平分辩率  像素数/米 U$6N-q  
  vResolution  As Long  '垂直分辩率 `TKe+oS)  
  ColorsinBMP As Long   '图中所用的颜色。对256色图像总为0x100 ^3IO.`|  
  ImportantColors As Long d raY /  
  Pallate(0 To 255) As Long  '图像每个值对应的实际显示颜色,项数对应PallateNumber所指调色板项数 LnvC{#TFO  
End Type i;`r zsRb  
L m"a3 Nb  
c3 ]ZU^  
2J9_(w  
Public BMPHeader As GrayBMPHeader, BMP1 As GrayBMPHeader 8vK Z;  
Public sRECT As RECT F)) +a&O  
$d%m%SZxv  
!HM{imT  
Public conn As ADODB.Connection >F6'^9|  
Public rsTrain As ADODB.Recordset 5YMjvhr?W  
Public rsOperater As ADODB.Recordset OT{wqNI  
Public rsGoods As ADODB.Recordset 8.Wf^j$+{  
Public rsGood2 As ADODB.Recordset UyBI;k^]  
Public rsSender As ADODB.Recordset Xm*gH, '  
Public rsReceover As ADODB.Recordset YY{S0jnhF  
Public rsTrainTMP As ADODB.Recordset c&IIqT@Gb0  
&%L1n?>Q}  
z#GZvB/z)  
'打开采集卡 bTE%p0  
'设置参数 XKLkJZN  
'设置为实时单帧采集到缓存方式 cF3V{b|bU  
'由另一线程查询采集状态,如果完成采集,传送至用户数组分析或保存 >}GtmnF  
5E?{>1  
!6\{q M  
Sub Main() QRhR.:M\  
  Dim i As Integer, status As Long QM`A74j0]\  
     M?x/C2|  
   InitBMPinfo > y"V%  
   '生成BMP文件头---该文件头是固定将pFRAME数组写成BMP文件 i[@*b/A  
    BMPHeader.Tag = &H4D42 <i`Ipj  
    BMPHeader.ImageWidth = FrameW i}N'W V`!  
    BMPHeader.ImageHeight = FrameH g5lf- }?  
    BMPHeader.BMPHeaderSize = &H28 2ksX6M3kY  
    BMPHeader.PlaneNumber = 1 6<.Ma7)lA  
    BMPHeader.bpp = 8 !.H< dQS  
    BMPHeader.Compression = 0 q5YgKz?IC  
    BMPHeader.hResolution = &H1274   'Windows pBrush.exe的默认值,PhotoED.exe默值为0 U)=?3}s(  
    BMPHeader.vResolution = &H1274 "zJ1vIZY  
    BMPHeader.ColorsinBMP = 256 =K~<& l8  
    BMPHeader.ImportantColors = BMPHeader.ColorsinBMP ,C lGa2O  
    BMPHeader.DataOffset = Len(BMPHeader) B<J} YN  
    For i = 0 To 255 3|-)]^1O  
      BMPHeader.Pallate(i) = RGB(i, i, i) ^tIs57!  
    Next i ])egke\!  
    BMPHeader.IMAGESIZE = FrameH * FrameW i]a0 "  
    BMPHeader.FileLength = Len(BMPHeader) + BMPHeader.IMAGESIZE DG}t!  
_n@#Lufx  
I0.{OJ-  
    MoveMemory BMP1, BMPHeader, Len(BMPHeader) 3i=+ [  
     /=A^@&:_#  
    BMP1.ImageWidth = FrameW ;S+*s'e  
    BMP1.ImageHeight = FrameH * 2 4!,x3H'  
    BMP1.IMAGESIZE = BMP1.ImageWidth * BMP1.ImageHeight c?"#x-<1s  
    BMP1.FileLength = Len(BMP1) + BMP1.IMAGESIZE #GT/Q3{C  
y|Tb&XPD  
  '确定标志位置,为pilarX, pilarY确定初始值 E$=!l{Ms  
   PilarW = mkW :% )va  
   PilarH = mkH  '此两项为固定值 ;'NB6[x  
   PilarX = GetSetting(App.EXEName, "Mark", "MarkX", mkX) uj,YCJ8UZs  
   PilarY = GetSetting(App.EXEName, "Mark", "MarkY", mkY)  '此两项需要在程序初始化时检查并进行调整 4*d$o=wa  
   cU?A|'  
   (e S4$$g  
  '连续采集记录文件 i]a 5cn  
  ' 建立一个缓冲区为页对齐方式的文件 .&=nP?ZPC6  
  If Dir(TmpFile) <> "" Then ^C^FxIA&  
    hFile = CreateFile(TmpFile, GENERIC_READ Or GENERIC_WRITE, _ LJ`*&J   
     0&, 0&, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, 0&) AK%`EsI^  
    ' 在95/98中,如果打开文件时没有声明overlapped方式,在读定文件时就不能使用overlapped参数项 7'z{FS S  
    ' 而必须用setfilepointer函数调节与操作系统保留的文件指针。 9lNO ~8  
  Else CEq0ZL-W  
    hFile = CreateFile(TmpFile, GENERIC_READ Or GENERIC_WRITE, _ PsMoH/+"  
     0&, 0&, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING, 0&) b=horvs/!  
  End If xCz(qR  
  If hFile = 0 Then iyAeR!`  
    MsgBox TmpFile & ": File Open Error", vbOKOnly f1y3l1/  
    Exit Sub C,Q>OkSc  
  End If e<6fe-g9;  
  '采集参数记录文件 A 'rfoA6  
hBCFile = FreeFile() !#` .Mv Z  
Open TmpFile + ".BC" For Binary Access Read Write As #hBCFile _Je<_pl!D  
   ,<0R'R  
hMEM = VirtualAlloc(ByVal 0&, hMemSize, MEM_COMMIT, PAGE_READWRITE)  ’分配系统内容 wP8Wx~Q=  
If hMEM = 0 Then wZ6LiYiHl  
    fStatus = GetLastError /]=Ih  
    MsgBox "内存分配错误: 错误代码 - " & Str(fStatus) & vbCrLf _ .z4 fJx  
     & "请向技术人员报告该错误代码。", vbOKOnly Lqq RuKi  
    CloseHandle hFile @  U xO!  
    Exit Sub zs:O HEZw  
End If {Y6U%HG{{r  
*cz nokq6  
hMemWork = VirtualAlloc(ByVal 0&, hMemWorkSize, MEM_COMMIT, PAGE_READWRITE) <V0]~3  
If hMemWork = 0 Then ~CCRs7V/L  
    fStatus = GetLastError b^_#f:_j  
    MsgBox "内存分配错误: 错误代码 - " & Str(fStatus) & vbCrLf _ "MQy>mD6  
     & "请向技术人员报告该错误代码。", vbOKOnly !f[LFQD  
     '释放已成功分配的内存 {.qeVE{  
    mStatus = VirtualFree(ByVal hMEM, hMemSize, MEM_DECOMMIT) S\b[Bq  
    mStatus = VirtualFree(ByVal hMEM, 0&, MEM_RELEASE) 109dB$+$  
     Y|FF ;[  
    CloseHandle hFile tSran  
    Exit Sub o8;>E>;  
End If  yaza  
=~6A c}$  
' Test writing q">lP (t  
'WriteFile hFile, ByVal hMEM, ByVal 4096&, bytesRW, ByVal 0& ^0p y  
     / E}L%OvE  
   '初始化采集卡参数 S#_g/3w  
   iCurrentCard = -1 )0 U VT[7  
   hBoard = okOpenBoard(iCurrentCard) `w';}sQA7  
   Debug.Print hBoard /#lhRNX  
   If hBoard = 0 Then t>"UenJt-  
      ExitGrabber b6Pi:!4  
      End I},.U&r  
   End If ? XN=Er^  
   okGetBufferSize hBoard, mBufferAddr, BufferSize N^z4I,GV(  
   If mBufferAddr = 0 Then FOVghq@  
     MsgBox "缓存不存在!" smaPZ^;; j  
     ExitGrabber Ndq/n21j  
   End If _b|mSo,{Y  
   Debug.Print Hex(mBufferAddr), Hex(BufferSize) PKFjM~J  
   o.W:R Ux  
   q{~59{Fha  
   currentBr = 128: currentContr = 128 /5 yjON{  
   '设置视频输入参数 R?Zv  
   okSetVideoParam hBoard, VIDEO_SOURCECHAN, 1 'Video2 r0t4\d _&  
      ' lParam=0,1.. Comp.Video; 0x100,101...to Y/C(S-Video), 0x200,0x201 to RGB Chan.Input `,a6su (?  
   okSetVideoParam hBoard, VIDEO_BRIGHTNESS, currentBr '亮度 wd*8w$\  
   okSetVideoParam hBoard, VIDEO_CONTRAST, currentContr '对比度  ---初始设置条件下如果图像亮度达不到基本要求则控制灯光 ZFwUau  
   okSetVideoParam hBoard, VIDEO_RGBFORMAT, FORM_GRAY8 '8位灰度模式 x`~YTOfYk  
   okSetVideoParam hBoard, VIDEO_TVSTANDARD, 0 'PAL制式 &0cfTb)dG  
   okSetVideoParam hBoard, VIDEO_SIGNALTYPE, &H10000 '逐行(低字)同步开槽(高字) 15dhr]8E  
   okSetVideoParam hBoard, VIDEO_RECTSHIFT, 144 + &H2C0000 '有效区起始位置:高字Y偏移,低字X偏移 (144/44经验值) "`HkAW4GZa  
   okSetVideoParam hBoard, VIDEO_AVAILRECTSIZE, FrameW + FrameH * 2 * &H10000 '有效区大小:低字X高字Y (768/576采集卡最大值) ?!TFoD2'  
   okSetVideoParam hBoard, VIDEO_FREQSEG, 0 ' 低频部分信号 BBuI|lr  
   V,:^@ 7d  
   '设置采集参数 1c8Nr&Jl  
   okSetCaptureParam hBoard, CAPTURE_INTERVAL, 0  '逐帧 m_YXTwwx  
   okSetCaptureParam hBoard, CAPTURE_CLIPMODE, 2 '裁剪方式 |`vwykhezO  
   okSetCaptureParam hBoard, CAPTURE_BUFRGBFORMAT, FORM_GRAY8  '8位灰度 `Cq&;-u  
   okSetCaptureParam hBoard, CAPTURE_HARDMIRROR, 0 '不作镜像变换 nX%b@cOXj  
   okSetCaptureParam hBoard, CAPTURE_FRMRGBFORMAT, FORM_GRAY8 '帧存格式 }zC9;R(E  
   okSetCaptureParam hBoard, CAPTURE_SAMPLEFIELD, 0 ' 逐场采集 kT)[<`p  
   okSetCaptureParam hBoard, CAPTURE_HORZPIXELS, 944  '水平像素数 PAL制式固定值 ._'AJhU$0  
   okSetCaptureParam hBoard, CAPTURE_VERTLINES, 625 '垂直线数 C'$w*^me  
   okSetCaptureParam hBoard, CAPTURE_SEQCAPWAIT, 0 '不等结束立即返回 S"hA@j  
   'okSetCaptureParam hBoard, CAPTURE_BUFBLOCKSIZE, FrameW + FrameH * 2 * &H10000 HR'sMu3  
   'Buffer Block Size不用设置,而用okSetTargetRect函数进行动态调节 VZuluV  
   )N$T&  
   8*o*?1.  
   okCloseBoard hBoard S v3O${B|  
   Sleep 50 4A0 ,N8ja}  
   hBoard = okOpenBoard(iCurrentCard)   '关闭后重新打开使新的设置值生效 G#yv$LY#  
   0x BO5[w,Y  
   '设置数据传送方式 y0s= yN_  
   'okSetConvertParam hBoard, CONVERT_FIELDEXTEND, FIELD_COPYEXTEND '逐行并扩展行 %d?.v_Hu0  
   '该设置对本程序无意义,因为程序直接用CopyMemory方法读缓存,而扩展行方式是在用采集卡内置函数读RECT过程中实现的。 l@:Tw.+/9  
   EMy>X  
   sRECT.Right = -1   '用于获得当前设置值 :Y wb  
   iFrames = okSetTargetRect(hBoard, BUFFER, sRECT) &?X0;,5)  
   Debug.Print sRECT.Left, sRECT.Right, sRECT.Top, sRECT.Bottom v2eLH:6  
   Debug.Print okSetCaptureParam(hBoard, CAPTURE_BUFBLOCKSIZE, -1)  'FrameW + FrameH * &H10000 w]L^)_'Th  
   sRECT.Left = 0 jHjap:i`cI  
   sRECT.Top = 0 1OI/!!t1$  
   sRECT.Right = sRECT.Left + FrameW h [*/Tnr  
   sRECT.Bottom = sRECT.Top + FrameH * 2 R 6JHRd  
   iFrames = okSetTargetRect(hBoard, BUFFER, sRECT) r+ v?~m!  
   TL u+5f  
   sRECT.Right = -1   '检查新设置值 R|&jvG=|  
   iFrames = okSetTargetRect(hBoard, BUFFER, sRECT) MX Qua:&HW  
   Debug.Print sRECT.Left, sRECT.Right, sRECT.Top, sRECT.Bottom En!X}Owh  
   Debug.Print Hex(okSetCaptureParam(hBoard, CAPTURE_BUFBLOCKSIZE, -1)) ]M3V]m  
   M;2@<,rM  
   If TESTSignal = False Then >,%or cN  
      'ExitGrabber lRA=IRQ]  
   End If kIl!n  
   K(jo[S  
   qFQO1"mu  
   F(h jP  
   '设为实时采集状态 ,GO H8h  
   'iFrames = okCaptureActive(hBoard, BUFFER, 0&) (|O9L s7N  
   r~rftw  
   Q$,AQyBlqc  
   '单帧采集 u%m,yPU ~B  
   'okWaitSignalEvent hBoard, EVENT_FRAMEHEADER, -1 $[f-{B{>*  
   'iFrames = okCaptureSingle(hBoard, BUFFER, 0&) @vyq?H$U;N  
   okCaptureTo hBoard, BUFFER, 0, 1 'single 709/'#- ^  
   'Do While okGetCaptureStatus(hBoard, False) <> 0 U]Y</>xGI  
   '   Sleep 20 P =3mLz-  
   'Loop phCItN;  
   okGetCaptureStatus hBoard, True suOWmq Ls  
   MoveMemory pFRAME(1, 1), ByVal mBufferAddr, pFrameSize %lsRj)n  
   '写入768*576测试图象 ZZ'5BfI"I%  
   ArrayToBMP TmpBMP d{/#A%.  
   ya3k;j2C  
   '打开数据库 P^'TI[\L9  
   Set conn = New ADODB.Connection CcCcuxtR  
   conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ tKS'#y!R  
      "Persist Security Info=False;Data Source=" & "c:\train\train.mdb" & _ @!'rsPrI  
      "; Mode=Read|Write" KXrZ:4bg  
   conn.Open zTBf.A;e7  
   6LRvl6ik  
   frmRecord.Picture1.Picture = LoadPicture(TmpBMP) Cb}I-GtO  
   frmRecord.Visible = True *Aqd["q  
   frmQuery.Visible = True vJ,r}$H3  
   Load frmReceiveFromComm 2WO5Af%  
   Ww=^P{q\  
   '调试参数 trx y3k;  
   If InStr(UCase(Command()), "/CAPTURE") > 0 Then WwDd62g  
     SignalBox.Visible = True N 2XL5<  
   End If q4MR9ig1E_  
   If InStr(UCase(Command()), "/COMM") > 0 Then !d.bCE~  
     frmReceiveFromComm.Visible = True `;j@v8n$*  
   End If b- 8}TTL>  
s5s'[<  
End Sub hs^K9Jt  
^sVr#T  
Sub ExitGrabber() |hl:!j.t  
  '关闭数据库 "ov270:  
  '关闭采集卡 wK]p`:3  
  mStatus = VirtualFree(ByVal hMEM, hMemSize, MEM_DECOMMIT) Oa.84a  
  mStatus = VirtualFree(ByVal hMEM, 0&, MEM_RELEASE) wn-1fz <d  
  mStatus = VirtualFree(ByVal hMemWork, hMemWorkSize, MEM_DECOMMIT) NH aY&\  
  mStatus = VirtualFree(ByVal hMemWork, 0&, MEM_RELEASE) C))x#P36  
  okStopCapture hBoard X 0vcBHh  
  okCloseBoard hBoard RCqd2$K"J+  
  CloseHandle hFile 6 2:FlW>  
  Close #hBCFile TJ_Wze-lQ  
  conn.Close 3xIelTf*  
  End 0Sj B&J  
End Sub aS! If>  
X aE;i57$l  
Function ArrayToBMP(ByVal File As String) q-hREO  
Dim BytesWrite As Long ]9 $iUA%Ef  
J?C#'2 /   
hTmpFile = CreateFile(File, GENERIC_READ Or GENERIC_WRITE, 0&, 0&, _ /hN;\Z[@  
  CREATE_ALWAYS, 0&, 0&) 9Bao~(j/k  
+)xjw9b  
If hTmpFile = 0 Then Ce/l[v  
   ArrayToBMP = False V O\g"Yc  
   Exit Function dtj+ av G  
End If [$X^r<|P@  
O!G!Gq&  
SetFilePointer hTmpFile, 0&, 0&, FILE_BEGIN do.AesdXaq  
WriteFile hTmpFile, BMPHeader, 2&, BytesWrite, ByVal 0& }]i.z:7+  
SetFilePointer hTmpFile, 2&, 0&, FILE_BEGIN Sx8RH),k  
WriteFile hTmpFile, BMPHeader.FileLength, Len(BMPHeader) - 2, BytesWrite, ByVal 0& C4aAPkcp2$  
oRZ98?Y\B  
SetFilePointer hTmpFile, Len(BMPHeader), 0&, FILE_BEGIN I>EEUQR/$H  
WriteFile hTmpFile, pFRAME(1, 1), pFrameSize, BytesWrite, ByVal 0& 5>6:#.f%!e  
EVlj#~mV  
If BytesWrite < pFrameSize Then H)k V8wU  
  ArrayToBMP = False q6PG=9d0B  
End If Xj9\:M-  
B#DnU;=O#+  
CloseHandle hTmpFile +)hxYLk&I  
~^TH5n  
End Function uG$*DeZti  
"&:H }Jd  
Function ArrayToBMP1(ByVal File As String) ^c<8|lK L@  
PrHoN2y5E  
Dim BytesWrite As Long ri Z :#I  
,njlKkFw^Z  
hTmpFile = CreateFile(File, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, _ VUi> ]v/e  
  CREATE_ALWAYS, 0&, 0&) Xf#+^cQ  
eo*l^7  
If hTmpFile = 0 Then 2@N9Zk{{J  
   ArrayToBMP1 = False uH&B=w  
   Exit Function ?$K.*])e  
End If P$x9Z3d_  
[ $5u:*  
SetFilePointer hTmpFile, 0&, 0&, FILE_BEGIN UgL FU#  
WriteFile hTmpFile, BMP1, 2&, BytesWrite, ByVal 0& xtBu]I)%  
c)3.AgT  
SetFilePointer hTmpFile, 2&, 0&, FILE_BEGIN "Zfm4Nx "  
WriteFile hTmpFile, BMP1.FileLength, Len(BMP1) - 2, BytesWrite, ByVal 0& Z;<:=#  
L} "b p  
SetFilePointer hTmpFile, Len(BMP1), 0&, FILE_BEGIN jM}(?^@  
WriteFile hTmpFile, pBuffer(1), pBufferSize, BytesWrite, ByVal 0& uUiS:Tp]  
O dbXna  
If BytesWrite < pBufferSize Then fK^W6)uuV  
  ArrayToBMP1 = False Ht:\ z;cu  
End If Q=6 1.lP6  
XV}}A ^  
CloseHandle hTmpFile +MZI\>  
G@KDRv  
End Function d6a3\f  
8_VGB0~3i  
'使用该过程建立的文件要求在用后关闭 ppo0DC\>  
Public Function ArrayToBMP2(File As String) As Boolean W#+f2 RR  
{O:{F?  
Dim BytesWrite As Long q3v v^~  
fK 6[ p&  
ArrayToBMP2 = True b "aF-,M>  
+ ZK U2N*  
hTmpFile = CreateFile(File, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, _ q9wObOS$  
  CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0&) g >@a  
km*Y#`{  
If hTmpFile = 0 Then @eM$S5&n$  
   ArrayToBMP2 = False 5 JlgnxRq  
   Exit Function 2!6E~<~HC  
End If &:&~[4>%a  
0l3[?YtXc  
SetFilePointer hTmpFile, 0&, 0&, FILE_BEGIN '?jsH+j+  
WriteFile hTmpFile, BMPHeader, 2, BytesWrite, ByVal 0& :>iN#)S  
^TD%l8o6  
SetFilePointer hTmpFile, 2&, 0&, FILE_BEGIN Er;qs*f  
WriteFile hTmpFile, BMPHeader.FileLength, Len(BMPHeader) - 2, BytesWrite, ByVal 0& A=0 {}B#  
nG";?TT  
SetFilePointer hTmpFile, Len(BMPHeader), 0&, FILE_BEGIN " IB36/9  
WriteFile hTmpFile, pFRAME(1, 1), pFrameSize, BytesWrite, ByVal 0& J'ZC5Xr  
TQu.jC  
If BytesWrite < pFrameSize Then &09&;KJ  
  ArrayToBMP2 = False ;mYZ@g%e  
End If H C=ZcK'W  
H| _@9V  
CloseHandle hTmpFile 0 *;i]owV  
k'_f?_PBu  
End Function 2-DG6\QX|  
EDz;6Z*4N  
Private Function TESTSignal() As Boolean XG*> yra`  
Dim extsign As Long, videotype As Long, scanlines As Long, fieldfrq As Long sv!zY= 6  
zYP6m3 n  
extsign = okGetSignalParam(hBoard, SIGNAL_VIDEOEXIST) E~#G_opQA  
m_;fj~m  
If extsign = 1 Then et/:vLl13  
   TESTSignal = True P-a8S*RRa  
Else .*f 6n|  
    If extsign = 0 Then Zs]n0iwM'@  
        MsgBox "无视频输入信号,检查摄像机电源!", vbOKOnly suzK)rJ9i  
        TESTSignal = False tz8 fZ*n  
        Exit Function ?=LT ^Zp`  
    End If +HPcv u?1  
End If 5S8>y7knQ  
\vJ0Mhk1  
'测试视频输入类型 wAw1K2d  
'video type sE'c$H  
okWaitSignalEvent hBoard, EVENT_ODDFIELD, 40 oNIYO *[  
videotype = okGetSignalParam(hBoard, SIGNAL_VIDEOTYPE) EjFn\|VK  
If videotype = 1 Then Yn[>Y)  
        '"隔行信号(Interlaced)" I-}ms  
Else c~4Cpy^  
   If videotype = 0 Then eKy!Pai  
       '"逐行信号(Non-interlaced)" $OG){'X  
   Else z{|0W!nHJ  
     If videotype = -1 Then t=X=",)f  
       ' "不支持" oN[}i6^,e  
     End If B~^*@5#0|  
   End If %W8iC%~  
End If Vz$ xV!  
+SF+$^T  
'测试垂直扫描线数 Ge/K.]>i  
'video scanlines L}CU"  
scanlines = -1 z"T+J?V/  
scanlines = okGetSignalParam(hBoard, SIGNAL_SCANLINES) er5!n e  
    If scanlines = -1 Then (6B;  
        ' "不支持" #6 vf:94  
    Else ;<q 2  
        'Trim(Str(ScanLines)) + " 行数/幅" *RxJ8.G  
    End If Y6&v&dA;  
1)^\R(l  
'测试帧频 KJV8y"^=Q  
'video field frequency ZG 0^O"B0  
    fieldfrq = okGetSignalParam(hBoard, SIGNAL_FIELDFREQ) v$0|\)E)  
    If fieldfrq = -1 Then HHZw-/ s,%  
        'lblSignal(8) = "不支持" yuy\T(7BN  
    Else G^tazAEfo  
        'lblSignal(8) = Trim(Str(FieldFRQ)) + " 场数/秒" O Bcz'f~  
    End If (~eS$8>.  
End Function "9r$*\wOf  
g5y`XFY  
$cK}Tl q  
Sub PicIdentify() cE:s\hG  
'本程序完成从文件中按顺序读出一幅图像并完成图像识别 P))B S  
'根据固定位置判断透过车皮连接处接收的对面的立柱影像。出现立柱后该帧前1-2帧与后1-2帧分别为车号信息与车皮信息 5q*s_acQ  
'判定标准:如果在立柱位置上有明显的模式反差,则视为车皮之间的间隔 wgIm{;T[u  
'方法:对立柱标志区进行平均值二值化,面积为32*40,亮区(255)与暗区(0)的亮度平均值理论差大于200倍,实际差值应不小于100倍 "b~C/-W I  
&9^4- 5]  
  Dim fPTR As Long, cFrame As Long `kuu}Y Ui  
  Dim i As Long, j As Integer, pTotal As Long, pAV As Integer %VFoK-a  
     a7c`[   
.hu7JM+  
cFrame = 0 i%!<6K6UT  
,@c1X:  
V]; i$  
Do While cFrame < tFrames $cIaLq  
   xh bN=L  
  fStatus = SetFilePointer(hFile, cFrame * pFrameSize, 0&, FILE_BEGIN) (D%vN&F  
  fStatus = ReadFile(hFile, ByVal hMEM, ByVal pFrameSize, bytesRW, ByVal 0&) zzhZ1;\  
  MoveMemory pFRAME(1, 1), ByVal hMEM, pFrameSize *~g*J^R}  
   L /:^;j`c  
  frmRecord.RText.Text = Str(cFrame) &BLCP d  
  frmRecord.RText.Refresh 6i-G{)=l  
       ~CT]&({  
  If CheckMark = True Then CV\^gTPmx  
   ArrayToBMP TmpBMP U+qyS|i  
   frmRecord.Picture1.Picture = LoadPicture(TmpBMP) )2RRa^=&  
   frmRecord.RText.Text = "第" & Str(cFrame) & "帧" jan}}7Dly  
   %-yzU/`JF  
   DrawSlice r}&&e BY f  
   lHtywZ@%3  
   'i = MsgBox("检测到立柱:第" & Str(cFrame) & "帧", vbYesNo) I]` RvT  
   'If i = vbNo Then bJetqF6 n  
   '  Exit Do pHmqwB~|  
   'End If r@}`Sw]@  
   'cFrame = cFrame + 1 ^7wqb'xg  
   iAZ8Y/  
  End If  NdRcA  
  DoEvents {N>ju  
  cFrame = cFrame + 1 Dc@O Mr  
Loop u{_,S3Aa  
End Sub x;)I%c  
<zR{'7L/  
g kO^J{_@q  
Function CheckMark(Optional iBlk As Integer = 30, Optional iWhite As Integer = 230) As Boolean ?[d4HKs   
2zqaR[C  
'如标志区模式反差存在则为TRUE,否则返回FALSE _$96y]Bpi  
ttUK~%wSx  
Dim i As Integer, j As Integer, mTotal As Long, mAV As Single, mTop As Long, mBot As Long 8 7(t<3V&  
CheckMark = True L&DjNu`!9  
   =X?fA,  
'复制标志区 $/s"It  
For i = 1 To mkH ". tW5O>  
   MoveMemory MKpilar((i - 1) * PilarW + 1), pFRAME(PilarX, PilarY + i), PilarW $*942. =Q  
Next i ",3v%$ >  
~w3u(X$m"  
For j = 1 To PilarW * PilarH / 2 }ofb]_C,  
   mTop = mTop + MKpilar(j) tO{{ci$-T  
Next j %h@1lsm1+  
I4G0 !"T+  
For j = PilarW * PilarH / 2 + 1 To PilarW * PilarH j{OA%G(I  
   mBot = mBot + MKpilar(j) udqrHR5  
Next j f]8MdYX(  
9tJ0O5  
mTop = mTop / PilarW / PilarH * 2 R1X'}#mU  
mBot = mBot / PilarW / PilarH * 2 ?).;cG:<  
+Q u.86dH  
mAV = (mTop + mBot) / 2 + (mBot - mTop) / 4 '标志区平均亮度 c 9f "5~  
mFF4qbe  
'平均值极值化 X#ttDB  
  For j = 1 To PilarH * PilarW {/]2~!  
    MKpilar(j) = IIf(MKpilar(j) > mAV, 255, 0) -DdHl8  
  Next j ##6\~!P  
   salC4z3  
mTop = 0: mBot = 0 `jGeS[FhR  
For j = 1 To PilarH * PilarW / 2 S~);   
  mTop = mTop + MKpilar(j) k}v`UiGM  
Next j a5 pl/d  
#zTy7 ZS,0  
For j = PilarH * PilarW / 2 + 1 To PilarH * PilarW x6`mv8~9Db  
  mBot = mBot + MKpilar(j) VIz(@  
Next j WVRIq'  
-y-}g[`  
KE3`5Y!  
  mTop = mTop / PilarH / PilarW * 3 6 X~><r  
  mBot = mBot / PilarH / PilarW * 3 `Y:]&w  
   UqI #F  
-}%J3j|R:  
If mBot > iWhite And mTop < iBlk Then ]0."{^ksL  
  CheckMark = True iT :3e%  
Else HpEd$+Mz  
  CheckMark = False 8{jXSCP#  
End If q13fmK(n-5  
End Function p[JIH~nb  
:oZ<[#p"*  
Sub Capture1Frame() &N^~=y^`C'  
   okCaptureTo hBoard, BUFFER, 0, 1 'single E`oA(x7l  
   okGetCaptureStatus hBoard, True FuiR\"Ww  
   MoveMemory pFRAME(1, 1), ByVal mBufferAddr, pFrameSize IFTNr2I  
End Sub &^"Ru?MK  
\W .CHSD  
D_d>A+  
Sub CopyMark(iBlk As Integer, iWhite As Integer) `f;w  
'复制标志区并返回标志区暗区与亮区的亮度平均值 :awkhx  
Dim i As Integer, j As Integer, mTotal As Long, mAV As Single, mTop As Long, mBot As Long, mMid As Single, bsTotal As Long Nu6NyYs  
   ;|WUbc6&g  
'复制标志区 Sv M\9  
For i = 1 To mkH M YF ^zheD  
   MoveMemory MKpilar((i - 1) * PilarW + 1), pFRAME(PilarX, PilarY + i), PilarW p qz~9y~  
Next i =$J(]KPv!?  
d$3rcH1  
For j = 1 To mkW * mkH / 2 gS~H1Ro  
   mTotal = mTotal + MKpilar(j) d <}'eBT'  
Next j LG&BWs!  
zG#5lzIu,  
iBlk = mTotal / (mkW * mkH / 2)  '标志区上部白区平均亮度 G1 "QX  
_li3cXE  
mTotal = 0 ByY2KJ7  
For j = mkW * mkH / 2 + 1 To mkW * mkH nZbI}kcm  
   mTotal = mTotal + MKpilar(j) xn3 _ ED  
Next j  Lto*L X  
gS'{JZu2  
iWhite = mTotal / (mkW * mkH / 2) '标志区下部黑区平均亮度 m`-);y  
H7X-\K 1w  
'背景亮度 cF8  2wg  
  MoveMemory BsLine(1), pFRAME(1, 1), 4 * FrameW }_'5Vb_  
  For i = 1 To 4 * FrameW t,7%| {  
    bsTotal = bsTotal + BsLine(i) W^[FWFUTY  
  Next i K5qCPt`'  
  bsAV = bsTotal / FrameW / 4 7<xnE]jdq  
`f>!/Zm%9  
End Sub Vx$;wU Y  
wtek5C^  
t Ly:F*1i  
Sub AdjIMGbright(Optional bInit As Boolean = True) !G3AD3   
`MVqd16Y  
  '自动调节亮度与对比度,此时处于无车辆状态(白天特别高,而夜间特别暗) mLuNl^)3  
  '图像平均亮度白天不高于200(当车辆通过时可能会下降到100左右),不低于100 &IQ=M.!r  
  '            夜间不高于80(过高时通常是由于雪花噪声引起),但立柱不低于30 0#8   
     P~trxp=k  
  Dim bsTotal As Long, i As Integer, iBlack As Integer, iBright As Integer 0(7 IsG=t  
   zvV&Hks-  
  '按标准亮度与对比度采集一帧,确定背景亮度 77@N79lqO  
  currentContr = 128   '初始对比度 PyQ .B*JJ  
  currentBr = 128   '初始亮度 mITB\,,G  
  okSetVideoParam hBoard, VIDEO_BRIGHTNESS, currentBr '亮度 1Z}5ykM3  
  okSetVideoParam hBoard, VIDEO_CONTRAST, currentContr '对比度 3%+ ~"4&  
  DoEvents _iJ~O1qx,w  
  Capture1Frame L~6%Fi&n4  
  '获得图像上缘4行象素 zL yI|%KH  
  MoveMemory BsLine(1), pFRAME(1, 1), 4 * FrameW a&_ h(  
  CopyMark iBlack, iBright   '图像标志区亮度 3^UdB9j;  
  For i = 1 To 4 * FrameW i=EOk}R  
    bsTotal = bsTotal + BsLine(i) |/gt;H~:  
  Next i rM7qBt  
  bsAV = bsTotal / FrameW / 4    '图像上缘基线亮度 cX-M9Cz  
   !1)aie+p6  
  Select Case bsAV ]j3>=Jb;  
     Case 0 To 60    '夜间通过灯光照明,完全没有背景 n4k q=Z%  
       currentBr = 150 yl-:9|LT  
       currentContr = 60 gyvrQ, u  
     Case 61 To 80   '有可见背景 >$ZG=&  
       currentBr = 140 j?2~6W/[  
       currentContr = 70 3s%?)z  
     Case 81 To 100  '有清晰背景 >B{NxL3->  
       currentBr = 128 }Z"iW/?"  
       currentContr = 80 BD C DQ  
     Case 100 To 150  '有明亮背景 $.jG O!  
       currentBr = 140                '5:30-6:00钟实测数据 >s^$ -  
       currentContr = 50 i5}Zk r  
     Case 151 To 180 Wzl/ @CPM  
       currentBr = 130 @)U.Dbm  
       currentContr = 60 63W;N7@  
     Case 181 To 220  '背景全为白色 ?#K.D vGJ  
       currentBr = 110 0#]fEi  
       currentContr = 130 [KK |_  
     Case 221 To 255  '背景全为白色 sC-o'13  
       currentBr = 100 RM|J |R  
       currentContr = 100 @N Yl4N  
  End Select d)AYY}pw  
   }9 3kHO{  
  Select Case (iBlack + iBright) / 2   '图像反射光强度修正 ^>IP"kF  
        Case 100 To 150 wm`< +K  
          currentBr = currentBr - 10 8S1@,O,  
        Case 151 To 255 ;R*-cm  
          currentBr = currentBr - 20 XZ%,h  
  End Select 9[.HWe,  
   x0<;Rm [u=  
  okSetVideoParam hBoard, VIDEO_BRIGHTNESS, currentBr '亮度 2`f{D~w  
  okSetVideoParam hBoard, VIDEO_CONTRAST, currentContr '对比度 XG/x Mz~  
End Sub a4,V(Hlm  
lMY\8eobcB  
Sub CopyCorner(rowID As Integer, diffL As Integer, diffR As Integer) _RIU,uJs  
    Dim i As Integer, j As Integer, L1 As Long, L2 As Long, R1 As Long, R2 As Long *kLFs|U  
     Q>{$Aqc,e  
    For i = 1 To 8 qi,) l*?f  
      MoveMemory LeftBK((i - 1) * 128 + 1, rowID), pFRAME(1, i), 128& [{7#IZL  
      MoveMemory RightBK((i - 1) * 128 + 1, rowID), pFRAME(640, i), 128& aN0[6+KP;  
    Next i ,clbD4  
     *cb|9elF^  
    For j = 1 To 1024 = 7y-o  
      L1 = L1 + LeftBK(j, 0) cLZ D\1Mt  
      L2 = L2 + LeftBK(j, 1) =?OU^ u`C  
      R1 = R1 + RightBK(j, 0) ]M5~p^ RB  
      R2 = R2 + RightBK(j, 1) ETHcZ  
    Next j 4zMvHe  
    diffL = Abs(L1 - L2) / 1024 WN'AQ~qA  
    diffR = Abs(R1 - R2) / 1024 T3{O+aRt  
End Sub c[Fc3  
xWG@<}H  
Function CheckSlice() As Boolean o'DtW#F  
  CopySlice avSL, avSLR, avSLL oV%:XuywT  
  If Abs(avSL - avSLL) > (Abs(avSLL - avSLR) + 5) * 4 Then kOQ )QX  
    CheckSlice = True eI1zRoIl-  
  Else s/"bH3Ob9v  
    CheckSlice = False :'p)xw4K|  
  End If U<j5s\Y,  
End Function Y7t#)?  
0/Q_% :  
Sub CopySlice(avSL As Integer, avSLR As Integer, avSLL As Integer) _w\9 \<%  
  Dim i As Long, j As Long, total As Long, totalL As Long, totalR As Long Ugri _  
  For i = 1 To FrameH f]NLR>$L}  
    MoveMemory Slice(1, i), pFRAME(sPos, i), sSize 0<m7:D Gd  
    MoveMemory SliceL(1, i), pFRAME(sPosL, i), sSize j[r}!;O  
    MoveMemory SliceR(1, i), pFRAME(sPosR, i), sSize 9\_s&p=:.  
  Next i x4q}xwH  
  For i = 1 To FrameH b9j}QK  
    For j = 1 To sSize g Q\.|'%  
       total = total + Slice(j, i) ] U>MYdGWb  
       totalL = totalL + SliceL(j, i) (e7!p=D  
       totalR = totalR + SliceR(j, i) At.& $ t  
    Next j Z@Rm^g]o  
  Next i |A3"Jc.2o  
  avSL = total / FrameH / sSize V"# 0\ |]m  
  avSLR = totalR / FrameH / sSize W>pe-  
  avSLL = totalL / FrameH / sSize 9<Pg2#*N0  
End Sub %> XsKXj  
t=P+m   
Sub DrawSlice() W22S/s  
   frmRecord.Picture1.Line (sPosL, 0)-(sPosL + sSize, FrameH), RGB(255, 0, 0), B #p(gB)o:l  
   frmRecord.Picture1.Line (sPos, 0)-(sPos + sSize, FrameH), RGB(0, 255, 0), B <j'K7We/tP  
   frmRecord.Picture1.Line (sPosR, 0)-(sPosR + sSize, FrameH), RGB(0, 0, 255), B 1bV G%N  
   frmRecord.RText.Text = Str(avSLL) & "/" & Str(avSL) & "/" & Str(avSLR) qf0pi&q  
End Sub u n v:sV#b  
Sub DrawMark(pic As Control) +M=h+3hw](  
   Dim i As Long, j As Long [\ao#f0WR  
   pic.Line (PilarX, FrameH - PilarY)-(PilarX + PilarW, FrameH - PilarY - PilarH / 2), RGB(255, 0, 0), B " |3I|#s  
   pic.Line (PilarX, FrameH - PilarY - PilarH / 2 - 1)-(PilarX + PilarW, FrameH - PilarY - PilarH), RGB(0, 0, 255), B wo`.sB&T  
   For i = 1 To PilarH R{@saa5I(>  
     For j = 1 To PilarW .\XRkr'-  
       pic.PSet (PilarX + PilarW + 10 + j, FrameH - PilarY - i), RGB(MKpilar((i - 1) * PilarW + j), 0, 0) &ivU4rEG  
     Next j E22o-nI?1  
   Next i | 1B0  
End Sub KtQs uL%  
lO-DXbgql$  
Function avIMG() As Integer i-CJ{l  
  Dim i As Long, j As Long, totalIMG As Long &hWELZe0vv  
  MoveMemory pBuffer(1), pFRAME(1, 1), pFrameSize Cv,WG]E7(  
  For i = 1 To pFrameSize "^4*,41U  
    totalIMG = totalIMG + pBuffer(i) 07.p {X R  
  Next i 5sY $  
  avIMG = totalIMG / pFrameSize E'WXi!>7p  
End Function puOtF YZ\  
Ij#mmj NW  
Function avRegion(barCol As Integer, barWidth As Integer) As Integer u2#q7}  
  Dim i As Long, j As Long, totalIMG As Long x@  =p  
  For i = 1 To FrameH wiN0|h>,  
     MoveMemory pBuffer((i - 1) * barWidth + 1), pFRAME(barCol, i), barWidth TZgtu+&  
  Next i i V{_?f1jo  
  For i = 1 To FrameH * barWidth TQn!MUj/^  
    totalIMG = totalIMG + pBuffer(i) ]ae(t`\l^  
  Next i 45JL{YRN  
  avRegion = totalIMG / pFrameSize !4p{ b f  
End Function )g:5}+  

伍胥之 09-06-2015 00:28
[attachment=78525] 一共这么多文件。 31G:[;g  
6 {+yAsI  
这是我用VB写出的最大的程序,也是用API最多的。

伍胥之 09-06-2015 00:31
拍下的火车 @)b'3~ D  
第6车皮 :qo[@x{  
[attachment=78526] 0fqcPi  
Mk*4J]PP  
第9车皮 'Dfs&sm  
q2%cLbI F  
  [attachment=78527]

伍胥之 09-06-2015 00:33
[attachment=78528] 从这里里分离出来的。

伍胥之 09-06-2015 00:38
[attachment=78529] Vl^x_gs#_]  
?\\wLZ  
这个地方现在已经变化很大了。以前紧靠山东农科院的实验田

伍胥之 09-06-2015 06:43
下一次练手,也是VB,不过只是用CCD测量济钢中板车间轧机出来的板的宽度。 MD[hqshoh  
Nn_fhc>  
这一次,我自己做了一个二进制的尺子,用CCD在一个盒子里读尺。

伍胥之 01-02-2021 03:35
继续填 BotNET 或Pynthon? 有没有XDJMs接龙啊 ? ,l&?%H9q  
Y][12{I{  

伍胥之 07-18-2021 23:50
继续填个坑: 2c Xae  
MXSD8]je  
用VBA控制WORD自己修订学生毕业文的格式。 I$"Z\c8;  


查看完整版本: [-- [ZT]我和电脑亲密接触的心路历程 --] [-- top --]


Powered by PHPWind v7.5 SP3 Code ©2003-2010 PHPWind
Time 0.026070 second(s),query:2 Gzip disabled

You can contact us