⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 46.asp

📁 ASPWeb数据库范例总览
💻 ASP
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
   <TITLE>VB 与 Windows API 讲座(一) - 进入 Windows API 的热身运动</TITLE>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
   <META NAME="Author" CONTENT="K.J. Wang">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">

<P>VB 与 Windows API 讲座(一) /王国荣</P>

<H1 ALIGN=CENTER>
<HR WIDTH="100%">进入 Windows API 的热身运动 
<HR WIDTH="100%"></H1>

<P>「VB 没有提供这样的功能, 必须呼叫 Windows API」, 有时候笔者會这样回答读者的问题, 虽然这麼回答有点偷懒, 或者说不负责任, 但这的确是事实, VB
所提供的叙述、函数、物件…虽然也不在少数, 但是都十分标准, 或者说规矩, 想变点花样, 通常是行不通的, 这是笔者决定开始撰写本文的主要原因。</P>

<P> </P>

<H2>
<HR WIDTH="100%">Windows API 是大家的
<HR WIDTH="100%"></H2>

<P> </P>

<P>感觉上 VB 程式要呼叫 Windows API 是一件比较困难的事情, 或者说比较麻烦的事情, 但别忘了
Windows API 是大家的, 凡是在 Windows 工作环境底下执行的应用程式, 都有权利呼叫
Windows API。</P>

<P> </P>

<P>Windows 这个多工作业系统除了协调应用程式的执行、分配记忆体、管理系统资源…之外, 她同时也是一个很大的服务中心, 呼叫这个服务中心的各种服务(每一种服务就是一个函数), 可以帮应用程式达到开启视窗、描绘图形、使用周边设备…等目的, 由於这些函数服务的对象是应用程式(Application), 所以便称之为
Application Programming Interface, 简称 API 函数。</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>但</FONT> Windows API 与 C 语言最亲近
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>虽然说呼叫 Windows API(以下简称 API 或 API 函数) 是每一个应用程式的权利, 但不可否认的
API 却与 C 语言最亲近, 因为 API 函数在参数的传递上就是以 C 语言为标准。</P>

<P> </P>

<P>但这并不表示 VB 程式不能呼叫含有参数的 API 函数, 如果传递的参数是单纯的资料型别, 例如「整数」, 则
VB 与 C 语言还是相通的, 如果是特殊的资料型别(包含「字串」), 则必须遵循一定的规范, 否则不是无法得到正确的结果, 就是因为违反规定而被踢出系统。如何正确地传递各种资料型别的参数, 是
VB 程式呼叫 API 很重要的课题, 当然也是本系列讲座的重点。</P>

<P> </P>

<H2>
<HR WIDTH="100%">物件 vs. handle
<HR WIDTH="100%"></H2>

<P> </P>

<P>除了参数传递方式有所不同之外, 要以 VB 程式呼叫 API, 还要具备 Windows
程式设计的 handle 观念。VB 的程式设计模式是以物件为核心, 但 Windows 的程式设计模式却是以
handle 为核心, 以下笔者先举个简单的例子来说明, 假设有一 VB 的表单 Form1, 若要改变此一表单的标题, 则使用的方法是设定表单物件的
Caption 属性, 叙述如下:</P>

<P> </P>

<DIR>
<P>Form1.Caption = &quot;新的标题&quot;</P>

<P> </P>
</DIR>

<P>若以 API 来执行相同的工作, 则叙述如下:</P>

<P> </P>

<DIR>
<P>ret = SetWindowText( Form1.hwnd, &quot;新的标题&quot; )</P>

<P> </P>
</DIR>

<P>其中 Form1.hwnd (hwnd 是 handle of window 的缩写)代表的是 Form1 这个表单「视窗」的
handle 。以下是呼叫此一 API 函数的完整程式:<BR>
</P>

<DIR>
<P>Private Declare Function SetWindowText Lib _<BR>
&quot;user32&quot; Alias &quot;SetWindowTextA&quot; _<BR>
(ByVal hwnd As Long, ByVal lpString As String) As Long<BR>
<BR>
Private Sub Command1_Click()</P>

<P>ret = SetWindowText(Me.hwnd, &quot;新的标题&quot;)</P>

<P>End Sub</P>

<P> </P>
</DIR>

<P>由於笔者接下来的解说會继续使用此一函数, 请将以上程式输入於表单的程式视窗中, 并且在表单上布置一个
Command1 命令钮。(如果懒得输入, 可进入笔者网站下载)</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>handle </FONT>是什麼?
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>handle 是什麼?让我们来检查看看, 首先在 SetWindowText 之後增加以下叙述:</P>

<P> </P>

<DIR>
<P>Print TypeName(Form1.hwnd)<BR>
Print Form1.hwnd</P>

<P> </P>
</DIR>

<P>结果 TypeName 印出 Long, 这表示 handle 的资料型别是 Long, 而接下来的
Form1.hwnd 则印出一个整数值。</P>

<P> </P>

<P>handle 只是一个整数值吗?一个整数值能够做什麼呢?</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>真实世界的</FONT> handle
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>handel 就字义来说, 是器具的「把手」, 以锅子为例, 把手的用途是方便我们取用锅子里的食物, 它本身虽然没什麼用, 却可以帮我们取得有用的食物, 再举个例子, 车子的门把也叫做
handle, 虽然门把好像也没什麼大用处, 但透过门把打开车门, 可以让我们使用整部车子, 也许有人會捧著锅子吃东西, 或者打破车窗进入车子, 但使用锅把取用食物及使用门把打开车门还是最方便的事情。</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>handle </FONT>者, 存取 Windows 资源之识别码
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>在 Windows 的世界里, 充满著各种不同的系统资源, 例如视窗、功能表、图片、记忆体、程式、程序…等, 都算是系统资源, 而
Windows 是这些资源的总管理者, 为了能够管理这些资源, Windows 必须给每一资源一个唯一的识别码, 此一识别码便称为
handle。</P>

<P> </P>

<P>Windows 世界的 handle 与真实世界的把手在观念上很类似, 由於每一个 handle
都是一个唯一的识别码, 因此当程式要求 Windows 提供存取资源的服务时, 须出具此一识别码, 如此
Windows 便可以找到此一识别码所对应的资源, 然後进行存取的工作, 所以 handle
虽然只是一个整数值, 但它就像是锅子的把手可用来取用锅子的食物一样, 此一数值则可用来取用
Windows 的系统资源。</P>

<P> </P>

<P>handle 最重要的特性是同一时间不會有两个资源的 handle 值是相同的, 在前面的
SetWindowText API 函数中, 程式传入 Form1 表单视窗的 handel, 所以 Windows
便能够根據此一唯一的 handle 值, 取得该 handle 所对应的视窗资源, 进而将把标题设定给这个视窗。</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>从</FONT> handle 到物件
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>对很多 VB 的物件而言, 都含有 handle 性质的属性, 如图-1, 当我们使用这类物件时, 除了可以利用该物件的属性及方法来操作物件外, 也可以利用其中
handle 性质的属性来呼叫 API, 直接启动 Windows 所提供的服务, 以前面的 SetWindowText(Form1.hwnd,
&quot;新的标题&quot;) 为例, hwnd 便是附属於 Form1 的 handle 性质属性。</P>

<P> </P>

<CENTER><P><IMG SRC="46-1.gif" HEIGHT=112 WIDTH=227></P></CENTER>

<CENTER><P>图-1 含有 handle 的物件</P></CENTER>

<P> </P>

<P>简单地说, VB 所提供的物件并没有把 Windows 的 handle 程式设计模式丢到一边, 而是将
handle 封装起来, 使之成为物件的一个属性。</P>

<P> </P>

<DIR>
<P>注:虽然说 Windows 的程式设计是以 handle 为核心, 但仍然有不少 API 函数是与
handle 无关的, 例如字串的复制, 这类 API 函数通常不會使用到 Windows 所配置的系统资源, 所以不需要使用
handle。</P>

<P> </P>
</DIR>

<H2>
<HR WIDTH="100%">使用 Windows API 的难处
<HR WIDTH="100%"></H2>

<P> </P>

<P>当我们要开始使用 API 时, 必须知道三件事情:</P>

<P> </P>

<DIR>
<DIR>
<P>(1) 要呼叫哪一个 API 函数。</P>

<P>(2) 如何宣告 API 函数。</P>

<P>(3) 如何传递参数。</P>

<P> </P>
</DIR>
</DIR>

<CENTER><P><FONT SIZE=+1>要呼叫哪一个</FONT> API 函数
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>这是以上三件事情当中最困难的一件, 主要的原因是 Windows 的 API 实在太多了, 大约有
1500 个, 这还不包含 OLE、ODBC…等特殊的 API, 此外, 如果我们把 API 按不同性质加以分类, 则使用每一类
API 函数所应具备的背景知识亦各有不同, 以系统注册区相关的 API 函数为例, 就必须先瞭解
Windows 如何安排系统注册区, 以及存取系统注册区的方式。</P>

<P> </P>

<P>不过也不必被 1500++ 个函数给打退堂鼓了, 因为不是所有的程式设计都要仰赖
API, 当我们面对一个问题时, 首先还是寻求 VB 的解决方案, 如果 VB 实在无法解决, 才考虑使用
API, 当然, 笔者接下来的讲座也不是 API 函数一个一个往下介绍, 而會先过滤掉那些可用
VB 完成的 API。</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>如何宣告</FONT> API 函数
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>在 VB 程式中, 若要使用 VB 内建的叙述或函数, 不必事先宣告直接呼叫即可, 若要使用
API 函数, 则必须在先把 API 函数的出处、函数名称、参数、传回值…等宣告在表单的
&quot;一般&quot; 区块或是一般模组(.bas 档案)中, 感觉上也是一件挺麻烦的工作, 但由於
VB 提供有辅助程式, 所以相对於另外两件事情, 反倒是最轻松的。</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>如何传递参数</FONT>
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>由於 API 采用了 C 语言的参数传递方式, 而 C 语言的参数传递又与 VB 有著不小的差异, 以致不少呼叫
API 所造成的错误都发生在参数传递时, 所以本期我们将會有不少的篇幅放在如何传递参数上面。</P>

<P> </P>

<H2>
<HR WIDTH="100%">如何宣告 Windows API
<HR WIDTH="100%"></H2>

<P> </P>

<P>API 函数的宣告并不困难, 因为我们可以请 VB 的「API 检视员」来帮忙, 以下是使用「API
检视员」的方法:</P>

<P> </P>

<DIR>
<P><B><FONT SIZE=+1>1</FONT></B>. 首先选取 VB 功能表的「增益集/增益功能管理员」, 然後在「增益功能管理员」交谈窗中核取「VB
API Viewer」, 按下「确定」钮後, VB 的「增益集」功能表栏底下就會出现「API
检视员」, 选取此一命令, 即可启动「API 检视员」。</P>

<P> </P>

<P><B><FONT SIZE=+1>2</FONT></B>. 第一次执行 API 检视员时, 须利用功能表的「档案/载入文字档」载入
VB Winapi 目录底下的 Win32api.txt, 接著在「可选项的项目」底下即會列出所有的
API 函数, 若我们双按其中的函数, 则该函数的宣告即會出现在「选取的项目」底下, 此时再按下「复制」钮, 可将选取的函数宣告复制到剪贴簿, 过程如图-2, 接著回到
VB 的程式视窗, 再选取功能表的「编辑/复制」, 即可将函数的宣告从剪贴簿中复制过来。</P>

<P> </P>

<CENTER><P><IMG SRC="46-2.gif" HEIGHT=377 WIDTH=516></P></CENTER>

<CENTER><P>图-2 利用「API 检视员」将 API 的宣告复制到剪贴簿</P></CENTER>

<P> </P>
</DIR>

<P>接下来请注意 API 宣告式复制到 VB 程式的位置, 此时您有两种选择:(1) 先利用
VB 功能表的「专案/新增模组」新增一个一般模组(.bas 档), 然後将 API 宣告式复制到此一模组的程式视窗中, 
(2) 将 API 宣告式复制到表单程式视窗的 &quot;(一般)&quot; 区块底下, 但复制过来之後, 必须在
Declare 前面加上 Private 保留字。</P>

<P> </P>

<P>将 API 宣告式放在一般模组与表单模组的差异是:放在一般模组的 API 函数, 可供同一专案的所有程式使用, 若放在表单模组, 则只有宣告
API 函数的表单可以使用。</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>提升载入</FONT> API 宣告式的速度
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>如果您经常使用 API 检视员, 就會发现载入 Win32api.txt 是蛮花时间的, API
检视员允许我们将此一档案转换成 mdb 格式的资料库, 此时所使用的命令是功能表的「转换文字档为资料库」, 转换之後, Win32api.txt
的所在目录會增加 Win32api.mdb 资料库档案, 将来我们便可以利用功能表的「档案/载入资料库档案」来载入此一资料库档案, 则载入的速度确实提升不少。</P>

<P> </P>

<P>不过 API 检视员实在有点「阿达」, 因为载入 Win32api.txt 的 API 检视员具有「搜寻」API
的功能, 但如果载入的是 Win32api.mdb 资料库档案, 则「搜寻」的功能反而不见了。笔者实在很不满, 所以决定撰写一个改良版的
API 检视员, 也取您阅读本文时, 也经完成了, 请随时注意笔者的网站。</P>

<P> </P>

<H2>
<HR WIDTH="100%">如何传递参数
<HR WIDTH="100%"></H2>

<P> </P>

<P>在 API 函数所定义的参数型别中, 大致上可分成「数值」、「自订型别」、「字串」(String)、及「Any」四种资料型别, 以下让笔者按照这四种资料型别来说明
VB 程式与 API 的参数传递方式:</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>数值的传递</FONT>
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>数值型别在 API 的参数定义中可能有两种形式:「参数名 As 数值型别」及「ByVal
参数名 As 数值型别」, 所代表的意义分别是数值的「传址」及「传值」呼叫, 与
VB 的习惯完全相同, 以 GetFileSize(读取档案的长度) API 为例, 其宣告式如下:</P>

<P> </P>

<DIR>
<P>Declare Function GetFileSize Lib &quot;kernel32&quot; Alias &quot;GetFileSize&quot;
(ByVal hFile As Long, lpFileSizeHigh As Long) As Long</P>

<P> </P>
</DIR>

<P>而呼叫的例子如下:</P>

<P> </P>

<DIR>
<P>Dim hFile As Long, lenFile As Long</P>

<P>hFile = OpenFile(…) ' OpenFile 也是 API 函数</P>

<P>ret = GetFileSize ( hFile, lenFile ) ' lenFile 将传回档案长度</P>

<P> </P>
</DIR>

<P>其中 hFile 参数为 Long 型别的「传值」呼叫, lenFile 参数则是 Long 型别的「传址」呼叫, 若呼叫成功, 则
GetFileSize 會将档案的长度设定给 lenFile。</P>

<P> </P>

<CENTER><P><FONT SIZE=+1>自订型别的参数传递</FONT>
<HR WIDTH="100%"></P></CENTER>

<P> </P>

<P>对 C 语言而言, 自订型别的参数只能以位址来传递, 因此在 API 函数中, 并没有「ByVal
参数名 As 自订型别」的参数宣告, 至於「参数名 As 自订型别」的传址呼叫, 则与
VB 的习惯完全相同, 以 GetCursorPos(读取滑鼠的位置) 为例, 其宣告式如下:</P>

<P> </P>

<DIR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -