发信人: aaaaaaaaa()
整理人: cobe(2000-02-12 23:55:37), 站内信件
|
编者的话
====================================================================
大家好!
这是关于VB和ASP的免费邮件列表。
如果您有问题或想回答别人的问题,请给我写信。
如果您有好的作品或您发现了好的作品,不要忘
了让大家共享。
热情欢迎您的参与!!!
版主 冯德平
[email protected]
=============================================
VB邮件(6.12)
a VB中访问API函数之防错技巧
郭少越
功能强大的API(应用程序接口)函数对于VB程序员来说,不愧是很好的编程
工具,然而使用API函数的程序员也许都遇到这样的现象。在VB集成环境下,程序
运行后,出现一错误信息对话框,按确定键后系统自动退出VB集成环境,此时如
果你的程序尚未存盘,那末很遗憾挽回损失已回天乏力。最后一次存盘之后的程
序都不复存在。这是你对API函数使用不当引起的一般保护故障(GPF)。
当一个GPF错发生时,你应允许Windows关闭你的应用。有些情况下你可能需
要退出Windows或者重新引导系统。出错程度视哪里内存被破坏而定。DLL(动态
链接库)函数中的类型不一致等错误是GPF错的主要原因。这些错误会导致GPF甚
至使Windows系统完全崩溃(需要重新引导系统)。
下面谈避免GPF的一些技巧。
用别名来提供强类型检查是避免GPF的有效措施之一。有些情况下,DLL函数
可以接受多种类型,LoadCursor函数就是这样一个例子,其定义如下:
HCursor LoadCursor(hInstance,lpCursorName)
这里HCursor是一个指向光标对象的16位句柄,hInstance是一个16位实
例句柄,lpCursorName是光标的名字或者是光标资源的32位整数ID。为了支持
两种类型的lpCursorName参数。VB有必要包含如下两个声明:
DeclareFunction LoadCursor Lib"USER"(ByVal hInstance As Integer,By
Val lpCursorName As String)As Integer
和
DeclareFunction LoadCursor Lib"USER"(ByVal hInstance As Integer,By
VallpCursorName As Long)As Integer
但是,这两个声明不能在一个程序中同时存在,因为Visual Basic会报重复
声明错。我们知道,As Any声明可使得任何参数都可以传递给DLL函数,因此可以
如下声明:
DeclareFunction LoadCursor Lib"USER"(ByVal hInstance As Integer ,B
yVal lpCursorName As Any )As Integer
上述声明意味着Visual Basic能支持一个参数可接受多种类型的DLL函数,然
而这就可能带来各种灾难性的后果,每当偶然情况下用不正确的参数调用该函数
时,都可以引发一个GPF,我们可以这样进行严格的类型检查并且帮助防止这类问
题。
这种方法就是在函数的声明中使用Alias技巧,看看下面的两个声明:
DeclareFunction LoadCursorByName Lib"USER"Alias "LoadCursor"(ByVa
l hInstance As Integer,ByVal lpCursorName As String)As Integer
DeclareFunction LoadCursorByID Lib"USER"Alias "LoadCursor"(ByVal
hInstance As Integer ,ByVallpCursorName As Long)As Integer
LoadCursorByName用字符串做lpCursorName参数访问DLL函数LoadCursor,
而LoadCursorByID访问同样的DLL函数LoadCursor,但是用长整型做lpCursorNam
e参数,这两个函数都对lpCursorName参数进行严格的类型检查,使Visual Basi
c能在调用DLL函数之前识别出不正确的变量类型,最大限度地减少引起GPF或者导
致系统崩溃的机会。
除此之外,使用API函数时运行之前最好先存盘,仔细检查调用API函数的参
数与声明的类型是否一致,以及严格检查参数是否有效都能减少引发GPF或者系统
崩溃。
b VB中Grid控件的打印方法
Grid控件是Visual Basic(以下简称VB)最常见控件之一,用它可以以表格的形
式显示、浏览数据。特别是在数据库应用中,直接绑定即可显示和浏览数据库信息
。然而,美中不足的是Grid没有编辑和打印功能,列与列的位置不能相互交换。笔
者曾尝试着给Grid增添了这些功能,使之功能更强大。下面给出改进方法及源程序
,读者可参考使用。该程序在HP5/100、Window 95环境下用VB5.0调试通过。
给Grid 控件增加打印方法有三种:一是直接打印控件,二是通过p rinter 来
实现打印功能,三是通过调用MS-Word及MS-Excel 来实现打印。
首先,打开一个应用,在FORM1中增加DATA控件DATA1,把DATA1的CO NNECT属性
设为dBA SEⅢ,再把DATABASENAME属性设为D:\PJXM.DBF。然后再在FORM1中增加M
SFLEXGRID控件GRID1,并把GRID1的DATASOURCE 属性设为DATA1。这样数据库PJXM
.DBF的信息就会在GRID1 中显示出来。下面分析介绍各种打印方法。
方法一:直接打印窗体
在FORM1中增加命令按钮(command),CAPTION属性设为直接打印, 再写入下列
代码:
Sub command_click
Form1.printform
End sub
这样即可通过打印窗体FORM1的方法把GRID1的数据打印出来。这种方法的缺
点是只能打印GRID1中显示的数据部分,显示不出来的则无法打印,而且这种打印方
法很像屏幕硬拷贝,而且不能灵活地控制字体等。
方法二:通过PRINTER实现打印
1. 加入打印命令按钮(command1)和函数(prnt1),写入下面代码, 读者稍加改
动可写成标准的函数或过程。Function prnt1 (x As Int eger, y As Integer,
font As Sing le, txt As String)
printer.CurrentX = x
printer.CurrentY = y
printer.FontBold = False
printer.FontSize = font
printer.Print txt End Function Sub command1_click
Dim fnt As Single
Dim pp as integer
Pp=0 '设置开始页码0
Dim stry,strx,strx1,stry1,linw,page1,p As Integer
Static a(8) As Integer '定义打印的列数
ss$ = "内部结算存入款对帐单" '定义表头
kan = 0
For i = 0 To 8
a(i) = 1500' 定义每列宽
kan = kan + a(i) '计算表格总宽度
Next
page1 = 50 ’定义每页行数
strx = 200
strx1 = 200 ’定义X方向起始位置
stry = 1400
stry1 = 1400 ’定义Y方向起始位置
linw = 240 ’定义行宽
fnt = 8 ’定义字体大小
printer.fontname = "宋体" ’定义字体
dd = prnt1(4000, 700, 18, ss$) ’打印标题
printer.Line (strx - 50, stry - 30)-(strx +
kan - 10, stry - 30)
For j = 0 To gridrow - 1
’gridrow为所要打印的行数
grid1.row = j
strx = strx1
printer.Line (strx - 50, stry - 30)-(strx +
kan - 10, stry - 30)
p = p + 1
For i = 0 To 8
grid1.col = i
dd = prnt1(strx, stry, fnt, grid1.text)
strx = strx + a(i)
Next
If p > page1 Then ’next page
p = 0
strx = strx1
printer.Line (strx - 50, stry + linw)-(strx + kan - 10, stry + li
nw)
stry = stry1
For n = 0 To 8
printer.Line (strx - 30, stry - 30)-(strx
- 30, stry + (page1 + 2) * linw)
strx = strx + a(n)
Next
printer.Line (strx - 30, stry - 30)-(strx -
30, stry + (page1 + 2) * linw)
pp=pp+1
foot$="第 "+cstr(pp)+" 页"
dd = prnt1(strx - 30-1000, stry + (page1 +
2) * linw+100, 10, foot$) ’打印页脚码
printer.NewPage ’next page
dd = prnt1(4000, 700, 18, ss$) ’打印标题
strx = strx1
stry = stry1
printer.Line (strx - 50, stry - 30)-(strx +
kan - 10, stry - 30) ’打印第一行
Else
stry = stry + linw
End If Next
st = stry
If p < page1 Then ’在最后页剩余划空行
For o = p To page1 + 1
strx = strx1
printer.Line (strx - 50, stry - 30)-(strx +
kan - 10, stry - 30)
stry = stry + linw
Next
End If
stry = stry1
strx = strx1
stry = stry1’line col
For n = 0 To 8
printer.Line (strx - 30, stry - 30)-(strx -
30, stry + (page1 + 2) * linw)
strx = strx + a(n)
Next
printer.Line (strx - 30, stry - 30)-(strx -
30, stry + (page1 + 2) * linw)
pp=pp+1
foot$="第 "+cstr(pp)+" 页"
dd = prnt1(strx - 30-1000, stry + (page1 +
2) * linw+100, 10, foot$) ’打印页脚码
printer.EndDoc ’打印结束
End sub
这种方法通过灵活的编程可以方便地调整字体、字型、线形、页面、纸张大
小等,可打印出比较满意的效果。
如果计算机上装有Microsoft Word和Microsoft Excel,则可把GR ID的表格通
过VB发送到这些应用程序中去,生成Microsoft Word和Mic rosoft Excel表格。这
样可以充分利用它们的打印、编辑功能,打印出更理想的效果。下面逐一介绍。
方法三:通过生成Word表格打印
1. 在declaration 中写入:
Dim msword As Object
2. 加入打印命令按钮(command2),CAPTION设为"生成Word表格", 写入下面代
码:Pri vate Sub command2_Click()
screen.MousePointer = 11
Set msword = CreateObject("word.basic")
Dim AppID, ReturnValue
appID = Shell("d:\office97\office\WIN-
WORD.EXE", 1) ’运行Word
msword.AppActivate "Microsoft Word"
full
Screen.MousePointer = 0 End Sub
3. 写入以下过程full() Sub full()
Dim i As Integer, j As Integer, col As Integer,
row As Integer
Dim cellcontent As String
Me.Hide
cols = 4 ’表格的列数
row = gridrow ’打印表的行数
msword.filenewdefault
msword.MsgBox "正在建立MS_WORD报表,请稍候
……", "", -1
msword.leftpara
msword.screenupdating 0
msword.tableinserttable , col, row, , , 16, 167
msword.startofdocument
for j=0 to gridrow ’表格的行数
grid1.row=j
For i = 1 To cols
Gri1d.col=i
If IsNull(grid1.text) Then
cellcontent$ = ""
Else
cellcontent$ = grid1.text
End If
msword.Insert cellcontent$
msword.nextcell
Next i
Next j
msword.tabledeleterow
msword.startofdocument
msword.tableselectrow
msword.tableheadings 1
msword.centerpara
’msword.startdocument
msword.screenrefresh
msword.screenupdating 1
msword.MsgBox "结束", "", -1
Me.Show End Sub
方法四:通过发送到Excel实现表格打印
1. 加入打印命令按钮(command3),CAPTION设为"生成EXCEL表格" ,写入下面
代码: Private Sub command3_Click()
Dim i As Integer
Dim j As Integer
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
Set xlBook = xlApp.Workbooks.Add
Set xlSheet = xlBook.Worksheets(1)
xlSheet.Cells(6, 1) = "i"
For i = 0 To gridrow
grid1.Row = i
For j = 0 To 6
Grid1.Col = j
If IsNull(Grid1.Text) = False Then
xlSheet.Cells(i + 5, j + 1) = Grid1.Text
End If
Next j
Next i End Sub
中原油田计算中心 武正伦 李俊海
c VB中的Unicode 和 Ansi 格式
Visual Basic 32-bit 版本的字串处理采用 Unicode,也就是说字串在 VB
内部是以Unicode 的格式来存放。
何谓 Unicode?简单的说,就是每一个字符都是以 2-byte 的形式表示,而
每个「实体字符」就是一个「字符」。因此,
Len("大家好")
Len("abc")
所返回的值都是 3,因为「大」和「a」都是一个字符。
但是这对一些中文字串处理,例如纯文字的数据文件,却是一个大灾难,因
为你必须以byte 来定位每个字符,可是 Unicode 却把一切的处理全搞砸了。例
如:
Len("Good Morning") 返回 12,而
Len("今天天气很好") 返回 6
对初学者而言,好不容易能使用 VB 来写程序已经是件了不起的事了,却马
上在中文处理上挨了一记闷棍,所受到的打击实在不小。但是不要怕,事实上只
要再多了解一些指令,就可以把中文处理的问题解决了。
是什么指令呢?最重要的莫过于 StrConv 了。StrConv 函数的语法为:Str
Conv(待转换字串, 转换格式)
其中转换格式在这里用到的是:
vbUnicode 将 Ansi 字串转换为 Unicode
vbFromUnicode 将 Unicode 字串转换为 Ansi
将字串转成 Ansi 之后,所有的字串处理指令都要加个 B,例如:LeftB, R
ightB,
MidB, ChrB, InstrB, LenB, InputB 等。例用这些指令来处理就行了。
当你处理完毕之后,你可以再将它再转回 Unicode,这样就可以使用一般的
字串处理指令了。
这样讲看得懂吗?如果还是不了解,看看下面的实例说明:
[●] 简易使用范例
看看下面的基本范例您应该就会对 VB 的字串处理方式有些概念。
Private Sub Command1_Click ()
Dim sUnicode As String
Dim sAnsi As String
' Unicode 运算
sUnicode = "王小明,A123456789,651023,上海市中山路100号,(02)2345678"
Debug.Print Len(sUnicode) ' 返回 44
Debug.Print Mid$(sUnicode, 5, 10) ' 返回 A123456789
Debug.Print Instr(sUnicode, "上海市") ' 返回 23
' 将 Unicode 字串转成 Ansi
sAnsi = StrConv(sUnicode, vbFromUnicode)
' Ansi 运算
Debug.Print LenB(sAnsi) ' 返回 54
Debug.Print MidB$(sAnsi, 8, 10) ' 返回 ?????,因为忘了转回 Unicode
Debug.Print StrConv(MidB$(sAnsi, 8, 10), vbUnicode) ' 返回 A123456789,
请注意转回 Unicode 的动作一定要做
Debug.Print InStrB(sAnsi, StrConv("上海市", vbFromUnicode)) ' 返回 23,
不要忘了要把"上海市"也转成 Ansi,否则会找不到
End Sub
[●] 读入文本文件
在 VB 的小技巧中,有一个是快速读文件法:
Private Sub Command1_Click ()
Dim sFile As String
Open "C:\filename.txt" For Input As #1
sFile = Input$(LOF(1), #1)
Close #1
End Sub
但是很不幸地,如果你读取的文件内含中文字,那上面这段程序会出现 Inp
ut pastend of file 的错误。因为 LOF 返回的是文件的 byte 数,而 Input 函
数读取的是字符数,由于文件内含中文,因此文件中的字符数将会小于 byte 数
,于是就发生错误了。
要解决这个问题,我们就要用到 StrConv 和 InputB 这两个函数了:
Private Sub Command1_Click ()
Dim sFile As String
Open "C:\filename.txt" For Input As #1
sFile = StrConv(InputB$(LOF(1), #1), vbUnicode)
Close #1
End Sub
上面修正程序先用 InputB 将文件读进来,不过使用 InputB 所读入的文件
是 Ansi格式的,所以要再用 StrConv 转成 Unicode 才行。
[●] 随机数据文件
许多文字数据文件是以固定字节的位置来加以区格,例如下面的数据格式:
王小民650110上海市中山路100号 (02)1234567
张大呆660824花莲县大甲镇广东街23号(03)9876543
......
像这种类型的文件要如何处理呢?这是就必须用到 Type 以及 byte array 了。
Private Type tagRecord
Username(5) As Byte ' 姓名 6 bytes
Birthday(5) As Byte ' 生日 6 bytes
Address(21) As Byte ' 地址 22 bytes
TEL(11) As Byte ' 电话 12 bytes
CrLf(1) As Byte ' 换行字符 2 bytes
End Type
Private Sub Command1_Click()
Dim uRecord As tagRecord
Open "C:\filename.dat" For Random As #1 Len = LenB(uRecord)
Get #1, 2, uRecord ' 取第二笔数据
With uRecord ' With ... End With 应该会用吧
Debug.Print .Username ' 返回 ???
Debug.Print StrConv(.Username, vbUnicode) ' 返回 "张大呆"
End With
Close #1
End Sub
在这个例子中,一定要用到 byte array,因为只有 byte array 才能正确地
定位到每个 byte 的位置。以前使用字串来定位的方法已经不适用了,千万要记
住!但是使用byte array 所读入的数据是 Ansi 格式,若要处理或是做运算的话
,记得还要转成Unicode 格式才行。
[●] 使用 Byte Array
除了上面必须使用 byte 精确定位的例子之外,纯文字的处理基本上是用不
到 bytearray 的。byte array 通常是用在处理 binary 数据。这方面的问题我
们将另文讨论。
看吧!只要熟悉使用 StrConv,你就可以在 Unicode 及 Ansi 格式之间自由
自在地变来变去,相信当您看完这篇文章之后,对处理中文应该不再烦恼了吧!
=============================================
问题征答(6.12)
a 我想用vb处理麦克风输入的语音音量,应怎么作,万望指教!
kenny
b 问题请教:
用VB6制作Active X 控件.
最后用Setup Wizard 制成 Web 发布的礖TML 文件 和 CAB 文件包.
HTML 的Souce Code 如下:
Main.htm
<HTML>
<HEAD>
<TITLE>Kiosk990521Ocx.CAB</TITLE>
</HEAD>
<OBJECT ID="Kiosk990521UC"
CLASSID="CLSID:2FEB808D-09E5-11D3-BFBF-0000F4903E24"
CODEBASE="Kiosk990521Ocx.CAB#version=1,0,0,1">
</OBJECT>
</BODY>
</HTML>
将HTML 文件 和 CAB 文件包
NT Server+Microsoft IIS 3.0 上
从Client端浏览main.htm是可以
自动下载并执行对应的Active X的,可是如果我
对原来的Active X有所修改,并新编译和用Setup Wizard
生成新的Html 和CAB,并重新Copy 至Server 上.从Client端
重新浏览该main.htm发现还是老的腁ctive X并没有自动更
新,这是为什么?
而且我发现VB6重新编译Active X 控件
其ID 永远是不变的,
如"CLSID:2FEB808D-09E5-11D3-BFBF-0000F4903E24"
而以前用VB5时每编译一次ID都会变的,
是否和这有关,还是VB6里另外有什么设置?请高手指教.
慧子([email protected])
c 你好,
我在写一个Word Automation程序,需要动态地取Word中打开文件的内容,
但在取图片内容时遇到了麻烦。
当选中Shape,copy到剪辑版时,查看剪辑版,每个机器拷贝的内容都不一
样,图
片内容好象经过了不同的变换,不知道是??原因,请高手指教。
或者可以有不同的方法取word的图片内容。
请将指教发给我的email信箱,万分感谢!!!
[email protected]
=============================================
其它
====================================================================
欢迎订阅VB免费邮件:
订阅地址 http://server.com/WebApps/mail-list-subscribe.cgi?id=16852
====================================================================
如果您觉得这个邮件列表好的话,请告诉您的朋友。
====================================================================
欢迎投稿 [email protected]
====================================================================
网易上的主页地址:http://www4.netease.com/~aaaaaaaaa
本网站主页镜像地址:goodvbhome.yeah.net
====================================================================
-- 欢迎访问主页:goodvbhonme.yeah.net
或:http://www4.netease.com/~aaaaaaaaa
http://personal.gz168.gnet.gd.cn/vbok/
※ 修改:.aaaaaaaaa 于 Jun 13 14:03:15 修改本文.[FROM: 202.103.47.245] ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.103.47.245]
|
|