注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

心情挺好的博客

正在等你光临呢 呵呵

 
 
 

日志

 
 
关于我

喜欢摄影的朋友看过来:) 有时间就跟我一起去拍照去吧. QQ272751 上海圣玛丽摄影化妆培训学校 16年专业摄影培训化妆培训学校 电话:15900513500。 http://www.smlsh.com

网易考拉推荐

在Visual Basic中使用导入API  

2008-04-21 10:12:37|  分类: 技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
如何在Visual Basic中使用导入API

在 Visual Basic 中使用导入 API会发现很难找到正确的 dll。我知道 C++ 中有一个 dll,但是,有没有可以从 VB 应用程序调用的 dll 呢?

回答是肯定的:

有两种方法可以完成这项工作。一种方法就是在 VB 的 DECLARE 部分列出您希望调用的 C API,然后利用标准

的调用序列从 VB 调用它,如下面的代码样本所示:


Type SQLCA_STRUCT

sqlcaid As String * 8

sqlcabc As Long

sqlcode As Long

sqlerrml As Integer

sqlerrmc As String * 70

sqlerrp As String * 8

sqlerrd(6) As Long

sqlwarn As String * 11

sqlstate As String * 5

End Type

Public Declare Function sqlepstart Lib "db2app" Alias "sqlepstart_api"

(ByVal junk&, ByRef sqlca As SQLCA_STRUCT) As Integer

'

DB2_start = sqlepstart(0, sqlca) ' Start DB2 call

另一种方法就是生成一个文件,然后发出一条命令在后台执行该函数(当然,取决于您正在试图做什么):

fileno = FreeFile

Open db2file For Output As #fileno

sqlstmt = "" + _

"db2start;" + vbNewLine + _

"quit;"

Print #fileno, sqlstmt ' Write commands to a file

Close #fileno ' Close it and execute the command

db2cmd = "db2cmd /i /c db2 -tvf " + db2file ' Generate the command

progID = Shell(db2cmd, vbMinimizedNoFocus) ' Shell out to run it

最后,DB2 的下一个版本将允许您象运行普通的 SQL 表函数那样运行特殊的 API 命令。这会返回有关目前可在 DB2 中找到的许多管理 API 的结果。因此,无需进行 API 调用,您只需使用 SQL 调用就可从 DB2 获取信。

  • 2006-12-15 8:44:17
    VB实现远程启动机器ABC_一.API 解决方案

    API 解决方案

       -用ActiveX Server进行本地重新启动和远程重新启动

      我们可以通过 API调用执行本地NT计算机的重新启动。其中最主要的调用是 ExitWindowsEx,但是在进行这个调用之前,必须首先取得当前过程的访问标记值OpenProcessToken,然后寻找在特定系统中使用的本地唯一识别号LUID,用它表示本地关机特权LookupPrivilegeValue。填充好TOKEN_PRIVILEGES结构后,调用AdjustTokenPrivileges以允许关闭计算机。最后,调用ExitWindowsEx(将可选标志位设置为强迫关机)完成整个操作周期。这里是可下载代码包: RebootNT_API.zip

      由于要解决远程重新启动的问题,那么为什么要首先提到本地重新启动的编程方法呢?这有一些原因。首先,你可能需要将重新启动机器作为程序的一部分,当在那个机器上发生一些特殊情况情况,比如发生致命错误时,就需要重新启动机器。第二,你可以创建一个ActiveX EXE或者服务程序,将它安装在远程机器上,这样就可以从一个中心计算机调用它来完成重新启动的工作。第三,重新启动Win9x机器要比NT 简单得多,请看下面的代码:

    Option Explicit

    Declare Function ExitWindowsEx _

    Lib "user32" _

    (ByVal uFlags As Integer, _

    ByVal dwReserved As Integer) As Integer

    Private Const EWX_FORCE As Long = 4&

    Private Const EWX_REBOOT As Long = 2&

    Public Sub ShutDown(ByVal xi_blnForce As Boolean)

    Dim p_lngRtn As Long

    Dim p_lngFlags As Long

    If xi_blnForce = False Then

    p_lngFlags = EWX_REBOOT

    Else

    p_lngFlags = EWX_REBOOT Or EWX_FORCE

    End If

    p_lngRtn = ExitWindowsEx(p_lngFlags, 0&)

    End Sub
  • 2006-12-15 8:43:34
    在VB中使用API函数(子类处理)

    子类处理

      当你一最大限度利用了VB所给你的并且还想知道更多的东西,或只是想更多地了解你自己的窗口,你将会发现子类处理的优势.

      子类处理是指用一个新的窗口函数来取代当前活动窗口函数.这个用户自定义函数能处理任何需要的消息,并能调用原来的窗口函数,它将在原来的窗口函数之前收到各种消息.但原来的那个窗口处理函数依然存在,并没有消失.如果你不想处理某条消息,你应该让原来的窗口函数去处理它.

      子类处理是通过调用SetWindowLong函数实现的,该函数将改变指定窗口的特殊属性.下面是它的声明:

    Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"(ByVal hwnd As Long, ByVal nIndex As Long,ByVal dwNewLong As Long) As Long

    第一个参数代表要进行子类处理的窗口,第二个参数应该是GWL_WNDPROC(-4),第三个参数是新的窗口函数的地址.参见回调和窗口函数一节.

    此函数将在窗口取得焦点,发生事件,或其他情况下(如其他进程改变了系统的某些参数)被随时调用.

    如果发生错误SetWindowLong函数将返回0,否则将返回原来的窗口函数的地址.这个地址特别重要,你应该把它保存在一个变量中或其他地方.当你不处理某些消息时(实际上,你可能只处理不到1%的消息,其他的都将由原窗口函数处理),调用原来的窗口函数就需要该地址.


    子类处理

      调用原窗口函数将由CallWindowProc来完成.这里是它的声明:

    Declare Function CallWindowProc Lib "user32" Alias"CallWindowProcA"(ByVal lpPrevWndFunc As Long,ByVal hWnd As Long,ByVal Msg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long

      第一个参数是原窗口函数的地址,其他的同你接收到的四个参数一样.你可以改变其中的值来控制对消息的处理.例如,当你收到了一条WM_MOUSEMOVE消息时,你从lParam中得到鼠标所在位置的坐标并将其改成了其他的坐标.那么原窗口函数就会认为鼠标位于其他的位置从而做出一些有趣的事如显示其他控件的Tooltip.

      你指定的返回值也是有意义的,它依赖于发送的消息.

    在结束你的程序时将控制权交回给原窗口函数是很重要的,通常在Form_Unload中完成如下:

    Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProcAddress)

    如果你在VB中启动程序时忘掉了这一行,结果将是VB崩溃并会丢失尚未保存的数据.千万要小心.

    这里是子类处理的一个简单示例:

    Dim oldWndProc As Long

    Private Sub Form_Load()

    oldWndProc = SetWindowLong(Me.Hwnd, GWL_WNDPROC, AddressOf MyWndProc)

    End Sub

    Private Sub Form_Unload()

    Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProc)

    End Sub

    Function MyWndProc(ByVal Hwnd As Long,ByVal wMsg as Long,ByVal wParam As Long,ByVal lParam As Long)

    Debug.Print wMsg & " " & wParam & " " & lParam

    Ret& = CallWindowProc(oldWndProc, Hwnd, wMsg, wParam, lParam)

    End Function


    处理参数

     有时函数并不以你所需的方式返回信息.一个典型的例子是将两个代表鼠标位置的整形(2 byte)数合并为一个4 Byte的数.还有一个例子是判断一个数的某位是否为1.你还可能得到一个代表一个结构地址的Long型数.

      合并和分离一个数并不需要过多的描述.你能在我们的网站(www.geocities.com/SiliconValley/Lab/1632/)上找到APIMacro.bas,它包含了你需要的多种函数.

    可以用一下方法检查一个数的第N位是否为1:

    If Value and (2^N) then ...

    置1

    Value = Value Or 2^N

    置0

    Value = Value And Not 2^N

      如果你想设定或取得预先知道的某位的信息,用1024代替2^10要快的多.因为这样VB无需自己进行计算(VB憎恨 "^" ?).

      如果你接收到一个类型的指针,你要做的工作将稍多一点.你可以使用CopyMem函数来取得信息.下面是它的声明:

    本文更多内容

  • 2006-12-15 8:43:34
    在VB中使用API函数(回调(CallBacks))

    回调(CallBacks)

      所谓回调,就是你自己定义一个函数,并告诉Windows何时为何调用.你可以写一个有特定数量和类型参数的函数,然后告诉Windows何时调用,并传递给它所需的参数.Windows就会调用你定义的函数,处理参数,并给你返回值.

      回调的一个典型应用是从Windows获得连续的数据流.这里是一个需要回调的函数的声明:

    Declare Function EnumWindows Lib "User32"ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

      第一个参数是你的回调函数的地址,第二个参数是你想传递的的任意数值.该值将被传递到你的函数,于是你就知道了它要调用什么.

    VB 5.0已经提供了一个很有用的操作符 AddressOf ,可以得到一个函数的地址.当你调用一个函数时它只能用在参数的前面,下面这种用法是错误的并且会导致出错:

    FuncP = AddressOf MyFunction

    因此你必须这样调用EnumWindows函数:

    Success& = EnumWindows(AddressOf cbFunc, 58&)

      你必须也要自己写回调函数.问题是有很多不同类别的回调并且有各种各样的参数,有关这些参数的描述可以在SDK帮助或MS SDK文档中找到.这里是一个回调的声明:

    Function cbFunc (ByVal Hwnd, ByVal lParam) as Long

    这里是一个回调的例子:

    Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA"(ByVal hwnd As Long,ByVal lpString As String,ByVal cch As Long) As Long

    Success& = EnumWindows(AddressOf cbFunc, 58&)

    Function cbFunc (ByVal Hwnd, ByVal lParam) as Long

    If lParam = 58 then ’enum windows

    Str$ = Space(255)

    Ret& = GetWindowText(Str$, Len(Str$))

    Debug.Print Left(Str$, Ret&)

    End If

    End Function

    这个例子将列出窗口的标题,(不包含子窗体)



    窗口程序

      Windows并不知道事件. 这些是VB特有的隐藏Windows获取你的窗口发生事件的真正方法的一种方式.VB很像是一个将Windows语言翻译成VB语言的解释器.

      但是事实并非如此,你很快就会遇到.设想你想知道用户何时加亮了菜单选项(不是点击,只是加亮即选择了)VB并不提供这种事件,但你可能见到其他的程序,但你浏览它的菜单时状态栏会出现相应的文字.如果他们能,你为何不能?

      OK,这里是大致的真实情况.每个窗口都有一个特殊的程序叫做窗口程序.它实际上是一个回调函数.该函数将在你的窗口发生事件的任何时间发送消息.这样当用户加亮一个菜单项时就会发送一条消息(WM_COMMAND).

      那为什么我看不到这条消息呢?这是因为是VB创建窗口程序而不是你.当Windows发送消息时,该程序将为之分派特定的事件,并将其参数转换为比较容易用的事件的参数.但是在有些情况下,它会忽略有些消息而不能收到真实的输入.如果你真的想得到这些消息,你必须对你的窗体进行子类处理,我们将在另外一个主题中谈到.

    这里是一个回调窗口程序的声明:

    Function WindowProc(ByVal Hwnd As Long, ByVal wMsg As Long,ByVal wParam As Long, ByVal lParam As Long) As Long

      第一个参数指定窗口的句柄,第二个参数是消息的标识符(如WM_COMMAND或WM_MOUSEMOVE),wParam和lParam时两个32位的数值,它们的意义依赖于消息的类型.

    子类处理

      当你一最大限度利用了VB所给你的并且还想知道更多的东西,或只是想更多地了解你自己的窗口,你将会发现子类处理的优势.

      子类处理是指用一个新的窗口函数来取代当前活动窗口函数.这个用户自定义函数能处理任何需要的消息,并能调用原来的窗口函数,它将在原来的窗口函数之前收到各种消息.但原来的那个窗口处理函数依然存在,并没有消失.如果你不想处理某条消息,你应该让原来的窗口函数去处理它.

      子类处理是通过调用SetWindowLong函数实现的,该函数将改变指定窗口的特殊属性.下面是它的声明:

    Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA"(ByVal hwnd As Long, ByVal nIndex As Long,ByVal dwNewLong As Long) As Long

    本文更多内容

  • 2006-12-15 8:43:34
    在VB中使用API函数(什么是API? )

    什么是API?

      API(Advanced Programmers Interface,高级程序员接口)(注:API实际是指Application Programming Interface,应用程序编程接口;此处疑为原文错误,不过在VB中也可以这么说吧!)是一套用来控制Windows的各个部件(从桌面的外观到位一个新进程分配的内存)的外观和行为的一套预先定义的Windows函数.用户的每个动作都会引发一个或几个函数的运行以Windows告诉发生了什么.

      这在某种程度上很象Windows的天然代码.其他的语言只是提供一种能自动而且更容易的访问API的方法.VB在这方面作了很多工作.它完全隐藏了API并且提供了在Windows环境下编程的一种完全不同的方法.

      这也就是说,你用VB写出的每行代码都会被VB转换为API函数传递给Windows.例如,Form1.Print...VB 将会以一定的参数(你的代码中提供的,或是默认参数)调用TextOut 这个API函数.

      同样,当你点击窗体上的一个按钮时,Windows会发送一个消息给窗体(这对于你来说是隐藏的),VB获取这个调用并经过分析后生成一个特定事件(Button_Click).

      API函数包含在Windows系统目录下的动态连接库文件中(如User32.dll,GDI32.dll,Shell32.dll...).


    API 声明

      正如在"什么是API"中所说,API函数包含在位于系统目录下的DLL文件中.你可以自己输入API函数的声明,但VB提供了一种更简单的方法,即使用API Text Viewer.

      要想在你的工程中声明API函数,只需运行API Text Viewer,打开Win32api.txt(或.MDB如果你已经把它转换成了数据库的话,这样可以加快速度.注:微软的这个文件有很多的不足,你可以试一下本站提供下载的api32.txt),选择"声明",找到所需函数,点击"添加(Add)"并"复制(Copy)",然后粘贴(Paste)到你的工程里.使用预定义的常量和类型也是同样的方法.

    你将会遇到一些问题:

      假设你想在你的窗体模块中声明一个函数.粘贴然后运行,VB会告诉你:编译错误...Declare 语句不允许作为类或对象模块中的 Public 成员...看起来很糟糕,其实你需要做的只是在声明前面添加一个Private(如 Private Declare Function...).--不要忘了,可是这将使该函数只在该窗体模块可用.

      在有些情况下,你会得到"不明确的名称"这样的提示,这是因为函数.常量或其他的什么东西共用了一个名称.由于绝大多数的函数(也可能是全部,我没有验证过)都进行了别名化,亦即意味着你可以通过Alias子句使用其它的而不是他们原有的名称,你只需简单地改变一下函数名称而它仍然可以正常运行.

      你可以通过查看VB的Declare语句帮助主题来获取有关Alias的详细说明.

    消息(Messages)

      好了,现在你已经知道什么是API函数了,但你也一定听说过消息(如果你还没有,你很快就会)并且想知道它是什么.消息是Windows告诉你的程序发生了哪些事件或要求执行特定操作的基本方法.例如,当用户点击一个按钮,移动鼠标,或是向文本框中键入文字时,一条消息就会被发送给你的窗体.

      所有发送的消息都有四个参数--一个窗口句柄(hwnd),一个消息编号(msg)还有两个32位长度(Long)的参数.

      hwnd即要接受消息的一个窗口的句柄,msg即消息的标识符(编号).该标识符是指引发消息的动作类型(如移动鼠标),另外两个参数是该消息的附加参数(例如当鼠标移动时光标的当前位置)

      但是,当消息发送给你时你为什么看不到呢--就象有人在偷你的信一样?请先别恼火,让我告诉你.
      小偷其实是Visual Basic.但它并没有偷走你的信,而是在阅读了之后挑出重要的以一种好的方式告诉你.这种方式就是你代码中的事件(Event).

      这样,当用户在你的窗体上移动鼠标时,Windows会发送一条WM_MOUSEMOVE消息给你的窗口,VB得到这条消息以及它的参数并运行你在事件MouseMove中的代码,同时VB会把这条消息的第二个32位数(它包含了x,y坐标,单位为像素(Pixel),每个位16位)转换为两个单精度数,单位为缇(Twip).

    本文更多内容

  • 2006-12-15 8:43:34
    在VB中使用API函数(Any)

    Any

      有些消息的参数声明为Any.这表示该参数是一种可变的类型(你可以以整型,字符串,用户自定义或其他的类型来传递).

    这有一个这样的例子:

    Public Declare Function SendMessage Lib "User32" Alias "SendMessageA" ByVal Hwnd as Long, ByVal wMsg as Long, ByVal wParam as Long, lParam as Any) as Long

    lParam 声明为Any并按引用(ByRef)传递.

      这里是在这个函数中如果lParam是不同类型的值时应遵循的规则:

    如果该值是 传递形式

    numeric ByVal(as Long,or as Any)

    Null ByVal(as Long,or as Any)

    String ByRef(as String,or as Any)

    Type ByRef(as Any)

    array of Type ByRef(as Any)

      如果你的函数声明同上面的一个而且你想传递一个Long型数,你应该这样写:

    Call SendMessage(Me.Hwnd,WM_XXXX,0&,ByVal LongValue)

      注意尽管头三个参数也是数值,但它们前边并没有ByVal.这是因为在函数声明中它们已经被声明为按值传递(ByVal).第四个参数,由于是按引用传递(ByRef)(VB并不知道你要传递参数的类型),因此你必须加上ByVal 你可以使用别名技术来传递不同类型的参数:

    Public Declare Function SendMessageLng Lib "User32" Alias "SendMessageA"(ByVal Hwnd as Long, ByVal wMsg as Long, ByVal wParam as Long, ByVal lParam as Long) as Long

    或:

    Public Declare Function SendMessageStr Lib "User32" Alias "SendMessageA"(ByVal Hwnd as Long, ByVal wMsg as Long, ByVal wParam as Long, lParam as String) as Long

      注意API参数类型本身是不会改变的.例子中的第四个参数总是一个4字节的长型数.当你按值(ByVal)传递一个Long或 Null时,该4字节长的数值就直接传递给函数.如果你传递一个String或其他的什么,你是按引用(ByRef)传递,VB传递的实际上是变量的地址,也是4个字节.


    参数传递

      你已经知道如何传递参数了,只需把他放到调用的函数中即刻.然而,当你使用API函数时,在传递参数是有一些你应该注意的 细节. ByVal还是ByRef. 通常情况下,你不用为此担心,VB的API浏览器已经为你做好了一切,只需你输入数值它就会照所声明的方式传递.总的来说,ByVal是把实际的数值传递给函数,而ByRef是把地址传给函数.唯一的麻烦就是 Any 类型. 把字符串传递给API函数也并不难.API函数需要的是字符串首字符的地址,然后读取该地址直到遇到一个Null字符.听起来很糟糕,但只是VB处理字符串的实际方法.你唯一要记住的是一定要按引用传递(ByRef)字符串 当你想得到所需的函数返回值信息时,情况有稍微的一点不同.

    这里是GetComputerName函数的声明:

    Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA"(ByVal lpBuffer As String, nSize As Long) As Long

    第一个参数是一个指向字符串的远程指针,第二个参数是字符串的长度.

      如果你只是简单的声明一个字符串类型的变量并把它传递给函数,就会出现错误.因此,你首先需要初始化字符串.这里是如何得到计算机名字的例子: Dim Buffer As String

    Buffer = Space(255)

    Ret& = GetComputerName(Buffer, Len(Buffer))

    if Ret& > 0 then CompName$ = Left(Buffer, Ret&)

      在这里,待传递的字符串被初始化为有255个空格的字符串.我们把它传递给函数同时还有它的长度.如果出错则返回值为0.


    参数传递

    CompName中将保存计算机名. 有些函数也需要传递数组,这里是一个例子:

    Declare Function SetSysColors Lib "user32" Alias "SetSysColors" (ByVal nChanges As Long, lpSysColor As Long, lpColorValues As Long) As Long

      最后两个参数是Long型数组.为了传递数组,你只需传递它的第一个元素.下面是示例代码:

    Const COLOR_ACTIVECAPTION = 2

    Const COLOR_INACTIVECAPTION = 3

    本文更多内容

  • 2006-12-15 8:43:34
    在VB中使用API函数(Windows一些特别之处)

    Windows的一些特别之处

      这个主题是要告诉你Windows 的一些与在VB中的不同的细节

      Windows通过句柄(Handle)识别每个窗体,控件,菜单,菜单项或其他任何你能想得到的东西.当你的程序运行时,它所包含的每个部件都有一个唯一确定的句柄用来同其他的部件相区别.例如,某个按钮得句柄就与其他部件不同,当你想要通过API来执行有关该按钮的某种操作时就必须使用这个句柄.从哪儿得到它呢?VB 为每个拥有Windows句柄的控件都提供了Hwnd属性来表示其句柄.

      Windows 使用像素(Pixel)而不是缇(Twip).因此,把涉及API函数调用的控件的ScaleMode属性设为3--(Pixel)是个不错的主意,这样你可以通过ScaleXXX属性得到它们的公制单位值.尽管这样,你可能有时仍需要进行从Twip到Pixel的转换(反之亦然),你可以通过Screen对象的TwipsPerPixelX和TwipsPerPixelY来实现.举例如下:

    PixelXValue=TwipXValue\Screen.TwipsPerPixelX

    PixelYValue=TwipYValue\Screen.TwipsPerPixelY

    TwipXValue=PixelXValue*Screen.TwipsPerPixelX

    TwipYValue=PixelYValue*Screen.TwipsPerPixelY

      我并没有在实际中见到过TwipsPerPixelX 和 TwipsPerPixelY 的值有什么不同,但你最好是把它们区别开来而不是混用,这至少是一种好的程序设计风格.另外需要注意的是,这里用的是" \ "(整除) 而不是 " / " ,这是因为像素值必须是整数.

      另外需要提到的是,Windows函数中用到了不同的坐标系统,因此需要注意.


    Windows的一些特别之处

      最后要注意的是,一旦你使用了API 函数,VB就可能不再可靠了---API调用中一个简单的语法错误就会导致VB 崩溃!(请经常保存您的工程).VB 并不能识别API调用中的错误,因此一旦你的程序出现异常,要先检查API调用---是否缺少 ByVal,或者是错误的类型,参数等等.

    从哪里得到有关函数的说明?

      这个主题不会告诉你如何通过API函数改变按钮文字或如何快速查找一个文件.这不是一个API函数文档.

      为了得到有关函数的说明,你需要SDK帮助或微软的SDK文档(至少有40M---我怎么可能放在这里?).这些SDK帮助通常都包含在Borland Dephli 3.0 开发包或者MS Visual C++中.到网上去或找您的朋友要一个,版本越新越好

      注意Win3.x 的SDK 帮助对你并没有用,因为很多函数已经过于陈旧甚至废弃不用,尽管他们中的大多数由于与 Windows95兼容而依然存在.

    API参数类型

      如果你已经有了一个SDK帮助,你肯定主意到了函数的返回之或参数有很多奇怪的类型如VOID,LPCSTR, 和DWORD.如果你对C语言比较熟悉的话,那你肯定明白它们的意思.对于其他不熟悉C语言的人,这里有一张摘自 VB

    Books Online(标题是:C语言声明到Visual Basic的转换)

    Books Online(标题是:C语言声明到Visual Basic的转换)

    <>
    bordercolordark="#FFFFFF" cellpadding="0">

    <>

    bordercolordark="#FFFFFF" cellpadding="0">

    C 语言数据类型 在VB中的声明 Call with
    ATOM ByVal variable As Integer An expression that evaluates to an Integer
    BOOL ByVal variable As Long An expression that evaluates to a Long
    BYTE ByVal variable As Byte   

              

    An expression that evaluates to a Byte
    CHAR ByVal variable As Byte   

              

    An expression that evaluates to a Byte
    COLORREF ByVal variable As Long                An

    expression that evaluates to a Long

    DWORD ByVal variable As Long   

              

    An expression that evaluates to a Long
    HWND, HDC,HMENU,etc.(Windows handles) ByVal variable As Long   

              

    An expression that evaluates to a Long
    INT, UINT ByVal variable As Long An expression that evaluates to a Long
    LONG ByVal variable As Long An expression that evaluates to a Long
    LPARAM   

                   

    ByVal variable As Long   

               

    An expression that evaluates to a Long
    LPDWORD variable As Long An expression that evaluates to a Long
    LPINT, LPUINT variable As Long An expression that evaluates to a Long
    LPRECT variable As type Any variable of that user-defined type
    LPSTR, LPCSTR ByVal variable As String An expression that evaluates to a String
    LPVOID variable As Any Any variable (use ByVal when passing a string)
    LPWORD variable As Integer An expression that evaluates to an Integer
    LRESULT ByVal variable As Long An expression that evaluates to a Long
    NULL As Any orByVal variable As Long ByVal Nothing or ByVal0& or vbNullString  
    SHORT   

                    

    ByVal variable As Integer An expression that evaluates to an Integer
    VOID Sub procedure Not applicable
    WORD ByVal variable As Integer An expression that evaluates to an Integer
    WPARAM ByVal variable As Long An expression that evaluates to a Long



    API参数类型

    本文更多内容

  • 2006-12-15 8:42:41
    感悟VB细水长流话API(四-1)

    感悟VB细水长流话API(四-1)

      经过前几期的连载,我们学到了几个有用的API,也许有的读者会希望我尽快介绍更多的API,不过有许多简单的API的用法是相似甚至相同的,所以为了让读者学到真正有用的知识,在连载的初期,我讲的API将是比较简单而又涉及到相关基础知识的。至于那些用法极相似甚至相同的,我会在适当的时候再介绍它们,只是详细程度和侧重点不同而已。这点希望引起读者的注意。

    第四话 使用自定义类型

      我在前面已经提到过自定义类型,这次我用一个简单的API来说明一个自定义类型在API中的使用。

      VB中规定了自定义类型的变量传递给函数或子程序时必须按引用来传递(关于按引用传递与按值传递,将在以后的文章中做详细介绍),因此下面这个API的声明,你会发现和前面所介绍的几个有少许不同。

    Public Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" (lpPoint As POINTAPI) As Long

    相比上一话中的一个API:

    Public Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

      可发现参数前面少了个ByVal。如果不加ByVal,或者把ByVal换成ByRef,就是按引用传递。POINTAPI不是VB的标准数据类型,它是一个自定义类型。从API浏览器中我们得到它的定义原形是这样的:

    Public Type POINTAPI

    x As Long

    y As Long

    End Type


      这里应该引起注意的是,你应该把POINTAPI的定义写在使用它的函数声明之前,否则VB会认为你的类型未定义。你也不可以把 x As Long 和 y As Long 的位置对调,如果对调了,在这个API中最多只会使原本 x 的值变成 y 的值,y 的值变成 x 的值,但在更复杂的自定义类型中,结果就不可预知了。

      这个API的作用是得到鼠标指针在屏幕中的坐标(以像素为单位)。你可以在自己的程序中试验它,比如:

    Dim tCursor As POINTAPI

    GetCursorPos tCursor

    Debug.Print tCursor.x, tCursor.y


    将从调试窗口打印鼠标指针的当前坐标。
  • 2006-12-15 8:42:41
    感悟VB细水长流话API(六-1)

    感悟VB细水长流话API(六-1)

    第八话 父与子

      在开始这一话之前,不知各位读者有没有使用过MDI Form呢?看看图1,这是一个标准的MDI Form和其中一个子窗体在标准和最大化情况下的外观。不过别误会,我不是想讲MDI,你再看看图2,我只是想让你区别图2的窗体不是MDI Form。图2的两个窗体都是一般的窗体,从最大化的外观就可以看出区别了。是不是觉得很有意思?其实也没有什么秘密。

      我说过Windows中多数东西都是一种窗口,比如按钮。一般情况下我们看到的按钮都是在一个窗体的里面,这是因为窗体和按钮有一种父与子的关系。当一个窗口成为另一个窗口的子窗口(Child),那么它的位置的变化就只发生在另一个窗口里,另一个窗口就是这个窗口的父窗口(Parent)。平时我们建立的窗体都是相互独立的,与其他的窗体没有关系,但我们可以通过API使它们建立起父与子的关系。这要用到SetParent:

    Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long

      SetParent接收两个参数,第一个是将成为子窗口的窗口句柄,第二个是将成为父窗口的窗口句柄。它的使用很简单,比如想把Form2作为Form1的子窗口,只需这样使用:

    SetParent Form2.hWnd, Form1.hWnd

      Windows会自动把Form2在新的父窗口中的位置调整为原父窗口的位置(即使是桌面,也是一个父窗口)。即是说,假如原来在桌面的Form2,位置为10,10,则它在新的父窗口中的位置也为10,10。但这个新的10,10是以新父窗口为参照物的,无论怎么变化,都是在新父窗口中。

      不过应该注意,并不是所有东西都适合当父窗口。因为每一种窗口都有为自己设计的行为,比如当画面重画时要画什么,如果我们为它添加了新的子窗口,那么它们将可能产生冲突,因为父窗口在设计时并没有考虑出现意外的子窗口的情况。为了说明这个问题,我做了一个示例。当我把按钮作为ListBox的子窗口时,你会看到由于ListBox在选择项目时进行了画面的重画,导致按 钮显示变得不正常,但当我按了一下按钮时,又因为按钮的重画,显示又正常了。

      值得一提的是,当我们把Form1中的一个子窗口(比如按钮)放置到Form2中,而我们又在Form1中为这个子窗口的某个事件写了执行代码,那么它还会被执行吗? Form2又需不需要为这个新的子窗口做特别处理呢?假如我的处理代码都是写在Form1中的,而所有控件都被我放到Form2中时(如图4),它们的点击事件的代码仍然能被执行。由于无法得知实际上VB内部是如何处理控件的消息循环的,所以我也无法对此中秘密进行解释,特别是一个应该注意的问题——当你把按钮(这里以按钮为例,但其实其他东西也一样)放到Form2中后,如果这个按钮在Form2中获得了焦点,那么你就无法从Form2切换回Form1,除非这时你可以让Form1中某个控件重新获得焦点——比如通过使某个控件从Form2中成为Form1的子窗口,或者使用 SetFocus让Form1的某个控件获得焦点。所以,实际应用中应该避免这种情况的发生。如果新的父窗口不是由VB所建立的窗体,那么这种事就不会发生,不过这已不是本话的内容了。

      在我写的示例源程序里,还有一个GetParent的API这里没有讲到,我用它判断当前的子窗口是哪个窗体的子窗口。它的作用是返回指定子窗口的父窗口的句柄。
  • 2006-12-15 8:42:41
    感悟VB细水长流话API(一)

    编写VB程序时,经常遇到的问题就是VB给我们准备的东西我们会用,控件组装就是一个程序,然而一旦想要实现VB没有直接提供的功能,就会不知所措。其实Windows操作系统本身就给我们准备了许多东西,VB没有的,或许Windows有。我们当然希望少花力气,多得效果。这里要讲的内容就是——学会利用Windows给我们的东西:API。

      然而,学会一种东西是需要付出相当的努力的,API也一样,它可以给我们带来很大的方便,但想要掌握它,就不是使用几个控件那么轻松的事了。所以在看这篇文章时,希望读者可以抱一个正确的态度,就是学习编程不是为好玩,而是为使用; 不要以自己对这方面是否有兴趣而看,而要为API是否能为你的程序带来效果而看。我并不是说一切都是那么严肃和困难,只是API对VB来说,已经可以算高级方面的应用了,所以“认真”和“仔细”是需要的。好了,放松一点,让我们从现在起一步步领略API的好处吧。

      前言

      1.API

      API全称为Application Programming Interface,直译的话可叫它“应用程序接口”。从意义上来说,API是一个操作系统或某个程序本身提供给其他程序使用的函数。在Windows操作系统中,有成千个Windows的函数提供给应用程序使用,本文所说的API,就是指这些函数。

      2.VB与API

      之所以写这篇文章(而不写VC或其他语言),是因为VB对API的支持不是直接的,而且是不完全的; 在使用上,Windows的API编写时是假设调用者是C或C++语言,因此VB调用API不是很方便,也经常有不必要的错误或不明白如何使用的情况出现。本文的对象主要还是对API没有很深研究的读者,如果你不想了解太多细节,你可以把一个合适的函数用法搬过去,或者你完全不知道API,或者只知道少数,对许多函数还不清楚如何使用,或者你希望可以从本文学到更多使用API的技巧甚至VB的技巧(但愿我可以让你学到),我想你都应该看这篇文章。但还是有个大前提,你必须是已经会使用VB的读者,因为以后讲到的内容不会有一个完整工程从头到尾教你做,有可能是一段简短的声明与调用代码,也可能是几个函数的组合,如果必要的话,也会讲述相关内容的VB技巧,但一定不会有完整的实例示范。

      3.本文原则和约定

      由于API中有的用法简单有的复杂,有的可单独使用有的却不行,加上各个API的主要用途不同,很难判断先说哪个再说哪个可以让人更容易理解,因此本文尽量从比较常用的说起,从可以对程序产生较大作用的说起。为了能让多数人理解,如果需要涉及到其他方面的知识,也将尽量讲述,让读者可以学到使用API的知识,并能够利用本文中的知识应付新的API。如果你对某个API有什么疑问,欢迎来信(webmaster@neocactus.com),但由于时间有限,不能对来信一一回复,如果有需要,将会在文中讲述。


      基础知识

      在讲API之前,让我先讲解一些与API相关的VB基础知识,后文如有涉及将不再详述。此处未提及的,将在本文中第一次接触时再做解释。

      1.自定义类型

      VB中可以使用Type关键字将已有的数据类型进行组合,成为一个新的类型,该类型就称为用户自定义类型。如:

    Type NewType
    sName As String
    lNumber As Long
    End Type

      定义了一个名为NewType的自定义类型。以后可以用Dim MyType As NewType来定义一个NewType类型的变量。

      sName As String类型的变量有两种,一种是变长,即运行时的字符串长度是可变的,另一种是定长,运行时字符串的长度是固定的。平常我们定义一个字符串变量: Dim strA As String 即定义了一个变长的字符串,但在使用API时经常要用到定长的字符串,应该这样定义: Dim strB As String * 30,即定义了一个可容纳30个字节字符的变量。

      2.声明

      VB中使用API之前,需要先对API进行声明,声明的方法是使用Declare关键字,如:
    Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    声明了一个名为SendMessage的API函数。许多API的声明可以在API浏览器中找到,而且本文在讲述一个API时也会给出声明,更深入的知识将在以后讲述。

      3.句柄

    本文更多内容

  • 2006-12-15 8:42:41
    感悟VB细水长流话API(四-2)

    感悟VB细水长流话API(四-2)

    第五话 坐标系

      在前一话中我们初次接触到了坐标的问题,那么当 VB在使用API时应该如何正确使用坐标系呢?这看起来似乎没什么特别的,不过事实并非如此。

      VB中的坐标系统比较丰富,有Twip、Point、Pixel、 Character、Inch、Millimeter、Centimeter和User。很复杂吧?在这里我要说的是Twip和Pixel,至于剩下的,由于和本文所说的应用无多大关系,请参考MSDN或相关书籍。

      VB中最常用的是Twip的坐标系统,按照微软的说法, Twip是一种与屏幕无关的测量单位,就是说,当我们使用Twip作为单位时,(在打印时)不需要担心屏幕的分辨率。看起来是挺方便的测量单位,但是在API应用中,它却显得有点多余,因为在API中使用的坐标系统是Pixel。Pixel是以像素为单位的测量单位,像素是构成屏幕的最小元素,因此它也是常用的一种测量单位。

      下面让我们来看看如何在API中应用这两个常用的坐标系统。我把上一话的示例扩展了一下,将要用到一个新的 API:ScreenToClient。

    Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

      ScreenToClient的作用是把屏幕中的坐标转换为客户区的坐标(关于什么是客户区,请参考前面的文章)。hwnd是客户区对象的句柄,而lpPoint则是已经存放着屏幕坐标的 POINTAPI类型,执行该函数后,lpPoint的内容将被转换为客户区坐标值。

    参考图1,它显示了当Form1的坐标系(ScaleMode)设置为Twip时:

    1.鼠标在屏幕中的坐标

    2.鼠标在Form1中的坐标(即由VB计算出来的客户坐标)

    3.把鼠标的屏幕坐标转换为Form1的客户坐标

    4.把以Pixel为单位的客户坐标转换为以Twip为单位的客户坐标

    看看我是如何计算这4对坐标值的:

    Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

    Dim tC As POINTAPI

    GetCursorPos tC

    Label1 = "1. Cursor Position: " & tC.X & Space(5) & tC.Y '注意这里是在屏幕中的坐标

    Label2 = "2. Cursor on Form Coordinate: " & X & Space(5) & Y

    ScreenToClient Me.hwnd, tC
    Label3 = "3. ScreenToClient: " & tC.X & Space(5) & tC.Y '这里把屏幕中的坐标转换为在 Form1 中的坐标
    Label4 = "4. Coordinate after transform: " & tC.X * Screen.TwipsPerPixelX & Space(5) & tC.Y * Screen.TwipsPerPixelY
    End Sub


      然后对比图2,和上面同样的代码,把Form1的ScaleMode设置为 Pixel 时计算出来的坐标值。
      在图1中,Form1的ScaleMode是Twip,当把鼠标的屏幕坐标转换为客户坐标时,我们发现它和Form1本身提供的X、Y值不同(2和3不同),这是因为此时VB程序给我们的坐标值是以Twip为单位的。所以这里我提供了一个方法来把以像素为单位的客户坐标转换为以Twip为单位,即把水平和竖直方向的坐标值分别乘以Screen.TwipsPerPixelX和Screen.TwipsPerPixelY(所以2和4相同)。

      Screen.TwipsPerPixelX和Screen.TwipsPerPixelY是由VB本身提供的,它们的作用是得到屏幕中在水平和竖直方向上每个像素各等于多少个Twip。你也可以使用另一个VB提供的方法:ScaleX()和ScaleY(),它们可以帮你把某一坐标系的值转换成另一坐标系的值。然而,作为一种习惯,我还是建议选择第一种方法,它显得直观一些,并且许多时候当看到这样一段代码时,我们可以马上就理解它的作用。

      再看图2,Form1的ScaleMode是Pixel,因此Form1本身提供的X、Y和我们用API计算出来的值是相同的(2和3相同),而不是图1中和被转换为Twip的4相同。

      看了上面的示例,我想你应该知道如何在API中使用 Twip和Pixel了。另外我还想补充一句,在一般应用中,我们使用得最多的还是Twip,原因之一是VB默认是使用它的,之二是用它来控制长度比用Pixel更准确,特别是在涉及到打印时——1 Point等于1/72英寸,1 Twip等于1/20 Point即1/1440英寸,每厘米有567 Twips; 而Pixel却因屏幕显示范围的不同而改变,这必将使得难以掌握打印长度。

    本文更多内容

  • 2006-12-15 8:42:41
    感悟VB细水长流话API(三)

    感悟VB细水长流话API(三)

    第三话 定长字符串的使用

      上一话讲 lstrlen 时我们传递字符串给API时是直接传递的,相当一部分API也是这样。当然在VB中这里面是有秘密的,我们现在还不对其进行讨论,现在我要讲另一个API,它用的是定长字符串。
      这是一个显示Windows的Temp目录、Windows安装目录以及System目录的路径的程序。这里用到了三个API分别得到这三个目录的路径。

    Private Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
    Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
    Private Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

      比较一下,可以看到这三个API都用到两个参数,一个是字符串缓存,用来保存得到的路径,另一个是指定该缓存的大小。为什么这里要指定大小呢?我把我的代码贴下来,你看一看。


    Private Sub Form_Load()
    Dim sPath As String * 260, lLen As Long
    lLen = GetTempPath(260, sPath)
    Text1 = Left(sPath, lLen)
    lLen = GetWindowsDirectory(sPath, 260)
    Text2 = Left(sPath, lLen)
    lLen = GetSystemDirectory(sPath, 260)
    Text3 = Left(sPath, lLen)
    End Sub


      我的sPath是让API去赋值的,因此必须指定大小,以避免当缓存比API要填充的字符串还小时出现错误。它们的返回值都是API已经填充了的字符个数。因为定长字符串长度是一定的,所以没被填充的空间仍留着,所以要用left来取出有用的部分。


      我在现在讲这个例子除了它实用简单,还因为我想让你知道定义长字符串在API中的应用,而且这里有个VB的知识要跟大家讲。当我们定义一个变长的字符串变量时,VB并不会像其他变量一样马上为它分配内存,而是当赋值给它时才分配合适大小的内存来存放。
      但是API并不会像VB一样为你的变量分配内存并赋值,它只是知道你想要得到一个字符串,那么它就给你,至于你的变量装不装得下,那是你的事。定长的字符在定义时,由于已经指定了大小,所以VB就同时分配了内存给它,所以在使用API填充一个字符串变量时就要用定长字符串并指定字符的大小了。

      但是,是不是定义时是变长的字符串变量就无法用来让API填充呢?其实是有办法的,就是事先让VB为它分配好足够的内存。看下面:


    Dim sPath As String
    sPath=Space(260)
    或者
    sPath=String(260,0)


      用这段代码来代替前面定长字符串变量的声明,得到的结果是一样的。

      Space(260)把260个空格赋给了sPath变长字符串变量,因此VB此时为它分配了可容纳260个空格的内存,而String(260,0)则把260个NULL字符(ASCII码为0的字符,在API中多数代表字符串的结尾)赋给sPath,它同样因此而得到260个字节的内存空间。当然你也可以用 String(260," "),让空格来填充这个空间,效果是一样的。

      好了,这一期的内容已经讲完,记得复习,我们下期再继续。
      源程序下载地址: http://www.cfan.net.cn/qikan/cxg/0203gwv.zip
  • 2006-12-15 8:42:41
    感悟VB细水长流话API(五-2)

    感悟VB细水长流话API(五-1)

    第七话 位置与常居顶端

      许多软件,特别是占桌面面积不是很大的软件(比如笔者的NaviEdit),通常都提供了一个常居顶端的功能(可能有的软件不是这么叫法,但作用是相同的),它的作用是保持窗口一直在其他窗口的上面,可以省去频繁切换窗口的动作。

    如果你想这么做,有一个API可以实现: SetWindowPos,声明是这样的:

    Private Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

      虽然参数很多,但实际用起来很简单。hwnd是窗口的句柄,x、y、cx、cy分别是窗口的x和y坐标、宽和高度。hWndInsertAfter用来指定窗口的Z位置(或称Z顺序)。如果你经常接触3D方面的软件,你就知道Z代表深度。这个参数接受5种值:HWND_BOTTOM、 HWND_NOTOPMOST、HWND_TOP、HWND_TOPMOST或者另一个窗口的句柄。而wFlags用来指定附加的选项。

      你可以用它改变窗口的位置和大小,而且它允许你同时改变Z位置(当然,在VB中不用API你也可以改变窗体大小和位置)。比如让窗口退到最下面,可以这么使用:

    SetWindowPos Me.hWnd, HWND_BOTTOM, 10&, 10&, 80&, 120&, 0&

      想要常居顶端,只需把HWND_BOTTOM改为 HWND_TOPMOST,而HWND_NOTOPMOST则是取消常居顶端,HWND_TOP是把窗口的Z位置改为最前。如果这个参数传递的是另一个窗口的句柄,则是把该窗口的Z 位置更改为在另一个窗口的下面。


      非常简单的事情。不过如果像上面一样做,是不是单单改个Z位置也要计算窗口位置和大小?最后一个参数又是干什么用的呢?wFlags可以让SetWindowPos忽略或执行某种行为。这里给出一部分:

    SWP_DRAWFRAME和SWP_FRAMECHANGED:强制发送 WM_NCCALCSIZE消息给窗口

    SWP_HIDEWINDOW:隐藏窗口

    SWP_NOACTIVATE:不激活窗口

    SWP_NOMOVE:保持当前位置(忽略x和y)

    SWP_NOREDRAW:窗口不自动重画

    SWP_NOSIZE:保持当前大小(忽略cx和cy)

    SWP_NOZORDER:保持窗口在列表的当前位置(忽略hWndInsertAfter)

    SWP_SHOWWINDOW:显示窗口

      这些参数可以使用Or运算组合,所以如果你不希望改变窗口位置和大小,你只需要给最后一个参数传递(SWP_NOMOVE Or SWP_NOSIZE)即可。如下:

    SetWindowPos Me.hWnd, HWND_TOPMOST, 0&, 0&, 0&, 0&, SWP_NOMOVE Or SWP_NOSIZE

      这里的x、y、cx、cy的值将被忽略。其他值的组合,你可以自己去试试。
      好了,这个看起来好像有点复杂的API已经变得很清晰,那么轮到上一话的收尾。

      WM_NCCALCSIZE消息是在计算窗口的客户区大小时被发送的,它主要是让程序可以收到该消息后重新计算客户区的大小。我们先不管它是不是也能像许多以WM_开头的消息一样由我们发送给程序让它产生作用,但它使用起来的复杂程度让我宁可选择改变窗体大小再改回去。当我们改变窗口的大小时,很明显的就是它一定会重新计算客户区大小以调整外观。既然这个函数可以强制发送WM_NCCALCSIZE消息,那么我们就应该试一试。

    SetWindowPos Me.hwnd, 0&, 0&, 0&, 0&, 0&, SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOMOVE Or SWP_FRAMECHANGED

      为了不改变窗口大小、位置和Z顺序(就是要窗口保持原状),我使用SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOMOVE,让它忽略前面所有的参数,最后加个 Or SWP_FRAMECHANGED 就是让它重新计算客户区大小。把上面的一行放到前一话中更改风格的那一句下面,再执行程序,成功了! 它已经能够正常刷新! 就是这样,问题马上变得这么简单。还有什么疑问吗?没有,好,那么我们下一期再见。

    本文更多内容

  • 2006-12-15 8:42:41
    感悟VB细水长流话API(二)

    感悟VB细水长流话API(二)

    第二话 字符串

      上一期我们已经对API有了大概了解,并学习了第一个API。为了方便以后的学习,我就先讲一点字符串知识和一个相关的API。

      用过VB5.0或者更早版本的读者应该知道VB有一个测试字符串长度的函数: Len。但当你升级到VB6时,会发现这里的Len并没有以前那么好用了——它变成了测试字符个数而不是字符串长度。就是说,当你用以前版本的VB执行Len("字符abc")时,返回值是7,因为中文字符每个有2个字节,所以总共有7个字节;而在VB6中执行,返回值是5。
      VB6不再有一个直接计算出字符串总字节数的函数了,因为VB6内部已经把字符串转换成了Unicode——一种比ANSI更新的字符编码方式。

      Unicode把每一个字,无论是中文还是其他文字都当成两个字节,如果是英文,则这两个字节中第二个字节保留着不使用,如果是双字节字符(如中文,双字节日文以及韩文),而由这两个字节的组合表示一个字符。所以Len可以方便地知道一共有多少个双字节字符,多少个单字节字符,也就出现了上面所说的情况。
      不过既然VB内部把ANSI字符转换成Unicode,那么它一定有对应方法转换回来。所以这里提供一个比较方便的方法来得到总字节数: LenB(StrConv("字符abc", vbFromUnicode))。


      这里用到了一个LenB() 函数,你可以自己试试它,比如 LenB("字符")、LenB("abc")、LenB("字符abc"),会发现返回值分别是4、6和10。
      为什么是4、6和10呢?
      我说过VB内部把ANSI字符转换为Unicode,每个Unicode字符用2个字节来表示,所以,LenB() 的作用是返回字符串的实际字节数。但是,这个实际字节数已经不是我所输入的字符串的,而是被VB转换过的(我们无法让VB函数在转换之前先算好长度),所以我们需要先把字符串转换回来,使用的是 StrConv() 函数。
      对于这个函数我不想太过详细解释它(一般应用中比较少用),你可以参考MSDN,我只提一提它的第二个参数:vbFromUnicode。

      StrConv()函数的第二个函数指定转换的类型,vbFromUnicode 指定把字符串从Unicode转换回来,如果是vbUnicode,则把字符串转换为Unicode。注意,虽然你的程序中写的是ANSI的字符而不是Unicode字符,但当这个函数执行时,它得到的却是已经被转换成为Unicode的字符串了。
      现在问题可以算解决了,但我们还需要另一个解决方法,因为这种方法太费时。想想看,每一次算长度都要进行 Unicode->ANSI 的转换,这将会花费太多时间。对少量字符还可以,对长字符串,时间就变得更长了。
      所以我们再讲一个API:lstrlen。


    Public Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long


      以上是lstrlen的声明。lstrlen的作用只有一个:
      得到字符串的字节数。所以执行 lstrlen("字符abc") 将返回7。我们不需要知道它内部是如何工作的,但它总是返回该字符串是ANSI时的长度,并且速度很快。
  • 2006-12-15 8:42:41
    感悟VB细水长流话API(五-1)

    感悟VB细水长流话API(五-1)

      在前面几期的连载中我们学到了一些有用的API和相关知识,这段时间里有一些读者来信问了一些问题,我发现这些问题大部分都出在很小的错误上,比如变量的声明、API声明的函数名写错等,其实这些都是可以避免的。在一开始我就说明了让VB进行显式声明的重要性,还有API的声明是可以从API浏览器中直接复制的,不要自己去键入,不然容易出现难以发现的错误。

    第六话 窗体和风格

      在Windows中大部分东西都是一个窗口,窗体、菜单、工具栏、状态栏、按钮、文本框……不要觉得奇怪,它们都是窗口——Window(是否从一个侧面说明了这个操作系统为何叫Windows,加了复数的Window)。

      从VB的IDE中你可以更改一个窗体的外观,图1是 IDE中各种外框风格的窗体。

      你可以看到它们有的有边框,有的没有;有的有标题栏,有的没有;有的有最大最小化按钮,有的没有。这些窗体的边框风格都是在窗体被创建时就定下来的。我们在建立VB程序的窗体时,不需要自己写创建窗体的代码,省去了许多重复的工作,但我们也因此失去了解其中秘密的机会。许多情况下窗体风格是在运行时就一直不变的,但有时我们要求在运行时改变,然而,类似BorderStyle等许多设置外观的属性只能在设计时才有效,在这种情况下,我们的这项工作就无法完成。所幸的是,实际上窗体的风格是能够在运行时被改变的,用SetWindowLong,我们就能解决这个问题。

      以前我写过子类的文章,用的也是SetWindowLong,但这次我们不是要用子类,它比子类简单得多。下面给出SetWindowLong的声明:

    Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

      要改变窗体的风格,我们需要用一个常量来使 SetWindowLong知道我们对窗体进行风格设置:GWL_STYLE。

      从API浏览器得到GWL_STYLE的值后,调用时,它是作为第二个参数传递出去的。那么第三个参数呢?这里显得有点复杂,因为它不是一个单一的参数,而是一组参数的组合。

      就如上面我所说的,一个窗体可能有边框,可能有最大最小化按钮,可能有标题栏,但也有可能一部分或全部都没有,如果我们在这里只用一个参数为其设置风格,那么这么多风格就需要一种特殊方法,使该API能够知道我们包含了哪些风格在里面。这就是Or运算。Or运算是把两个数值进行或运算,而微软为了可以方便分离进行Or运算的值,对这些值都精心设计过,因此我们可以放心地将它们组合。如,把 1 和 2 进行Or运算,然后传递给函数,函数会自己分离出 1 和 2,就知道我们传递了 1 和 2 两个值。但有时我们不仅是要组合几个值,而且要把一个组里的某个值去除,所以还需要用另一种方法: And Not(这里的And 不是布尔运算的And,而是位运算的And)。比如把 1 和 2 进行 Or 运算后的值中的 1 去掉,则将其 And Not 1。如果想知道是否含有一个值,可以用And,如 If 64 And 3 Then ……这里只是提供一种方法让你可以使用,如果你想知道它们是如何工作的,我建议你参考位运算的相关书籍。


      我说过窗体、按钮等许多东西都是一种窗口,那么这个函数也就理所当然的是针对所有窗口而设计的了,因此可供设置的风格非常多,并且新风格在新操作系统出现时也可能被增加,这里只能给出大部分最常用的,更多的风格请参考 MSDN的Window Styles部分。

    WS_BORDER:窗口带有一个薄边框

    WS_DLGFRAME:带有一般对话框的风格,但没有标题栏

    WS_CAPTION:窗口带有一个标题栏,经测试,实际上等于 (WS_BORDER Or WS_DLGFRAME)

    WS_SIZEBOX 和 WS_THICKFRAME:窗口带有一个可以调整窗口大小的边框(即VB里的Sizable,其他地方的边框均指不具调整大小功能的边框)

    本文更多内容

  • 2006-12-15 8:42:41
    感悟VB细水长流话API(六-2)

    感悟VB细水长流话API(六-1)

    第九话 寻找子窗口

      这里又是一个特别的例子,图像处理我还会两下,不过这可不是处理来的,而是真实的抓图。我把开始按钮移到这里来了。再看看图6,怎么样?有意思吧?

    这里我要介绍几个API:

    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long


    Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long


    Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long


      首先是FindWindow。FindWindow可以根据所给的条件,从桌面上寻找一个窗口,lpClassName是窗口的类名,而lpWindowName是窗口的标题。我们可以传递lpClassName,让它找符合的类名的窗口,或传递 lpWindowName,让它找符合的标题的窗口,如果我们不需要两个条件都符合,则另一个参数可以传递vbNullString,让它忽略。它的返回值就是找到的窗口的句柄。

      那么什么是类名?避开C++的相关术语来说,其实Windows的窗口都是某种类中的一种,这个“类”可以是Textbox、 Combobox,也可以是由用户来定义的,这个窗口是属于哪一类的,它的类名就是什么。GetWindow也可以用来寻找某个窗口并返回其句柄,但它只限于在某个窗口中寻找子窗口,因此它需要传递hWnd以表示在哪个窗口里寻找。而 wCmd用来描述要找的子窗口与父窗口的关系。它的值如下:

    GW_CHILD:寻找第一个子窗口

    GW_HWNDFIRST:寻找第一个同级窗口,或寻找第一个顶级窗口

    GW_HWNDLAST:寻找最后一个同级窗口,或寻找最后一个顶级窗口

    GW_HWNDNEXT:寻找下一个同级窗口

    GW_HWNDPREV:寻找前一个同级窗口

    GW_OWNER:寻找窗口的所有者(即父窗口)

      我们先来理解什么是同级窗口和顶级窗口。打个比方,如果一个窗口有三个子窗口,则这三个窗口都是同一级的,互为同级窗口。如果我们从没寻找过一个子窗口,那么API 不知道我们要找的是和哪个窗口同级,那么此时它找的是顶级窗口,顶级窗口即是子窗口,但这个子的关系是直接的,而不会是子窗口的子窗口(即孙子,别笑,这里的术语不是我自己造的)。最后一个GetClassName和以前讲过的几个字符串相关的API用法差不多,hWnd是窗口句柄,lpClassName是用来接收窗口类名的缓冲区,nMaxCount则是说明缓冲区的大小。


    那么接下来我是如何用它们的呢?看这里:

    Dim hTaskbar As Long, hStartbutton As Long

    Dim sClass As String * 250


    hTaskbar = FindWindow("Shell_traywnd", vbNullString)

    hStartbutton = GetWindow(hTaskbar, GW_CHILD)


    Do

    GetClassName hStartbutton, sClass, 250

    If LCase(Left$(sClass, 6)) = "button" Then Exit Do

    hStartbutton = GetWindow(hStartbutton, GW_HWNDNEXT)

    Loop


      我使用FindWindow从桌面上找到了一个类名为 “Shell_traywnd”的窗口,它就是任务栏(不要问我是怎么知道它的类名的)。然后我又用GetWindow函数,从任务栏找到第一个子窗口。接下来,我用一个Do…Loop结构的循环为上一次找到的子窗口检查其类名,如果类名是button,则说明是个按钮,一般来说,任务栏上只有一个是button类的,所以一找到,它势必就是“开始”按钮了。如果没找到,则仍使用GetWindow,但这次和第一次不同,我传递的不是任务栏的句柄,而是上一次找到的子窗口的句柄,为的是找下一个同级窗口,就这样一次次循环直到找到开始按钮。

      那么,开始按钮就被我这么找到了,然后我就可以像对待其他窗口一样对待它:比如将它移动。不要忘了上一期所讲的内容,SetWindowPos将在这里产生作用,你可以移动它,或者为最后一个参数组合上SWP_HIDEWINDOW,让开始按钮变得不可见,或者组合SWP_SHOWWINDOW重新显示……

    本文更多内容

  • 2006-12-15 8:42:41
    感悟VB细水长流话API

    出处:电脑爱好者

    编写VB程序时,经常遇到的问题就是VB给我们准备的东西我们会用,控件组装就是一个程序,然而一旦想要实现VB没有直接提供的功能,就会不知所措。其实Windows操作系统本身就给我们准备了许多东西,VB没有的,或许Windows有。我们当然希望少花力气,多得效果。这里要讲的内容就是——学会利用Windows给我们的东西:API。

      然而,学会一种东西是需要付出相当的努力的,API也一样,它可以给我们带来很大的方便,但想要掌握它,就不是使用几个控件那么轻松的事了。所以在看这篇文章时,希望读者可以抱一个正确的态度,就是学习编程不是为好玩,而是为使用; 不要以自己对这方面是否有兴趣而看,而要为API是否能为你的程序带来效果而看。我并不是说一切都是那么严肃和困难,只是API对VB来说,已经可以算高级方面的应用了,所以“认真”和“仔细”是需要的。好了,放松一点,让我们从现在起一步步领略API的好处吧。

      前言

      1.API

      API全称为Application Programming Interface,直译的话可叫它“应用程序接口”。从意义上来说,API是一个操作系统或某个程序本身提供给其他程序使用的函数。在Windows操作系统中,有成千个Windows的函数提供给应用程序使用,本文所说的API,就是指这些函数。

      2.VB与API

      之所以写这篇文章(而不写VC或其他语言),是因为VB对API的支持不是直接的,而且是不完全的; 在使用上,Windows的API编写时是假设调用者是C或C++语言,因此VB调用API不是很方便,也经常有不必要的错误或不明白如何使用的情况出现。本文的对象主要还是对API没有很深研究的读者,如果你不想了解太多细节,你可以把一个合适的函数用法搬过去,或者你完全不知道API,或者只知道少数,对许多函数还不清楚如何使用,或者你希望可以从本文学到更多使用API的技巧甚至VB的技巧(但愿我可以让你学到),我想你都应该看这篇文章。但还是有个大前提,你必须是已经会使用VB的读者,因为以后讲到的内容不会有一个完整工程从头到尾教你做,有可能是一段简短的声明与调用代码,也可能是几个函数的组合,如果必要的话,也会讲述相关内容的VB技巧,但一定不会有完整的实例示范。

      3.本文原则和约定

      由于API中有的用法简单有的复杂,有的可单独使用有的却不行,加上各个API的主要用途不同,很难判断先说哪个再说哪个可以让人更容易理解,因此本文尽量从比较常用的说起,从可以对程序产生较大作用的说起。为了能让多数人理解,如果需要涉及到其他方面的知识,也将尽量讲述,让读者可以学到使用API的知识,并能够利用本文中的知识应付新的API。如果你对某个API有什么疑问,欢迎来信(webmaster@neocactus.com),但由于时间有限,不能对来信一一回复,如果有需要,将会在文中讲述。

    基础知识

      在讲API之前,让我先讲解一些与API相关的VB基础知识,后文如有涉及将不再详述。此处未提及的,将在本文中第一次接触时再做解释。

      1.自定义类型

      VB中可以使用Type关键字将已有的数据类型进行组合,成为一个新的类型,该类型就称为用户自定义类型。如:

    Type NewType
    sName As String
    lNumber As Long
    End Type

      定义了一个名为NewType的自定义类型。以后可以用Dim MyType As NewType来定义一个NewType类型的变量。

      sName As String类型的变量有两种,一种是变长,即运行时的字符串长度是可变的,另一种是定长,运行时字符串的长度是固定的。平常我们定义一个字符串变量: Dim strA As String 即定义了一个变长的字符串,但在使用API时经常要用到定长的字符串,应该这样定义: Dim strB As String * 30,即定义了一个可容纳30个字节字符的变量。

      2.声明

      VB中使用API之前,需要先对API进行声明,声明的方法是使用Declare关键字,如:
    Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

    本文更多内容

  • 2005-8-7 20:53:00
    利用API创建文件目录

    Private Declare Function CreateDirectory Lib "kernel32" Alias "CreateDirectoryA" (ByVal lpPathName As String, lpSecurityAttributes As SECURITY_ATTRIBUTES) As Long

    Private Type SECURITY_ATTRIBUTES
    nLength As Long
    lpSecurityDescriptor As Long
    bInheritHandle As Long
    End Type

    Sub Main()  

    在C盘创建了"VB API"目录
    Call CreateNewDirectory("C:\VB API")
    MsgBox "在C盘创建了 VB API 目录"



    End Sub

    Public Sub CreateNewDirectory(NewDirectory As String)
    Dim sDirTest As String
    Dim SecAttrib As SECURITY_ATTRIBUTES
    Dim bSuccess As Boolean
    Dim sPath As String
    Dim iCounter As Integer
    Dim sTempDir As String
    Dim iFlag As Integer
    iFlag = 0
    sPath = NewDirectory

    If Right(sPath, Len(sPath)) <> "\" Then
    sPath = sPath & "\"
    End If

    iCounter = 1
    Do Until InStr(iCounter, sPath, "\") = 0
    iCounter = InStr(iCounter, sPath, "\")
    sTempDir = Left(sPath, iCounter)
    sDirTest = Dir(sTempDir)
    iCounter = iCounter + 1  

    创建目录

    SecAttrib.lpSecurityDescriptor = &O0
    SecAttrib.bInheritHandle = False
    SecAttrib.nLength = Len(SecAttrib)
    bSuccess = CreateDirectory(sTempDir, SecAttrib)
    Loop
    End Sub

  • 2005-8-7 20:53:00
    ShellExecute API应用整理

    作者: yanek

    1.  执行“打开“,“查找“,“资源管理器“和”打印“
    必要的声明:
    ' nShowCmd
    Public Const SW_HIDE = 0
    Public Const SW_SHOWNORMAL = 1
    Public Const SW_SHOWMINIMIZED = 2
    Public Const SW_SHOWMAXIMIZED = 3
    Public Const SW_MAXIMIZE = 3
    Public Const SW_SHOWNOACTIVATE = 4
    Public Const SW_SHOW = 5
    Public Const SW_MINIMIZE = 6
    Public Const SW_SHOWMINNOACTIVE = 7
    Public Const SW_SHOWNA = 8
    Public Const SW_RESTORE = 9

    ' Error Code
    Public Const ERROR_FILE_NOT_FOUND = 2
    Public Const ERROR_PATH_NOT_FOUND = 3
    Public Const ERROR_BAD_FORMAT = 11

    Public Const SE_ERR_FNF = 2
    Public Const SE_ERR_PNF = 3
    Public Const SE_ERR_ACCESSDENIED = 5
    Public Const SE_ERR_OOM = 8
    Public Const SE_ERR_SHARE = 26
    Public Const SE_ERR_ASSOCINCOMPLETE = 27
    Public Const SE_ERR_DDETIMEOUT = 28
    Public Const SE_ERR_DDEFAIL = 29
    Public Const SE_ERR_DDEBUSY = 30
    Public Const SE_ERR_NOASSOC = 31
    Public Const SE_ERR_DLLNOTFOUND = 32

    Public Declare Function ShellExecute Lib "shell32.dll" _
        Alias "ShellExecuteA" _
        (ByVal hwnd As Long, _
        ByVal lpOperation As String, _
        ByVal lpFile As String, _
        ByVal lpParameters As String, _
        ByVal lpDirectory As String, _
        ByVal nShowCmd As Long) As Long



    “打开“操作
                ShellExecute Me.hwnd, "open", _
                        Text1.Text, _
                        vbNullString, vbNullString, _
                        SW_SHOWNORMAL


    “查找“操作
            ShellExecute Me.hwnd, "find", _
                    LocalDir, _
                    vbNullString, vbNullString, _
                    SW_SHOWNORMAL


    “打印“操作
                ShellExecute Me.hwnd, "print", _
                        Text1.Text, _
                        vbNullString, vbNullString, _
                        SW_SHOWNORMAL


    “资源管理器“
            ShellExecute Me.hwnd, "explore", _
                    LocalDir, _
                    vbNullString, vbNullString, _

    本文更多内容

  • 2005-8-7 20:53:00
    VB中调用Windows API函数检测当前系统环境

    杨洪勇

    (山东农业大学)


    摘要 本文介绍了在Visual Basic中用 Declare语句声明所要调用的Windows API的方法,以及如何调用API函数来检测当前的系统环境。用Visual Basic能够直接控制和处理计算机的系统参数和硬件资源,增加了程序设计人员在Windows环境中开发软件的灵活性,使软件与Windows系统达到了最完美的结合。本文最后给出了一个调用的Windows API的检测系统环境实例。
    关键字 Visual Basic Declare 语句 Windows API函数 系统

    前言
    Visual Basic是一个Windows系统下的应用程序开发平台。方便的界面设计、强大的扩充能力使程序员能节省大量时间,把主要精力集中在应用程序核心代码的编写上。Visual Basic目前已成为Windows系统下一种高效灵活的开发工具,而调用API(Application Program Interface,应用程序接口)函数正是对Visual Basic功能的强有力扩充,它使得Visual Basic能够直接控制和处理计算机的系统参数和硬件资源。借助于API使得Visual Basic能克服Windows编程的难点,同时又增加供了使用Windows环境的灵活性。
    利用Visual Basic调用API函数的方法:
    (1)用Declare语句声明所要调用的API函数,若该函数无返回值,可声明为Sub过程;若有返回值,则可声明为Function函数。
    (2)一旦声明了某一个API函数后,就可以象调用Visual Basic的函数一样。但如果参数传递不对,可能会导致死机。

    一、检测系统参数的API函数
    检测系统环境的参数所需要的Windows API函数有GetWindowsDirectory,GetWinFlags,GetVersion,GetKeyboardType等,具体的使用方法见下面声明。
    1.GetWinflags声明
    Declare Function GetWinflags Lib "kernel32" () As Long
    功能:该函数返回Windows运行系统上的系统配置。

    返回标志值
    含意
    WF_80X87
    Intel数字协处理器
    WF_CPU386
    80386 CPU
    WF_CPU486
    80486 CPU
    WF_ENHANCED
    Windows 系统运行在386增强模式
    WF_PMODE
    Windows 系统运行在保护模式
    WF_STANDARD
    Windows 系统运行在标准模式
    WF_WLO
    运行在OS/2下

    2.GetKeyboardType声明
    Declare Function GetKeyboardType Lib "user32" (ByVal nTypeFlag As Long) As Long
    功能:该函数得到系统键盘类型,nTypeFlag=0时返回键盘类型。

    返回值
    含意
    1
    IBM PC/XT 或兼容键盘
    2
    Olivetti "ICO" 键盘(102个键)
    3
    IBM 或兼容键盘(84个键)
    4
    IBM 增强型或相似键盘(101或102个键)
    5
    Nokia1050或相似键盘
    6
    Nokia9140或相似键盘
    7
    日本键盘

    3.GetWindowsDirectory声明
    Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
    功能:该函数获取Windows目录的路径。  

    4.GetVersion声明
    Declare Function GetVersion Lib "kernel32" () As Long
    功能:该函数返回当前Windows版本号和DOS版本号。返回值的低位字节说明Windows主版本号,返回值的低位字的高位字节说明Windows副版本号,高位字的低位字节说明DOS副版本号,高位字的高位字节说明DOS主版本号。

    5.GetSystemDirectory声明
    Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA"
    (ByVal lpBuffer As String, ByVal nSize As Long) As Long
    功能:该函数获取Windows系统子目录的路径。

    二、检测系统参数程序实例
    有了上面对所需Windows API函数的声明以后,就可以使用这些API函数,编写下面的用户自定义函数。
    1.检测系统子目录函数
    Function WinDir()
    Temp = Space$(255)
    StringLen = GetWindowsDirectory(Temp, 255)
    WinDir = Left$(Temp, StringLen)
    End Function

    2.检测系统键盘函数
    Function KeyType()
    KbType = GetKeyboardType(0)
    Select Case KbType
    Case 1
    KeyType="IBM PC\XT,or compatible"
    Case 2
    KeyType="Olivetti 'ICO'(102key)"
    Case 3

    本文更多内容

  • 2005-8-7 20:53:00
    Win32 API 注册表类的编制以及使用

    一、问题的提出
    Windows 已由原来的16位 windows 3.x 升级为现今我们使用的32位windows 95/97/98 以其 Windows NT,用户不仅在使用上应逐步适应,对于程序开发人员来说在编程技术上也应紧跟操作系统的技术发展,就如同 在 Linux 操作系统下, X-Window 编程就显得很重要一样。作为一个完整成熟的 Windows 程序,需要保存程序所有的环境变量和私有信息。诸如用户的偏好,文件装入的列表、退出时用户使用的窗口位置 .存盘历史纪录等。过去在 windows 3.x时代 ,常用 Win16函数 Get/RegWrite ProfileString 将有关程序的信息写入 *.ini 文件,但现在该项技术由 Win32注册表所替代。
    可以这样说,注册表是当今32位 Windows 操作系统的灵魂,一切信息都在其中,也就是为什么Windows98在Windows95的基础上升级可以不重装软件等等的如此方便的应用,其原理就是根据了原注册表中的信息来完成各种方便的处理,所以Windows注册表对应用程序的重要性就显而易见了。
    原来的 Win16程序存储私有信息是在一个平面文件INI中,这样做有很多弊端,例如该INI文件没有任何安全机制,用户可以直接在INI文件中修改各种参数和程序入口,这样就可能造成不可估计的严重后果,还有该文件只能支持和文本数据不能存入二进制数据等各种不利因素,所以微软的工程师也认识到这一点,于是注册数据库就诞生了,注册数据库就是为了解决在 Windows 3.x 的一些关于 OLE 的此类问题而创建的,现在 Win32 应用程序的注册数据库通过微软带给我们的新的 Win32 API 得到了显着的改善。使用访问注册表的 Win32 函数比起使用管理 INI 文件的 Win16函数要灵活的多,这意味着在功能上将大大增强,但是,另一方面,如果你还未用过,就会对处理注册表的Win32 API 的新规则感到困惑或不知所措。本文就是本着这一目的,逐步让你懂得并掌握怎样用 Win32API 函数来处理32位 Windows 程序注册表的方法。



    二 . 技术的实现原理

    为了在以后自己编写的程序中更多的体现模块化思想以及使编程变得更加简单,应尽可能的建立自己实现各种功能的类,以类作为实现应用程序各种功能的单位。 在此,可以创建一个包括注册表许多常用功能而接口简单的类库,下面将建立 CMyRegKey类,对应用程序处理注册表的具体细节进行封装,从而在外部通过这个功能类方便地实现进行访问注册表信息的各种操作,在外部调用其成员函数即可。以后,你就可以在每一个应用程序中包含此类并用其外部接口进行编程了。

    三 . 实现代码与步骤



    1. 建立功能类的头文件:

    创建一个新的头文件 MyRegKey.h ,在其中加入以下的代码。



    #include "winreg.h"

    // 包含头文件 winreg.h , 因注册表Win32 API 函数在其内定义

    // 建立 CMyRegKey 类:
    class CMyRegKey
    {


    // Construction
    public:
    CMyRegKey();
    virtual ~CMyRegKey ();

    // Attributes
    public:

    // 定义打开和关闭注册表的成员函数:

    LONG RegRegOpen(HKEY hKeyRoot,LPCTSTR pszPath);
    void RegRegClose();

    // 利用函数重载实现对注册表键值(串值,二进制值,DWORD值 ) 的读和写:

    LONG RegRead (LPCTSTR pszKey,DWORD& dwVal);
    LONG RegRead (LPCTSTR pszKey,CString& sVal);
    LONG RegRead (LPCTSTR pszKey,BYTE *pData,DWORD& dwLength);

    LONG RegWrite (LPCTSTR pszKey,DWORD dwVal);
    LONG RegWrite (LPCTSTR pszKey,LPCTSTR pszVal);
    LONG RegWrite (LPCTSTR pszKey,const BYTE *pData,DWORD dwLength);

    protected:
    HKEY m_hKey;
    CString m_sPath;
    };

    2. 建立功能类的Cpp文件定义 CMyRegKey类:

    创建一个新文件 MyRegKey.cpp ,代码如下:


    #include "MyRegKey.h"

    /////////////////////////////////////////////////////////////////////////////
    // CMyRegKey

    本文更多内容

  • 2005-8-7 20:52:00
    用API函数实现Windows颜色渐变

    文/方建文

      用API函数实现颜色渐变

      方建文

      颜色渐变在Windows应用程序中应用广泛,最典型的是窗口标体的背景色及Windows安装窗口的背景色等。本文就这种颜色渐变的实现,提供API函数的实现方法。

      
      在Windows 98或Windows NT 5.0及更高版本中提供了一个新的API函数来实现渐变颜色的填充,这个函数就是GradientFill。这个函数不仅能实现方形的填充,还能实现三角形的填充,所以这种方法更有效率。API声明如下:

      Public Declare Function GradientFillTriangle Lib "msimg32" Alias "GradientFill" (ByVal hDC As Long, pVertex As TRIVERTEX, ByVal dwNumVertex As Long, pMesh As GRADIENT_TRIANGLE, ByVal dwNumMesh As Long, ByVal dwMode As Long) As Long

      Public Declare Function GradientFillRect Lib "msimg32" Alias "GradientFill" (ByVal hDC As Long, pVertex As TRIVERTEX, ByVal dwNumVertex As Long, pMesh As GRADIENT_RECT, ByVal dwNumMesh As Long, ByVal dwMode As Long) As Long

      其中GradientFillTriangle用于三角形的填充,GradientFillRect用于矩形填充。hDC是表示要填充对象的窗口句柄;pVertex常常是一个数组,用来存放各顶点的位置及颜色信息,顶点在TRIVERTEX中定义;dwNumVertex表示顶点的个数;pMesh也常常是一个数组结构,表示组成图形的各顶点顺序,表示一个矩形用两个顶点,三角形要用三个顶点;dwNumMesh表示矩形或三角形的个数;dwMode表示填充的模式:水平填充,垂直填充,三角形填充。以下是示例程序:

      在这个示例里您可以任意选择两种颜色,然后用两种颜色对一个Picture1进行渐变的填充。

      包含的部件

      Form1—AutoRedraw:True

      Picture1---Align:1—Align Top

      Frame1----Caption:渐变模式

      Option1—Caption:由上到下

      Value:True

      Option2---Caption:由左到右

      Label1(0)---Caption:颜色1

      Command1(0)—Style:1—Graphical

      Label1(1)---Caption:颜色2

      Command1(1)—Style:1—Graphical

      CommonDialog1--(Microsoft CommonDialog Control6.0)用于选择颜色

      Command2----Caption:填充

      代码模块Module1中的代码

      Option Explicit

      Public Const GRADIENT_FILL_RECT_H = &&H0

      Public Const GRADIENT_FILL_RECT_V = &&H1

      Public Const GRADIENT_FILL_TRIANGLE = &&H2‘以上为三种填充模式

      Public Type GRADIENT_TRIANGLE

      Vertex1 As Long

      Vertex2 As Long

      Vertex3 As Long

      End Type

      Public Type GRADIENT_RECT

      UpperLeft As Long

      LowerRight As Long

      End Type

      Public Type TRIVERTEX‘顶点类型

      x As Long

      y As Long

      Red As Integer

      Green As Integer

      Blue As Integer

      Alpha As Integer

      End Type

      Public Declare Function GradientFillTriangle Lib "msimg32" Alias "GradientFill" (ByVal hDC As Long, pVertex As TRIVERTEX, ByVal dwNumVertex As Long, pMesh As GRADIENT_TRIANGLE, ByVal dwNumMesh As Long, ByVal dwMode As Long) As Long

      Public Declare Function GradientFillRect Lib "msimg32" Alias "GradientFill" (ByVal hDC As Long, pVertex As TRIVERTEX, ByVal dwNumVertex As Long, pMesh As GRADIENT_RECT, ByVal dwNumMesh As Long, ByVal dwMode As Long) As Long

      Public Function UIntToInt(UInt As Long) As Integer‘类型转换

      If UInt<&&H7FFF Then

      UIntToInt = CInt(UInt)

      Else

      UIntToInt = CInt(UInt - &&H10000)

      End If

      End Function

      Public Function Color16(Clr As Byte) As Integer

    本文更多内容

  • 2005-8-7 20:52:00
    用Windows API取得窗体句柄二例

      文/胡克

      Windows通过句柄(Handle)识别每个窗体、控件、菜单和菜单项,当程序运行时,它所包含的每个部件都有一个惟一确定的句柄同其他的部件相区别句柄在Windows API中具有举足轻重的作用,现举三例,有兴趣的读者不妨一试。

      获取窗体和控件的句柄

      
      步骤如下:

      1、为了看到显示于屏幕上所有的窗体和控件的句柄,用SetWindowPos函数设置窗口始终在最上面,其他窗口不能覆盖它,并使其只以标题显示于屏幕左上角。

      (1)新建一工程,打开API Viwer:Add-ins→API Viewer→File→Load text file→Win32api.txt。

      (2)将SetWindowPos函数的声明粘贴到窗体的声明部分:Private Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long。

      (3)程序启动时调用SetWindowPos函数,窗体Load事件代码如下:

      Private Sub Form_Load()

      SetWindowPos Me.hwnd, -1, 0, 0, 0, 0, conSwpNoActivate Or conSwpShowWindow'使窗体一直置于最顶层

      End Sub

      卧龙传说提醒:当第二个参数hWndInsertAfter的值为-1时置于顶层;值为-2时不置于顶层。

      2、为了找到鼠标指针的X和Y坐标,用上面同样的方法,通过API Viewer工具把获取的鼠标指针位置的API函数GetCursorPos的声明和结构类型声明粘贴到窗体的声明部分:

      Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long

      Private Type POINTAPI

       x As Long

       y As Long

      3、用API Viewer把指定点的窗口的句柄的API函数WindowFromPointXY的声明粘贴到窗体的声明部分:

      Private Declare Function WindowFromPointXY Lib "user32" Alias

      "WindowFromPoint" (ByVal xPoint As Long, ByVal yPoint As Long) As Long

      4、在窗体上添加timer控件,并把Interval属性设为500(毫秒),用如下的Timer事件完成操作:

      Private Sub Timer1_Timer()

      Dim xy As POINTAPI'(声明变量类型)

      GetCursorPos xy'(取得XY的座标)

      ahwnd = WindowFromPointXY(xy.x, xy.y) '(取得当前鼠标坐标下窗口的句柄)

      Me.Caption = ahwnd'(在标题栏显示当前坐标下窗口的句柄)

      End Sub

      获取激活窗口的句柄

      用GetFocus函数可获得激活窗口(拥有输入焦点的窗口)的句柄。

      1、用API Viewer工具将函数GetFocus的声明粘贴到窗体的声明部分:

      Private Declare Function GetFocus Lib "user32" Alias "GetFocus" () As Long

      2、新建一工程,添加两个文本框text1和text2,两个文本框控件的GotFocus事件代码如下:

      Sub Text1_GotFocus()

       h&& = GetFocus&&()

       Debug.Print h&&(在立即窗口显示当前窗口句柄)

      End Sub

      Private Sub Text2_GotFocus()

       h&& = GetFocus&&()

      Debug.Print h&

      End Sub

  • 2005-8-7 20:52:00
    一种调用Win95 API实现串行通信的查询方法

         摘要 在Win95中,串行通信的机制相对Windows 3.x已作了改进和标准化。本文结合一个实例从调用API接口的角度,具体阐述了一种用简单的串口查询法来实现串行通信的思路。

    关键词 API、串行通信、Visual Basic、多线程、Win95

    Visual Basic是一个Windows系统下流行的应用程序开发平台。其方便的界面设计使程序员能节省大量时间,并把最大的精力集中在应用程序核心代码的编写上。VB4目前已成为Win95系统下一种最高效灵活的主流开发工具之一,而调用API应用程序接口则正是对VB4功能的强有力扩充,它使得VB4能够直接控制和处理PC硬件资源,而不必依赖于MS-DOS系统服务。可以说,正是借助于API使得VB即能隐藏大部分Windows编程的难点,同时又提供了使用Windows环境的灵活性。

    因而在串行通信中使用调用API接口的方法是实现在VB中直接控制串行口硬件的简便可行的解决方案。

    一、关于Win95的多线程及32位API的描述

    微软于95年推出的Win95操作系统是对其旧版本Windows性能的一次全面提升。它率先提出并实现了应用程序多线程的编程思想,这是Win95系统区别于其他系统最显着和最重要的特征之一。进程是应用程序的执行实例,而线程则是进程内部执行的路径,从根本上说,线程是可由系统调度的一个最简单的代码单元,每个线程有自己的一组CPU寄存器和堆栈。Win95为每个独立的线程安排一些CPU时间,操作系统以轮转方式向线程提供时间片,这样每个线程从外观上看就象都在同时运行一样。一个多线程的应用程序实际上在其内部实现了多任务扩展,为代码赋予了并行执行的特性。

    多线程应用程序的主要优势就是可以用尽量少的时间对用户的要求作出响应。多线程并不代表代码会运行得更快,准确地说,它仅仅意味着应用程序可以更好地利用系统资源(调度机制、内存和物理设备)。从而能建立一个非常灵活的应用程序,它能随时接收用户输入,并得到满意的效果。

    因此为了在32位的Win95系统中建立更快速、可靠和健壮的代码,多线程技术是必须掌握的关键技术之一。

    API(即应用编程接口)是附带在Win95内部的一个极其重要的组成部分。Win95的32位API主要是一系列很复杂的函数、消息的集合。它可以看作是Win95系统为在其下运行的各种开发系统提供的开放式通用功能增强接口。它使编程人员可以更容易地用不同类型的语言编制出运行在Win95系统上的应用程序。

    与Windows 3.x的16位API相比,附带在Win95中的Win32 API是API质量最显着的一次提升。它正逐渐成为应用广泛的一种目标平台。Win32 API包括了1000多个API调用,加上API附带的几百种Windows常量、消息和数据类型结构,使用户拥有了一系列用于Win95编程的复杂的而又有效的工具。

    API接口是对VB功能的最重要的扩充。几乎所有用VB的标准功能不能处理的问题都可以用调用API接口函数的方法来解决。API接口调用不仅给VB提供了大量可扩充的功能强劲的函数。更为重要的是,它提供了一种最切实地扩充VB功能的思路和方法。尤其在一些直接和硬件交互的低级操作中,调用API接口函数往往是唯一的可行办法。

    总之,调用API接口并结合多线程的编程技术已成了Win95环境下最流行的一种高级技术。大多数应用程序的代码都不得不涉及到这个高级专题。

    二、Win95串行通信的工作机理

    常用的DOS系统主要是工作在响应中断方式。PC机串行通信程序大多利用其BIOS块的INT14H中断,以查询串口的方式完成异步串行通信。

    与DOS响应中断的工作方式不同,Windows是一个事件驱动的,并与设备无关的多用户操作系统。同时Windows禁止应用程序直接和硬件交互,程序员只能通过Windows提供的各类驱动程序来管理硬件。在这种情况下,Windows系统充当了应用程序与硬件之间的中介。

    Windows系统函数即包含了通信支持中断功能。Win95系统为每个通信设备开辟了用户定义的输入输出缓冲区(即读/写缓冲区),数据进出通信口均由系统后台来完成。应用程序只需完成对输入输出缓冲区操作就可以了。实际过程是每接收一个字符就产生一个低级硬件中断,Win95系统中的串行驱动程序就取得了控制权,并将接收到的字符放入输入数据缓冲区。然后将控制权返还正在运行的应用程序。如果输入缓冲区数据已满,串行驱动程序用当前定义的流控制机制通知发送方停止发送数据。队列中的数据按“先进先出”的次序处理。

    本文更多内容

  • 2005-8-7 20:52:00
    用api调用chm格式的帮助文件

    HtmlHelp函数VB声明如下(API浏览器中没有,我自己照VC的声明改的):

    Private Declare Function HtmlHelpA Lib "hhctrl.ocx" (ByVal hwndCaller As Long, ByVal pszFile As String, ByVal uCommand As Long, ByVal dwData As Long) As Long

    hwndCaller指出调用者的窗口,pszFile指出要调用的文件,uCommand是发送给
    HtmlHelp的命令,dwData是uCommand的参数。

    这个函数位于system\hhctrl.ocx中,你安装了IE4以上版本浏览器就应该有

    调用举例: HtmlHelpA Form1.hWnd, "C:\WINDOWS\HELP\CALC.CHM", 0, 0 这个是
    最简单的例子,uCommand和dwData的组合能产生许多非常复杂的功能具体情况可
    查找MSDN:HTMLHelp API Reference主题

    函数的C语言原型和所用到的结构和常量定义参见HTML Help Workshop\include\
    htmlhelp.h 当然你必须先安装了Html Help Workshop

    hhctrl.ocx文件虽然后缀是OCX却不是控件,而是一个标准的DLL

    林夕:

    我有点不明白,VB中好象可以直接调用*.chm嘛,如下例,有什么不妥吗?请各位
    大虾指正。

    Private Sub Form_Load()
    App.HelpFile = "c:\a\a.chm" 注释:如不指明路径,默认为Windows目录下的Help
    Me.HelpContextID = 10001
    End Sub Private

    Sub Command1_Click()
    SendKeys "{F1}" 注释:按F1键,系统自动调用帮助
    End Sub

    hmg:

    我用一个小程序试验了一下

    form_load()
    app.helpfile="c:\1.chm" 注释:文件名是1.chm
    end sub

    ......._click()
    cd1.helpfile="c:\1.hlp" 注释:cd1是公用对话框,我故意写成1.hlp
    cd1.helpcommand=&h3
    cd1.showhelp
    end
    以上程序居然能成功,莫名其妙可是在我的大程序里,就不那末顺利,奇怪?

    一个偶然的机会我发现 windows目录下的hh.exe可以调用chm的帮助,因此我想到可
    以用shell语句, .........
    shell "hh.exe 1.chm,.......
    ..........

    hh.exe可以拷到任一目录下执行. 

  • 2005-8-7 20:52:00
    在VB中调用API函数动态改变及恢复屏幕设置

    作者:王志红

    对于Windows平台,显示器的分辩率和颜色数很重要,尤其是对于多媒体应用软件和游戏软件。但许多情况下,用户当前的屏幕设置并不适合软件的运行需要。软件通常的做法是提示用户将屏幕设置到软件要求的分辩率及颜色数,再重新启动软件。这样无疑会增加普通用户操作上的负担和困难,降低了软件的友好性和易用性。
    ---- 理想的作法是:在软件开始时,动态的改变屏幕设置来达到软件运行的要求。在软件运行结束后,再自动把屏幕设置改回原来的设置值。这一切过程都在不知不觉中完成。这一做法可以通过在VB中调用API(应用程序接口)函数做到。实现方法如下:

    ---- 一、打开一个标准的EXE工程。

    ---- 二、在“工程”菜单栏下,选取“添加模块”,为工程添加一个模块。

    ---- 并在模块中添加如下代码:

    ‘---------------以下代码用于得到屏幕的设置参数--------------
    Declare Function GetDeviceCaps Lib
    "gdi32" (ByVal hdc As Long,
    ByVal nIndex As Long) As Long
    ‘取指定设备信息API函数
    Public Const HORZRES = 8
    ‘三个屏幕常量
    Public Const VHORZRES = 10
    Public Const BITSPIXEL = 12
    ‘---------------通过字符COPY进行数据类型转换--------------
    Private Declare Function lstrcpy Lib "kernel32"
    Alias "lstrcpyA" (lpString1 As Any, lpString2 As Any) As Long
    ‘------------------以下结构用于屏幕的初始化-----------------
    Const CCHDEVICENAME = 32
    Const CCHFORMNAME = 32

    Private Type DEVMODE
    dmDeviceName As String * CCHDEVICENAME
    dmSpecVersion As Integer
    dmDriverVersion As Integer
    dmSize As Integer
    dmDriverExtra As Integer
    dmFields As Long
    dmOrientation As Integer
    dmPaperSize As Integer
    dmPaperLength As Integer
    dmPaperWidth As Integer
    dmScale As Integer
    dmCopies As Integer
    dmDefaultSource As Integer
    dmPrintQuality As Integer
    dmColor As Integer
    dmDuplex As Integer
    dmYResolution As Integer
    dmTTOption As Integer
    dmCollate As Integer
    dmFormName As String * CCHFORMNAME
    dmUnusedPadding As Integer
    dmBitsPerPel As Integer
    dmPelsWidth As Long
    dmPelsHeight As Long
    dmDisplayFlags As Long
    dmDisplayFrequency As Long
    End Type
    ‘------------------设置屏幕的核心API-----------------
    Private Declare Function ChangeDisplaySettings
    Lib "User32" Alias "ChangeDisplaySettingsA"
    (ByVal lpDevMode As Long, ByVal dwflags As Long) As Long
    ‘------------------设置屏幕的函数-----------------
    Public Function SetDispMode(Width As Integer,
    Height As Integer, Color As Integer) As Long
    (SetDispMode是自己构造的更改屏幕设置的函数来,
    它的三个参数Width、Height和Color分别是屏幕的横向分辨率、
    纵向分辨率,颜色位数,其值可为24,16,0等。0为原有颜色设置。)
    Const DM_PELSWIDTH = &H80000
    Const DM_PELSHEIGHT = &H100000
    Const DM_BITSPERPEL = &H40000
    Dim NewDevMode As DEVMODE
    Dim pDevmode As Long
    With NewDevMode
    .dmSize = 122
    If Color = 0 Then
    ‘如果Color=0则只改变屏幕的分辨率,而不改变色彩。
    .dmFields = DM_PELSWIDTH Or DM_PELSHEIGHT
    Else
    ‘如果Color不等0则改变屏幕的分辨率和色彩。
    .dmFields = DM_PELSWIDTH Or DM_PELSHEIGHT Or DM_BITSPERPEL
    End If
    .dmPelsWidth = Width
    .dmPelsHeight = Height
    If Color < > 0 Then
    .dmBitsPerPel = Color
    End If
    End With
    pDevmode = lstrcpy(NewDevMode, NewDevMode)
    ‘得到一个指向NewDevMode结构的Long型的指针。
    ChangeDisplaySettings pDevmode, 0
    End Function

    ---- 三、在工程窗体中,加入两个按钮Command1和Command2,其Caption属性分别为“800x600x16”和“恢复原设置”。

    本文更多内容

  • 2005-8-7 20:52:00
    API实现完美的图片出现效果

    作者:罗玉强

    在用Visual Basic编程的时候,通常要调用图片,如果图片出现的时候是以各种完美的效果出现的,(如马赛克效果,百叶窗效果等)则你的程序就会显得更加灵活,你的程序就会更加专业化。本文讲述了Visual Basic中如何调用API函数,以及用API函数中的BitBlt函数实现各种完美的图片出现效果的过程。

    §1 一般的图片出现效果

      一般情况下,要使Visual Basic中的图片出现,例如,要显示Picture1中的图片,只需一句代码:

    Picture1.Visible=True

      使用以上方法时,图片是突然出现的。也可以编复杂一点的代码,使图片从左到右、从上到下或从中间向四周扩大。例如,使Picture1中的图片从左到右出现,其代码为:

    Picture1.Width = 0

    Picture1.Visible = True

    For i = 0 To 5000 Step 50 注释:5000代表图片的高度

    Picture1.Width = i

    Next i

    使Picture1中的图片从上到下出现的代码为:

    Picture1.Height = 0

    Picture1.Visible = True

    For i = 0 To 4000 Step 40 注释:4000代表图片的宽度

    Picture1.Height = i

    Next i

    使Picture1中的图片从中间向四周扩大的代码为:

    Picture1.Width = 0

    Picture1.Height = 0

    Picture1.Visible = True

    For i = 0 To 100

    Picture1.Width = Picture1.Width + 50

    Picture1.Height = Picture1.Height + 40

    Picture1.Left = Picture1.Left - 100

    Picture1.Top = Picture1.Top - 80

    Next i

      当然,你可以灵活地应用以上办法实现其他更加好看的图片出现效果。然而,同Authorware等其他软件编制的程序相比,你的图片出现效果仍然会黯然失色,因为Authorware编程时,可以很容易地实现从上到下、从左到右、百叶窗、开门、关门等完美的图片出现效果,要在Visual Basic中做到这些效果并非易事。

    但“天无绝人之路”,强大的Windows API函数中的BitBlt函数将帮助您实现这一愿望。

    §2 BitBlt函数

    一、 BitBlt函数的功能

    BitBlt API函数的功能是将屏幕上任何一块拷贝到屏幕上其它任何一个地方。

    二、 声明BitBlt函数

    1. 运行Visual Basic4.0程序组中的API Text Viewer程序项。
    2. 在API Text Viewer中,单击File菜单下的Load Text File...命令。

    3. 在出现的Select a Text API File对话框中,选择Win32api.txt文件。

    4. 为了使以后拷贝Windows API函数更快,你可以将Win32api.txt文件转换成为一个数据库。如图,单击“是(Y)”。

    5. 在API Type下拉框中选择Declare。

    6. 在Available Items中选择BitBlt,如图,单击Add按纽,于是BitBlt便出现在Selected Items框中,单击Copy按纽。BitBlt函数变拷贝到剪贴板上。

    7. 关闭API Text Viewer,打开Visual Basic程序,使用Insert菜单下的Module命令新建一个Module1,使用Edit菜单下的Paste命令,将剪贴板上的BitBlt函数拷贝到Module1中。这样,在您的程序中,就可以使用BitBlt函数了。

    三、BitBlt函数中各参数简介

    Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

      以上是BitBlt函数的声明格式,其中,各参数定义如下:

    参数

    描述

    hDestDC

    接收位图的设备描述表

    X

    目标矩形左上角的逻辑X坐标

    Y

    目标矩形左上角的逻辑Y坐标

    nWidth

    目标矩形的宽度

    nHeight

    目标矩形的高度

    hSrcDC

    源设备描述表

    xSrc

    源位图左上角的逻辑X坐标

    ySrc

    源位图左上角的逻辑Y坐标

    dwRop

    拷贝模式

    dwRop的各种可能值为:

    &HCC0020

    dest=source

    &HEE0086

    dest=source OR dest

    &H8800C6

    dest=source AND dest

    &H660046

    dest=source XOR dest

    &H440328

    dest=source AND (NOT dest)

    本文更多内容

  • 2005-8-7 20:52:00
    用Visual Basic 5.0设计E-mail程序(MAPI)

    前言
    随着计算机网络的发展,人与人之间信息传输的时间大为缩短。许多文件都是以电子邮件的形式来传送;通常使用过计算机的人,或多或少都会用到E-Mail来传输信息。本文将介绍如何用Microsoft MAPI (Messaging Application ProgramInterface)来设计Mail程序。首先用Visual Basic所提供的MAPISession control及MAPIMessage control 来设计Mail收发程序,然后用Microsoft Internet Explorer 3.0所提供的E-Mail程序来测试程序设计的正确性。

    MAPI简介

    MAPI接口是由微软公司提供的一系列供使用者开发Mail、Scheduling、bulletin board、communication程序的编程接口。在使用MAPI设计程序时,首先必须在程序和MAPI之间建立一条或数条Session;当Session建立好之后,Client端程序就可以使用MAPI所提供的功能。

    MAPI的功能主要分成三大部分:Address Books、Transport和Message Store。Address Books主要负责设置E-mail type、protocol等参数;Transport负责文件的发送和接收等功能;Message Store则负责发送接收等信息的处理。

    说了这么多,MAPI接口好像很可怕。不过没关系,VisualBasic所提供的MAPISession control及MAPIMessage control,已经将许多复杂的部分包装成简单的property和功能,我们只需要对property及功能作一些简单的设置,就可以写一个mail发送和接收的程序。

    以下笔者将用Visual Basic的MAPI control,来设计mail传送和接收的程序。

    E-mail发送部分

    Step 1:设置Exchange各项参数

    进入Exchange系统,选择新增设置文件;屏幕上会显示所需要的信息服务,选择Internet Mail。将设置文件的名称设为test。屏幕会显示两个选项,您可以选择以modem方式,或以network 方式连接。笔者所用的是Internet专线,所以选择network;假若您是使用 PPP拨号方式连接Internet,就要选择modem。选择network后,Exchange会要求我们输入mail server的IPaddress。笔者现在所使用的 Mail server地址是202.96.128.111,在本程序中便将它设置为该地址。接着将Transform message的模式设置为automatic,这样当我们连接到Mail server时,新的信息会自动download到local

    端。

    接下来,将您所使用的Email address、full name、password、download path一步一步设置好,这样就完成了Exchange各项

    参数的设置。

    Step 2:程序设计

    在File选项中选择New Project建立一个新的工程,这时屏幕上会看到许多选项,例如ActiveX Document.EXE、ActiveXDocument.DLL、ActiveX.EXE、ActiveX Control等...,这时要选Standard.EXE。

    在Project下,选择Property属性选项;在general选项下,将Project Name改为email-send, 并将Form名称及Caption更改为email-send

    在屏幕的Form上加入一个MAPImessage control,取名为MAPIm1;加入一个MAPIsession control,取名为MAPIs1;加入三个textbox control,取名为subject、content、addr。并在三个textbox前各加入一个Label,将Caption分别改为subject、content、addr。

    为方便读者了解彼此关系,以下表解释一遍:

    (TextBox) Name

    subject (输入信件标题)

    content (输入信件内容)

    addr (输入信件要传送的位址)

     
    --------------------------------------------------------------------------------



    (Label) Caption

    subject (输入信件标题提示)

    content (输入信件内容提示)

    addr (输入信件要传送的位址提示)

    将MAPIm1的各项property设置如下:

    download mail=TRUE

    logoUI= TRUE

    newsession=FALSE

    username="test"

    这里将download mail设置为TRUE,当程序和mail server第一次连接时,会将新的mail download到local端。将logoUI设置为TRUE,则当您程序中logon名称输入错误时,系统会显示一个Message Box来让您输入正确的名称。由于这个程序仅使用到一条session,我们将它的值设置成FALSE。当然啦!如果您有许多session要建立的话,也可以将它设置成TRUE。 username中所填的,是我们在Exchange中所新增的设置文件名称;如果没有填内容的话,系统将会显示一些message box请您输入文件。 在屏幕的Form上加入三个Button control,logon、logoff与send,分别将Caption改为log on、log off、send。

    本文更多内容

  • 2005-8-7 20:52:00
    VB中利用API函数实现特殊窗体的两种方法

    ---- 在VB集成开发环境(IDE)中,设计程序时所新建、添加的窗体都是矩形的。如果出于某种需要,想让窗体在运行时呈现出特殊的形状,就必须借助API函数编写相应的代码。

    ---- [方法一]使用区域创建函数

    ---- 常用的区域创建函数有:

    ---- CreateEllipticRgn ‘创建一个椭圆或圆形区域

    ---- CreateRoundRectRgn ‘创建一个圆角矩形区域

    ---- CreatePolygonRgn ‘创建一个由一系列点围成的区域

    ---- CombineRgn ‘将两个区域组合为一个新区域

    ---- SetWindowRgn ‘设置新的窗口区域。

    ---- 通过CombineRgn可以取两个区域的并集、交集等组合,从而创建出复杂形状的窗体。

    ---- 例程1得到的窗体是两个相连的月牙形:

    ---- ‘例程1

    Option Explicit
    ‘API声明
    Private Declare Function CreateEllipticRgn Lib "gdi32" _
    (ByVal x1 As Long,  ByVal Y1 As Long, _
      ByVal x2 As Long, ByVal Y2 As Long) As Long
    Private Declare Function CombineRgn Lib "gdi32" _
    (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, _
      ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
    Private Declare Function SetWindowRgn Lib "user32" _
    (ByVal hWnd As Long, ByVal hRgn As Long, _
    ByVal bRedraw As Boolean) As Long
    ‘常数声明
    Const RGN_XOR = 3

    Private Sub Form_Load()
        Dim x1, x2
        x1 = CreateEllipticRgn(100, 100, 400, 400)
        x2 = CreateEllipticRgn(200, 100, 500, 400)
        CombineRgn x1, x1, x2, RGN_XOR
        SetWindowRgn hWnd, x1, 1
    End Sub

    ---- [方法二]使用BeginPath、EndPath、TextOut、PathToRegion等函数

    ---- BeginPath函数调用启动一个路径分支,在这个命令后执行的GDI绘图命令会自动成为路径的一部分,Windows95中合法的路径函数有文本绘图函数TextOut、绘制多边形函数Polygon等。

    ---- EndPath函数用于结束定义一个路径,如果调用成功,BeginPath函数和它之间发生的所有绘图操作都将在指定设备场景的路径中生效。BeginPath函数一般与EndPath函数成对出现。

    ---- PathToRegion函数调用将当前选定的路径转换到指定区域中。

    ---- TextOut函数的声明如下:

    Declare Function TextOut Lib "gdi32" Alias
    "TextOutA" (ByVal hdc As Long, ByVal x As
    Long, ByVal y As Long, ByVal lpString As
    String, ByVal nCount As Long) As Long

    ---- 参数说明如下:

    ---- hdc :设备场景的句柄 ;

    ---- x,y :绘图的起点,采用逻辑坐标 ;

    ---- lpString:欲绘制的字串 ;

    ---- nCount:字串中要绘制的字符数量,一个汉字的字符数量为2 。

    ---- 例程2生成一个宋体的“国”字形的窗体:

    ---- ‘例程2

    Option Explicit
    ‘类型声明
    Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
    End Type
    ‘API声明
    Private Declare Function BeginPath Lib "gdi32" _
        (ByVal hdc As Long) As Long
    Private Declare Function TextOut Lib "gdi32" _
        Alias "TextOutA" (ByVal hdc As Long, _
        ByVal X As Long, ByVal Y As Long, _
        ByVal lpString As String, _
        ByVal nCount As Long) As Long
    Private Declare Function EndPath Lib "gdi32" _
        (ByVal hdc As Long) As Long
    Private Declare Function PathToRegion Lib "gdi32" _
        (ByVal hdc As Long) As Long
    Private Declare Function GetRgnBox Lib "gdi32" _
        (ByVal hRgn As Long, lpRect As RECT) As Long

    本文更多内容

  • 2005-8-7 20:52:00
    用API函数改进ListView控件的显示效果

    王建兵

    ListView使用简介
      ListView控件是VB开发者非常喜爱的控件之一。作为Windows95公共控件组(COMCTL32.OCX) 的成员,它经常与经常与TreeView、ImageList等控件联合使用。即用TreeView显示一个的树 型结构,而用ListView显示选中的节点(Node)对象的记录
    集。
      这是笔者在开发财务软件项目中的$#@60;$#@60;凭证管理$#@62;$#@62;模块的一个用户界 面。屏幕左边是一个TreeView控件,用来显示会计凭证的类别;右边是一个istView,用来显示 对应类别的凭证目录;上方是一个菜单条控件(MenuBar)和一个工具条控件(ToolBar);下方是 一个状态栏控件(StatusBar),用来显示凭证数个当前日期。

      大家可以看到图中所 示的界面非常类似于Window95/98的资源浏览器,Windows的界面风格做为一种标准已为广大 用户所接受。而Windows操作系统的主要的优点就是为所有的应用程序提供了公用的界面。知道 如何使用基于Windows的应用程序的用户,很容易学会使用其他应用程序。

      这种使 用Windows95公共控件组合的方法能够达到与Windows界面的一致性,所以在目前VB5.0应用 程序的开发中经常使用。

    二、填充大量结果集所遇到的问题
      在实际应用开发中,经常用ListView填充一个数据库结果集(Recordset)的内容。即先写 一段SQL查询语句,产生一个结果集,然后将结果集的每一条记录用DO...LOOP循环语句中填到ListView 中。

      但是当结果集很大时(例如有5000条以上的记录),填充所需要的时间会很长。 用户不得不等很长时间完成一个查询。所以在查询的过程中必须允许用户按Escape键退出。具 体做法是在DO...LOOP循环体中加一条DoEvents函数,并写一段中断退出程序代码。

       DoEvents函数的功能是:转让控制权,以便让操作系统处理其它的事件。这样在长时间的查询 过程中,如果用户按了Escape键,将退出循环体,结束查询过程。

      但是这样又会引 发另外一个问题:由于DoEvents可以让操作系统响应别的事件,循环体中填充每一条ListView 项目(ListItem)的过程也会显示出来,所以在填充的过程中屏幕会不停的闪动,这种现象当然 不能被用户所接受。如何解决这个问题呢?

    三、解决方案
      用WindowsAPI函数可以解决这个问题。首先对几个用到的API函数做一解释和说明。

       1.GetClientRectLib"user32"(ByValhwndAsLong,lpRectAsRECT)As Long

      此函数的功能是获得一个指定对象窗 Window)的矩型框区域(rectangle)。

       Hwnd为指定对象或窗体的句柄。LpRect为返回矩型框的结构(必须定义为结构类型的变量)。

       2.ValidateRectLib"user32"(ByValhwndAsLong,lpRectAsRECT)As Long

      此函数的功能是使指定的矩型区域生效。这样会通知Windows不必对指定 的区域进行重画(Redraw)。

      3.InvalidateRectLib"user32"(ByVal hwndAsLong,lpRectAsRECT,ByValbEraseAsLong)AsLong

      此函数的 功能是使指定的矩型区域无效。这样会通知Windows要对指定的区域进行重画。

       具体实现的步骤如下:

      1.在填充结果集之前先用GetClientRect函数获得ListView的 显示区域。

      2.在增加完一个显示项目(ListItem)后用ValidateRect函数置这一 区域为有效。这样Windows就不会显示每一条ListItem,屏幕闪动的现象就会消失。

       3.在填充结果集之后,用InvalidateRect函数置这一区域为无效。这样Windows就会重画ListView 的内容,结果集被完整的显示出来。

      下面是笔者在项目开发中的一个程序实例。程 序名为FillListView。该程序将填写一个Access数据库(FISCAL.MDB)的凭证表(Table)的内容 到ListView中。

      首先进入VB5.0,新建一个窗体(Form),名为Form1。

       然后在Form中增加下列控件。


    控件名Name

    ListViewLvw

    ImagelistimlList

    CommandButton。Command1


      将ImageList控件中充填一个名为“item”的图象后与ListView控件关联。

    本文更

  •   评论这张
     
    阅读(574)| 评论(0)
    推荐 转载

    历史上的今天

    评论

    <#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    页脚

    网易公司版权所有 ©1997-2017