分类存档: Desktop - 第2页

用VB写一个你自己的Flash播放器

前天在PConline下了一个孙鑫的《Java从入门到精通》的视频教程,Flash格式,在看的时候感觉很不爽,每一课开始的时候有一大段广 告,而且前面的一部分颇为啰嗦,讲了乱七八糟的东西,不知道是不是因为“入门”的关系,然后就把以前做的一个Flash播放器找出来,直接跳到自己要看的 地方~

要想用VB做一个自己的Flash播放器还是比较方便的,因为Macromedia已经提供了Shockwave Flash控件, 可以方便来的播放Flash影片。要想使用这个控件,首先要在工程里添加这个控件,选中菜单“工程->部件”,找到 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

是 否正在播放

TotalFrames

Flash影片的总帧数

好了, 有了这些资料就可以开始写自己的Flash播放了~

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

完成窗体的设计,开始编写代码。

‘ 先给打开按钮添加过程

Private Sub cmdOpen_Click()

dlg.Filter = “Flash(*.swf)|*.swf”  ‘ 设 置文件名过滤器,只显示Flash文件

dlg.ShowOpen

If dlg.FileName = “” Then Exit Sub ‘ 如 果用户点了取消则退出处理

swf.Movie = dlg.FileName           ‘ 加载影片

hslFrame.Max = swf.TotalFrames     ‘ 获 取总帧数,并赋值给滚动条的最大值

End Sub

‘ 接着是播放按钮

Private Sub cmdPlay_Click()

If swf.Playing = True Then   ‘ 如 果正在播放则暂停

swf.StopPlay

cmdPlay.Caption = “播 放” ‘ 按钮文本设置为“播放”

Else

swf.Play                 ‘ 否 则就继续播放

cmdPlay.Caption = “暂停” ‘ 按钮文本设置为“暂停”

End If

End Sub

‘ 停 止按钮

Private Sub cmdStop_Click()

swf.Stop  ‘ 停止

End Sub

‘ 前 一帧按钮

Private Sub cmdPrev_Click()

swf.Back

End Sub

‘ 后 一帧按钮

Private Sub cmdNext_Click()

swf.Forward

End Sub

‘ 为 了可以拖动滚动条来进行播放,下面处理hslFrame的OnChange事件

Private Sub hslFrame_Change()

swf.GotoFrame hslFrame.Value  ‘ 跳 到滚动条值所在的帧

End Sub

好了,一个简单的Flahs播放器就做好了,当然你也可以在这个此基础上加上更多的功能。

[ASM] 是男人就下100层,交出序列号来

某天(前天:),看了两个小时高数(具体不详:)之后,想放松一下,找到《是男人就下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:[<&USER32.GetDlgItemText>]

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]

00407AB5  PUSH EAX

00407AB6  PUSH 4

00407AB8  MOV EAX,DWORD PTR DS:[40E200]

00407ABD  PUSH EAX

00407ABE  CALL DWORD PTR DS:[<&USER32.LoadStringA>]

; 下面就是弹出出错提示框的代码了

00407AC4  PUSH 10

00407AC6  PUSH 是男人就.0040D270

00407ACB  LEA EAX,DWORD PTR SS:[EBP-104]

00407AD1  PUSH EAX

00407AD2  MOV EAX,DWORD PTR SS:[EBP+8]

00407AD5  PUSH EAX

00407AD6  CALL DWORD PTR DS:[<&USER32.MessageBoxA>]

00407ADC  JMP 是男人就.00407B22

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

00407AA4  JNZ 是男人就.00407AE1

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

00407A8D  CALL DWORD PTR DS:[<&USER32.GetDlgItemText>]

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

00407C5F  PUSH EBP ; C函数标准开头

00407C60  MOV EBP,ESP

00407C62  SUB ESP,4   ; 局部变量,分析后面的代码可知是用来作计数器的

00407C65  PUSH EBX ; 保护寄存器

00407C66  PUSH ESI

00407C67  PUSH EDI

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

00407C68  MOV EAX,DWORD PTR SS:[EBP+8]  ; 这句之后EAX指向序列号

00407C6B  XOR ECX,ECX

00407C6D  MOV CL,BYTE PTR DS:[EAX+7]    ; 得到序列号第8位

00407C70  TEST ECX,ECX ; 判断是否为0

00407C72  JE 是男人就.00407C7F    ; 是刚跳转

00407C78  XOR EAX,EAX ; EAX清零

00407C7A  JMP 是男人就.00407DC4    ; 这里跳到函数结尾

00407C7F  MOV DWORD PTR SS:[EBP-4],0    ; 计数器清零

00407C86  JMP 是男人就.00407C8E

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

00407C8B  INC DWORD PTR SS:[EBP-4]    ; 计数器加1

00407C8E  CMP DWORD PTR SS:[EBP-4],7  ; 判断计数器是否大于7

00407C92  JGE 是男人就.00407CC3       ; 大于等于就

00407C98  MOV EAX,DWORD PTR SS:[EBP-4] ; 取计数器值到EAX

00407C9B  MOV ECX,DWORD PTR SS:[EBP+8] ; 取序列号地址到ECX

00407C9E  MOV AL,BYTE PTR DS:[EAX+ECX; 取序列号第N位到AL,N为计数器值

00407CA1  PUSH EAX ; 压入堆栈,调用处理函数

00407CA2  CALL 是男人就.00407DC9  ; 将1位序列号从ASCII转换成二进制值

00407CA7  ADD ESP,4   ; 恢复堆栈

00407CAA  XOR ECX,ECX ; ECX清零

00407CAC  MOV CL,AL ; 将处理过的1位序列号存到CL

00407CAE  CMP ECX,24  ; 判断是否大于0x24

00407CB1  JLE 是男人就.00407CBE  ; 大于就出错了

00407CB7  XOR EAX,EAX ; 大于0x24,跳到函数结束,返回0

00407CB9  JMP 是男人就.00407DC4

00407CBE  JMP 是男人就.00407C8B  ; 继续处理下一位

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

00407CA2  CALL 是男人就.00407DC9

这个调用得看看,F7跟进:

00407DC9  PUSH EBP

00407DCA  MOV EBP,ESP

00407DCC  PUSH EBX

00407DCD  PUSH ESI

00407DCE  PUSH EDI

00407DCF  XOR EAX,EAX

00407DD1  MOV AL,BYTE PTR SS:[EBP+8]    ; 取参数,即1位序列号

00407DD4  CMP EAX,61

00407DD7  JL 是男人就.00407DE8

; 判断是否大于0x61,如果对ASCII码表熟悉的话可以知道0x61对应的是a

; 小于则跳转,好,上面那个判断应该不是用来判断这个字符是否为小写字母了

; 不是则跳到后面继续处理,是则进行下面的处理过程

00407DDD  XOR EAX,EAX ; EAX清零

00407DDF  MOV AL,BYTE PTR SS:[EBP+8]    ; 取字符

00407DE2  SUB EAX,20     ; 减0x20,变大写字母

00407DE5  MOV BYTE PTR SS:[EBP+8],AL ; 保存

; 不管是否为小字字母,经过上面的判断和处理都会变成大写字母,继续进行处理

00407DE8  XOR EAX,EAX ; EAX清零

00407DEA  MOV AL,BYTE PTR SS:[EBP+8]    ; 取字符

00407DED  CMP EAX,41

00407DF0  JL 是男人就.00407E01

; 判断是否大于,0x41对应的ASCII字符为A

; 小于则跳转,说明这里是判断字符是否为大写字母

; 不是则跳到后面继续处理,是则进行下面的处理过程

00407DF6  XOR EAX,EAX ; EAX清零

00407DF8  MOV AL,BYTE PTR SS:[EBP+8]    ; 取字符

00407DFB  SUB EAX,7      ; 减去7

00407DFE  MOV BYTE PTR SS:[EBP+8],AL ; 保存

; 如果不是大写字母就跳到这里了,当然如果是大写字母的话

; 经过上面的处理过程同样要进行下面的处理过程

00407E01  XOR EAX,EAX ; EAX清零

00407E03  MOV AL,BYTE PTR SS:[EBP+8]    ; 取字符

00407E06  SUB EAX,30     ; 减去0x30

00407E09  JMP 是男人就.00407E0E  ; 函数结束

00407E0E  POP EDI

00407E0F  POP ESI

00407E10  POP EBX

00407E11  LEAVE

00407E12  RETN

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

char是否为小写字母 -> 是则减去0x20变成大写字母,不是则保持不变 -> char是否为大写字母 -> 是则减去7,不是则保持不变 -> char减0x30

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

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

00407CB1  JLE 是男人就.00407CBE  ; 大于就出错了

00407CB7  XOR EAX,EAX ; 大于0x24,跳到函数结束,返回0

00407CB9  JMP 是男人就.00407DC4

00407CBE  JMP 是男人就.00407C8B  ; 继续处理下一位

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

00407CC3  MOV EAX,DWORD PTR SS:[EBP+8]

00407CC6  MOV AL,BYTE PTR DS:[EAX+5]  ; 取序列号第6位

00407CC9  PUSH EAX

00407CCA  CALL 是男人就.00407DC9      ; 转换成数值

00407CCF  ADD ESP,4

00407CD2  XOR EBX,EBX

00407CD4  MOV BL,AL ; 序列号第6位值保存到EBX

00407CD6  MOV EAX,DWORD PTR SS:[EBP+8]

00407CD9  MOV AL,BYTE PTR DS:[EAX+2]  ; 取序列号第3位

00407CDC  PUSH EAX

00407CDD  CALL 是男人就.00407DC9      ; 转换成数值

00407CE2  ADD ESP,4

00407CE5  XOR ECX,ECX

00407CE7  MOV CL,AL ; 序列号第3位值保存到ECX

00407CE9  MOV ESI,24   ; ESI=0x24

00407CEE  LEA EAX,DWORD PTR DS:[ECX+EBX*2+1D] ; EAX=ECX+EBX*2+1D

00407CF2  CDQ ; 扩展成64位

00407CF3  IDIV ESI ; 除以0x24

00407CF5  MOV EBX,EDX ; EDX为余数,存到EBX

00407CF7  MOV EAX,DWORD PTR SS:[EBP+8]

00407CFA  MOV AL,BYTE PTR DS:[EAX]  ; 取序列号第1位

00407CFC  PUSH EAX

00407CFD  CALL 是男人就.00407DC9    ; 转换成数值

00407D02  ADD ESP,4

00407D05  XOR ECX,ECX

00407D07  MOV CL,AL ; 序列号第1位值存到ECX

00407D09  CMP EBX,ECX ; EBX=ECX?

00407D0B  JNZ 是男人就.00407DBD  ; 不等,验证失败,跳到函数结束

; 头有些大了,用心看发现这里在判断序列号是否符合规则

; (第3位+第6位*2+0x1D)%0x24==第1位

; 跟着又是两段代码类似的,不难发现也是判断,不过规则有小小的不同

; 下面这段的判断规则是

; (第2位+第5位*2+0x1D)%0x24==第7位

00407D11  MOV EAX,DWORD PTR SS:[EBP+8]

00407D14  MOV AL,BYTE PTR DS:[EAX+4]

00407D17  PUSH EAX

00407D18  CALL 是男人就.00407DC9

00407D1D  ADD ESP,4

00407D20  XOR EBX,EBX

00407D22  MOV BL,AL

00407D24  MOV EAX,DWORD PTR SS:[EBP+8]

00407D27  MOV AL,BYTE PTR DS:[EAX+1]

00407D2A  PUSH EAX

00407D2B  CALL 是男人就.00407DC9

00407D30  ADD ESP,4

00407D33  XOR ECX,ECX

00407D35  MOV CL,AL

00407D37  MOV ESI,24

00407D3C  LEA EAX,DWORD PTR DS:[ECX+EBX*2+1D]

00407D40  CDQ

00407D41  IDIV ESI

00407D43  MOV EBX,EDX

00407D45  MOV EAX,DWORD PTR SS:[EBP+8]

00407D48  MOV AL,BYTE PTR DS:[EAX+6]

00407D4B  PUSH EAX

00407D4C  CALL 是男人就.00407DC9

00407D51  ADD ESP,4

00407D54  XOR ECX,ECX

00407D56  MOV CL,AL

00407D58  CMP EBX,ECX

00407D5A  JNZ 是男人就.00407DBD

; 下面这段的判断规则是

; (第1位+第7位*2+0x1D)%0x24==第4位

00407D60  MOV EAX,DWORD PTR SS:[EBP+8]

00407D63  MOV AL,BYTE PTR DS:[EAX+6]

00407D66  PUSH EAX

00407D67  CALL 是男人就.00407DC9

00407D6C  ADD ESP,4

00407D6F  XOR EBX,EBX

00407D71  MOV BL,AL

00407D73  MOV EAX,DWORD PTR SS:[EBP+8]

00407D76  MOV AL,BYTE PTR DS:[EAX]

00407D78  PUSH EAX

00407D79  CALL 是男人就.00407DC9

00407D7E  ADD ESP,4

00407D81  XOR ECX,ECX

00407D83  MOV CL,AL

00407D85  MOV ESI,24

00407D8A  LEA EAX,DWORD PTR DS:[ECX+EBX*2+1D]

00407D8E  CDQ

00407D8F  IDIV ESI

00407D91  MOV EBX,EDX

00407D93  MOV EAX,DWORD PTR SS:[EBP+8]

00407D96  MOV AL,BYTE PTR DS:[EAX+3]

00407D99  PUSH EAX

00407D9A  CALL 是男人就.00407DC9

00407D9F  ADD ESP,4

00407DA2  XOR ECX,ECX

00407DA4  MOV CL,AL

00407DA6  CMP EBX,ECX

00407DA8  JNZ 是男人就.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  MOV EAX,1   ; EAX=1

00407DB3  JMP 是男人就.00407DC4  ; 跳到返回

00407DB8  JMP 是男人就.00407DC4

00407DBD  XOR EAX,EAX ; 任何验证的情况下均返回0

00407DBF  JMP 是男人就.00407DC4

00407DC4  POP EDI

00407DC5  POP ESI

00407DC6  POP EBX

00407DC7  LEAVE

00407DC8  RETN

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

#include <stdio.h>

int main()

{

char bin2char(int bin);

int tmp,b1,b2,b3,b4,b5,b6,b7;

printf(“register codes:\n”);

for(b1=0;b1<36;b1++)

for(b2=0;b2<36;b2++)

for(b3=0;b3<36;b3++)

for(b4=0;b4<36;b4++)

for(b5=0;b5<36;b5++)

for(b6=0;b6<36;b6++)

for(b7=0;b7<36;b7++)

{

tmp = b3 + b6*2 + 0x1D;

if (b1!=tmp%0x24) break;

tmp = b2 + b5*2 + 0x1D;

if (b7!=tmp%0x24) break;

tmp = b1 + b7*2 + 0x1D;

if (b4!=tmp%0x24) break;

printf(“%c%c%c%c%c%c%c\n”,

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

}

}

char bin2char(int bin)

{

if(bin<10) return(bin+0x30);

else return(bin-10+0x41);

}

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

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

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

[VB] 一个操作多线程的类

根据点睛工作室的多线程类改写的,不过没有经过严格测试,好像工作不是很稳定,如果使用不当会出错的说。

Option Explicit

Private Type SECURITY_ATTRIBUTES

nLength As Long

lpSecurityDescriptor As Long

bInheritHandle As Long

End Type

Private Declare Function CreateThread Lib “kernel32” (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

Private Declare Function CreateThreadL Lib “kernel32” Alias “CreateThread” (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

Private Declare Function TerminateThread Lib “kernel32” (ByVal hThread As Long, ByVal dwExitCode As Long) As Long

Private Declare Function SetThreadPriority Lib “kernel32” (ByVal hThread As Long, ByVal nPriority As Long) As Long

Private Declare Function GetThreadPriority Lib “kernel32” (ByVal hThread As Long) As Long

Private Declare Function ResumeThread Lib “kernel32” (ByVal hThread As Long) As Long

Private Declare Function SuspendThread Lib “kernel32” (ByVal hThread As Long) As Long

Private Declare Function GetCurrentThread Lib “kernel32” () As Long

Private Declare Function GetCurrentThreadId Lib “kernel32” () As Long

Private Declare Sub ExitThread Lib “kernel32” (Optional ByVal dwExitCode As Long = 0)

Private Declare Function GetLastError Lib “kernel32” () As Long

‘ 常数常量

Private Const MAXLONG = &H7FFFFFFF

‘ 线程优先级常量

Private Const THREAD_BASE_PRIORITY_IDLE = -15

Private Const THREAD_BASE_PRIORITY_LOWRT = 15

Private Const THREAD_BASE_PRIORITY_MAX = 2

Private Const THREAD_BASE_PRIORITY_MIN = -2

Private Const THREAD_PRIORITY_HIGHEST = THREAD_BASE_PRIORITY_MAX

Private Const THREAD_PRIORITY_IDLE = THREAD_BASE_PRIORITY_IDLE

Private Const THREAD_PRIORITY_LOWEST = THREAD_BASE_PRIORITY_MIN

Private Const THREAD_PRIORITY_NORMAL = 0

Private Const THREAD_PRIORITY_TIME_CRITICAL = THREAD_BASE_PRIORITY_LOWRT

Private Const THREAD_PRIORITY_ABOVE_NORMAL = (THREAD_PRIORITY_HIGHEST – 1)

Private Const THREAD_PRIORITY_BELOW_NORMAL = (THREAD_PRIORITY_LOWEST + 1)

Private Const THREAD_PRIORITY_ERROR_RETURN = (MAXLONG)

‘ 线程创建标志

Private Const CREATE_ALWAYS = 2

Private Const CREATE_NEW = 1

Private Const CREATE_NEW_CONSOLE = &H10

Private Const CREATE_NEW_PROCESS_GROUP = &H200

Private Const CREATE_NO_WINDOW = &H8000000

Private Const CREATE_PROCESS_DEBUG_EVENT = 3

Private Const CREATE_SUSPENDED = &H4

Private Const CREATE_THREAD_DEBUG_EVENT = 2

‘ 线程优先级结构

Public Enum ThreadPriority

Lowest = THREAD_PRIORITY_LOWEST

BelowNormal = THREAD_PRIORITY_BELOW_NORMAL

Normal = THREAD_PRIORITY_NORMAL

AboveNormal = THREAD_PRIORITY_ABOVE_NORMAL

Highest = THREAD_PRIORITY_HIGHEST

End Enum

Private mAttrib As SECURITY_ATTRIBUTES

Private mEnabled As Boolean

Private mThreadHandle As Long

Private mThreadID As Long

Private mTerminate As Boolean

Public Property Get ThreadID() As Long

ThreadID = mThreadID

End Property

Public Property Get ThreadHandle() As Long

ThreadHandle = mThreadHandle

End Property

Public Function Create(ByVal cFunction As Long, Optional ByVal cPriority As ThreadPriority, Optional ByVal cEnabled As Boolean = True) As Long

Dim CreateFlag As Long

If mThreadHandle <> 0 Then TerminateMe

mEnabled = cEnabled

If mEnabled Then

CreateFlag = CREATE_NEW

Else

CreateFlag = CREATE_SUSPENDED

End If

mAttrib.nLength = Len(mAttrib)

mThreadHandle = CreateThreadL(0, 0, cFunction, 0&, CreateFlag, mThreadID)

If mThreadHandle = 0 Then

MsgBox “Create thread failed!Error code:” & GetLastError, vbOKOnly Or vbCritical, “Error”

End If

End Function

Public Sub SuspendMe()

If mThreadHandle = 0 Or mEnabled = False Then Exit Sub

If SuspendThread(mThreadHandle) <> -1 Then

mEnabled = False

Else

MsgBox “Suspend thread failed!Error code:” & GetLastError, vbOKOnly Or vbCritical, “Error”

End If

End Sub

Public Sub ResumeMe()

If mThreadHandle = 0 Or mEnabled = True Then Exit Sub

If ResumeThread(mThreadHandle) <> -1 Then

mEnabled = True

Else

MsgBox “Resume thread failed!Error code:” & GetLastError, vbOKOnly Or vbCritical, “Error”

End If

End Sub

Public Sub TerminateMe()

If mThreadHandle = 0 Then Exit Sub

TerminateThread mThreadHandle, 0

mThreadHandle = 0

‘mTerminate = True

‘Do

‘    DoEvents

‘Loop Until mTerminate

End Sub

Private Sub Class_Terminate()

‘TerminateThread mThreadHandle, 0

End Sub

用汇编实现符串操作函数

不管是在系统开发还是在平时的编程当中,字符串操作都是很重要的一部分。在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:

lodsb       ; 载入一个字节

or al,al     ; 是0?

je end     ; 是 则结束

inc cx      ; 字符串长度+1

jmp next ; 继续下一个字节

end:

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

pop bx     ; 恢复寄存器

pop si

ret

strcat 字 符串连接

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

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

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

今天这篇就到这里喽~~难得写教 程之类的文章,今天还算顺手^-^~~

BMP 文件格式学习

由于改进IMAGELIS的需要,我对BMP文件的格式进行了一些研究,写在这里做为学习笔记,也给需要的朋友做为参考。如果没有特别说明,我所用的位图文件都是由WinowXP自带的画图产生。

BMP文件格式在网上已经很多教程之类的,不过我这里讲的是一些它们没提到的。

1.数据区起始位置

我在网上找到许多有关BMP文件格式的说明都说数据区起始位置在相对文件开头51个字节处,但我却发现数据区起始在相关文件开头55个字节处,不知是网上的错了还是我错了,不过我这样用了好像也没出错,有空再研究研究。

2.像素保存顺序

位图保存时扫描顺序是从下至上,从左至右,即在位图数据区,位图第一行保存在位图数据区的最后,而位图最后一行保存在位图数据区的开始,例有一个4×4的位图,那么它有4行,4列,像素保存在数据区的顺序是这样的:

line3 pixel 0 1 2 3

line2 pixel 0 1 2 3

line1 pixel 0 1 2 3

line0 pixel 0 1 2 3

因此,如果我们要自己产生一个位图文件,那么保存时就应该从最后一行,第一个像素开始保存,保存好一行后就往上一行直到第一行保存完毕,当然,我们必须在位图数据之前加上位图文件头,文件头的格式可以在网上找资料。

3.行字节对齐

可能是为了数据区的读取更快速,BMP格式规定一行的字节数必须是4的倍数,如果不足,就用0补足。例如有一幅5×5的24位色位图,那么本来每一行的字节数是24/8*5=15个字节,但15不是4的倍数,还需要1个字节来补足,于是在数据区这一行的数据就是:

pixel 0 1 2 3 4 0x00

同理如果宽度是7那么就需要补3个字节等等。如果是12×12单色位图,那么一行有12/2=6个字节,就需要在每一行的数据的最后补2个字节。

这个补0的问题很多朋友在处理位图的时候没有注意,以致于程序在处理诸如32×32之类的位图时能很好的运行,而处理如31×32这样的就不行了。

4.颜色数少于256时的数据位

在颜色数少于256时一个字节里就可能保存1个或者更多个像素,这时就要注意像素在字节里的保存顺序了。像素在字节内保存的顺序原则是前面的像素在高位,后面的像素在低位。例:

在16色位图里,每一个像素需要4个bit来保存,因此1个字节里就保存了两个像素,假如有一个2×1的16色位图,第一个像素是黑色,数据是0x0,第二个像素白色,数据是0xF,那么根据上面的原则,这两个像素在字节里是这样保存的:

pixel 0      1

bits  0000 1111

同理,如果是单色位图,也是前面的像素在高位,后面的像素在低位。

以上呢就是我在研究BMP格式时得到的一些经验,当然,如果有错或者有什么问题可以给我写信:)

[C] 冒泡排序

冒泡排序法:)记得在一本三级A类教程上看过怎么优化的,现在又给忘了,只写了这么个东东。

#include <stdio.h>

#define N 100

int main(int argc, char *argv[])

{

int a[N];

int i,j,temp;

for(i=0;i<N;i++) a[i]=rand();

printf(“start: %d\n”,st=(unsigned)time(NULL));

for(i=0;i<N;i++)

{

for(j=i;j<N-1;j++)

{

if(a[j]>a[j+1])

{

temp=a[j];

a[j]=a[j+1];

a[j+1]=temp;

}

}

}

for(i=0;i<N;i++) printf(“%d “,a[i]);

printf(“\n”);

return 0;

}

[MenuetOS] HotCats 0.1 代码分析

用来在MEOS里抓取屏幕,不过这个版本并不完善。

在这个版本里,程序所用的方法是扫描屏幕上的点然后再写到缓存最后写到文件,这样就会导致速度很慢。

BMP格式文档可以去我的网络硬盘下载http://osdev.ys168.com

;=======================================

;    HotCats

;    Ver : 0.1

;    BLOG: http://hotheart.go.3322.org

;=======================================

bits 32

org    0x0

db ‘MENUET01’ ; 8 byte id

dd 0x01                        ; header version

dd START                        ; start of code

dd I_END                        ; size of image

dd 0x300000                    ; memory for app

dd 0xffff                        ; esp

dd 0x0 , 0x0                    ; I_Param , I_Icon

START:                                ; start of execution

mov eax,14                    ; 获取屏幕分辨率

int 0x40

xor ebx,ebx

mov bx,ax

shr eax,16

inc eax ; X size

inc ebx ; Y size

mov [scr_x],eax

mov [scr_y],ebx

mov [img_w],eax

mov [img_h],ebx

imul ebx

imul eax,3                    ; image data size

mov [img_s],eax

add eax,0x36                ; BMP header size

mov [imgf_s],eax

mov [f_s],eax

mov esi,bminfo                ; fill the header

mov edi,filestart

mov ecx,0x36/4

cld

repz movsd

call draw_window                ; draw the window

still:

mov eax,10                    ; wait here for event

int 0x40

cmp eax,1                    ; redraw request ?

je red

cmp eax,2                    ; key in buffer ?

je key

cmp eax,3                    ; button in buffer ?

je button

jmp still

red:                                ; redraw

call draw_window

jmp still

key:                                ; key

mov eax,2                    ; just read it and ignore

int 0x40

jmp still

button:                            ; button

mov eax,17                    ; get id

int 0x40

cmp ah,1                    ; button id=1 ?

jne .cmdcap

mov eax,-1                    ; close this program

int 0x40

.cmdcap:

cmp ah,cmdcap                ; is the Capture button ?

jne .cmdsave

call capall                    ; capture the whole screen

jmp still

.cmdsave:

cmp ah,cmdsave                ; is the save button

jne .end

call savefile                ; save the file

jmp still

.end:

jmp still

;   *********************************************

;   *******  WINDOW DEFINITIONS AND DRAW ********

;   *********************************************

draw_window:

mov eax,12                    ; function 12:tell os about windowdraw

mov ebx,1                    ; 1, start of draw

int 0x40

; DRAW WINDOW

mov eax,0

mov ebx,[scr_x]

sub ebx,win_w+5

imul ebx,65536

add ebx,win_w

mov ecx,[scr_y]

sub ecx,win_h+25

imul ecx,65536

add ecx,win_h

mov edx,0x03ffffff

mov esi,0x40ffffff

mov edi,0x00ffffff

int 0x40

; WINDOW LABEL

mov eax,4                    ; function 4 : write text to window

mov ebx,8*65536+8            ; [x start] *65536 + [y start]

mov ecx,0x10ddeeff            ; font 1 & color ( 0xF0RRGGBB )

mov edx,labelt                ; pointer to text beginning

mov esi,labellen-labelt        ; text length

int 0x40

; Button Capture

mov eax,8

mov ebx,10*65536+40

mov ecx,(win_h-10-14)*65536+14

mov edx,cmdcap

mov esi,0xaabbcc

int 0x40

; Button Save

mov eax,8

mov ebx,(10+40+10)*65536+40

mov ecx,(win_h-10-14)*65536+14

mov edx,cmdsave

mov esi,0xaabbcc

int 0x40

; Button Text

mov eax,4                        ; function 4 : write text to window

mov ebx,18*65536+(win_h-10-14+4); [x start] *65536 + [y start]

mov ecx,0x00444444                ; font 1 & color ( 0xF0RRGGBB )

mov edx,btext                    ; pointer to text beginning

mov esi,btexte-btext            ; text length

int 0x40

mov eax,12                    ; function 12:tell os about windowdraw

mov ebx,2                    ; 2, end of draw

int 0x40

ret

mov eax,47                    ; display the screen size

mov ebx,4*65536

mov ecx,[scr_x]

mov edx,120*65536+30

mov esi,0x0

int 0x40

mov eax,47

mov ebx,4*65536

mov ecx,[scr_y]

mov edx,120*65536+40

mov esi,0x0

int 0x40

capall:

mov edi,imgarea

mov ecx,[scr_y]

cld

.nextline:

mov ebx,ecx

dec ebx

imul ebx,[scr_x]

push ecx

mov ecx,[scr_x]

.capline:

push edi

push ebx

mov eax,35                    ; get pixel

int 0x40

stosd

pop ebx

pop edi

inc ebx

add edi,3

loop .capline

pop ecx

loop .nextline

.end:

ret

savefile:                            ; save the file

mov eax,58

mov ebx,fileinfo

int 0x40

ret

; DATA AREA

win_w        equ 250

win_h        equ 50

cmdcap        equ 2

cmdsave        equ 3

filestart    equ 0x20000

imgarea        equ filestart+0x36

scr_x    dd 0

scr_y    dd 0

zoom    dd 2

fileinfo:

dd 1                    ; 1=WRITE

dd 0x0                    ; not used

f_s  dd 800*600*3+0x36        ; bytes to write

dd filestart            ; source data pointer

dd 0x10000                ; work area for os – 16384 bytes

db ‘/HD/1/TEST.BMP’,0    ; ASCIIZ dir & filename

btext:  db ‘ Cat     Save  ‘

btexte:

labelt:

db ‘HotCats 0.1 – HotHeart HotWorks 2005’

labellen:

bminfo:

db ‘BM’ ; 0000-0001 位图标志

imgf_s    dd 800*600*3+0x36    ; 0002-0005 文件大小

dd 0x0                ; 0006-0009 保留

db 0x36,0x0,0x0,0x0; 000A-000D 文件头信息块大小,图像描述信息块的大小,图像颜色表的大小,保留(为01)

dd 0x28            ; 000E-0011 图像描述信息块的大小,常为28H。

img_w    dd 800                ; 0012-0015    图像宽度。

img_h    dd 600                ; 0016-0019    图像高度。

dw 0x1                ; 001A-001B    图像的plane总数(恒为1)。

dw 24                ; 001C-001D    数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)。

dd 0                ; 001E-0021    记录像素的位数,很重要的数值,图像的颜色数由该值决定。

img_s    dd 800*600*3        ; 0022-0025    图像区数据的大小。

dd 0x0                ; 0026-0029    水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。

dd 0x0                ; 002A-002D    垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。

dd 0x0                ; 002E-0031    此图像所用的颜色数,如值为0,表示所有颜色一样重要。

dd 0x0                ; 0032-0035 未用

I_END:

[MenuetOS] HotRun 0.4 代码分析

; Made by HotHeart

http://www.xujiwei.com

; vipxjw@tom.com

; MENUET RUN 0.4

; 1) 缺省目录 /RD/1/

; 2) 可以更改程序目录,在SETUP里设置硬盘后可以运行

;    硬盘上的程序

; 3) 只能访问根目录

; 4) 自动根据屏幕大小调整窗口位置(限任务栏为文字模式)

use32

org    0x0

db ‘MENUET01’ ; 8 byte id

dd 0x01                    ; header version

dd START                   ; start of code

dd I_END                   ; size of image

dd 0x100000                ; memory for app

dd 0x7fff0                 ; esp

dd 0x0 , 0x0               ; I_Param , I_Icon

START:                          ; start of execution

; 计算窗口位置

mov eax,14

int 0x40

mov [screenysize],ax

xor eax,eax

mov ax,[screenysize]

sub eax,116+20

imul eax,65536

add eax,116

mov [winy],eax

; 初始化变量

mov [filestr],dword runprogram

mov [dir],dword rundir

mov [ya],dword 53

mov [yb],dword 69

call draw_window

still:

mov eax,23                 ; wait here for event

int 0x40

cmp eax,1                  ; redraw request ?

je red

cmp eax,2                  ; key in buffer ?

je key

cmp eax,3                  ; button in buffer ?

je button

jmp still

red:                          ; redraw

call draw_window

jmp still

key:                          ; key

mov eax,2                  ; just read it and ignore

int 0x40

jmp still

button:                       ; button

mov eax,17                 ; get id

int 0x40

cmp ah,4                  ; id=4 结束

je close

cmp ah,1

je close

cmp ah,2                  ; id=2 输入文件名

je inputfile

cmp ah,5                  ; id=5 输入路径

je inputdir

cmp ah,3                  ; id=3 运行程序

je runp

jmp still

file_start: dd 16

dd 0,0,0,0×10000

rundir:     db ‘/RD/1/’ ; 缺省目录

runprogram: db ‘RUN’,0        ; 缺省程序

times 60 db 0

filestr  dd 0x0

dir      dd 0x0

addr dd 0x0

ya       dd 0x0

yb       dd 0x0

;==========================================================

close:

;结束程序

mov eax,-1

int 0x40

inputfile:

;输入文件名

call read_string_file

jmp still

inputdir:

;输入路径

call read_string_dir

jmp still

;==========================================================

runp:

;运行程序

mov eax,58        ;运行

mov ebx,file_start

int 0x40

jmp still

;==========================================================

read_string_file:

;输入文件名

mov edi,[filestr]

mov eax,0

mov ecx,40

cld

rep stosb

call print_file

mov edi,[filestr]

file_fun:

mov eax,23        ; 等待事件

mov ebx,100    ; 延时100毫秒

int 0x40

cmp eax,0        ; eax=0 无事件

je file_fun    ; 继续等待事件过程

cmp eax,2        ; eax=2 按钮事件

jne file_read_done    ; 跳到读取键盘事件结束

mov eax,2        ; 获取击键 ascii 码

int 0x40

shr eax,8

cmp eax,13        ; 是否为回车键

je file_read_done    ; 是则跳到读取结束

cmp eax,8        ; 是否为退格键

jnz file_nobsl    ; 不是则跳到 nobsl

cmp edi,[filestr]

jz file_fun

sub edi,1        ; 字符数量减 1

mov [edi],byte 32    ; 退格

call print_file    ; 显示字符串

jmp file_fun    ; 继续读取

file_nobsl:

cmp al,95        ; 判断是否为小写

jbe file_cok    ; 是则跳到 cok

sub al,32        ; 不是则将 ascii 减去 32

file_cok:

mov [edi],al ; 添加到字符串

call print_file    ; 显示字符串

add edi,1        ; 已读取字符数量

mov esi,[filestr]    ; 读入字符串地址

add esi,30        ; 加上 30

cmp esi,edi ; 比较

jnz file_fun    ; 未到最大长度

file_read_done:    ; 读取结束

mov [edi],byte 0    ; 结束标志

call print_file    ; 显示字符串

jmp still        ; 事件循环

;==========================================================

read_string_dir:

mov edi,[dir]

mov eax,0

mov ecx,6

cld

rep stosb

call print_dir

mov edi,[dir]

dir_fun:

mov eax,23        ; 等待事件

mov ebx,100    ; 延时100毫秒

int 0x40

cmp eax,0        ; eax=0 无事件

je dir_fun    ; 继续等待事件过程

cmp eax,2        ; eax=2 按钮事件

jne dir_read_done    ; 跳到读取键盘事件结束

mov eax,2        ; 获取击键 ascii 码

int 0x40

shr eax,8

cmp eax,13        ; 是否为回车键

je dir_read_done    ; 是则跳到读取结束

cmp eax,8        ; 是否为退格键

jnz dir_nobsl    ; 不是则跳到 nobsl

cmp edi,[filestr]

jz dir_fun

sub edi,1

mov [edi],byte 32

call print_dir    ; 显示字符串

jmp dir_fun    ; 继续读取

dir_nobsl:

cmp al,95        ; 判断是否为小写

jbe dir_cok    ; 是则跳到 cok

sub al,32        ; 不是则将 ascii 减去 32

dir_cok:

mov [edi],al ; 添加到字符串

call print_dir    ; 显示字符串

add edi,1        ; 已读取字符数量

mov esi,[dir]    ; 读入字符串地址

add esi,6        ; 加上 6

cmp esi,edi ; 比较

jnz dir_fun    ; 未到最大长度

dir_read_done:    ; 读取结束

call print_dir    ; 显示字符串

jmp still        ; 事件循环

;==========================================================

print_dir:

;显示路径

pusha

mov eax,13        ; 画底纹

mov ebx,55*65536+31*6

mov ecx,[ya]

shl ecx,16

mov cx,12

sub ecx,2*65536

mov edx,0xeeeeee

int 0x40

mov eax,4        ; 显示路径

mov edx,[dir]

mov ebx,56*65536

add ebx,[ya]

mov ecx,0x444444

mov esi,6

int 0x40

popa

ret

;==========================================================

print_file:

;显示文件名

pusha

mov eax,13        ; 画底纹

mov ebx,55*65536+31*6

mov ecx,[yb]

shl ecx,16

mov cx,12

sub ecx,2*65536

mov edx,0xeeeeee

int 0x40

mov eax,4        ; 显示文件名

mov edx,[filestr]

mov ebx,56*65536

add ebx,[yb]

mov ecx,0x444444

mov esi,30

int 0x40

popa

ret

;==========================================================

;   *********************************************

;   *******  WINDOW DEFINITIONS AND DRAW ********

;   *********************************************

draw_window:

mov eax,12                    ; function 12:tell os about windowdraw

mov ebx,1                     ; 1, start of draw

int 0x40

; DRAW WINDOW

mov eax,0                ; function 0 : define and draw window

mov ebx,1*65536+250    ; [x start] *65536 + [x size]

mov ecx,[winy]            ; [y start] *65536 + [y size]

mov edx,0x03ffffff        ; color of work area RRGGBB,8->color gl

mov esi,0x805080d0        ; color of grab bar  RRGGBB,8->color gl

mov edi,0x005080d0        ; color of frames    RRGGBB

int 0x40

; WINDOW LABEL

mov eax,4                ; function 4 : write text to window

mov ebx,8*65536+8        ; [x start] *65536 + [y start]

mov ecx,0x10ddeeff        ; font 1 & color ( 0xF0RRGGBB )

mov edx,labelt            ; pointer to text beginning

mov esi,labellen-labelt; text length

int 0x40

mov eax,8                ; 路径输入 id=5

mov ebx,13*65536+40

mov ecx,50*65536+12

mov edx,5

mov esi,0xaabbcc

int 0x40

mov eax,8                ; 文件名输入 id=2

mov ebx,13*65536+40

mov ecx,66*65536+12

mov edx,2

mov esi,0xaabbcc

int 0x40

mov eax,8                ; 确定 id=3

mov ebx,128*65536+48

mov ecx,84*65536+18

mov edx,3

mov esi,0xaabbcc

int 0x40

mov eax,8                ; 取消 id=4

mov ebx,182*65536+48

mov ecx,84*65536+18

mov edx,4

mov esi,0xaabbcc

int 0x40

mov ebx,13*65536+34    ; 提示信息

mov ecx,0x666666

mov edx,txttxt

mov esi,30

mov eax,4

int 0x40

mov eax,4                ; Path按钮文本

mov ebx,21*65536+53

mov ecx,0x666666

mov edx,txtdir

mov esi,4

int 0x40

mov ebx,21*65536+69    ; File按钮文本

mov ecx,0x444444

mov edx,txtfile

mov esi,4

mov eax,4

int 0x40

mov ebx,140*65536+89    ; 确定取消按钮文本

mov ecx,0x444444

mov edx,txtbutton

mov esi,13

mov eax,4

int 0x40

call print_dir

call print_file

mov eax,12                ; function 12:tell os about windowdraw

mov ebx,2                ; 2, end of draw

int 0x40

ret

; DATA AREA

tcolor      dd 0x000000

txttxt      db ‘请输入要运行程序的路径和文件名’,‘x’

txtdir      db ‘Path’,‘x’

txtfile     db ‘File’,‘x’

txtbutton   db ‘确定     取消’,‘x’

screenysize dw 0x0

winy        dd 0x0

labelt:

db ‘运行’

labellen:

I_END:

[本日志由 xujiwei 于 2005-07-22 06:24 PM 编辑]

Comments (0), Views (2955), Pings (0), Leave a response!

系统开发资源

中断大全

http://www.ctyme.com/intr/int.htm

操 作系统资源(英文)

http://www.nondot.org/sabre/os/articles

内核版之OS设 计

http://www.linuxforum.net/forum/printthread.php?Ca … mp;main=334068&type=thread

Linux的一些Kernel资源

http://diy-os.gro.clinux.org/file.html

纯 C论坛文档资源中心

http://purec.binghua.com/Article/Index.asp

实模式进保护模式

在写自己的操作系统时,不能总在实模式下,进入保护模式才是”正道”,不过怎么进入保护模式又是一个问题,我把

XuOS里进入保护模式的代码分析一下.

; 装入GDT

mov  eax,ds  ;设置GDT在物理内存中的正确位置

shl  eax,4

add  [gdt_addr+2],eax

cli  ; 关中断

lgdt [gdt_addr] ;载入GDT

; 下面打开A20地址线,这段代码可以在OSzone上找到相关解释.

call  Empty_8042

mov  al,0xd1

out  0x64,al

call  Empty_8042

mov  al,0xdf

out  0x60,al

call  Empty_8042

; 进入保护模式

mov  eax,cr0 ;置PE位

or   eax,1

mov  cr0,eax

jmp oscodesel:code_32  ; 跳到32位代码处执行

Empty_8042:

in   al,0x64

test al,0x2

jnz  Empty_8042

ret

; GDT的内容

gdt:

gdt_null:

dd  0x0000

dd  0x0000

gdt_system_code:

oscodesel equ $-gdt  ; 段选择子

dd  0x0000ffff,0x00cf9a00

gdt_system_data:

osdatasel equ $-gdt

dd  0x1000ffff,0x00cf9200

videosel equ $-gdt

dd  0x0000ffff,0x00cf920a

gdt_addr:

dw  gdt_addr-gdt-1

dd  gdt        ; ;GDT表的位置

当然,由于XuOS目前还比较简单,还没有设置IDT,GDT中段也比较少,况且我的理解也有可能有些偏差或者表述

有些不清楚,这里只提供一个思路,更多更强的功能还是要靠自己才行.