VBGood网站全文搜索 Google

搜索VBGood全站网页(全文搜索)
首页 - 经验之谈 - VB中访问API函数之防错技巧
发表评论(0)作者:郭少越, 平台:VB6.0+Win98, 阅读:9170, 日期:2001-01-02
  功能强大的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,byval lpcursorname as string)as integer

declarefunction loadcursor lib"user"(byval hinstance as integer,byvallpcursorname as long)as integer
  但是,这两个声明不能在一个程序中同时存在,因为visual basic会报重复声明错。我们知道,as any声明可使得任何参数都可以传递给dll函数,因此可以如下声明:
declarefunction loadcursor lib"user"(byval hinstance as integer ,byval lpcursorname as any )as integer
  上述声明意味着visual basic能支持一个参数可接受多种类型的dll函数,然而这就可能带来各种灾难性的后果,每当偶然情况下用不正确的参数调用该函数时,都可以引发一个gpf,我们可以这样进行严格的类型检查并且帮助防止这类问题。
  这种方法就是在函数的声明中使用alias技巧,看看下面的两个声明:
declarefunction loadcursorbyname lib"user"alias "loadcursor"(byval 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,但是用长整型做lpcursorname参数,这两个函数都对lpcursorname参数进行严格的类型检查,使visual basic能在调用dll函数之前识别出不正确的变量类型,最大限度地减少引起gpf或者导致系统崩溃的机会。
  除此之外,使用api函数时运行之前最好先存盘,仔细检查调用api函数的参数与声明的类型是否一致,以及严格检查参数是否有效都能减少引发gpf或者系统崩溃。




用vb开发应用程序如何使用ini文件


  为了方便用户使用和使系统具有灵活性,大多数win-dows应用程序将用户所做的选择以及各种变化的系统信息记录在初始化(ini)文件中。因此,当系统的环境发生变化时,可以直接修改ini文件,而无需修改程序。由此可见,ini文件对系统功能是至关重要的。本文将介绍采用visualbasicforwindows(下称vb)开发windows应用程序时如何读写ini文件。

ini文件是文本文件,由若干部分(section)组成,在每个带括号的标题下面,是若干个以单个单词开头的关键词(keyword)和一个等号,每个关键词会控制应用程序某个功能的工作方式,等号右边的值(value)指定关键词的操作方式。其一般形式如下:



[section1]
keyword1=valuel
keyword2=value2
……
[section2]
keyword1=value1
keyword2=value2
……



其中,如果等号右边无任何内容(即value为空),那就表示windows应用程序已为该关键词指定了缺省值,如果在整个文件中找不到某个关键词(或整个一部分),那同样表示为它们指定了缺省值。各个部分所出现的顺序是无关紧要的,在每一个部分里,各个关键词的顺序同样也无关紧要。

读写ini文件通常有两种方式:一是在windows中用“记事本”(notepad)对其进行编辑,比较简单,无需赘述;二是由windows应用程序读写ini文件,通常是应用程序运行时读取ini文件中的信息,退出应用程序时保存用户对运行环境的某些修改。

关键词的值的类型多为字符串或整数型,应分两种情况读写。为了使程序具有可维护性和可移植性,最好把对ini文件的读写封装在一个模块(rwini.bas)中,在rwi-ni.bas中构造getinis和getinin函数以及setinis和se-tinin过程,在这些函数和过程中需要使用windowsapi的“getprivateprofilestring”、“getprivateprofileint”和“writeprivateprofilestring”函数。

rwini.bas模块的程序代码如下:

在general-declearation部分中声明使用到的windowsapi函数:



declarefunctiongetprivateprofilestringlib“ker-nel”(byvallpappnameasstring,
byvallpkeynameasstring,byvallpdefaultasstring,byvallpretrm-stringas
string,byvalcbreturnstringasinteger,byvalfilenameasstring)asinteger
declarefunctiongetprivatepfileintlib“kernel”(byvallpappnameasstring,
byvallpkeynameasstring,byvallpdefaultasinteger,byvalfilenameasstring)as
integer
declarefuncitonwriteprivateprofilestringlib“kernel”(byvallpapplicationname
asstring,byvallpkeynameasstring,byvallpstringasstring,byvallplfilename
asstring)asinteger
functiongetinis(byvalsectionnameasstring,byvalkeywordasstring,byvaldefstring
asstring)asstring
dimresultstringasstring*144,tempasinteger
dimsasstring,iasinteger
temp%=getprivateprofilestring(sectionname,keyword,“”,resultstring,144,appprofilename())
‘检索关键词的值
iftemp%>0then‘关键词的值不为空
s=“”
fori=1to144
ifasc(mid$(resultstring,i,1))=0then
exitfor
else
s=s&mid$(resultstring,i,1)
endif
next
else
temp%=writeprivateprofilesstring(sectionname,keyword,defstring,ppprofilename())
‘将缺省值写入ini文件
s=defstring
endif
getinis=s
endfunction
functiongetinin(byvalsectionnameasstring,byvalkeywordasstring,byvaldefvalue
asineger)asinteger
dimdaslong,sasstring
d=defvalue
getinin=getprivateprofileint(sectionname,
keyword,defvalue,ppprofilename())
ifd<>defvaluethen
s=“”&d
d=writeprivateprofilestring(sectionname,
keyword,s,appprofilename())
endif
endfunction
subsetinis(byvalsectionnameasstring,btvakeywordasstring,byvalvalstr
asstring)
dimres%
res%=writeprivateprofilestring(sectionname,keyword,valstr,appprofilename())
endsub
subsetinin(byvalsectionnameasstring,byvalkeywordasstring,byvalvalint
asinteger)
dimres%,s$
s$=str$(valint)
res%=writeprivateprofilestring(sectionname,keyword,s$,appprofilename())
endsub

sectionname为每一部分的标题,keyword为关键词,getinis和getinin中的defvalue为关键词的缺省值,setinis和setinin的valstr和valint为要写入ini文件的关键词的值。为了能更好地说明如何使用以上函数和过程,下面举两个实例。

实例1:

开发应用程序通常要使用数据库和其它一些文件,这些文件的目录(包括路径和文件名)不应在程序中固定,而是保存在ini文件中,程序运行时由ini文件中读入。读入数据库文件的代码如下:



dimdatabasenameasstring
databasename=getinis(“数据库”,“职工”,“”)
ifdatabasename=“”thendatabasename=inputbox(“请输入数据库《职工》的目录”),
app.title)’也可通过“文件对话框”进行选择
onerrorresumenext
setdb=opendatabas(databasename)
iferr<>0then
msgbox“打开数据库失败!”,mb-
iconstop,app.title:gotoerrorprocessing
else
setinis“数据库”,“职工”,databasename
endif
onerrorgoto0
……



实例2:

为了方便用户操作,有时需要保存用户界面的某些信息,例如窗口的高度和宽度等。装载窗体时,从ini文件中读入窗体高度和宽度,卸载窗体时将窗体当前高度和宽度存入ini文件,代码如下:



sub form1_load()
……
forml.height=getinin(“窗体1”,“高度”,6000)
form1.width=getinin(“窗体1”,“高度”,4500)
endsub
……
sub form1_unload()
……
setinin“窗体1”,“高度”,me.height
setinin“窗体1,”宽度“,me.width
……
end sub  



如何用vb编辑windows注册表中的"(默认)"键值
读取注册表键值的函数是:regqueryvalueex,而写入键值的函数是:regsetvalueex,只要将这两个函数的lpvaluename 参数设置为空字符串就可以了,例如下面的范例:
dim hkey
dim astr as string

regopenkey hkey_current_user, "software", hkey
debug.print regqueryvalueexstring(hkey, "", 0, reg_sz, astr, 256)
regsetvalueex hkey, "", 0, reg_sz, "abcdefg", 7