Windows 8仍然支持Visual Basic 6编写的程序

不久前微软宣布Windows 8继续支持Visual Basic 6平台的消息,让VB6再一次接到“死缓”的通知,貌似Windows 7宣布支持VB6时就有消息称,Windows 7之后的平台可能不再支持VB6,看来这次要感谢微软的手下留情,我也不得不怀念一下VB这个编程语言以及其IDE环境Visual Basic 6。

我还记得这个是我接触的第一门计算机编程语言,而且还是上高中信息课上老师教授的,可以说VB算是我编程生涯的引路人吧,但是曾经风光无限的VB6,如今已经风中残烛了,微软也算是亲手缔造也亲自毁灭了她,不由得想起了过去的ASP,一款以VBScript为主的动态网页技术,如今也没落了,就和VB6一样。微软为了其.NET计划真的放弃了太多,但是有一点不得不承认,那就是微软的东西确实上手容易,有利于提高开发效率,所以这也是很多人喜欢微软产品的原因。

继续阅读“Windows 8仍然支持Visual Basic 6编写的程序”

VB/VBA/VBScript根据出生日期计算年龄函数ComputeAge

有时需要处理一些Excel,这些Excel规定的日期格式是类似2012.02.26这样的形式,当我用到VBA或者VBScript处理这些日期时就很难识别并转换类似的日期格式。一般做法都是通过Split按点对其进行拆分。如果要求计算精确到年的话还好办,直接拿今年的年去减出生年就可以了,比如出生日期是1976.01,那么直接用今年2012 – 1976就得出按年算的年龄,有时可能会要求苛刻一点,比如说要求精确到月,呵呵,再Split,再判断,颇显麻烦,今天终于静下心来搞个统一的函数ComputeAge来处理这些问题,当然要能够识别我目前遇到的形如1972.01、1972.01.02、1972.1.2、72.01、72.01.02、19720102、197201日期格式,计算年龄嘛,我就让这个函数支持精确到日吧(可能用不上)。

单单是计算年龄,可能还不能满足我的胃口,当要统计类似1986年前出生的人的时候,我还要将1986转换一次,感觉麻烦,于是给ComputeAge添加了个比较时间的功能,比较的结果按照标准的-1、0、1进行返回。

比较特别的是这个函数还有个附加的功能就是把形如1972.01、1972.01.02、1972.1.2、72.01、72.01.02、19720102、197201日期格式转换为标准的脚本内置日期变量Date,好啦,说了这么多,函数在这里,用法注释已经写得详细了:

继续阅读“VB/VBA/VBScript根据出生日期计算年龄函数ComputeAge”

VB利用键盘勾子实现按键消息截获

好久不用VB写程序了,但是不得不承认VB的简单和高开发效率,这点比C/C++要好很多,尤其是一些开发周期短,实用性较强的软件。近期应单位要求,开发个××系统(名称保密),然后有个功能就是截获按键,实现特殊的按键热键的功能,首先想到的就是SetWindowsHookEx、CallNextHookEx 和UnhookWindowsHookEx,是的,想法很好,但是在实际运用时发现这几个C/C++下好用的函数老是容易导致VB崩溃,有时连IDE一起挂了,纠结了,因为这个系统最大的要求就是稳定,不能中途崩溃,为此我还特地建立了崩溃恢复机制,好了废话不说,这个问题总是要解决的,网上找到的一类代码比较混杂,大多是有问题的,最终我在vbaccelerator找到了个稳定可行的版本,那就是《Win32 Hooks in VB – The vbAccelerator Hook Library》这篇文章所介绍的Hook Library[下载地址][源代码]

使用方法很简单,下载那个ActiveX DLL,然后VB引用,然后在窗体级代码中输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Implements IWindowsHook
 
Private Sub Form_Load()
   InstallHook Me, WH_JOURNALRECORD
End Sub
 
Private Sub Form_QueryUnload( _
      Cancel As Integer, UnloadMode As Integer)
   RemoveHook Me, WH_JOURNALRECORD
End Sub
 
Private Function IWindowsHook_HookProc( _
      ByVal eType As vbalWinHook.EHTHookTypeConstants, _
      ByVal nCode As Long, _
      ByVal wParam As Long, _
      ByVal lParam As Long, _
      bConsume As Boolean) As Long
 
   If (eType = WH_JOURNALRECORD) Then
 
      Dim cEvent As cJournallParam
      Set cEvent = JournalRecordlParam(lParam)
 
      ' cEvent now contains information about
      ' the Journal record message.
 
   End If
 
End Function

当然《Using a Journal Record Hook to Capture Mouse and Key Events from any System Window》给出了一个完整的示例,大家不妨参考一下。

后来发现一个问题,那就是Visual Basic的ListView控件老是接收到我们要处理的按键,原本是想要处理的按键被按键勾子截获后就被“吃掉”不再继续传递,但是即使将IWindowsHook_HookProc的bConsume设为True也无济于事,后来我想起了以前看到的一个简单的办法,那就是KeyPress,看下面的代码:

1
2
3
4
Private Sub ListView1_KeyPress(KeyAscii As Integer)
  ' 如果按下字母B,则“吃掉”这个按键
  If KeyAscii = vbKeyB Then KeyAscii = 0
End Sub

上述代码中,如果接收到字母则将KeyAscii置0,这样控件本身就不再处理这个按键了。

VB与C语言的DLL新线程回调问题

原文由本人于2007年8月1日 18:52:59 发布于wyev.com(该域名已停用)。

不使用新线程回调成功,但使用新的线程回调VB出现<程序遇到问题需要关闭…>的错误。我为这个问题已经头疼几天了,问了微软的工程师,答复如下:

In vb6,Calling a function back from a different thread will cause access violations, so, Please prevent such designs.

看来还是要另想办法啦^_^。

—源代码如下—
MyTest.Dll (编译环境:VS2005)
MyTest.c

#include <stdio .h>
#include <stdlib .h>
#include <malloc .h>
#include <string .h>
#include <windows .h>
typedef void (__stdcall *FUNPTR)(BSTR pbstr);
typedef struct _TEST_PARA{
	long pfunA;
	long pfunB;
}UTESTMY;
 
DWORD __stdcall NewRun(UTESTMY *pAt){
	FUNPTR vbFunA,vbFunB;
	vbFunA=(FUNPTR)(pAt->pfunA);
	vbFunB=(FUNPTR)(pAt->pfunB);
	vbFunA(SysAllocString(L""回调A""));
	vbFunB(SysAllocString(L""回调B""));
	free(pAt);
	return 0;
}
//线程结构体传参数回调VB显示程序遇到问题需要关闭
void __stdcall TheRun(long pfunA,long pfunB){
	HANDLE hThread;
	DWORD dwThreadId;
	UTESTMY *pAt;
	pAt=(UTESTMY *)malloc(sizeof(UTESTMY));
	pAt->pfunA=pfunA;
	pAt->pfunB=pfunB;
	hThread = 
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)NewRun,pAt,0,&dwThreadId);
	WaitForSingleObject(hThread,INFINITE); 
	CloseHandle(hThread);
}
 
//下面这个在VB里调用是正常的
DWORD __stdcall ComRun(long pfunA,long pfunB){
	FUNPTR vbFunA,vbFunB;
	vbFunA=(FUNPTR)(pfunA);
	vbFunB=(FUNPTR)(pfunB);
	vbFunA(SysAllocString(L""回调A""));
	vbFunB(SysAllocString(L""回调B""));
	return 0;
}</windows></string></malloc></stdlib></stdio>

继续阅读“VB与C语言的DLL新线程回调问题”