“程序设计”目录存档

用C语言屏蔽键盘和鼠标

2010年06月22日,星期二

调用windows API中的SetWindowsHookEx函数释放键盘和鼠标钩子就可以实现,没有什么技术含量。只不过看到Google关键词“C语言 屏蔽键盘”没有好的链接,所以才写出来。当然,Ctrl+Alt+Del这个组合键是无法通过钩子函数屏蔽的,目前我还没有找到屏蔽的方法,如果你知道,请留言告诉我,谢谢。

很久很久以前我觉得让别人的鼠标不能动是很神奇的事情,这也算是学编程的一个动机罢。初学C语言的时候发现学完只能拿来算数学题,很没有成就感。后来才发现,其实并没有想象中的那么难。借用别人说的一句话,C语言是一种需要很长时间锻炼才知道它很无敌的语言。本文不打算详细介绍钩子函数,只给出了我写的示例代码,感兴趣的可以看看,写的不怎么好,高手请自觉路过。钩子函数的详细用法请自己参阅MSDN文档

代码下载地址,如果你觉得程序有效,请留言告诉我:

[download id=15]

用VBS生成GUID

2010年06月21日,星期一

这个程序应该是出自微软的脚本专家,网上也有很多人复制粘贴过,代码一模一样而且不注明出处,这我不想多说,我说过很多次了。我要说的是里面生成的GUID是无法直接使用的,在我写《桌面上出现无法删除图标的解决方法》中的VBS程序时曾经测试过用VBS代码模拟那些流氓软件,在桌面上创建删不到的图标(其实也就写写注册表,一点技术含量也没有,拿来忽悠不明真相的群众罢了),写注册表的时候要用到GUID,按脚本专家给出的代码却产生了错误。

Set TypeLib = CreateObject("Scriptlet.TypeLib")
Wscript.Echo TypeLib.Guid

表面上正确输出了一个形如

{24DD18D4-C902-497F-A64B-28B2FA741661}

的GUID,但是如果直接在脚本中使用,会出现问题。原因如下

Set TypeLib = CreateObject("Scriptlet.TypeLib")
Wscript.Echo TypeLib.Guid
WScript.Echo Len(TypeLib.Guid)

Len(TypeLib.Guid)返回的值是40而不是38,也就是说在前38个字符后面有两个不可打印的字符,所有如果直接在脚本中使用会多出两个额外的字符,写入注册表的时候就达不到预期的效果。

综上,正确的代码应该是

Set TypeLib = CreateObject("Scriptlet.TypeLib")
strGUID = Left(TypeLib.Guid,38)
WScript.Echo strGUID

在此奉劝不明真相的同学,在复制粘贴别人的代码的时候最好测试一下,并给出原文的链接,尊重别人的知识产权。

用VBS检测U盘插入和弹出事件

2010年06月20日,星期日

貌似网上很多人问怎么用VBS检测U盘插入和弹出,其实这很容易实现,WMI赋予了VBS十分强大的功能。可以说,对WMI的掌握程度的多少直接决定了你的VBS水平高低。看过网上普遍流传VBS版U盘小偷程序,基本上都是靠无限循环实现的,一点技术含量也没有,文章的末尾给出了我写的VBS版U盘小偷程序的下载地址。虽然用WMI也得无限循环,但是效率是不一样的。

使用WMI的Win32_VolumeChangeEvent类就可以实现,下面是示例代码,更详细的信息请参考MSND文档

Const Configuration_Changed = 1
Const Device_Arrival = 2
Const Device_Removal = 3
Const Docking = 4
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" _
    & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService. _
    ExecNotificationQuery( _
        "Select * from Win32_VolumeChangeEvent")
Do
    Set objLatestEvent = colMonitoredEvents.NextEvent
    Select Case objLatestEvent.EventType
    	Case Device_Arrival
    		WScript.Echo "U盘插入,盘符为" & _
    		objLatestEvent.DriveName
    	Case Device_Removal
    		WScript.Echo "U盘弹出,盘符为" & _
    		objLatestEvent.DriveName
	End Select
Loop

我也写了一个U盘小偷程序,自以为比网上抄来抄去的代码要好,感兴趣的可以下载来看看。

[download id=14]

VBS和C语言效率比较

2010年06月19日,星期六

上一篇文章讲到用VBS写二进制文件,为了写二进制文件,首先我们要得到一个文件的二进制值的数组。可以通过程序获取文件的二进制值,本来我是用VBS实现的,但是发现VBS效率实在太低,只好改用C语言。一直知道VBS的效率是很低的,但是不知道和C语言比差多少,于是就有了这篇文章。两个程序都是读取文件的二进制值并转换成十进制后写入一个txt文件,并输出程序运行的时间。

VBS程序代码

Option Explicit
Dim begin_time,end_time,elapse_time
Dim str,length,i,c
Dim ado,fso,file
begin_time = Timer
Set ado = CreateObject("adodb.stream")
Set fso = CreateObject("scripting.filesystemobject")
Set file = fso.OpenTextFile("foo.txt",2,True)
ado.Type = 1
ado.Open
ado.LoadFromFile("foo.jpg")
str = ado.Read
length = LenB(str)
For i = 1 To length
	c = AscB(MidB(str,i,1))
	file.WriteLine c & "," & "_"
Next
ado.Close
end_time = Timer
elapse_time = end_time - begin_time
WScript.Echo elapse_time

C语言程序代码

#include <stdio.h>
#include <time.h>
int main(void)
{
	clock_t end,begin=clock();
	int c;
	FILE *in,*out;	

	in = fopen("foo.jpg","rb");
	out = fopen("bar.txt","wb");
	while((c=fgetc(in))!=EOF)
		fprintf(out,"%d\r\n,_",c);
	end = clock();
	printf("%f\n",(float)(end-begin)/1000);
	return 0;
}

同是用一个100kb大小的foo.jpg文件作测试,VBS程序平均运行了7.5秒左右,而C语言程序只运行了0.04秒左右,效率的差别可以看出。如果文件的大小增大,效率的差别更加的明显。

用VBS读写二进制文件

2010年06月18日,星期五

网上关于VBS读写二进制文件和二进制数据的文章很少,估计是高手们都很忙,那就由我这个菜鸟来写吧。不知道会不会被很多人复制粘贴然后还不注明出处,应该是会的。恩,我要好好学习知识产权法。

查了很多资料,很多不明真相的同学都叫嚣说用adodb.stream对象就可以实现。不错,是通过adodb.stream实现读写二进制文件的功能,问题是如何实现,你有自己测试过吗?给出的代码都是先用adodb.stream对象读取,然后又写入,这样做有什么意义,还不如直接复制。我想实现的是用adodb.stream直接写我保存在代码中的数据。我试过使用adodb.stream对象的write方法,但是每次都弹出"ADODB.Stream: Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another."错误。想到Linux之父Torvalds Linus的一句话:“Talk is cheap. Show me the code.”光说有什么用,把代码给出来啊。没有代码,就不要说话。

下面是读写二进制文件的两个函数(过程),并不是我写的,我没有那么高的水平,也没有那么厚的脸皮说是我写的,而是国外一位VBS高人写的,膜拜之。ReadBinary函数从文件读取二进制数据并返回数组,WriteBinary将数组中的数据以二进制的形式写到文件中。

Function ReadBinary(FileName)
  Dim Buf(), I
  With CreateObject("ADODB.Stream")
    .Mode = 3: .Type = 1: .Open: .LoadFromFile FileName
    ReDim Buf(.Size - 1)
    For I = 0 To .Size - 1: Buf(I) = AscB(.Read(1)): Next
    .Close
  End With
  ReadBinary = Buf
End Function

Sub WriteBinary(FileName, Buf)
  Dim I, aBuf, Size, bStream
  Size = UBound(Buf): ReDim aBuf(Size \ 2)
  For I = 0 To Size - 1 Step 2
      aBuf(I \ 2) = ChrW(Buf(I + 1) * 256 + Buf(I))
  Next
  If I = Size Then aBuf(I \ 2) = ChrW(Buf(I))
  aBuf=Join(aBuf, "")
  Set bStream = CreateObject("ADODB.Stream")
  bStream.Type = 1: bStream.Open
  With CreateObject("ADODB.Stream")
    .Type = 2 : .Open: .WriteText aBuf
    .Position = 2: .CopyTo bStream: .Close
  End With
  bStream.SaveToFile FileName, 2: bStream.Close
  Set bStream = Nothing
End Sub

非常的强大,我写了一个示例程序,用WriteBinary过程写了一张图片,感兴趣的可以下载来测试一下。

[download id=13]