找回密码
 注册
Simdroid-非首页
查看: 288|回复: 10

[推荐]vb技巧集

[复制链接]
发表于 2005-5-11 08:13:38 | 显示全部楼层 |阅读模式 来自 山东青岛
建议版主给加个精啊

vb技巧之2-读写INI文件的四个函数
文件名SourceDB.ini文件
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias
"GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal
lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal
lpFileName As String) As Long
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias
"WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal
lpString As Any, ByVal lpFileName As String) As Long

'以下两个函数,读/写ini文件,固定节点setting,in_key为写入/读取的主键
'仅仅针对是非值
'Y:yes,N:no,E:error
Public Function GetIniTF(ByVal In_Key As String) As Boolean
On Error GoTo GetIniTFErr
GetIniTF = True
Dim GetStr As String
GetStr = VBA.String(128, 0)
GetPrivateProfileString "Setting", In_Key, "", GetStr, 256, App.Path & "\SourceDB.ini"
GetStr = VBA.Replace(GetStr, VBA.Chr(0), "")
If GetStr = "1" Then
   GetIniTF = True
   GetStr = ""
Else
   GoTo GetIniTFErr
End If
Exit Function
GetIniTFErr:
   Err.Clear
   GetIniTF = False
   GetStr = ""
End Function

Public Function WriteIniTF(ByVal In_Key As String, ByVal In_Data As Boolean) As Boolean
On Error GoTo WriteIniTFErr
WriteIniTF = True
If In_Data = True Then
WritePrivateProfileString "Setting", In_Key, "1", App.Path & "\SourceDB.ini"
Else
WritePrivateProfileString "Setting", In_Key, "0", App.Path & "\SourceDB.ini"
End If
Exit Function
WriteIniTFErr:
   Err.Clear
   WriteIniTF = False
End Function

'以下两个函数,读/写ini文件,不固定节点,in_key为写入/读取的主键
'针对字符串值
'空值表示出错
Public Function GetIniStr(ByVal AppName As String, ByVal In_Key As String) As String
On Error GoTo GetIniStrErr
If VBA.Trim(In_Key) = "" Then
   GoTo GetIniStrErr
End If
Dim GetStr As String
GetStr = VBA.String(128, 0)
GetPrivateProfileString AppName, In_Key, "", GetStr, 256, App.Path & "\SourceDB.ini"
  GetStr = VBA.Replace(GetStr, VBA.Chr(0), "")
If GetStr = "" Then
   GoTo GetIniStrErr
Else
   GetIniStr = GetStr
   GetStr = ""
End If
Exit Function
GetIniStrErr:
   Err.Clear
   GetIniStr = ""
   GetStr = ""
End Function

Public Function WriteIniStr(ByVal AppName As String, ByVal In_Key As String, ByVal In_Data As String) As Boolean
On Error GoTo WriteIniStrErr
WriteIniStr = True
If VBA.Trim(In_Data) = "" Or VBA.Trim(In_Key) = "" Or VBA.Trim(AppName) = "" Then
   GoTo WriteIniStrErr
Else
WritePrivateProfileString AppName, In_Key, In_Data, App.Path & "\SourceDB.ini"
End If
Exit Function
WriteIniStrErr:
   Err.Clear
   WriteIniStr = False
End Function
 楼主| 发表于 2005-5-11 08:14:44 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

Simdroid开发平台
vb技巧之3-如何取得计算机名
程序说明:

  这个程序比较简单,大家自己看吧

  计算机名就是你打开 控制面板-系统-网络标识-完整的计算机名称

  程序代码:

Form1

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

Private Sub Command1_Click()
Dim Name As String, Length As Long

Length = 225
Name = String(Length, Chr(0))
GetComputerName Name, Length
Name = Left(Name, Length)
Label1.Caption = Name

End Sub

vb技巧之4-计算Windows从启动后所运行的总时间
利用Api函数计算Windows从启动后所运行的总时间

Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Sub Timer1_Timer()
Dim hour As Integer
Dim minute As Integer
Dim second As Integer
hour = GetTickCount \ 1000 \ 60 \ 60
Label1.Caption = Str(hour) + "小时"

minute = (GetTickCount - hour * 60 * 60 * 1000) \ 1000 \ 60
Label2.Caption = Str(minute) + "分钟"

second = (GetTickCount - Val(Label1.Caption) * 60 * 60 * 1000 - Val(Label2.Caption) * 60 * 1000) \ 1000
Label3.Caption = Str(second) + "秒钟"
End Sub
 楼主| 发表于 2005-5-11 08:15:54 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之5-使窗体右上角的X按钮失效删除系统菜单
内容简介:
删除系统菜单Dim MHwd  As Long
MHwd = GetSystemMenu(Me.hwnd, False)
MsgBox DeleteMenu(MHwd, &H0&, &H400)
源代码内容:
窗体右上角的X按钮通常用来关闭一个程序,这个小X按钮实际上是和系统菜单的“关闭”菜单项关联在一起的,什么?不知道什么是系统菜单,系统菜单是指我们点击窗体左上角的小图标时所弹出的菜单,其中好象有“恢复”、“移动”、“最大化”、“最小化”、“关闭”这么几个按钮。这个菜单用普通的方法是不能编辑和改变的,但是我们可以通过API函数GetSystemMenu来得到它的句柄,然后通过菜单相关的API函数就能改变它了,下面一起看看怎么做吧。

  为了学习方便,下面先给出源码,并且已经作了详细的中文注释:

程序说明:
本例利用API函数GetSystemMenu得到系统菜单的句柄
X按钮是系统菜单的一菜单项,然后用RemoveMenu函数
删去这一菜单项,也就是使X按钮失效了。
-------------------------------------------
【VB声明】

Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long

【说明】
取得指定窗口的系统菜单的句柄。在vb环境,“系统菜单”的正式名称为“控制菜单”,即单击窗口左上角的控制框时出现的菜单

【返回值】
Long,如执行成功,返回系统菜单的句柄;零意味着出错。如bRevert设为TRUE,也会返回零(简单的恢复原始的系统菜单)

【备注】
在vb里使用:系统菜单会向窗口发送一条WM_SYSCOMMAND消息,而不是WM_COMMAND消息

【参数表】
hwnd ----------- Long,窗口的句柄

bRevert -------- Long,如设为TRUE,表示接收原始的系统菜单

Private Declare Function GetSystemMenu Lib "user32" ( _
ByVal hwnd As Integer, _
ByVal bRevert As Integer _
) As Integer

【VB声明】

Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
【说明】
删除指定的菜单条目。如删除的条目属于一个弹出式菜单,那么这个函数不会同时删除弹出式菜单。首先应该用GetSubMenu函数取得弹出式菜单的句柄,再在以后将其删除

【返回值】
Long,非零表示成功,零表示失败。会设置GetLastError

【备注】
强烈建议大家使用vb菜单的visible属性从菜单中删除条目,而不要用这个函数,否则会造成指定菜单中其他菜单条目的visible属性对错误的菜单条目产生影响

【参数表】
hMenu ---------- Long,菜单的句柄

nPosition ------ Long,欲改变的菜单条目的标识符。如在wFlags参数中指定了MF_BYCOMMAND,这个参数就代表欲改变的菜单条目的命令ID。如设置的是MF_BYPOSITION,这个参数就代表菜单条目在菜单中的位置(第一个条目的位置为零)

wFlags --------- Long,常数MF_BYCOMMAND或MF_BYPOSITION,取决于nPosition参数

Private Declare Function RemoveMenu Lib "user32" ( _
ByVal hMenu As Integer, _
ByVal nPosition As Integer, _
ByVal wFlags As Integer _
) As Integer

Private Sub Command1_Click()
Unload Me
End Sub

Private Sub Form_Load()
Dim R As Integer
MyMenu = GetSystemMenu(Me.hwnd, 0)
RemoveMenu MyMenu, &HF060, R
End Sub  

  程序中用到了两个API函数GetSystemMenu、RemoveMenu,其中GetSystemMenu函数用来得到系统菜单的句柄,RemoveMenu用来删除指定的菜单条目,我们先来看看这个函数的声明和参数:

   Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long

   Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long  
其中各GetSystemMenu参数的意义如下表:

参数 意义
hwnd Long 系统菜单所在窗口的句柄
bRevert Long 如设为TRUE,表示恢复原始的系统菜单
返回值 Long 如执行成功,返回系统菜单的句柄;零意味着出错。如bRevert设为TRUE,也会返回零(简单的恢复原始的系统菜单)

  而RemoveMenu参数的意义如下表:

参数 意义
hMenu Long 菜单的句柄
nPosition Long 欲改变的菜单条目的标识符。如在wFlags参数中指定了MF_BYCOMMAND,这个参数就代表欲改变的菜单条目的命令ID。如设置的是MF_BYPOSITION,这个参数就代表菜单条目在菜单中的位置(第一个条目的位置为零)
wFlags Long 常数MF_BYCOMMAND=&H0&或MF_BYPOSITION=&H400&,取决于nPosition参数
返回值 Long,非零表示成功,零表示失败

  然后就可以在程序中使用这两个函数了,我们在窗体的Form_Load()过程中加入如下代码:

   MyMenu = GetSystemMenu(Me.hwnd,0)    得到系统菜单的句柄,Me.hwnd表示当前窗体的句柄

   RemoveMenu MyMenu, &HF060, MF_BYCOMMAND 移去“关闭”菜单项,&HF060“关闭”菜单项的命令ID

  接着我们运行程序,看看窗体右上角的X按钮是不是已经不可点击了,系统菜单中的“关闭”项也消失了,很有趣,不过一定记着为程序留一个“退出”按钮哦!

vb技巧之6-VB托盘程序详解
这样我们就取得并处理了来自托盘图标的消息,现在的问题是在鼠标右键菜单弹出后,怎么控制程序主窗体的状态,这时我们需要用到SendMessage函数来向主窗体发送最大化、最小化、关闭、移动等消息,具体的代码实现如下,其中HWnd是主窗体的句柄,WM_SYSCOMMAND表示发送的是系统控制类的消息,SC_MOVE、SC_SIZE、SC_RESTORE便是要发送的消息了:

   '托盘图标右键菜单上的“移动”项被点击时
   Private Sub mnuTrayMove_Click()
     SendMessage HWnd, WM_SYSCOMMAND, SC_MOVE, 0&
   End Sub
   '托盘图标右键菜单上的“恢复”项被点击时
   Private Sub mnuTrayRestore_Click()
     SendMessage HWnd, WM_SYSCOMMAND, SC_RESTORE, 0&
   End Sub
   '托盘图标右键菜单上的“退出”项被点击时
   Private Sub mnuTraySize_Click()
     SendMessage HWnd, WM_SYSCOMMAND, SC_SIZE, 0&
   End Sub  

  最后要提醒你,在程序退出时一定要把窗口过程的地址恢复为默认值,同时把托盘图标移去哦。




vb技巧之7-妙用GetSystemMetrics函数
在Windows9x编程过程中,我们经常需要了解当前系统的运行状态。例如,如果Win9x运行于安全模式,那么多媒体等部件可能无法正确运行。程序中有必要对此做相应处理,以提高程序安全性,增强系统的适应能力。VB中没有直接提供此类控制或函数,但是我们可以通过API函数GetSystemMetrics轻松地实现对Win运行模式的判断。

  GetSystemMetrics函数原型如下:
  

  Public Declare Function GetSystemMetrics Lib “user32” (ByVal nIndex As Long) As Long

  其中nIndex的不同取值可以使该函数实现不同的功能。例如返回Win桌面中各种显示单元的宽度和高度、是否安装了鼠标、是否调换了鼠标左右键的定义等。

  当nIndex = 67(SM_CLEANBOOT)时,该函数的返回值表示Windows9x的当前运行模式。

  在以下的示例中我们可以看到GetSystemMetrics函数的用法和作用。首先在BAS模块文件中做如下说明:

  Option Explicit
  Public Const SM_CLEANBOOT = 67
  Public Declare Function GetSystemMetrics Lib “user32” (ByVal nIndex As Long) As Long

  在窗体中添加标签Label1和命令按钮Command1,设置如下代码:

  Private Sub Command1_Click()
   Select Case GetSystemMetrics(SM_CLEANBOOT)

   Case 0abel1=“系统运行于正常模式”
   Case 1:Label1=“系统运行于安全模式”
   Case 2:Label1=“系统运行于网络环境下的安全模式”
   End Select
  End Sub
 楼主| 发表于 2005-5-11 08:17:09 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之9-如何加长加宽ComboBox的下拉选单
Combo 预设的下拉长度只有 5,6 个选项,当选项很多时,要卷老半天才能找到资料,很不方便!要加长 ComboBox 的下拉选单,方法如下:

在声明区中放入以下声明及 Subroutine

Private Declare Function MoveWindow Lib "user32" _
(ByVal hwnd As Long, ByVal x As Long, ByVal y As _
Long, ByVal nWidth As Long, ByVal nHeight As Long, _
ByVal bRepaint As Long) As Long

Public Sub SetComboHeight(oComboBox As ComboBox, lNewHeight As Long)
Dim oldscalemode As Integer
′ This procedure does not work with frames: you
′ cannot set the ScaleMode to vbPixels, because
′ the frame does not have a ScaleMode Property.
′ To get round this, you could set the parent control
′ to be the form while you run this procedure.
If TypeOf oComboBox.Parent Is Frame Then Exit Sub
′ Change the ScaleMode on the parent to Pixels.
oldscalemode = oComboBox.Parent.ScaleMode
oComboBox.Parent.ScaleMode = vbPixels
′ Resize the combo box window.
MoveWindow oComboBox.hwnd, oComboBox.Left, _
oComboBox.Top, oComboBox.Width, lNewHeight, 1
′ Replace the old ScaleMode
oComboBox.Parent.ScaleMode = oldscalemode
End Sub

在任何时候 (不一定是 Form_Load 或 Combo_DropDown),想要加长 ComboBox 的下拉选单时,只要加入以下程序即可:

Call SetComboHeight(Combo1, 270) ′设定的单位是 Pixels
如何加宽 ComboBox 的下拉选单?

和 ListBox 一样, ComboBox 也会有宽度不够的情形, Combo 下拉之后资料看不完整,当 Form 上的物件不多时,还可以拉长一点,但有时候也没办法!这时候,还是得靠 API 了!

在声明区中放入以下声明及 Subroutine

Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, _
lParam As Long) As Long
Const CB_SETDROPPEDWIDTH = &H160

Public Sub SetComboWidth(oComboBox As ComboBox, lWidth As Long)
′ lWidth 是宽度,单位是 pixels
SendMessage oComboBox.hwnd, CB_SETDROPPEDWIDTH, lWidth, 0
End Sub

在任何时候 (不一定是 Form_Load 或 Combo_DropDown),想要加宽 ComboBox 的下拉选单时,只要加入以下程序即可 (若设定的宽度小于 Combo 原来的宽度则无效):

Call SetComboWidth(Combo1, 270) ′设定的单位是 Pixels




vb技巧之10-ListBoxComboBox中寻找字串
Const LB_FINDSTRING = &H18F
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
        (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
         lParam As Any) As Long

Private Sub Form_Load()
List1.Clear
List1.AddItem "Apples"
List1.AddItem "Banana"
List1.AddItem "Bread"
List1.AddItem "Break"
Text1.Text = ""
End Sub

Private Sub Text1_Change()
List1.ListIndex = SendMessage(List1.hwnd, LB_FINDSTRING, -1, _
    ByVal CStr(Text1.Text))
End Sub

'用在 ComboBox也可以
'只要将 SendMessage中的 LB_FINDSTRING 换成 CB_FINDSTRINGEXACT即可
'Public Const CB_FINDSTRINGEXACT& = &H158

vb技巧之11-VB调用API函数建立控制台窗口上
随着软件的界面设计的发展,人机交互的方式同过去也有了很大的不同,图形用户
界面,鼠标操作甚至语音等早已经率见不先了。但是在有一些程序中,还是要使用到
象过去那种老式的主机——终端那样的字符型控制台窗口式样的界面。而实际上,在
Windows中也保留了这样的一系列控制台函数,下面的范例演示了如何建立控制台窗口
以及让用户在其中输入字符同计算机进行交互对话。
    首先在选VB菜单中的 Project | Module 项向工程文件中加入一个模块,然后在
这个Module中加入以下代码:

Option Explicit

Private Declare Function AllocConsole Lib "kernel32" () As Long

Private Declare Function FreeConsole Lib "kernel32" () As Long

Private Declare Function GetStdHandle Lib "kernel32" _
(ByVal nStdHandle As Long) As Long

Private Declare Function ReadConsole Lib "kernel32" Alias _
"ReadConsoleA" (ByVal hConsoleInput As Long, _
ByVal lpBuffer As String, ByVal nNumberOfCharsToRead As Long, _
lpNumberOfCharsRead As Long, lpReserved As Any) As Long

Private Declare Function SetConsoleMode Lib "kernel32" (ByVal _
hConsoleOutput As Long, dwMode As Long) As Long

Private Declare Function SetConsoleTextAttribute Lib _
"kernel32" (ByVal hConsoleOutput As Long, ByVal _
wAttributes As Long) As Long

Private Declare Function SetConsoleTitle Lib "kernel32" Alias _
"SetConsoleTitleA" (ByVal lpConsoleTitle As String) As Long

Private Declare Function WriteConsole Lib "kernel32" Alias _
"WriteConsoleA" (ByVal hConsoleOutput As Long, _
ByVal lpBuffer As Any, ByVal nNumberOfCharsToWrite As Long, _
lpNumberOfCharsWritten As Long, lpReserved As Any) As Long

Private Const STD_INPUT_HANDLE = -10&
Private Const STD_OUTPUT_HANDLE = -11&
Private Const STD_ERROR_HANDLE = -12&

Private Const FOREGROUND_BLUE = &H1
Private Const FOREGROUND_GREEN = &H2
Private Const FOREGROUND_RED = &H4
Private Const FOREGROUND_INTENSITY = &H8
Private Const BACKGROUND_BLUE = &H10
Private Const BACKGROUND_GREEN = &H20
Private Const BACKGROUND_RED = &H40
Private Const BACKGROUND_INTENSITY = &H80

'For SetConsoleMode (input)
Private Const ENABLE_LINE_INPUT = &H2
Private Const ENABLE_ECHO_INPUT = &H4
Private Const ENABLE_MOUSE_INPUT = &H10
Private Const ENABLE_PROCESSED_INPUT = &H1
Private Const ENABLE_WINDOW_INPUT = &H8
'For SetConsoleMode (output)
Private Const ENABLE_PROCESSED_OUTPUT = &H1
Private Const ENABLE_WRAP_AT_EOL_OUTPUT = &
 楼主| 发表于 2005-5-11 08:18:16 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之12-VB调用API函数建立控制台窗口下
Private hConsoleIn As Long ' The console's input handle
Private hConsoleOut As Long ' The console's output handle
Private hConsoleErr As Long ' The console's error handle

'''''M A I N'''''''''''''''''''''''''''''''''''''''''
Private Sub Main()
    Dim szUserInput As String

    AllocConsole    '建立一个控制台窗口
    SetConsoleTitle "VB Console Example" '设置窗口标题

    '获得控制窗口的句柄
    hConsoleIn = GetStdHandle(STD_INPUT_HANDLE)
    hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE)
    hConsoleErr = GetStdHandle(STD_ERROR_HANDLE)

    SetConsoleTextAttribute hConsoleOut, _
    FOREGROUND_RED Or FOREGROUND_GREEN _
    Or FOREGROUND_BLUE Or FOREGROUND_INTENSITY _
    Or BACKGROUND_BLUE

    ConsolePrint "VB Console Example" & vbCrLf
   
    SetConsoleTextAttribute hConsoleOut, _
    FOREGROUND_RED Or FOREGROUND_GREEN _
    Or FOREGROUND_BLUE
   
    ConsolePrint "lease Enter Your Name Here--> "

    '获得用户名
    szUserInput = ConsoleRead()
    If Not szUserInput = vbNullString Then
        ConsolePrint "Hello, " & szUserInput & "!" & vbCrLf
    Else
        ConsolePrint "Hello,But who are you?" & vbCrLf
    End If

    ConsolePrint "Press Enter To Close The Console"
    Call ConsoleRead

    FreeConsole ' Destroy the console
End Sub

Private Sub ConsolePrint(szOut As String)
    WriteConsole hConsoleOut, szOut, Len(szOut), vbNull, vbNull
End Sub

Private Function ConsoleRead() As String
    Dim sUserInput As String * 256
   
    Call ReadConsole(hConsoleIn, sUserInput, Len(sUserInput), vbNull, vbNull)
    'Trim off the NULL charactors and the CRLF.
    ConsoleRead = Left$(sUserInput, InStr(sUserInput, Chr$(0)) - 3)
End Function
    选VB菜单中的 Project | Project1 Properties项,将Startup Object改变为Sub Main,然后
运行程序,程序就会弹出一个控制台窗口,用户可以根据控制台窗口中的提示信息与程序进行交互
对话。
    上面的程序在Win98、VB6下运行通过

vb技巧之13-用WinSock设计Chat程序上
用WinSock设计Chat程序
  
  
摘要
随着Internet的蓬勃发展,网络界面的交流使我们能够即时收到各地所发生的各项
信息。我们在使用各种Browser浏览各网点时,只要Server能提供Chat(闲聊)的服
务项目,我们就可以通过Browser所提供的Chat程序与网络上的其他使用者即时对谈
及交流心得。本篇文章通过Visual Basic 5.0所提供的WInSock control,设计一个
Chat应用程序。我们通过Client及Server之间的文件传输,可以了解Chat程序的工
作原理。

WinSock control简介

WinSock是windows系统提供的一种网络文件传输协议。以往我们使用WinSock设计程
序时,必须调用系统提供的API来完成;但是在Visual Basic中调用API,因涉及参
数传递类型,用起来并不方便。Visual Basic 5.0 提供WinSock control简化我们
的设计流程。它可以利用User Datagram Protocol(UDP)或Transmission Control
Protocol(TCP),来设计网络的Client-Server 程序。

TCP是一种Connection base的Protocol,在文件传输时会先行建立Link,通过Link
可确保文件传输的正确性;UDP则是一种Connectionless的Protocol,它在传输文件
时不会确保传输端的文件能够正确无误的传送到接收端,所以当我们使用UDP
protocol时,我们通常要自己作接收确认的工作。

UDP protocol看起来好像比较没效率,其实不然!UDP protocol有一个好处:当文
件很小,或我们要做网络boardcast (广播)时,会比较有效率。 所以了!当我
们利用WinSock设计程序时,首先要依自己的需要,决定使用那一种protocol。本文
将分别教您使用TCP及UDP Protocol来设计Chat程序。

以TCP设计Chat程序

Step 1:找出Domain name及IP address

在“我的电脑”中选择“控制面板”。Double click“网络”选项,选择“标识”
,您将会发觉您的计算机名称、工作组名等信息。将它记录起来,我们稍后会用
到。

Step 2:设计TCP Server程序

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

接着在Project下选择Property属性选项,在General选项下将ProjectName改为
TCP-Server,并将Form名称及Caption更改为Server。在屏幕的Form上加入一个
WinSock control,取名为Tcps;加入两个TextBox control(Outtext、Intext),并
在两个TextBox前加入两个label,分别将caption改为Outtext、Intext。
〈TextBox〉

Name

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

Outtext(输出文件)

Intext(输入文件)

〈Label〉

Caption

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

Outtext(输出文件)

Intext(输入文件)

在Form_Load()中加入以下程序代码,这个动作是设置好我们Local的传输端口,并
到接收的状态:

Tcps.protocol=0-scktcp protocol

Tcps.LocalPort = 1002

Tcps.Listen

双击Tcps,在Tcps_ConnectionRequest(ByVal requestID As Long) 中加入以下程
序代码,这表示winsock接受了连接请求:

Tcps.Accept requestID

双击Outtext到Outtext_change(),加入以下程序代码,当Outtext内容改变后,文
件就会自动送出:

Tcps.SendData Outtext.text

在Tcps_DataArrival(ByVal bytesTotal As Long)中加入以下程序代码,这是用来
把所接收的文件显示在Intext这个TextBox中。

Dim S As StrIng

Tcps.GetData S

InText.Text = S

这样我们就完成了Server端的设计。

Step 3:设计TCP Client程序

在File选项中选择New Project建立一个新的工程,在屏幕上看到许多选项,如
ActiveX Document.EXE、ActiveX Document.DLL、ActiveX.EXE、ActiveX Control
等。选Standard.EXE。接着在 Project下,选择Property属性选项,在General选项
下,将Project Name改为TCP-Client,并将FORM名称及Caption更改为Client。

vb技巧之14-用WinSock设计Chat程序中
在屏幕的Form上加入一个WinSock control,取名为 Tcpc,将protocol property设
置成 0-scktcp protocol,加入两个TextBox control(Outtext、Intext),并在两
个TextBox前加入两个Label,分别将其Caption改为Outtext、Intext。接着放入一
个Button(button1)并将Caption 改为Connect。

(TextBox)

Name

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

Outtext(输出文件)

Intext(输入文件)

(Label)

Caption

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

Outtext(输出文件)

Intext(输入文件)

〈Button〉

Name Caption

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

Button1(执行建立session命令) Connect

在Form_Load()中加入以下程序代码,这个动作是设置好我们Remote所要连接的传输
端口及其网络名称。我们要连接的计算机网络名称为DAVID:

Tcpc.RemoteHost ="David"

Tcpc.RemotePort=1002

双击Outtext到Outtext_change()加入以下程序代码,当Outtext内容改变后,文件
会自动送出:

Tcpc.SendData Outtext.text

在Tcpc_DataArrival(ByVal bytesTotal As Long)中加入以下程序代码,这是用来
把所接收的文件显示在Intext这个TextBox 中。

Dim S As StrIng

Tcpc.GetData S

InText.Text = S

这样就完成了Client端的设计。

Step 4:测试TCP Chat程序

分别执行Server及Client程序,这时在Client的屏幕上显示In及Out TextBox及一个
Connect Button;在Server屏幕上显示In及Out TextBox。

我们按Client程序Connect button建立连接,连接建立成功后,我们可尝试在
Client的Outbox 中输入一些字符串:Hello nice to meet you!我们将在Server端
的Inbox看到这些字串。 接着我们在Server的Outbox也输入一些字符串:Nice to
meet you, too! 我们将在Client 端的Inbox看到这些字符串。结果证明我们成功
了!

用UDP设计Chat程序

Step 1:设计第一个UDP(UDP1)程序

在File选项中选择New Project建立一个新的工程,屏幕上会看到许多选项,如
ActiveX Document.EXE、ActiveX Document.DLL、ActiveX.EXE、ActiveX Control
等,这时选Standard.EXE。接着在Project下选择Property属性选项,在General选
项下将Project Name改为UDP1,将protocol property设置成0-udptcp protocol,
并将Form名称及Caption更改为UDP1。

在屏幕的Form上加入一个WinSock control,取名为UDP1;加入两个TextBox
control ( Outtext、Intext),并于两个TextBox
  

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

Transfer interrupted!
3">Label control,分别
将Caption改为 Outtext、 Intext。

(TextBox)

Name

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

Outtext(输出文件)

Intext(输入文件)

(Label)

Caption

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

Outtext(输出文件)

Intext(输入文件)

在Form_Load()中加入以下程序代码,这个动作是设置好我们要连接的远端输入端口
为 1001,并将输入端口设为1002。

UDP1.RemoteHost = "DAVID"

UDP1.RemotePort = 1001

UDP1.BInd 1002

双击Outtext到Outtext_change(),加入以下程序代码,当Outtext 内容改变,文件
会自动送出:

UDP1.SendData Outtext.text

在UDP1_DataArrival(ByVal bytesTotal As Long)中加入以下程序代码,这是用来
把所接收的文件显示在Intext这个TextBox 中。

Dim S As String

UDP1.GetData S

InText.Text = S

这样我们就完成了UDP1的设计。
 楼主| 发表于 2005-5-11 08:19:16 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之15- 用WinSock设计Chat程序下
Step 2:设计第二个UDP(UDP2)程序

在File选项中选New Project建立一个新的工程,屏幕上会看到许多选项,如
ActiveX Document.EXE、 ActiveX Document.DLL、ActiveX.EXE、ActiveX Control
等,这时要选Standard.EXE。接着在 Project下,选择Property属性选项,在
General选项下,将Project Name改为UDP2,将protocol property设置成0-udptcp
protocol,并将Form名称及Caption更改为UDP2 。

在屏幕的Form上加入一个WinSock control取名为UDP2 ,加入两个TextBox
control ( Outtext、Intext),并在两个TextBox control前加入两个Label
control,分别将Caption改为Outtext、Intext。

(TextBox)

Name

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

Outtext(输出文件)

Intext(输入文件)

(Label)

Caption

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

Outtext(输出文件)

Intext(输入文件)

在Form_Load()中加入以下程序代码,这个动作是设置好我们要连接的远端输入端
口,设置为1002,并将输入端口设置为1001。

UDP2.RemoteHost = "MARY"

UDP2.RemotePort = 1002

UDP2.Bind 1001

双击Outtext到Outtext_change()加入以下程序代码,当Outtext内容改变,文件就
会自动送出:

UDP2.SendData Outtext.text

在UDP2_DataArrival(ByVal bytesTotal As Long) 中加入以下程序代码,这是用来
把所接收的文件显示在Intext这个TextBox 中。

Dim S As StrIng

UDP2.GetData S

InText.Text = S

这样我们就完成了UDP2的设计。

Step 3:测试UDP Chat程序

分别执行UDP1及UDP2程序。这时UDP1的屏幕上显示In及Out TextBox;UDP2屏幕也显
示In及Out两个TextBox。我们在UDP1的Outbox中输入一些字符串 I want talk to
Mary,我们将在UDP2端的Inbox看到这些字符串。接着我们在UDP2的Outbox也输入一
些字符串This is Mary speaking!,我们将在UDP1端的Inbox看到这些字串。结果证
明我们成功了

vb技巧之16-制作透明的任务栏上
Option Explicit

Private Const GWL_EXSTYLE = (-20)
Private Const WS_EX_LAYERED = &H80000
Private Const WS_EX_TRANSPARENT = &H20&
Private Const LWA_ALPHA = &H2&

Private Declare Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowLong Lib "User32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function SetLayeredWindowAttributes Lib "User32" (ByVal hwnd As Long, ByVal crey As Byte, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long

Private Const ERROR_SUCCESS = 0&
Private Const REG_OPTION_NON_VOLATILE = 0    ' Key is preserved when system is rebooted

Private Const SYNCHRONIZE = &H100000
Private Const STANDARD_RIGHTS_ALL = &H1F0000
Private Const KEY_QUERY_VALUE = &H1
Private Const KEY_SET_VALUE = &H2
Private Const KEY_CREATE_SUB_KEY = &H4
Private Const KEY_ENUMERATE_SUB_KEYS = &H8
Private Const KEY_NOTIFY = &H10
Private Const KEY_CREATE_LINK = &H20
Private Const KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL Or KEY_QUERY_VALUE Or _
  KEY_SET_VALUE Or KEY_CREATE_SUB_KEY Or KEY_ENUMERATE_SUB_KEYS Or _
  KEY_NOTIFY Or KEY_CREATE_LINK) And (Not SYNCHRONIZE))

Private Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias "RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, ByVal Reserved As Long, ByVal lpClass As String, ByVal dwOptions As Long, ByVal samDesired As Long, lpSecurityAttributes As Any, phkResult As Long, lpdwDisposition As Long) As Long
Private Declare Function RegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, lpData As Any, ByVal cbData As Long) As Long     ' Note that if you declare the lpData parameter as String, you must pass it By Value.
Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long




vb技巧之17- 制作透明的任务栏下
Private Function prvGetLevel() As Byte
  Dim LnLevel As Byte
  Dim LsCommand As String
  Dim LnToken As Integer
  Dim LsKey As String
  Dim LsInput As String
  
  LsCommand = Command()
  LsKey = "/translevel:"
  LnToken = InStr(1, LsCommand, LsKey, vbTextCompare)
  If (LnToken = 0) Then
    LsInput = InputBox("Enter transparency level for task bar" & vbCrLf & "1 to 255", , 100)
  Else
    Dim LnEnd As Integer
    
    LnToken = (LnToken + Len(LsKey))
    LsInput = Mid$(LsCommand, LnToken, 3)
  End If
  If (Trim$(LsInput) = 0) Then
    LnLevel = 100
  Else
    LnLevel = Val(Left$(LsInput, 3))
  End If
  If (LnLevel > 255) Then LnLevel = 255
  If (LnLevel < 50) Then LnLevel = 50
  prvGetLevel = LnLevel
End Function

Private Sub prvMakeTransparent(LhWnd As Long, bLevel As Byte)
  Dim lOldStyle As Long
  lOldStyle = GetWindowLong(LhWnd, GWL_EXSTYLE)
  SetWindowLong LhWnd, GWL_EXSTYLE, lOldStyle Or WS_EX_LAYERED
  SetLayeredWindowAttributes LhWnd, 0, bLevel, LWA_ALPHA
End Sub

Public Sub Main()
  Dim LhWnd As Long
  Dim LnLevel As Byte

  LnLevel = prvGetLevel
  If (InStr(1, Command(), "/silent", vbTextCompare) = 0) Then
  '  If SetAutoStart(LnLevel) Then
  '    MsgBox "TransTaskBar will be loaded when OS starts.", vbOKOnly Or vbInformation
  '  End If
  Else
  End If
  LhWnd = FindWindow("Shell_TrayWnd", vbNullString)
  If (LhWnd <> 0) Then
    prvMakeTransparent LhWnd, LnLevel
  End If
End Sub

Public Function SetAutoStart(nLevel As Byte) As Boolean
  Dim nRet As Long
  Dim hKey As Long
  Dim nResult As Long
  Dim LsFullPath As String
 
  With App
    LsFullPath = App.Path & "\" & App.EXEName & ".exe"
  End With
  If (InStr(1, LsFullPath, " ") > 0) Then
    LsFullPath = """" & LsFullPath & """"
  End If
  LsFullPath = LsFullPath & " /silent /TransLevel:" & CStr(nLevel)
  ' Open (or create and open) key
  nRet = RegCreateKeyEx(&H80000001, "Software\Microsoft\Windows\CurrentVersion\Run", 0&, vbNullString, _
    REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, ByVal 0&, hKey, nResult)
  If nRet = ERROR_SUCCESS Then
  ' Write new value to registry
    nRet = RegSetValueEx(hKey, App.EXEName, 0&, 1&, ByVal LsFullPath, Len(LsFullPath))
    Call RegCloseKey(hKey)
  End If
  SetAutoStart = (nRet = ERROR_SUCCESS)
End Function
 楼主| 发表于 2005-5-11 08:21:38 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之18- 图象转换上
功能 Picture对象相关操作
'类别 模块

Option Explicit

'*****************************************************************
'* 将 icon 对象转换为 VB 的 picture 对象
'* 参数∶ hIcon 一个有效的图标句柄
'*****************************************************************
Function IconToPicture(ByVal hIcon As Long) As IPicture
  Dim ipic As IPicture
  Dim picdes As PICTDESC, iidIPicture As IID

  If hIcon = hNull Then Exit Function
  picdes.cbSizeofstruct = Len(picdes)
  picdes.picType = vbPicTypeIcon
  picdes.hgdiobj = hIcon
  ' Fill in magic IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
  iidIPicture.Data1 = &H7BF80980
  iidIPicture.Data2 = &HBF32
  iidIPicture.Data3 = &H101A
  iidIPicture.Data4(0) = &H8B
  iidIPicture.Data4(1) = &HBB
  iidIPicture.Data4(2) = &H0
  iidIPicture.Data4(3) = &HAA
  iidIPicture.Data4(4) = &H0
  iidIPicture.Data4(5) = &H30
  iidIPicture.Data4(6) = &HC
  iidIPicture.Data4(7) = &HAB
 
  OleCreatePictureIndirect picdes, iidIPicture, True, ipic
 
  Set IconToPicture = ipic
End Function

'******************************************************************
'* 将 Cursor 对象转换为 VB 的 Picture 对象
'* 参数∶ hIcon 一个有效的光标句柄
'******************************************************************
Function CursorToPicture(ByVal hIcon As Long) As IPicture
  ' It's just an alias
  Set CursorToPicture = IconToPicture(hIcon)
  End Function

'******************************************************************
'* 将 bitmap 对象转换为 VB 的 picture 对象
'* 参数∶ hBmp 一个有效的位图句柄
'* hpal 一个有效的调色板句柄
'******************************************************************
Function BitmapToPicture(ByVal hBmp As Long, _
             Optional ByVal hPal As Long = hNull) As IPicture
 
  Dim ipic As IPicture
  Dim picdes As PICTDESC, iidIPicture As IID
  picdes.cbSizeofstruct = Len(picdes)
  picdes.picType = vbPicTypeBitmap
  picdes.hgdiobj = hBmp
  picdes.hPalOrXYExt = hPal
  ' Fill in magic IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
  iidIPicture.Data1 = &H7BF80980
  iidIPicture.Data2 = &HBF32
  iidIPicture.Data3 = &H101A
  iidIPicture.Data4(0) = &H8B
  iidIPicture.Data4(1) = &HBB
  iidIPicture.Data4(2) = &H0
  iidIPicture.Data4(3) = &HAA
  iidIPicture.Data4(4) = &H0
  iidIPicture.Data4(5) = &H30
  iidIPicture.Data4(6) = &HC
  iidIPicture.Data4(7) = &HAB

  OleCreatePictureIndirect picdes, iidIPicture, True, ipic
 
  Set BitmapToPicture = ipic
End Function


vb技巧之19-图象转换下
**********************************************************************
'* 刷新 PictureBox 控件的 Picture 对象。对PictureBox中的任何绘图操作,
'*                  通过它即可转换为Picture对象
'* 使用该函数可将PictureBox内的图象编辑结果永久更新为 Picture 对象
'* 参数∶ PicBox PictureBox控件名
'*        lWidth 需要更新的图象宽度(按你的需要,不局限于目前Picture对
'*               象的实际大小),也是最后要形成的Picture对象的图象宽度(单位∶像素)
'*        lHeight 需要更新的图象高度,其他类同与 lWidth(单位∶像素)
'**********************************************************************
Function UpdatePicture(ByRef PicBox As Object, Optional ByVal lWidth As Long = -1, _
            Optional ByVal lHeight As Long = -1) As Boolean
 
 On Error GoTo errHandle

  Dim oldScMode As Integer
  Dim hNewDC As Long
  Dim hOldBit As Long
  Dim hNewBit As Long

  oldScMode = -1
  oldScMode = PicBox.ScaleMode
  If lWidth = -1 Then
    lWidth = PicBox.ScaleX(PicBox.Picture.Width, 8, vbPixels)
  End If
  If lHeight = -1 Then
    lHeight = PicBox.ScaleY(PicBox.Picture.Height, 8, vbPixels)
  End If

  hNewDC = CreateCompatibleDC(PicBox.hdc)
  hNewBit = CreateCompatibleBitmap(PicBox.hdc, lWidth, lHeight)
  hOldBit = SelectObject(hNewDC, hNewBit)

  BitBlt hNewDC, 0, 0, lWidth, lHeight, PicBox.hdc, 0, 0, vbSrcCopy
  SelectObject hNewDC, hOldBit

  PicBox.Picture = BitmapToPicture(hNewBit)

  DeleteObject hNewDC
  DeleteDC hNewDC
  If oldScMode <> -1 Then PicBox.ScaleMode = oldScMode
  UpdatePicture = True

  Exit Function
errHandle:
  UpdatePicture = False
  If oldScMode <> -1 Then PicBox.ScaleMode = oldScMode
End Function
有关的API函数声明

Option Explicit

Public Const hNull = 0

Public Type IID
   Data1 As Long
   Data2 As Integer
   Data3 As Integer
   Data4(0 To 7) As Byte
End Type

Public Type PICTDESC
  cbSizeofstruct As Long
  picType As Long
  hgdiobj As Long
  hPalOrXYExt As Long
End Type

Public Declare Sub OleCreatePictureIndirect Lib "olepro32.dll" ( _
  lpPictDesc As PICTDESC, _
  riid As IID, _
  ByVal fPictureOwnsHandle As Long, _
  ipic As IPicture)
Public Declare Function CreateCompatibleDC& Lib "gdi32" (ByVal hdc As Long)
Public Declare Function CreateCompatibleBitmap& Lib "gdi32" ( _
  ByVal hdc As Long, _
  ByVal nWidth As Long, _
  ByVal nHeight As Long)
Public Declare Function DeleteDC& Lib "gdi32" (ByVal hdc As Long)
Public Declare Function SelectObject& Lib "gdi32" ( _
  ByVal hdc As Long, _
  ByVal hObject As Long)
Public Declare Function DeleteObject& Lib "gdi32" (ByVal hObject As Long)



vb技巧之19- 编程规范一
第一条:什么是编程规范:所谓编程规范即是千百万有经验的程序员经历长期教训后,极少数的一些人通过总结和反思而养成的信条和习惯。这一规范可给你:
高效率地编程
高质量的代码
高奖金的回报
第一章 项目管理
(善于鼓舞人心的领导,应能乐观看待一切,把失败当作是学习经验,则会有新的重大的突破。)
第二条:项目的管理由项目主管(经理)、技术主管(经理)、产品主管(经理)分工合作,共同管理。
项目主管(经理)必须由最有经验的程序员担任,职责是管理代码的规范性,程序编码进度。
技术主管(经理)也必须由有最有经验的程序员担任,技术主管必须了解当前市场最新技术。职责是代码实现技术,解决开发疑难,以及设计文档与实际开发的一致性维护与细化和程序抟量控制。
产品主管(经理)必须了解市场需求,管理需求文档的建立和软件的测试。
第二章 程序质量控制:
第三条:质量标准:程序应具备可移植性,是空间及速度上达最大优化。同时,对于程序可能的出错,必须要有相应的错误捕获。具体质量参数如下:
1, 空间,如果不是持殊要求,程序应当尽可能少用空间。
2, 速度,程序应当是能在最优化的即最快的速度运行。
3, 鲁棒性,不会应任何误操作(包括非法数值)使程序崩溃。
4, 安全性,对于有用户数据,或网络程序,应当保证其数据或网络的安全。
5, 可测试性,产品应有测试版(BETA版),能生成测试报告。
6, 可维护性,详细的注解,且程序应当具有面向对象的构件及模快。并且遵守对象与变量的命名规范。
7, 简单,易操作,易使用。
8, 可复用性,构件能用于其它产品中。
9, 可移植性。易于转换到不同的操作系统中。
第四条:界面要求:程序应具有以下友好的界面:1,操作简便,2,外观漂亮
第五条:质量控制原则:
1, 任何程序在编程或制作前应有详细设计文档,保证有了方案后再写代码。
2, 必须利用面向对象的原则将项目细分,使其构件化,并将构件作为小的项目看待。
3, 不得使用长于两个月周期的项目。应何产品,都应当有长度约为一周的短期目标。每一目标应当是可以运行且能够看到结果的目标。
4, 如果要实现某一功能,则一定要使其完善,即,送给用户"夹生的",不如只给用户"做熟的"。
5, 时刻应当注意,产品是一个整体,即只要有任一构件不足,则会毁了本产品。
6, 国际化:任何产品,不可将文字写在图片上,应只使用无文字的图片,界面文字,如能保存在资源文件中,则必须使用资源文件。保证产品易于国际化。
第六条:编程时的质量保证:
1, 程序员应从写代码时就开始查错。
2, 从写代码时就应保证代码(构件)可共享(可复用)。即开始编程时,就考虑,这一构件是否有可能用于今后的其它产品中,如果是,则应做成可复用性的构件,使其能共享。
3, 任何程序员都应当独立工作,公司按程序员的实际工作量付薪酬,而不是按工作时间付薪酬。因而,程序员应当严格遵守编程规范,以保证效率。
4, 保证无错代码:如果遵守以下原则,则无错代码是可能的:
(1) 在用法不确定时,查看帮助。
(2) 编译通过时,应作边界值查错。
(3) 对于有警告选项的开发工具(如:VC),应当打开编译器警告开关。
(4) 数据库操作时,应当加入错误捕获。
(5) 动用编程时,应先理顺思路。(好的思路可能使代码更少,且效率更高)
(6) 当一个逻辑单元的程序写好时,及时加上详细的注解,写明逻辑流程。
(7) 动手编程时,应当考虑,该设计的实现手段易出错的程度如何?如果易出错,则应当找出更好的不易出错的手段再开始写程序。
(8) 微软在VB中的原则:
可用几个方法避免在应用程序中产生错误:
写出相关事件以及代码响应每个事件的方法,精心设计应用程序。为每个事件过程和每个普通过程都指定一个特定、明确的目标。
多加注释。如果用注释说明每个过程的目的,那么,在回过头来分析代码时,就能更深入理解这些代码。
尽可能显式引用对象。要象对象浏览器中所列举对象那样声明对象,而不用 Variant 或一般的 Object 数据类型。
在应用程序中对变量和对象提出一种前后一致的命名方案。更详细的信息,请参阅"编程约定"。
造成错误的一个最普通的原因就是键入了不正确的变量名,或把一个控件与另一个控件搞混了。可用 Option Explicit 避免变量名的拼写错误。 关于要求显式变量声明的详细信息,请参阅"编程基础"中的"变量、常量和数据类型概述"。
第七条:查错原则:
1, 在编程时,当程序发现错误,应当立即改错。现在就改,以避免程序完成时遗漏未改的错误。
2, 发现错误时,应当找出从错误的源头再修改。(对此,应当摒弃"工作量太大了"的思想)
3, 当代码有错时,绝不可以猜测错在哪里。试图碰运气改正它。必须停下来思考已发现的错误,从而判断是否别的地方有相关的错误还没有暴露出来。思考如何更易发现错误,如何避免此类错误。
第三章 技术会议
第八条:技术会议应遵守下列原则:
1, 不可分割工作时间,即:唯有周一早上或周五下午才是最佳时间。
2, 会议要有目的,即能通过会议作出决定时或确有重要信息传达时才开技术会议。
3, 会议最终一定要落实最终目标,具体实现用各人的具体任务。
4, 会议只对将来,故总结也为了将来,因而绝不可以有冗长的总结。
5, 会议一定要有详细的会议记录,以备查实际落实情况。
6, 应当遵守"不要带来问题,应当带来解决方案"的原则。不可将问题留到下一次会议。
7, 一个良好且具体的解决方案应明确:问题,详细方案,负责人与最后期限。
第四章 编码约定
第九条:为什么要进行编码约定?
使用统一编码约定集的主要原因,是使应用程序的结构和编码风格标准化,以便于阅读和理解这段编码。
好的编码约定可使源代码严谨、可读性强且意义清楚,与其它语言约定相一致,并且尽可能的直观。
最小编码约定
一组通用目的的编码约定应该定义完成上述目的所必需的、能让程序员自由地创建程序逻辑和功能流程的最小的要求。
最小编码约定的目的是使程序易于阅读和理解,而不是用过份的约束和绝对的限制来束缚程序员本身的创造性。
所以,该附录中提出的约定是简洁和建意性的。这些约定中没列出每一个可能的对象或控件,也没列出每种有用的信息注释。根据工程及机构的特殊要求,也许希望扩充这些准则,以包含附加的元素,如:
对于在家庭中开发的或从第三方厂商购买的特定对象及组件的约定。
描述机构的商业活动或设备的变量。
工程或企业认为对清楚性和可读性很重要的任何其它元素。
第十条:以下内容以VB为蓝本,任一开发工具均以此为参考。地加以改正。

vb技巧之20- 编程规范二
第十一条:对象命名约定
应该用一致的前缀来命名对象,使人们容易识别对象的类型。下面列出了一些推荐使用的对象约定。
推荐使用的控件前缀
控件类型 前缀 例子
3D Panel  pnl pnlGroup
ADO Data ado adoBiblio
Animated button ani aniMailBox
Check box chk chkReadOnly
Combo box, drop-down list box cbo cboEnglish
Command button cmd cmdExit
Common dialog  dlg dlgFileOpen
Communications  com comFax
Control ctr ctrCurrent
Data dat datBiblio
Data-bound combo box dbcbo dbcboLanguage
Data-bound grid dbgrd dbgrdQueryResult
Data-bound list box dblst dblstJobType
Data combo dbc dbcAuthor
Data grid dgd dgdTitles
Data list dbl dblPublisher
Data repeater drp drpLocation
Date picker dtp dtpPublished
Directory list box dir dirSource
Drive list box drv drvTarget
File list box fil filSource
Flat scroll bar f*** f***Move
Form frm frmEntry
Frame fra fraLanguage
Gauge gau gauStatus
Graph gra graRevenue
Grid grd grdPrices
Hierarchical flexgrid flex flexOrders
Horizontal scroll bar h*** h***Volume
Image img imgIcon
Image combo imgcbo imgcboProduct
ImageList ils ilsAllIcons
Label lbl lblHelpMessage
Lightweight check box lwchk lwchkArchive
Lightweight combo box lwcbo lwcboGerman
Lightweight command button lwcmd lwcmdRemove
Lightweight frame lwfra lwfraSaveOptions
Lightweight horizontal scroll bar lwh*** lwh***Volume
Lightweight list box lwlst lwlstCostCenters
Lightweight option button lwopt lwoptIncomeLevel
Lightweight text box lwtxt lwoptStreet
Lightweight vertical scroll bar lwv*** lwv***Year
Line lin linVertical
List box lst lstPolicyCodes
ListView lvw lvwHeadings
MAPI message mpm mpmSentMessage
MAPI session mps mpsSession
MCI mci mciVideo
Menu mnu mnuFileOpen
Month view mvw mvwPeriod
MS Chart ch chSale***yRegion
MS Flex grid msg msgClients
MS Tab  mst mstFirst
OLE container ole oleWorksheet
Option button opt optGender
Picture box pic picVGA
Picture clip clp clpToolbar
Progres***ar prg prgLoadFile
Remote Data rd rdTitles
RichTextBox rtf rtfReport
Shape shp shpCircle
Slider sld sldScale
Spin spn spnPages
Statu***ar sta staDateTime
SysInfo sys sysMonitor
TabStrip tab tabOptions
Text box txt txtLastName
Timer tmr tmrAlarm
Toolbar tlb tlbActions
TreeView tre treOrganization
UpDown upd updDirection
Vertical scroll bar v*** v***Rate

vb技巧之21-编程规范三
第十二条:常量和变量命名约定
除了对象之外,常量和变量也需要良好格式的命名约定。
变量应该总是被定义在尽可能小的范围内。全局 (Public) 变量可以导致极其复杂的状态机构,并且使一个应用程序的逻辑非常难于理解。全局变量也使代码的重用和维护更加困难。所以,全局变量,在一个产品中应当不多于10 个。
在Visual Basic中变量可以有下列范围:
范围 声明位置 可见位置
过程级 过程,子过程或函数过程中的 'Private' 在声明它的过程中
模块级 窗体或代码模块(.frm、.bas )的声明部分中的 'Private' 窗体或代码模块中的每一个过程
全局 代码模块(.bas)的声明部分中的 'Public' 应用程序中的每一处
在应用程序中,只有当没有其它方便途径在窗体之间共享数据时才使用全局变量。当必须使用全局变量时,在一个单一模块中声明它们,并按功能分组。给这个模块取一个有意义的名称,以指明它的作用,如 Public.bas。
较好的编码习惯是尽可能写模块化的代码。例如,如果应用程序显示一个对话框,就把要完成这一对话任务所需要的所有控件和代码放在单一的窗体中。这有助于将应用程序的代码组织在有用的组件中,并减小它运行时的开销。
除了全局变量(应该是不被传递的),过程和函数应该仅对传递给它们的对象操作。在过程中使用的全局变量应该在过程起始处的声明部分中标识出来。此外,应该用 ByVal 将参数传递给 Sub 过程及 function 过程,除非明显地需要改变已传递的参数值。
变量范围前缀
随着工程大小的增长,划分变量范围的工作也迅速增加。在类型前缀的前面放置单字母范围前缀标明了这种增长,但变量名的长度并没有增加很多。
范围 前缀 例子
全局 g gstrUserName
模块级 m mblnCalcInProgress
本地到过程 无 dblVelocity
如果一个变量在标准模块或窗体模块中被声明为 Public,那么该变量具有全局范围。如果一个变量在标准模块或窗体模块中被分别声明为 Private,那么该变量有模块级范围。
注意  一致性是卓有成效地使用这种技术的关键;Visual Basic 中的语法检查器不会捕捉以 "p." 开头的模块级变量。
常量
常量名的主体是大小写混合的,每个单词的首字母大写。尽管标准 Visual Basic 常量不包含数据类型和范围信息,但是象 i、s、g 和 m 这样的前缀对于理解一个常量的值和范围还是很有用的。对于常量名,应遵循与变量相同的规则。例如:
mintUserListMax      '对用户列表的最大限制
                  '(整数值,本地到模块)
gstrNewLine            '新行字符
                  '(字符串,应用程序全局使用)
变量
声明所有的变量将会节省编程时间,因为键入操作引起的错误减少了(例如,究竟是 aUserNameTmp,还是 sUserNameTmp,还是 sUserNameTemp)。在"选项"对话框的"编辑器"标签中,复选"要求变量声明"选项。Option Explicit 语句要求在 Visual Basic 程序中声明所有的变量。
应该给变量加前缀来指明它们的数据类型。而且前缀可以被扩展,用来指明变量范围,特别是对大型程序。
变量数据类型
用下列前缀来指明一个变量的数据类型。
数据类型 前缀 例子
Boolean bln blnFound
Byte byt bytRasterData
Collection col colWidgets
Currency cur curRevenue
Double dbl dblTolerance
Error err errOrderNum
Inteage int intQuantity
Long lng lngDistance
Object obj objCurrent
Single sng sngAverage
String str strFName
User-def udt udtEmployee
Variant vnt vntCheckSum
描述变量和过程名
变量或过程名的主体应该使用大小写混合形式,并且应该足够长以描述它的作用。而且,函数名应该以一个动词起首,如 InitNameArray 或 CloseDialog。
对于频繁使用的或长的项,推荐使用标准缩略语以使名称的长度合理化。一般来说,超过 32 个字符的变量名在 VGA 显示器上读起来就困难了。
当使用缩略语时,要确保它们在整个应用程序中的一致性。在一个工程中,如果一会儿使用 Cnt, 一会儿使用 Count,将导致不必要的混淆。
用户定义的类型
在一项有许多用户定义类型的大工程中,常常有必要给每种类型一个它自己的三个字符的前缀。如果这些前缀是以 "u" 开始的,那么当用一个用户定义类型来工作时,快速识别这些类型是很容易的。例如,ucli 可以被用来作为一个用户定义的客户类型变量的前缀。

vb技巧之22-编程规范四
第十三条:结构化编码约定
除了命名约定外,结构化编码约定,可以极大地改善代码的可读性,如代码注释和一致性缩进。
代码注释约定
所有的过程和函数都应该以描述这段过程的功能的一段简明注释开始(这段例程干什么)。这种描述不应该包括执行过程细节(它是怎么做的),因为这常常是随时间而变的,而且这种描述会导致不必要的注释维护工作,甚至更糟-成为错误的注释。代码本身和必要的嵌入注释将描述实现方法。
当参数的功能不明显且当过程希望参数在一个特定的范围内时,也应描述传递给过程的参数。被过程改变的函数返回值和全局变量,特别是通过引用参数的那些,也必须在每个过程的起始处描述它们。
过程头注释块应该包括下列节标题。关于例子,请参阅下节"格式化代码"。
节标题 注释描述
目的 该过程完成什么(而不是怎么完成)。
假设 列出每个外部变量、控件、打开文件或其它不明显元素。
效果 列出每个被影响的外部变量、控件、或文件及其作用(只有当它不明显时)。
输入 每一个可能不明显的参数。参数分别在单独的行上,并嵌入注释。
返回 函数返回值的说明。
记住下列几点:
每一个重要变量的声明应该包括一个嵌入注释,来描述该变量的使用。
变量、控件及过程的命名应该足够清楚,使得只有复杂的执行细节才需要嵌入注释。
.Bas 模块包含工程的 Visual Basic 一般常量声明,在其起始处,应该包括描述应用程序的综述,列举主要数据对象、过程、算法、对话、数据库及系统需求。有时,一段描述算法的伪码可能会有所帮助。
格式化代码
因为许多程序员仍然使用 VGA 显示器,所以在允许代码格式来反映逻辑结构和嵌套的同时,应尽可能地省屏幕空间。下面列出几点:
标准的、基于制表位的嵌套块应该被缩进四个空格(缺省情况下)。
过程的功能综述注释应该缩进一个空格。跟在综述注释后面的最高级的语句应该缩进一个制表位,而每一个嵌套的块再缩进一个制表位。例如:
'*****************************************************
'目的:      在用户列表数组中找出
'            一个指定用户的第一次出现位置。
'输入:
'  strUserList():  被搜索的用户列表。
'  strTargetUser:  要搜索的用户名。
' 返回:  在rasUserList 数组中rsTargetUser
'            的第一次出现的索引。
'            如果目标用户没找到,返回-1。
'*****************************************************

Function intFindUser (strUserList() As String, strTargetUser As _
  String)As Integer
  Dim i As Integer            ' 循环计数器。
  Dim blnFound As Integer      ' 目标寻找标志。
  intFindUser = -1
  i = 0
  While i <= Ubound(strUserList) and Not blnFound
      If strUserList(i) = strTargetUser Then
        blnFound = True
        intFindUser = i
      End If
  Wend
End Function
给常量分组
变量和定义的常量应该按功能分组,而不是分散到单独区域或特定文件中。Visual Basic 一般常量应该在单一模块中分组,以将它们与应用程序特定的声明分开。

& 和 + 运算符
在连接字符串时总是使用 & 运算符,而当处理数值时常用 + 运算符。当在两个变体上操作时,用 + 运算符来连接可能会导致问题。例如:

vntVar1 = "10.01"
vntVar2 = 11
vntResult = vntVar1 + vntVar2    'vntResult = 21.01
vntResult = vntVar1 & vntVar2  'vntResult = 10.0111

为 MsgBox、InputBox 及 SQL 查询创建字符串
当产生长字符串时,使用下划线连接字符产生多行代码,这样便于阅读或调试字符串。当显示一个消息框 (MsgBox) 或输入框 (InputBox),或产生一个 SQL 字符串时,这一技术特别有用。例如:

Dim Msg As String
Msg = "This is a paragraph that will be " _
& "in a message box. The text is" _
& " broken into several lines of code" _
& " in the source code, making it easier" _
& " for the programmer to read and debug."
MsgBox Msg

Dim QRY As String
QRY = "SELECT *" _
& " FROM Titles" _
& " WHERE [Year Published] > 1988"
TitlesQry.SQL = QRY
第五章:程序验收
第十四条:测试与验收:任何程序需经测试无错后,方能通过验收。
第十五条:程序测试应有详细的测试报告。程序员应根据测试报告无条件




vb技巧之23-在VB中用API实现多媒体
在VB中用API实现多媒体主要是调用Windows的mmsystem.dll库。以下为调用API的声明(这些代码放在程序的声明部分中):
1.′播放CD和AVI所需要的声明。
  Declare Function mciSendString Lib ″MMSYSTEM″(ByVal lpstrCommand as String,ByVal lpstrReturnStr as Any,By Val wRetumLen as Integer,ByVal hCallBack as Integer) as Long
  ′播放WAV所需要的声明
  Declare Function sndPlaySound Lib ″MMSYSTEM.DLL″(ByVal lpszSoundName as String,ByVal wF1ags as Integer) as Integer
  ′检测声卡所需要的声明
  Declare Function auxGetNaumDevs Lib ″MMSYSTEM″()as Integer
  ′所用到的全局变量声明
  Global Const SND_SYNC=&H0000   ′播放WAV用到的全局变量
  Global Const SND_ASYNC=&-H0001 ′播放WAV用到的全局变量
  Global Const SND_NODEFAULT=&H0002 ′播放WAV用到的全局变量
  Global Const SND_LOOP=&H0008 ′播放WAV用到的全局变量
  Global Const SND_NOSTOP=&-H0010 ′播放WAV用到的全局变量
  ′接下来是调用这些声明
  Function auxTest()as Boolean
  Dim i As Integer
  i=auxGetNumDevs()
  If i>0 Then
  AuxTest=True ′如果有声卡则返回真
  Exit Function
  Else
  AuxTest=False ′如果未检测到声卡则返回假
  Exit Function
  Else
  AuxTest=False ′如果未检测到声卡则返回假
  Exit Function
  End If
  End Function
2.播放CD的源代码
  Sub PlayCD(b As Integer)
  ′ b为所播的音轨号
  Dim a As Long
  a=mciSendString(″open cdaudio alias cd wait″,0&,0,0) '初始化驱动
  a=mciSendString(″set cd time format tmsf″,0&,0,0)
  a=mciSendString(″play cd from″& Str(b),0&,00) ′播放音轨
  End Sub
3.播放AVI的源代码
  Sub playAVI(AVIFile As String)
  Dim RVal as Long
  AVIFile=″play″+AVIFile+″fullscreen″ ′全屏幕播放AVI文件
  RVal=mciSendString(AVIFile,0&,0,0&)
  End Sub
4.播放WAV的源代码
  Sub playWAV(WAVFile As String)
  Dim Flag as Integer
  Dim a as Integer
  wFlag=SND_ASYNC or SND_NODEFAULT
  a=sndPlaySound(WAVFile,Flag)
  End Sub
  以上程序是我在调用多媒体时所常用的模块,你只需将上面的模块在程序中直接调用即

vb技巧之24-DoEvents函数
转让控制权,以便让操作系统处理其它的事件。

DoEvents 函数会返回一个 Integer,以代表 Visual Basic 独立版本中打开的窗体数目,例如,Visual Basic,专业版,在其它的应用程序中,DoEvents 返回 0。

DoEvents 会将控制权传给操作系统。当操作系统处理完队列中的事件,并且在 SendKeys 队列中的所有键也都已送出之后,返回控制权。

DoEvents 对于简化诸如允许用户取消一个已启动的过程 — 例如搜寻一个文件 — 特别有用。对于长时间过程,放弃控制权最好使用定时器或通过委派任务给 ActiveX EXE 部件来完成。以后,任务还是完全独立于应用程序,多任务及时间片由操作系统来处理。

小心 确保以 DoEvents 放弃控制权的过程,在第一次 DoEvents 返回之前,不能再次被其他部分的代码调用;否则会产生不可预料的结果。此外,如果其它的应用程序可能会和本过程以不可预知的方式进行交互操作,那么也不要使用 DoEvents,因为此时不能放弃控制权。

使用 DoEvents

尽管 Timer 事件是后台处理的最好工具,对耗时极多的任务,情况更是如此,但是,DoEvents 函数还是提供了一种取消任务的简便方法。例如,下列代码将显示一个 "rocess" 按钮,单击这个按钮时,它将变成 "Cancel" 按钮。再次单击按钮又将中断正在执行的任务。

'此按钮标题是 "Process"
Private Sub Command1_Click()
'过程的所有实例都共享静态变量。
  Static blnProcessing As Boolean
  Dim lngCt As Long
  Dim intYieldCt As Integer
  Dim dblDummy As Double
  '按下按钮时,检测是否在处理
  If blnProcessing Then
   '如果正在处理,则取消
      blnProcessing = False
  Else
      Command1.Caption = "Cancel"
      blnProcessing = True
      lngCt = 0
   '执行一百万次浮点乘法计算。每一千次后,检测是否要取消。
      Do While blnProcessing And (lngCt < 1000000)
        For intYieldCt = 1 To 1000
            lngCt = lngCt + 1
            dblDummy = lngCt * 3.14159
        Next intYieldCt
      'DoEvents 语句允许其它事件发生,包括第二次按此按钮。
        DoEvents
      Loop
      blnProcessing = False
      Command1.Caption = "Process"
      MsgBox lngCt & " multiplications were performed"
  End If
End Sub

DoEvents 将控制切换到操作环境内核。只要此环境中的所有应用程序都有机会响应待处理事件,应用程序就又恢复控制。这不会使应用程序放弃焦点,但会使后台事件能够得到处理。

这种妥协的结果可能并不总是达到预期目标。例如,下述 Click 事件代码在单击按钮后要一直等候十秒钟,而后才显示一条信息。如果在按钮正在等待期间单击它,则将以相反顺序完成单击操作。

Private Sub Command2_Click()
  Static intClick As Integer
  Dim intClickNumber As Integer
  Dim dblEndTime As Double
      '每次单击按钮时
      '赋予唯一数值。
  intClick = intClick + 1
  intClickNumber = intClick
      '等待十秒。
  dblEndTime = Timer + 10#
  Do While dblEndTime > Timer
      '不做任何事情,仅仅允许
      '其它应用程序处理
      '它们的事件。
      DoEvents
  Loop
  MsgBox "Click " & intClickNumber & " is finished"
End Sub

对于通过 DoEvents 放弃控制的事件过程,有时可能希望防止在 DoEvents 返回之前重新调用这一过程。否则将无穷无尽地调用该过程,直到系统资源消耗殆尽。可暂时禁止控件,或象上例一样,使用一个静态的“标志”变量防止此事发生。

在使用全局数据时避免 DoEvents
当一个函数已通过 DoEvents 放弃控制时,可相当安全地再次调用函数。例如,下一过程将检测质数并用 DoEvents 语句周期地启动其它应用程序处理事件:

Function PrimeStatus (TestVal As Long) As Integer
  Dim Lim As Integer
  PrimeStatus = True
  Lim = Sqr(TestVal)
  For I = 2 To Lim
      If TestVal Mod I = 0 Then
        PrimeStatus = False
        Exit For
      End If
      If I Mod 200 = 0 Then DoEvents
  Next I
End Function

该代码中每重复 200 次就调用一次 DoEvents 语句。这样一来,当该环境的其余部分对事件作出响应时,只要有必要,PrimeStatus 过程就可继续计算。

考虑在调用 DoEvents 期间发生的事情。在其它窗体和应用程序处理事件时将暂停执行应用程序代码。这些事件之一有可能是一个按钮单击操作,它将再次启动 PrimeStatus 过程。

这将导致重新进入 PrimeStatus 过程的,但是,因为在函数每次出现时,堆栈都为其参数和局部变量分配了空间,所以重入不会引发冲突。当然,如果过多调用 PrimeStatus,则可能出现“溢出堆栈空间”错误。

如果 PrimeStatus 使用或改变模块级变量或全局数据,情况就会完全不同。此时,在 DoEvents 能够返回之前执行 PrimeStatus 的另一个实例,这将导致模块数据或全局数据的值完全不同于它们在调用 DoEvents 之前的值。于是,PrimeStatus 的结果将会难以预料
 楼主| 发表于 2005-5-11 08:23:25 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之25-VB编程动态注册ActiveX控件
在使用VB和其它一些Win9X下的编程软件,就要同ActiveX控件打交道,注册
和反注册控件是一件令人很头疼的事情。有时从网上下载了一个控件,但是在使用
时VB总是提示控件没有注册。又或者想删除一个控件却无法从注册中抹去。
    实际上,每一个ActiveX控件都有两个输出函数:DllRegisterServer和
DllUnRegisterServer。顾名思义,通过这两个函数就可以注册和反注册控件了,
下面通过程序说明如何通过编程来注册。
    首先在Form中加入两个CommandButton,不要改变它们的属性。然后在Form中
加入如下代码:
Private Declare Function RegComCtl32 Lib "ComCtl32.OCX" _
        Alias "DllRegisterServer" () As Long
Private Declare Function UnRegComCtl32 Lib "ComCtl32.OCX" _
        Alias "DllUnregisterServer" () As Long
Private Declare Function FormatMessage Lib "kernel32" _
        Alias "FormatMessageA" (ByVal dwFlags As Long, _
        lpSource As Any, ByVal dwMessageId As Long, _
        ByVal dwLanguageId As Long, ByVal lpBuffer _
        As String, ByVal nSize As Long, Arguments As _
        Long) As Long
Private Declare Function GetLastError Lib "kernel32" () As Long

Const ERROR_SUCCESS = &H0

Private Sub Command1_Click()
    Dim astr As String
   
    '反注册ComCtl32.Ocx
    If RegComCtl32 = ERROR_SUCCESS Then
        MsgBox "注册成功"
    Else
        astr = String$(256, 20)
        FormatMessage FORMAT_MESSAGE_FROM_SYSTEM Or _
            FORMAT_MESSAGE_IGNORE_INSERTS, 0&, GetLastError, _
            0&, astr, Len(astr), ByVal 0
        MsgBox astr
    End If
End Sub

Private Sub Command2_Click()
    Dim astr As String

    '反注册ComCtl32.Ocx   
    If UnRegComCtl32 = ERROR_SUCCESS Then
        MsgBox "反注册成功"
    Else
        astr = String$(256, 20)
        FormatMessage FORMAT_MESSAGE_FROM_SYSTEM Or _
            FORMAT_MESSAGE_IGNORE_INSERTS, 0&, GetLastError, _
            0&, astr, Len(astr), ByVal 0
        MsgBox astr
    End If
End Sub
    运行程序,点击Command2反注册ComCtl32.Ocx控件,在VB菜单中选 Project|components
或按Ctrl+T,在控件列表框中可以看到已经没有ComCtl32.Ocx了。再运行程序,点击Command1
重新注册控件。
    以上程序再VB5,WIN95下运行通过


vb技巧之26-向过程传递参数上
过程中的代码通常需要某些关于程序状态的信息才能完成它的工作。信息包括在调用过程时传递到过程内的变量。当将变量传递到过程时,称变量为参数。

参数的数据类型
过程的参数被缺省为具有 Variant 数据类型。不过,也可以声明参数为其它数据类型。例如,下面的函数接受一个字符串和一个整数:

Function WhatsForLunch(WeekDay As String, Hour As Integer) As String
  '根据星期几和时间,返回午餐菜单。
  If WeekDay = "Friday" then
      WhatsForLunch = "Fish"
  Else
      WhatsForLunch = "Chicken"
  End If
  If Hour > 4 Then WhatsForLunch = "Too late"
End Function

详细信息 关于 Visual Basic 的数据类型,请参阅本章前面部分。也可以在语言参考中查找指定的数据类型。

按值传递参数
按值传递参数时,传递的只是变量的副本。如果过程改变了这个值,则所作变动只影响副本而不会影响变量本身。用 ByVal 关键字指出参数是按值来传递的。

例如:

Sub PostAccounts (ByVal intAcctNum as Integer)

End Sub

按地址传递参数
按地址传递参数使过程用变量的内存地址去访问实际变量的内容。结果,将变量传递给过程时,通过过程可永远改变变量值。按地址传递参数在 Visual Basic 中是缺省的。

如果给按地址传递参数指定数据类型,就必须将这种类型的值传给参数。可以给参数传递一个表达式,而不是数据类型。Visual Basic 计算表达式,如果可能的话,还会按要求的类型将值传递给参数。

把变量转换成表达式的最简单的方法就是把它放在括号内。例如,为了把声明为整数的变量传递给过程,该过程以字符串为参数,则可以用下面的语句:

Sub CallingProcedure ()
  Dim intX As Integer
  intX = 12 * 3
  Foo (intX)
End Sub

Sub Foo (Bar As String)
  MsgBox Bar            'Bar的值为'36'
End Sub

使用可选的参数
在过程的参数列表中列入 Optional 关键字,就可以指定过程的参数为可选的。如果指定了可选参数,则参数表中此参数后面的其它参数也必是可选的,并且要用 Optional 关键字来声明。下面两段示例代码假定有一个窗体,其内有一命令按钮和一列表框。

例如,这段代码提供所有可选参数:

Dim strName As String
Dim strAddress As String

Sub ListText(Optional x As String, Optional y _
As String)
  List1.AddItem x
  List1.AddItem y
End Sub

Private Sub Command1_Click ()
  strName = "yourname"
Optional
  strAddress = 12345            '提供了两个参数。
  Call ListText (strName, strAddress)
End Sub

而下面的代码并未提供全部可选参数:

Dim strName As String
Dim varAddress As Variant

Sub ListText (x As String, Optional y As Variant)
  List1.AddItem x
  If Not IsMissing (y) Then
      List1.AddItem y
  End If
End Sub

Private Sub Command1_Click ()
  strName = "yourname"            '未提供第二个参
                        '数。
  Call ListText (strName)
End Sub

vb技巧之27-向过程传递参数下
在未提供某个可选参数时,实际上将该参数作为具有 Empty 值的变体来赋值。上例说明如何用 IsMissing 函数测试丢失的可选参数。

提供可选参数的缺省值
也可以给可选参数指定缺省值。在下例中,如果未将可选参数传递到函数过程,则返回一个缺省值。

Sub ListText(x As String, Optional y As _
Integer = 12345)
  List1.AddItem x
  List1.AddItem y
End Sub

Private Sub Command1_Click ()
  strName = "yourname"  '未提供第二个参
                    '数。
  Call ListText (strName)  '添加“yourname”和
                        '“12345”。
End Sub

使用不定数量的参数
一般说来,过程调用中的参数个数应等于过程说明的参数个数。可用 ParamArray 关键字指明,过程将接受任意个数的参数。于是可以这样来编写计算总和的 Sum 函数:

Dim x As Integer
Dim y As Integer
Dim intSum As Integer

Sub Sum (ParamArray intNums ())
  For Each x In intNums
      y = y + x
  Next x
  intSum = y
End Sub

Private Sub Command1_Click ()
  Sum 1, 3, 5, 7, 8
  List1.AddItem intSum
End Sub

用命名的参数创建简单语句
对许多内建函数、语句和方法,Visual Basic 提供了命名参数方法来快捷传递参数值。对命名参数,通过给命名参数赋值,就可按任意次序提供任意多参数。为此,键入命名参数,其后为冒号、等号和值 (MyArgument := "SomeValue") ,可以按任意次序安排这些赋值,它们之间用逗号分开。注意,下例中的参数顺序和所要参数的顺序相反:

Function ListText (strName As String, Optional strAddress As String)
  List1.AddItem strName
  List2.AddItem strAddress
End Sub

Private Sub Command1_Click ()
  ListText strAddress:=”12345”, strName:="Your Name"
End Sub

如果过程有若干不必总要指定的可选参数,则上述内容更为有用。

确定对命名参数的支持
要确定哪一个函数、语句和方法支持命名参数,用“代码”窗口中的“AutoQuickInfo”功能,检查“对象浏览器”,或者参阅语言参考。使用命名参数时要注意以下几点:

在 Visual Basic (VB) 对象库中的对象的方法不支持命名参数。而 Visual Basic for applications (VBA) 对象库中的所有的语言关键字都支持命名的参数。

在语法中,命名参数是用粗体和斜体字表示的。所有其它参数只用斜体字表示。
重点 使用命名参数时不能省略所需参数的输入。可以只省略可选参数。对于 Visual Basic (VB) 和 Visual Basic for applications (VBA) 对象库,“对象浏览器”对话框将可选参数用方括号 [ ] 括起来。



vb技巧之28-数据库查询结果的动态排序一
在公共新闻组中,一个经常出现的问题是“怎样才能根据传递给存储过程的参数返回一个排序的输出?”。在一些高水平专家的帮助之下,我整理出了这个问题的几种解决方案。

一、用IF...ELSE执行预先编写好的查询

  对于大多数人来说,首先想到的做法也许是:通过IF...ELSE语句,执行几个预先编写好的查询中的一个。例如,假设要从Northwind数据库查询得到一个货主(Shipper)的排序列表,发出调用的代码以存储过程参数的形式指定一个列,存储过程根据这个列排序输出结果。Listing 1显示了这种存储过程的一个可能的实现(GetSortedShippers存储过程)。

【Listing 1: 用IF...ELSE执行多个预先编写好的查询中的一个】

CREATE PROC GetSortedShippers

@OrdSeq AS int

AS

IF @OrdSeq = 1

SELECT * FROM Shippers ORDER BY ShipperID

ELSE IF @OrdSeq = 2

SELECT * FROM Shippers ORDER BY CompanyName

ELSE IF @OrdSeq = 3

SELECT * FROM Shippers ORDER BY Phone

  这种方法的优点是代码很简单、很容易理解,SQL Server的查询优化器能够为每一个SELECT查询创建一个查询优化计划,确保代码具有最优的性能。这种方法最主要的缺点是,如果查询的要求发生了改变,你必须修改多个独立的SELECT查询——在这里是三个。  

二、用列名字作为参数

  另外一个选择是让查询以参数的形式接收一个列名字。Listing 2显示了修改后的GetSortedShippers存储过程。CASE表达式根据接收到的参数,确定SQL Server在ORDER BY子句中使用哪一个列值。注意,ORDER BY子句中的表达式并未在SELECT清单中出现。在ANSI SQL-92标准中,ORDER BY子句中不允许出现没有在SELECT清单中指定的表达式,但ANSI SQL-99标准允许。SQL Server一直允许这种用法。

【Listing 2:用列名字作为参数,第一次尝试】

CREATE PROC GetSortedShippers

@ColName AS sysname

AS

SELECT *

FROM Shippers

ORDER BY

CASE @ColName

WHEN 'ShipperID' THEN ShipperID

WHEN 'CompanyName' THEN CompanyName

WHEN 'Phone' THEN Phone

ELSE NULL

END

  现在,我们来试一下新的存储过程,以参数的形式指定ShipperID列:

EXEC GetSortedShippers 'ShipperID'

  此时一切正常。但是,当我们视图把CompanyName列作为参数调用存储过程时,它不再有效:

EXEC GetSortedShippers 'CompanyName'

  仔细看一下错误信息:

Server: Msg 245, Level 16, State 1, Procedure GetSortedShippers, Line 5

Syntax error converting the nvarchar value 'Speedy

Express' to a column of data type int.

  它显示出,SQL Server试图把“Speedy Express”(nvarchar数据类型)转换成一个整数值——当然,这个操作是不可能成功的。出现错误的原因在于,按照“数据类型优先级”规则,CASE表示式中最高优先级的数据类型决定了表达式返回值的数据类型。“数据类型优先级”规则可以在SQL Server Books Online(BOL)找到,它规定了int数据类型的优先级要比nvarchar数据类型高。前面的代码要求SQL Server按照CompanyName排序输出,CompanyName是nvarchar数据类型。这个CASE表达式的返回值可能是ShipperID(int类型),可能是CompanyName(nvarchar类型),或Phone(nvarchar类型)。由于int类型具有较高的优先级,因此CASE表达式返回值的数据类型应该是int。
为了避免出现这种转换错误,我们可以尝试把ShipperID转换成varchar数据类型。采用这种方法之后,nvarchar将作为最高优先级的数据类型被返回。Listing 3显示了修改后的GetSortedShippers存储过程。

【Listing 3:用列名字作为参数,第二次尝试】

ALTER PROC GetSortedShippers

@ColName AS sysname

AS

SELECT *

FROM Shippers

ORDER BY

CASE @ColName

WHEN 'ShipperID'

THEN CAST(ShipperID AS varchar(11))

WHEN 'CompanyName'

THEN CompanyName

WHEN 'Phone'

THEN Phone

ELSE NULL

END

  现在,假设我们再把三个列名字中的任意一个作为参数调用存储过程,输出结果看起来正确。看起来就象指定的列正确地为查询输出提供了排序标准。但这个表只有三个货主,它们的ID分别是1、2、3。



vb技巧之29- 数据库查询结果的动态排序二
假设我们把更多的货主加入到表,如Listing 4所示(ShipperID列有IDENTITY属性,SQL Server自动为该列生成值)。

【Listing 4:向Shippers表插入一些记录】

INSERT INTO Shippers VALUES('Shipper4', '(111) 222-9999')

INSERT INTO Shippers VALUES('Shipper5', '(111) 222-8888')

INSERT INTO Shippers VALUES('Shipper6', '(111) 222-7777')

INSERT INTO Shippers VALUES('Shipper7', '(111) 222-6666')

INSERT INTO Shippers VALUES('Shipper8', '(111) 222-5555')

INSERT INTO Shippers VALUES('Shipper9', '(111) 222-4444')

INSERT INTO Shippers VALUES('Shipper10', '(111) 222-3333')

  现在调用存储过程,指定ShipperID作为排序列:

EXEC GetSortedShippers 'ShipperID'

  表一显示了存储过程的输出。ShipperID等于10的记录位置错误,因为这个存储过程的排序输出是字符排序,而不是整数排序。按照字符排序时,10排列在2的前面,因为10的开始字符是1。

表一:记录排序错误的查询结果

ShipperID CompanyName Phone

1 Speedy Express (503) 555-9831

10 Shipper10 (111) 222-3333

2 United Package (503) 555-3199

3 Federal Shipping (503) 555-9931

4 Shipper4 (111) 222-9999

5 Shipper5 (111) 222-8888

6 Shipper6 (111) 222-7777

7 Shipper7 (111) 222-6666

8 Shipper8 (111) 222-5555

9 Shipper9 (111) 222-4444
为了解决这个问题,我们可以用前置的0补足ShipperID值,使得ShipperID值都有同样的长度。按照这种方法,基于字符的排序具有和整数排序同样的输出结果。修改后的存储过程如Listing 5所示。十个0被置于ShipperID的绝对值之前,而在结果中,代码只是使用最右边的10个字符。SIGN函数确定在正数的前面加上加号(+)前缀,还是在负数的前面加上负号(-)前缀。按照这种方法,输出结果总是有11个字符,包含一个“+”或“-”字符、前导的字符0以及ShipperID的绝对值。

【Listing 5:用列名字作为参数,第三次尝试】

ALTER PROC GetSortedShippers

@ColName AS sysname

AS

SELECT *

FROM Shippers

ORDER BY

CASE @ColName

WHEN 'ShipperID' THEN CASE SIGN(ShipperID)

WHEN -1 THEN '-'

WHEN 0 THEN '+'

WHEN 1 THEN '+'

ELSE NULL

END +

RIGHT(REPLICATE('0', 10) +

CAST(ABS(ShipperID) AS varchar(10)), 10)

WHEN 'CompanyName' THEN CompanyName

WHEN 'Phone' THEN Phone

ELSE NULL

END

  如果ShipperID的值都是正数,加上符号前缀就没有必要,但为了让方案适用于尽可能多的范围,本例加上了符号前缀。排序时“-”在“+”的前面,所以它可以用于正、负数混杂排序的情况。
现在,如果我们用任意三个列名字之一作为参数调用存储过程,存储过程都能够正确地返回结果。Richard Romley提出了一种巧妙的处理方法,如Listing 6所示。它不再要求我们搞清楚可能涉及的列数据类型。这种方法把ORDER BY子句分成三个独立的CASE表达式,每一个表达式处理一个不同的列,避免了由于CASE只返回一种特定数据类型的能力而导致的问题。

【Listing 6:用列名字作为参数,Romley提出的方法】

ALTER PROC GetSortedShippers

@ColName AS sysname

AS

SELECT *

FROM Shippers

ORDER BY

CASE @ColName WHEN 'ShipperID'

THEN ShipperID ELSE NULL END,

CASE @ColName WHEN 'CompanyName'

THEN CompanyName ELSE NULL END,

CASE @ColName WHEN 'Phone'

THEN Phone ELSE NULL END

  按照这种方法编写代码,SQL Server能够为每一个CASE表达式返回恰当的数据类型,而且无需进行数据类型转换。但应该注意的是,只有当指定的列不需要进行计算时,索引才能够优化排序操作

vb技巧之30-手工签署证书的方法
虽然在安装MOD_SSL时已经使用 make certificate 命令建立了服务器
的证书签名,但是有时你可能需要改变它。

当然有很多自动的脚本可以实现它,但是最可靠的方法是手工签署
证书。

首先我假定你已经安装好了openssl和MOD_SSL,如果你的openssl安装时
的prefix设置为/usr/local/openssl,那么把/usr/local/openssl/bin加入
执行文件查找路径。还需要MOD_SSL源代码中的一个脚本,它在MOD_SSL的
源代码目录树下的pkg.contrib目录中,文件名为 sign.sh。
将它拷贝到 /usr/local/openssl/bin 中。

先建立一个 CA 的证书,
首先为 CA 创建一个 RSA 私用密钥,
[S-1]
openssl genrsa -des3 -out ca.key 1024
系统提示输入 PEM pass phrase,也就是密码,输入后牢记它。
生成 ca.key 文件,将文件属性改为400,并放在安全的地方。
[S-2]
chmod 400 ca.key
你可以用下列命令查看它的内容,
[S-3]
openssl rsa -noout -text -in ca.key

利用 CA 的 RSA 密钥创建一个自签署的 CA 证书(X.509结构)
[S-4]
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
然后需要输入下列信息:
Country Name: cn 两个字母的国家代号
State or Province Name: An Hui 省份名称
Locality Name: Bengbu 城市名称
Organization Name: Family Network 公司名称
Organizational Unit Name: Home 部门名称
Common Name: Chen Yang 你的姓名
Email Address: sunstorm@263.net Email地址
生成 ca.crt 文件,将文件属性改为400,并放在安全的地方。
[S-5]
chmod 400 ca.crt
你可以用下列命令查看它的内容,
[S-6]
openssl x509 -noout -text -in ca.crt

下面要创建服务器证书签署请求,
首先为你的 Apache 创建一个 RSA 私用密钥:
[S-7]
openssl genrsa -des3 -out server.key 1024
这里也要设定pass phrase。
生成 server.key 文件,将文件属性改为400,并放在安全的地方。
[S-8]
chmod 400 server.key
你可以用下列命令查看它的内容,
[S-9]
openssl rsa -noout -text -in server.key

用 server.key 生成证书签署请求 CSR.
[S-10]
openssl req -new -key server.key -out server.csr
这里也要输入一些信息,和[S-4]中的内容类似。
至于 'extra' attributes 不用输入。

你可以查看 CSR 的细节
[S-11]
openssl req -noout -text -in server.csr

下面可以签署证书了,需要用到脚本 sign.sh
[S-12]
sign.sh server.csr
就可以得到server.crt。
将文件属性改为400,并放在安全的地方。
[S-13]
chmod 400 server.crt

删除CSR
[S-14]
rm server.csr

最后apache设置
如果你的apache编译参数prefix为/usr/local/apache,
那么拷贝server.crt 和 server.key 到 /usr/local/apache/conf
修改httpd.conf
将下面的参数改为:
SSLCertificateFILE /usr/local/apache/conf/server.crt
SSLCertificateKeyFile /usr/local/apache/conf/server.key
 楼主| 发表于 2005-5-11 08:27:12 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之48-直接通过ODBCAPI访问SQL数据库一
*********************************
ODBC - Open DataBase Connectivity
*********************************

Basic Steps

Connecting to the SQL Server DataBase for retrieving information from tables

*************************************************************
The steps 1 - 3 are for connecting to the SQL Server Database
*************************************************************

1. Allocate ODBC Environment Handle

If SQLAllocEnv(glEnv) <> 0 Then
  MsgBox "Unable to initialize ODBC API drivers!"
  End
End If
______________________________________________________________

2. Allocate ODBC Database Handle

Dim iStatus As Integer

If SQLAllocConnect(glEnv, glDbc) <> 0 Then
  MsgBox "Could not allocate memory for connection Handle!"
  ODBCInit = False

  ' Free the Environment
  iStatus = SQLFreeEnv(lEnv)

  If iStatus = SQL_ERROR Then
    MsgBox "Error Freeing Environment From ODBC Drivers"
  End If

  ' Quit the Application
  End
End If
______________________________________________________________

3. Connect using the sConnect string - SQLDriverConnect

Dim sResult As String
Dim iSize As Integer
Dim sConnect As String

sConnect = "DSN=" & gsDSN & ";UID=" & gsLoginID & "WD=" & gsPassword & ";APP=" & gsAppCode & ";DATABASE=" & gsDatabase

If SQLDriverConnect(glDbc, Screen.ActiveForm.hWnd, sConnect, Len(sConnect), sResult, Len(sResult), iSize, 0) <= 0 Then
  MsgBox "Could not establish connection to ODBC driver!"
End If
______________________________________________________________

***************************************************
The steps 4 - 8 are for retrieving data from tables
***************************************************

4. Allocate ODBC Statement Handle

If SQLAllocStmt(glDbc, glStmt) <> 0 Then

   MsgBox "Could not allocate memory for a statement handle!"

End If
______________________________________________________________

5. Execute ODBC Statement - SQLExecDirect

Dim lRet As Long, lErrNo As Long
Dim iLen As Integer
Dim sSQLState As String * MAX_DATA_BUFFER
Dim sErrorMsg As String * MAX_DATA_BUFFER
Dim sMsg As String

sSQL = "SELECT name, location FROM authors"

If SQLExecDirect(glStmt, sSQL, Len(sSQL)) <> SQL_SUCCESS Then
  ' Also Check for ODBC Error message - SQLError
  lRet = SQLError(glEnv, gldbc, glStmt, sSQLState, lErrNo, sErrorMsg, MAX_DATA_BUFFER, iLen)
  sMsg = "Error Executing SQL Statement" & Chr$(13) & Chr$(10)
  sMsg = sMsg & "ODBC State = " & Trim$(Left$(sSQLState, InStr(sSQLState, Chr$(0)) - 1)) & Chr$(13) & Chr$(10)
  sMsg = sMsg & "ODBC Error Message = " & Left$(sErrorMsg, iLen)
  MsgBox sMsg, vbInformation, "Execute Query"
End If
______________________________________________________________

6. Fetch one row of results from executed ODBC Statement - SQLFetch

Code in Step 7.



vb技巧之49-直接通过ODBCAPI访问SQL数据库二
7. Get the Data in each field of the Fetched row - SQLGetData

Dim bPerform As Integer, iStatus As Integer
Dim sData As String * MAX_DATA_BUFFER
Dim lOutLen As Long

bPerform = SQLFetch(glStmt)

Do While bPerform
  bPerform = SQLFetch(lStmt)     ' Get the next row of data
  If bPerform = SQL_SUCCESS Then    ‘ If rows of data available  
    bPerform = True

    ' Get Author Name - iColumn = 1 for first field i.e. name in sSQL
    iStatus = SQLGetData(glStmt, iColumn, 1, sData, MAX_DATA_BUFFER, lOutLen)

    ' lOutlen = length of the valid data in sData
    ' Data value will be = Left$(sData, lOutlen), lOutlen = -1 if no data or Null data

    ' Get Location - iColumn = 2 for second field i.e. location in sSQL
    iStatus = SQLGetData(glStmt, iColumn, 1, sData, MAX_DATA_BUFFER, lOutLen)

     ' Add the Field Data to Correponding Data Display Controls for this row
  Else
    bPerform = False  ' No more rows available
  End If
Loop

'Release the ODBC Statement Handle
bPerform = SQLFreeStmt(glStmt, SQL_DROP)
______________________________________________________________

8. Release the ODBC Statement Handle - SQLFreeSTmt

Code in Step 7.
______________________________________________________________

*******************************************************************
The steps 9 - 11 are for Disconnecting from the SQL Server DataBase
*******************************************************************

9. Disconnect from ODBC Database - SQLDisconnect

iStatus = SQLDisconnect(glDbc)
______________________________________________________________

10. Release the ODBC Database Handle - SQLFreeConnect

iStatus = SQLFreeConnect(glDbc)
______________________________________________________________

11. Release the ODBC Environment Handle - SQLFreeEnv

iStatus = SQLFreeEnv(glEnv)
______________________________________________________________

***********************************************************************
The following entries are required in the ODBCAPI module
***********************************************************************

' ODBC Variables and Constants
 
Global glEnv As Long
Global glDbc As Long
Global sSQL As String
 
Global Const MAX_DATA_BUFFER = 255
Global Const SQL_SUCCESS = 0
Global Const SQL_SUCCESS_WITH_INFO = 1
Global Const SQL_ERROR = -1
Global Const SQL_NO_DATA_FOUND = 100
Global Const SQL_CLOSE = 0
Global Const SQL_DROP = 1
Global Const SQL_CHAR = 1
Global Const SQL_NUMERIC = 2
Global Const SQL_DECIMAL = 3
Global Const SQL_INTEGER = 4
Global Const SQL_SMALLINT = 5
Global Const SQL_FLOAT = 6
Global Const SQL_REAL = 7
Global Const SQL_DOUBLE = 8
Global Const SQL_VARCHAR = 12
Global Const SQL_DATA_SOURCE_NAME = 6
Global Const SQL_USER_NAME = 8

'ODBC Declarations
'The hWnd is a Long in Windows 95 & Windows NT



vb技巧之50-直接通过ODBCAPI访问SQL数据库二三
#If Win32 Then
  Declare Function SQLAllocEnv Lib "odbc32.dll" (env As Long) As Integer
  Declare Function SQLFreeEnv Lib "odbc32.dll" (ByVal env As Long) As Integer
  Declare Function SQLAllocConnect Lib "odbc32.dll" (ByVal env As Long, ldbc As Long) As Integer
  Declare Function SQLConnect Lib "odbc32.dll" (ByVal ldbc As Long, ByVal Server As String,ByVal serverlen As Integer, ByVal uid As String, ByVal   uidlen As Integer, ByVal pwd As String, ByVal pwdlen As Integer) As Integer

  Declare Function SQLDriverConnect Lib "odbc32.dll" (ByVal ldbc As Long, ByVal hWnd As Long, ByVal szCSIn As String, ByVal cbCSIn As   Integer,ByVal szCSOut As String, ByVal cbCSMax As Integer, cbCSOut As Integer, ByVal f As Integer) As Integer

  Declare Function SQLFreeConnect Lib "odbc32.dll" (ByVal ldbc As Long) As Integer
  Declare Function SQLDisconnect Lib "odbc32.dll" (ByVal ldbc As Long) As Integer
  Declare Function SQLAllocStmt Lib "odbc32.dll" (ByVal ldbc As Long, lStmt As Long) As Integer
  Declare Function SQLFreeStmt Lib "odbc32.dll" (ByVal lStmt As Long, ByVal EndOption As Integer) As Integer
  Declare Function SQLTables Lib "odbc32.dll" (ByVal lStmt As Long, ByVal q As Long, ByVal cbq As Integer, ByVal o As Long, ByVal cbo As Integer,   ByVal t As Long, ByVal cbt As Integer, ByVal tt As Long, ByVal cbtt As Integer) As Integer

  Declare Function SQLExecDirect Lib "odbc32.dll" (ByVal lStmt As Long, ByVal sqlString As String, ByVal sqlstrlen As Long) As Integer

  Declare Function SQLNumResultCols Lib "odbc32.dll" (ByVal lStmt As Long, NumCols As Integer) As Integer
  Declare Function SQLDescribeCol Lib "odbc32.dll" (ByVal lStmt As Long, ByVal colnum As Integer, ByVal colname As String, ByVal Buflen As   Integer, colnamelen As Integer, dtype As Integer, dl As Long, ds As Integer, n As Integer) As Integer

  Declare Function SQLFetch Lib "odbc32.dll" (ByVal lStmt As Long) As Integer
  Declare Function SQLGetData Lib "odbc32.dll" (ByVal lStmt As Long, ByVal col As Integer, ByVal wConvType As Integer, ByVal lpbBuf As String,   ByVal dwbuflen As Long, lpcbout As Long) As Integer

  Declare Function SQLGetInfo Lib "odbc32.dll" (ByVal ldbc As Long, ByVal hWnd As Long, ByVal szInfo As String, ByVal cbInfoMax As Integer,   cbInfoOut As Integer) As Integer

  Declare Function SQLError Lib "odbc32.dll" (ByVal env As Long, ByVal ldbc As Long, ByVal lStmt As Long, ByVal SQLState As String, NativeError As   Long, ByVal Buffer As String, ByVal Buflen As Integer, Outlen As Integer) As Integer

#Else



vb技巧之51-直接通过ODBCAPI访问SQL数据库四
Declare Function SQLAllocEnv Lib "odbc.dll" (env As Long) As Integer
  Declare Function SQLFreeEnv Lib "odbc.dll" (ByVal env As Long) As Integer
  Declare Function SQLAllocConnect Lib "odbc.dll" (ByVal env As Long, ldbc As Long) As Integer
  Declare Function SQLConnect Lib "odbc.dll" (ByVal ldbc As Long, ByVal Server As String, ByVal serverlen As Integer, ByVal uid As String, ByVal   uidlen As Integer, ByVal pwd As String, ByVal pwdlen As Integer) As Integer

  Declare Function SQLDriverConnect Lib "odbc.dll" (ByVal ldbc As Long, ByVal hWnd As Integer, ByVal szCSIn As String, ByVal cbCSIn As Integer,   ByVal szCSOut As String, ByVal cbCSMax As Integer, cbCSOut As Integer, ByVal f As Integer) As Integer

  Declare Function SQLFreeConnect Lib "odbc.dll" (ByVal ldbc As Long) As Integer
  Declare Function SQLDisconnect Lib "odbc.dll" (ByVal ldbc As Long) As Integer
  Declare Function SQLAllocStmt Lib "odbc.dll" (ByVal ldbc As Long, lStmt As Long) As Integer
  Declare Function SQLFreeStmt Lib "odbc.dll" (ByVal lStmt As Long, ByVal EndOption As Integer) As Integer
  Declare Function SQLTables Lib "odbc.dll" (ByVal lStmt As Long, ByVal q As Long, ByVal cbq As Integer, ByVal o As Long, ByVal cbo As Integer,   ByVal t As Long, ByVal cbt As Integer, ByVal tt As Long, ByVal cbtt As Integer) As Integer

  Declare Function SQLExecDirect Lib "odbc.dll" (ByVal lStmt As Long, ByVal sqlString As String, ByVal sqlstrlen As Long) As Integer

  Declare Function SQLNumResultCols Lib "odbc.dll" (ByVal lStmt As Long, NumCols As Integer) As Integer
  Declare Function SQLDescribeCol Lib "odbc.dll" (ByVal lStmt As Long, ByVal colnum As Integer, ByVal colname As String, ByVal Buflen As Integer,   colnamelen As Integer, dtype As Integer, dl As Long, ds As Integer, n As Integer) As Integer

  Declare Function SQLFetch Lib "odbc.dll" (ByVal lStmt As Long) As Integer
  Declare Function SQLGetData Lib "odbc.dll" (ByVal lStmt As Long, ByVal col As Integer, ByVal wConvType As Integer, ByVal lpbBuf As String, ByVal   dwbuflen As Long, lpcbout As Long) As Integer

  Declare Function SQLGetInfo Lib "odbc.dll" (ByVal ldbc As Long, ByVal hWnd As Integer, ByVal szInfo As String, ByVal cbInfoMax As   Integer,cbInfoOut As Integer) As Integer

  Declare Function SQLError Lib "odbc.dll" (ByVal env As Long, ByVal ldbc As Long, ByVal lStmt As Long, ByVal SQLState As String, NativeError As   Long, ByVal Buffer As String, ByVal Buflen As Integer, Outlen As Integer) As Integer

#End If
 楼主| 发表于 2005-5-11 08:30:51 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

vb技巧之52-网络数据库教程一
一、第一天

错误的技术被用于解决错误的问题

你可能会注意到现在有很多有关互联网的技术。但是,实际上这些技术中90%都是没有用的。我是说,如果它们有用的话,光是学习这些技术就会把你给累死。大多数的网络技术之所以不被人重视,我想是因为以下原因:

没有用,很漂亮很有趣,但没有什么意义。
不能通用于所有浏览器。例如,JavaScript 在不同的浏览器中会出不同的问题。更不用说ActiveX了。
速度慢、占用过多的带宽,没有到可以实际应用的地步。(任何一种技术...咳咳...包括 Java)
技术的失败并不使我感到惊奇。太多的人只是将精力集中在自己做的东西有多漂亮,却忘记了制作它是要用于什么用途。还有。许多技术必须是基于客户端的技术,当你必须依赖客户的要求来决定采用或者技术手段时,则不是一件容易的事。

好在互联网公众并不太关注这些好看但没有用途的东西。它他们希望互联网能为其提高特定的服务或娱乐,帮助他们获得工作甚至找到女朋友,检查银行帐户、股票价格、利率、订购机票等等等等。

要使互联网为你提供这些服务,你必须首先将相关的数据作出合理得力组织安排,并且随时可以将这些数据更新和修改。对数据的管理需要比较复杂的技术(但绝不是上面所说的无用的绣花枕头)。

二、设想访问你的站点的都是什么人

假设有一个公司叫做"Widgets Inc",我们看看对于不同的用户,它意味着什么。

顾客到网站检查他们发给该公司的订单的状况,同时还要看看该公司本周的产品报价和价格表。
销售代表来该网站浏览所收集到的订单,仓库存货、退单的情况,以及最新的促销奖励。销售代表很有可能直接从该网页中获得订购商品的订单。为什么可能呢?互联网为你提供了一切便利的条件。
经理从销售代表处获得总结报告(地区。季度、陆运、海运和空运)。
其他人也空运充该网站获益。供应商、零售商、投资者....机会无所不在。
或许Widgets Inc是一个具有深谋远虑的公司,所以他们准备了相应的技术和技术支持。有关他们的产品和服务的新闻甚至可以从互联网中直接发布给公众。在他们的网页中提供了内容丰富的动态信息,可以吸引每一个用户。

但是要使一个网站具备全面的能力,该网站海需要有完善的安全机制。这个机制基于用户名、口令等等。

让我们进一步假设:你的经理让你为一个重要的客户提供所有历史销售记录。则存储所有历史销售记录也必须是该网站所应具备的功能。

三、我的选择是什么

我架构了这个"Widgets Inc" 例子来说明数据在互联网中扮演的角色。将数据库集成到网站中在我所举的这个例子中具有非常强大的作用。显示中的例子比如互联网电影数据库。这种数据库加入只采用文本文件的形式组织这样一个灵活的数据库是不可能的。它需要有一个数据库。或者说它需要重新设计其外观和运行机制,它需要用新技术来更新。如果没有一个数据库系统或模板系统,这个工作将无法开展,因为你不可能将这个庞大网站的每一页靠手从键盘输入就架设起来。一个用途广泛动态的网站必须靠数据来支持,简单的网站中的数据只能供你浏览,而要提供网站和用户之间的互动浏览功能,则网站的架构就要复杂许多。更先进的网站可以实现用户和数据之间的互动,就需要使网站数据能够被添加、删除和修改。

现在我们谈谈网站数据的处理可能采取的结构:

无结构
这个主意很糟糕。只是一大把文本文件组成的网站不能满足复杂的功能。
有组织的文本文件:Delimited or fixed-width fields
这个主意稍好些,担它仍然存在很多技术问题。你必须无休止地加工数据或者必须牺牲用户介入的速度。数据的维护也将是一个很令人头疼的事。除了必须加入新数据,并且还得处理由于各种疏忽所造成的错误。你还必须编码以处理文件,处理锁定、只读、允许写盘和允许生成数据的结构以及数据之间的各种联系。这样做实在是太费事了。
标识语言:HTML, SGML, XML,
这种方法可以实现数据存放和牺牲的很多灵活性,但是你仍然必须建立非常系统的结构化的数据对象。有些语言Perl和Omnimark 在努力实现数据的结构化。很多语言恩公提供这些功能,但同时也得牺牲速度和简单性。
很多时候编制复杂的数据库常常使人们感到沮丧不已。而这也使得许多公司受到启发。他们制作出相应的软件帮助你处理这些问题,于是出现乐数据库服务器-database server。
你已经听说过这些名称:Oracle, Sybase, Microsoft SQL Server, Informix, Ingress. 这些程序提供了处理数据库非常好的结构:

它们将数据存储在表格(tables)中。 Tables的域可以包含许多种结构不同的数据类型,例如整数(integer)、字符串( character string)、货币(money)、日期(date)和二进制大型对象(Binary Large OBject-BLOB)。
它们提供乐管理表格的管理机制。
表格和管理机制通过复杂的用户/口令/域保卫机制保证数据的安全性。
你可以使用功能强大而且相对容易使用的语言同数据交流。例如SQL。而且。你可以将建立存储后的SQL声明,这样即使用户不懂这种语言也可以利用数据库。
数据库的优势还在于:已经有很多人在使用数据库。你会发现你所要放入你的数据库的很多数据已经具有乐某种数据库格式。你可以充分利用数据的现成结构。

四、为什么要使用互联网

在我上学的时候,教授曾经问过这样一个问题:为什么鲸鱼要生活在极地海洋?有一个同学回答说:因为鲸鱼块头太大了,它们的皮肤面积太大,保温的鲸脂层太厚以及因为它们的新陈代谢系统的原因。他总结说:如果鲸鱼不生活在极地海洋中,它们就会热死。

我的答案很简单:因为极地海洋中有它们所需要的足够的食物。

那么,你为什么要上互联网呢?因为互联网上有你的观众。那么观众为什么要上互联网呢?因为在互联网中可以找到他们需要的东西。
vb技巧之53-网络数据库教程二
即使在一个公司内部的环境中,网络浏览器也是无所不在。它使得网络成为信息交流的方便途径。
浏览器可以移植。你不需要随身带着你的计算机和个人软件。只要有浏览器你就可以通过网络找到你的数据。
网络同数据的接口非常快,而且容易编程,即使同某些快速的开发语言例如Visual Basic相比也是如此。
你无需费心向你的用户(内部网络的用户还不算多,但外部网络的用户则无法用数字估量)分发专门用于你的数据库的软件。
你无需考虑为每个用户提供软件升级。只要你升级乐拟定服务器上的软件,则你的每一个用户都会获益。
你无需培训用户使用你的软件几乎所有上网的用户都知道如何使用浏览器及知道如何填写表单。
当然,一些专业技术例如Visual Basic或Visual C++, Powerbuilder或Developer 2000可以帮你生成数据库界面。但是我在前面的讨论中已经谈了这种制作方法的费时费力。所以我不打算教你用这些语言制作数据库。

五、如何应用

如何应用?这是一个很难用一句话就能回答清楚的问题。事实上,我需要把其余几天的时间都用来回答这个问题。

明天我将向你介绍目前可以应用的技术有哪几种。这里所说的技术包括操作系统,你可以用 Windows NT或Unixe的一种。接下来我们将可一下数据库、网络服务器和网络开发工具以及语言。检查完所有这些选项之后,我将以其中的一种为例向你介绍如何用它搭建数据库。

第3天的课程中我将集中谈两种软件:网络服务器(相对较简单)和数据库服务器(相对较难),什么是服务器,我如何利用服务器工作?这些问题都将得到回答。我还将揭示应用表格和SQL(结构化重新语言- Structured Query Language)的秘诀。

第4天的课程中我将讨论将数据库同外部网络集成的技术和技巧。

第5天将是第3和第4天课程的深化。其实我还需要在准备一次课程详细探讨目前所讲的概念。

你可以进入这些利用数据库搭建的网站了解一下我们所要讲解的什么。

互联网电影数据库
这个站点非常有趣。如果你项了解某部电影或某个演员,这个站点可以提供你这些信息。信息我,这个站点可不是用单纯的外部文件就能搭建起来的。
热联线成员中心
该站点处理数据的方式不是那么明显,但实际上,在这个站点中显示的页面只是一种"虚拟文件" - 它们看起来项网页,但实际上它们是用模板和数据库给拼出来的。
CD数据库
这个站点为那些播放在CD-ROM光驱中播放CD时懒得键入歌曲名称的人服务。

网络数据库教程-第2日
浏览: 292 次
一 确定系统类型
二 Windows NT和Linux的对比
三 安装Linux和相应软件
四 设定你的期望   

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

一、确定系统类型

Know your playing field

The story so far ...

现在我们已经懂得了人们需要什么:数据。而数据库是处理数据最好的途径。并且我们了解了网络对于数据库来说是一个了不起的界面。

那么,接下来我们需要了解数据库如何工作。

决策,决策...

我们是否应该使用Windows NT或UNIX类型的系统作为我们的互联网网络服务器平台?

在我们决定使用何种技术之前,我要提请你注意:生成数据库支持的网站绝不象编写HTML文件那样简单。这不仅因为数据库要复杂许多,而且因为它需要同互联网服务器集成应用。

要安装、配置和初始化网络数据库的技术,你必须是系统的管理员。在UNIX系统中,系统管理员用户叫做"root"或者有时候叫做"the superuser"。在Windows NT系统中,系统管理员就叫做"管理员"。

在某些提供免费主页存放的站点,例如Geocities, Angelfire或其他当地的ISP来说,他们能为你提供5到10Mb的空间,但目前他们还不允许你为自己的网页设立数据库管理机制。

所以,你必须主管一个系统来运行数据库。架设你现在就在管理一个系统,你需要选择用Windows NT系统和UNIX系统来建立你的数据库,该系统需要被细分为各个子目录。我将集中介绍每一种系统的规范设置。该设置包括一个操作系统、一个网络服务器、一个SQL服务器和一个网络开发工具。这些是你运行一个网络数据库的核心。

二、Windows NT和Linux的对比

Windows NT服务器4和MS IIS和MS SQL服务器以及Allaire Cold Fusion

Slackware Linux & Apache & TCX Mysql & Perl (带模块)
的对比

(注意:我在使用作为UNIX OS系统的代表,因为它比较便宜并且具有通用性。其他的UNIX平台的工作也比较好,但其中的某些命令可能和我在本文中用到的有些区别。)

Windows NT的优点

使用方便
Windows软件相对而言容易安装,它的界面直观,运行简便(我很喜欢SQL服务器)和ODBC(开放数据库互联-Open DataBase Connectivity)非常好用。
产品系列的稳定性
许多人都非常喜欢微软软件的稳定性和强大的功能。微软是一个能随时提供持续稳定的支持的公司。它的产品系列不会突然之间枯竭,你不用害怕自己用微软产品某一天找不到升级和更新的技术支持。微软还是技术趋势的领头人。很多人喜欢微软,因为他们都在用微软的视窗产品。
Windows NT的缺点

软件成本太高
要配备这个系统你需要花几千美元。而且其他和Windows相关的就是成本也很高。要配备这个系统,你先得准备好你的钱包。
"必须花钱的支持"是一个逆喻。使用商业软件的优点在于包括了技术支持。从使用角度讲,你所得到的支持从是离理想要差那么一点点。即使你
得到他们的技术支持,你也需要为此付出种种额外的费用。如果你真的发现他们的软件中存在某些问题,你要想让问题得到解决,可能得需要几周的时间。
功能不灵活
商业软件只能完成它既定的使命,除此之外,没有其他用途。如果你想获得什么特别的东西,你必须等待它的新版本面市。可能会在明年。
功能有限
商业软件的哲学就是:“保持它的简洁”。而这样以来,某些功能也过于简单,不能作进一步的开发。
Linux的优点



vb技巧之54-网络数据库教程三
这种软件很便宜。
Linux整个系统只需花US$200。如果你只将其用于个人目的,你几乎不用花多少钱,但是你必须用你可怜的调制解调器从网上下载300 Mb的程序。而你付30美元就可以获得linux的发行版。另外,Linux带有很多你需要的工具(例如邮件服务器mail server, C/C++ 编译器等等),你无需在单买这些软件。
高性能软件
Linux、Apache、和Perl建立的系统速度快、稳定,可以开发出许多功能。还可以支持和结合超文本:Mod_perl将Apache附加到Perl上,DBI将Perl附加到数据库上,ePerl 可以随意处理网络编程模式......
Linux的缺点

心脏不好者慎用
     
一旦你掌握了Linux,在整个领域内你将无所不能。然而不幸的是,要掌握这门技术可不是一件容易的事。Perl, Apache,和Mysql也是如此。怎么说呢,天上不会掉馅饼。
艰难的说服过程
除非你所生存的空间不存在任何组织或者叫没有任何官僚体制,否则你必须说服你的上级去应用一种免费的系统。你的上级会反问你这样的问题:你怎么可以在工作中冒这样的险?免费的东西,会好使吗?
最后的赢家是...

在我看来呢,应选择Linux。在实际应用中,我采用两种方式。对于本教程来说呢,我们假设的是读者还没有建立自己的网络数据库系统。那么对于你们而言,你们希望采用免费的东西还是必须花大笔钱的东西?

还有许多使用免费系统的优点,在之后几天的课程中我将逐步谈到这些优点。

三、安装Linux和相应软件

如果你了解UNIX,你可以继续读下面的各段,否则,你需要:

 

买或借一本有关的好书。
为自己获得一个UNIX帐户,如果你是一个学生,这会比较容易。否则,你可以找提供UNIXshell介入服务的ISP。
花时间学习和使用它。
你需要获得一个Linux软件。我对Slackware很熟悉,所以我在此以它为例。但是Red Hat, S.u.S.E., 和Caldera也很不错。我建议你查询Linux Online。整个站点不仅告诉你各种Linux 软件的情况,而且还告诉从哪里可以找到他们。还有大量有关Linux的文献可供参考。

你还可以从CD-ROM中安装Slackware的Linux软件。最新的版本是3.4。不要用更低版本的东西。

你无需将你的计算机完全用于运行Linux;其安装选项可以让你选择"multi-boot" 来选择从Windows OS 或Linux来驱动计算机。你所需的只是将硬盘分区。你可以买一个新硬盘,或者使用分区工具。

安装Linux我有几个不成规矩的建议:

不要安装Perl。
不要安装Apache。
你肯定会需要这些,但是3.4版本的Slackware软件实际上还不是最新的软件。你可以从相应的站点下载最新版本http://www.perl.com/ and http://www.apache.org/。Perl的最新?..枰??男鹿δ堋?/a>

下载的过程中你可以顺便下载这些:

LinuxThreads
以下Perl模块,也是来自Comprehensive Perl Archive Network, 或称作CPAN,你可以在http://www.perl.com/找?
Data-Dumper (在Data子目录)
Data-ShowTable (在Data子目录)
MD5
MIME-Base-64 (在MIME子目录)
CGI
libnet (在Net子目录)
libwww-perl (在LWP子目录)
最新版本的mod_perl。你也可以从CPAN获得整个软件,但你最好看一下mod_perl 的主页。
ePerl, "嵌入式(Embedded)Perl"语言。
Mysql数据库软件包。
你可能还需要获得Netscape的linux版本。
大部分的这些文件都是.tar.gz格式的文件。它是"磁带归档文件(Tape Archive)"格式的文件,它用GNU Zip进行了压缩。要解压缩这些文件,你需要使用

tar xvzf /path/to/file/file.tar.gz
只是假设在tar中已经包含了一个子目录。你可以检查一个子目录是否包含了

tar tvzf /path/to/file/file.tar.gz | less
我建议解压缩(un-tar.gz-ing)所有/usr/src 子目录中的文件,但ePerl, Apache, Mysql和mod_perl除外。这些文件需要扩展到 /usr/local/src中。还存在将这些文件放置到其他路径的可能性,我欢迎这些建议。

你需要重新建立Linux内核,例如包括对网卡的支持。这样做时注意按照README和INSTALL中的指南去执行。你还需要将你的内核更新到最新的版本,它可以从The Linux Archives获得。

我建议你按照的每种文件都带有如何编译的指南。如果你只了解Windows环境,可能你很少用到代码编译。依照README和INSTALL文件中的指南执行即可。

首先安装(不只是解压缩un-tar.gz,而是实际安装) Perl,接着安装LinuxThreads,然后是各种Perl模块。mod_perl的安装最简单,它将Apache在编译的同时即安装,所以你无需单独编译Apache,你只需处理Apache配置文件。

接下来安装ePerl。ePerl欲求两步不同的安装程序:第一种是将其作为独立的程序安装,然后作为Perl(和mod_perl)模块。第2步需要你重新处理Apache配置文件。

我详细介绍安装过程是因为出于我“痛苦”的经历。Mysql的运行需要LinuxThreads的支持。而LinuxTheads需要Perl,Mysql也需要Perl和Data-ShowTable模块的支持。Mod_perl需要Apache 和libwww-perl,而Libwww-perl需要libnet。

四、设定你的期望

要将这一切组装在一起要花将近一天的时间,而这也是因为我已经重复这样的过程不下10次。第1次安装需要花1周的时间,而且那时候没有人给我任何指南。

我还不能说最坏的情况已经过去。明天我们还必须处理网络服务器的配置(configurations)和Mysql数据库引擎。最麻烦的事情便是细节的处理...



vb技巧之55-网络数据库教程四
一、第三天

网络数据库是一个很大的课题,用一个5天的教程不可能谈到所有的内容。我为你教授基础的知识,剩下的就要靠你自己在实践中体会和学习。

在本教程中我们只有时间讲解于网络数据库有关的设置问题。

Apache

Apache网络服务器 是一项性能相当不错的软件。简单地说,它的目的就是让用户能从你的计算机中请求网络信息。通常这些信息是HTML网页和图象(GIF和JPEG图象),但是现代的网络服务器都支持CGI (网络编程)。

这是Apache简单版本的功能。对于特定的应用,你需要对其进行设置,让其真正发挥功能。

Apache的功能实际上非常强大,你可以对其进行多种设置,执行多种功能。但现在我们只能讲解有关网络数据库的设置。今天所讲的需要和Apache其他的文献或我们在这里使用的软件包一起应用。

二、常规的Apache设置

进行常规Apache设置:

 

选择DocumentRoot子目录
ePerl
mod_perl
DocumentRoot概念比较容易理解。假设我们设立了域www.example.com。而URL可能如下所示:

http://www.example.com/webmonkey/day3.html
我喜欢将我的DocumentRoot设置为/web/docs/,这样以来,相对应于该URL的文件将是/web/docs/webmonkey/day3.html.

假设你按照我昨天的课程中的建议安装了Apache,则你需要编辑/usr/src/apache_1.2.6/conf/srm.conf将DocumentRoot设置为/web/docs。 (编辑方法很简单,你一看就知道该怎么做。你还需要相应改变/usr/src/apache_1.2.6/conf/access.conf. (也不难)。在Unix提示符下,注意一定要实际建立该DocumentRoot子目录:

     mkdir /web; mkdir /web/docs
Perl和ePerl (将是明天的主要课程内容),和mod_perl一起就可建立起世界一流的数据库支持下的网站。缩头的课程中我建议你们使用了mod_perl的自动Apache创立功能,所以现在你应该有了这样一个文件 /usr/src/apache_1.2.6/src/httpd。

接下来,你应该:

第1步:建立/usr/src/apache_1.2.6/src/httpd和/usr/***in/httpd之间的标志性链接。
建立标志性链接的意义是:你的Linux操作系统希望httpd放置在/usr/***in子目录中,但是以后对httpd的任何重新的设置将把它该在/usr/src/apache_1.2.6/src下。整个特点使你无需每次将httpd拷贝到/usr/***in下。
    cd /usr/***in

    ln -s /usr/src/apache_1.2.6/src/httpd httpd
第2步:检查确保拟定设置中包括了mod_perl。
现在我们做一个快速检查,键入以下指令:
     /usr/***in/httpd -v
屏幕将显示一条短信息:

     Server version Apache/1.2.6 mod_perl/1.08.
第3步”设置你的/etc/rc.d/rc.M文件。
该文件和DOS的自动批处理文件(autoexec.bat)类似。它在你的Linux服务器启动时运行。确保使所有必要的重新都被初始化并在boot时能够正常运行。如果你的rc.M文件中没有以下设置,你应该加入:
     # Start Web server:

     if [ -x /etc/rc.d/rc.httpd ]; then

       . /etc/rc.d/rc.httpd

     fi
这些代码意思是说:Linux的启动过程将激活文件/etc/rc.d/rc.httpd的内容 (以启动你的httpd)。这时,屏幕应显示:

     echo  httpd

     /usr/***in/httpd -f /usr/src/apache_1.2.6/conf/httpd.conf &
或许你还没有整个文件,所以你需要生成该文件

第4步:使Apache能够处理CGI和ePerl文件。
现在你需要进行大量细节的设置。回到/usr/src/apache_1.2.6/conf子目录,然后:
在access.conf中,确保以加重字体(bold)加入下列文字:

     <Directory /web/docs>

     Options Indexes FollowSymLinks ExecCGI

     AllowOverride None

     order allow,deny

     allow from all

     </Directory>
现在,修改srm.conf:

     DirectoryIndex index.iphtml index.cgi index.html
你还需要"uncomment" 某行,所以最后的设置为:

     AddHandler cgi-script .cgi
在httpd.conf中,, 在<VirtualHost>区域之上加入以下文字:

     Perlrequire /web/docs/startup.perl

     PerlModule Apache::ePerl

     <Files ~ ".+\.iphtml$">

         SetHandler  perl-script

         PerlHandler Apache::ePerl

     <Files>
现在你的/web/docs子目录下需要一个startup.perl文件,你可以拷贝我的:

     #!/usr/bin/perl

     use strict;

     use Apache::Registry;

     use CGI;

     use DBI ();

     1;



vb技巧之56-网络数据库教程五
缺省情况下,除了你指定的/cgi-bin/子目录之外,Apache不会允许CGI程序在任何其他子目录中运行,如果安全性是你的首要考虑,这一条很重要。但由于现在我们谈的是网络数据库编程,所以在第4步中的设置让Apache运行CGI程序在其他子目录中也能运行。

我们还告诉Apache遇到带有特殊后缀.iphtml的文件时应该怎么做。这种文件叫做内部剖析后的HTML文件。现在Apache知道应该将这种文件转交ePerl进行进一步的处理。最后。我们告诉Apache在服务器初始化之后立即运行文件startup.perl。该文件把几个非常有用的模块载入服务器内存,重要之后的程序需要使用这些模块时就 无需重新载入它们。

 

三、MySQL和整个数据库/服务器系统

在第1天的教程中,我了解了数据库服务器常驻内存并可以回应请求、存储数据、提供管理界面确保数据只能在授权范围内被处理。现在我们将使用MySQL来实践这些概念。

 

建立好你的MySQL后,你需要进行的设置比起对Apache的设置就少多了。执行完完整的MySQL安装过程(包括运行/usr/local/src/mysql-VERSION/scripts/mysql_install_db)后,还有一项工作需要执行:将其设置为常驻内存的守护程序。这个过程和我们对httpd的做法相同。编辑/etc/rc.d/rc.M 文件使其包括以下代码:

     # Start mysql database server:

     if [ -x /etc/rc.d/rc.mysql ]; then

       . /etc/rc.d/rc.mysql

     fi
生成相应的rc.mysql文件。非常简单:

     /usr/local/bin/mysql.server start
当我使用MySQL时,我经常使用这两个程序:/usr/local/bin/mysql和/usr/local/bin/mysqlshow。你不需要键入所有这些内容,- mysql和mysqlshow就能够正常工作,因为/usr/local/bin是指令路径的环境变量的一部分。

让我们试一下:

     rdice:# mysqlshow

     +-----------+

     | Databases |

     +-----------+

     | mysql     |

     | test      |

     +-----------+
这就是你应该看到的(假设你已经正确安装了Perl和Data::ShowTable)。这项输出项我们显示了:MySQL在最高级别上将数据安排到数据库中。上述两个显示由MySQL自动生成,每一项都有特殊用途:mysql被MySQL自己使用来生成程序自己的内部设置,test作为某种暂存区供所有用户使用,但是它没有任何安全防护机权限设置。也就是说,不要将任何重要信息放在test暂存区内。

我们再来一遍。但是这次我们将欲求mysqlshow告诉我test数据库中的内容:

     rdice:# mysqlshow test

     Database: test

     +--------+

     | Tables |

     +--------+

     +--------+
表格(Tables)是数据库中的下一级。你可以将表格想象为电子工作表:列(columns)代表数据域,而行(rows)则代表单个的记录。

从屏幕输出中我们可以看到test数据库是空的。我们将配合使用 mysql程序和MySQL并在数据库中放入具体的内容。

四、MySQL, SQL, DDL,和DML

同MySQL的互动交流指的是用它的语言SQL(结构化程序语言)。SQL一般划分为两部分,第1部分叫做DDL,即数据定义语言(data definition language),你用SQL这个单元告诉MySQL如何设立表格。还有一部分是DML,即数据控制语言( data manipulation language),这个单元用于从你的表格中获取数据。

这里是计划:我将启动mysql,生成一个表格,然后在表格中输入数据,然后检查我刚输入的数据。(我用加重体显示的文字解释各项指令的含义)

     rdice:# mysql test

     Welcome to the MySQL monitor.  Commands end with ; or \g.

     Your MySQL connection id is 4 to server version:
3.21.28-gamma-log

     

     Type 'help' for help.

     

     mysql> create table albums (            这里我在使用DDL
         -> title varchar(100),              设置表格,在表格中
         -> artist varchar(100),             我将存储一些
         -> released date);                  音乐资料

     Query OK, 0 rows affected (0.07 sec)

     

    现在是DML,用于告诉MyDQL在album中加入记录

     mysql> insert into albums(title,artist,released)

         -> values('Selling England By The Pound','Genesis','
1973-01-01');

     Query OK, 1 row affected (0.08 sec)



vb技巧之57-网络数据库教程六
这里是DML声明,它将使我看到我刚才加入的内容
      注意*在SQL语言中指“所有列”
     mysql> select * from albums;

     +------------------------------+---------+------------+

     | title                        | artist  | released   |

     +------------------------------+---------+------------+

     | Selling England By The Pound | Genesis | 1973-01-01 |

     +------------------------------+---------+------------+

     1 row in set (0.06 sec)
 

MySQL所认可的所有SQL的语法在MySQL文献中都有详细说明,你随时可以查阅。即使今天的课程也已经涉及了许多进出知识,所以你应该仔细研究一下它。

生成表格的级别语法是:

     create table 表格名 (

        列1 列1数据类型,

        列2 列2数据类型,

        ...

        列_x 列_x数据类型

     )
各列可以使用的数据类型可以在MySQL文献中找到。在本例中我使用了"date"数据类型以及变量长度字符串。"varchar" 字符串的长度由预设的长度限制,在变量中,是100。

要结束mysql中的一个声明,你需要键入一个分号,然后回车。mysql将告诉你的“query(SQL中任何指令的术语)”状态,以及处理所用时间。

insert(插入)的语言更简单:

     insert into 表格(列1,列2,...,列_x)

     values(value1,value2,...,value_x)
字符串必须用引号圈起来。

select(选择)是SQL非常有用的声明,必要的时候,它的用法可能会非常复杂。

如果在该数据库中我存储了几百个音乐文件,而且我只想看一下有Genesis创作的作品,我就可以用select发出一个声明查询我所需要的内容:

     select title, released

     from  albums

     where artist = 'Genesis'

     order by released
这次我按名称圈定了我所感兴趣的列,而不是用* 通配符。命令行where artist = 'Genesis'限制必须查询MySQL记录中由Genesis创作的作品,我还命令MySQL将该作曲家的唱片按照发行日期排序。

除了insert和select指令,还有两种基本的DML指令:update(更新)和delete(删除)。 update使你能够改变在表格行中存储的数据;delete使你能删除表格中的一行。

这些指令的使用范例:

     我发现Selling England 的发行日期是2月1日而不是1月1日。所以我更新
我的记录:

     mysql> update albums

         -> set    released = '1973-02-01'

         -> where  title = 'Selling England by the Pound'

         ->        and artist = 'Genesis';

     Query OK, 1 row affected (0.03 sec)

     

     mysql> select * from albums;

     +------------------------------+---------+------------+

     | title                        | artist  | released   |

     +------------------------------+---------+------------+

     | Selling England by the Pound | Genesis | 1973-02-01 |

     | Wind & Wuthering             | Genesis | 1976-01-01 |

     | We Can't Dance               | Genesis | 1991-01-01 |

     +------------------------------+---------+------------+

     3 rows in set (0.00 sec)

     如果我认为我不喜欢Genesis ...     

     mysql> delete from albums where artist = 'Genesis';

     Query OK, 3 rows affected (0.00 sec)

     

     mysql> select * from albums;

     Empty set (0.00 sec)
使用"update" 和"delete" 指令时,你需要用where指明查询条件(否则你的表格中的每一行都会被修改或删除,你必须小心)

互联网中有一个很好的SQL教程,我建议仔细阅读该教程。它并不完全适用于MySQL,这是因为SQL也有不同的“方言”。该教程所讲的内容基本适用于MySQL,但有一些细微的区别,在MySQL的SQL文献中有具体说明。

今天的课程的最后,我们将再次研究一下mysqlshow:

     rdice:# mysqlshow test

     Database: test

     +--------+

     | Tables |

     +--------+

     | albums |

     +--------+



vb技巧之58-网络数据库教程七
rdice:# mysqlshow test albums

     Database: test  Table: albums  Rows: 0

     +----------+--------------+------+-----+---------+-------+

     | Field    | Type         | Null | Key | Default | Extra |

     +----------+--------------+------+-----+---------+-------+

     | title    | varchar(100) | YES  |     |         |       |

     | artist   | varchar(100) | YES  |     |         |       |

     | released | date         | YES  |     |         |       |

     +----------+--------------+------+-----+---------+-------+
mysqlshow记录了我们在mysql中所作的一切工作。当你要求mysqlshow显示表格信息时,它并不告诉你在表格中具体有什么信息,它只是告诉你表格中目前有多少行,它告诉你的是表格的结构。我们已经了解了"Field"和"Type" ,其他的表格资料年可以从MySQL的文献中找到详细内容)。

五、我们不是在建立互联网站点吗,我是不是漏了什么东西?

我们现在已经了解了数据库的基本知识。下面我们的任务是将这些SQL技术应用到互联网中。我们将用DBI(Perl的数据库界面)实现这一目的。我将SQL语言直接写入ePerl程序中,并用Perl的DBI模块支持其运行。

不要着急。我们已经建立了系统,剩下的只是编码。
网络数据库教程-第4日
浏览: 282 次
一 网络数据库教程 - 第四天
二 ePerl - Perl和HTML的结合
三 DBI - Perl的数据库接口
四 前景 ...

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

一、 第四天

嵌入式网络编程理念

几年前,网络编程起始于公共网关接口(Common Gateway Interface)简称CGI。CGI的基本概念如下:

当一个用户发出一个CGI请求时,URL将加入一些信息让服务器将其按照CGI请求进行处理。URL加入的信息形式可能如下:
用户请求的CGI一般在/cgi-bin/ 子目录:http://www.somewhere.com/cgi-bin/某个CGI程序
网络服务器的配置可能会自动将某些文件的扩展名识别为可以执行的CGI程序:http://www.erehwon.org/gosearch.py.py 通常被理解为Python程序,这是另外一种很流行的网络编程语言。
文件的扩展名可能直接采用CGI作为扩展名:http://www.xyz.net/dosomething.cgi
在这些情况中,网络服务器将用户请求交给URL指定的程序进行处理,并提供相应的信息:通常是环境变量和标准输入(STDIN)。
然后程序开始运行,生成子进程并生成相应的信息,然后将其发送给标准输出(STDOUT),通常程序会生成一个尽可能简短的HTTP头信息,作为其输出的一部分。
网络服务器将“捕捉”到的捕捉输出流发通过网络送给用户。用户的浏览器根据HTTP头将其进行翻译,其结果通常是HTML文本,但是CGI程序也可以很容易地生成字节流最后将其还原为JPEG图象或RealAudio节目。
标准的简单C程序如下:

     #include <stdio.h>

     int main () {

         print("Hello, world!\n");

     }
我可以很容易地将其转化成CGI程序,只需加入一个HTTP头。

     #include <stdio.h>

     int main () {

         print("Content-type: text/plain\n\n");

         print("Hello, world!\n");

     }
下面所需作的只是编译代码,将编译后的二进制文件放在我的网络目录中适当的位置。

CGI在互联网世界的应用很广泛,但是对它也有很多不满意之处。

生成子进程是一个相当复杂的工作,耗费很多时间和内存,许多访问率相当高的站点的开发人员常因为由此造成的速度问题抱怨不已。
网络服务器包含很多信息,而不只是环境变量和标准输入(STDIN)。有时候如果网络程序能够访问这些资料将会带来许多便利。
传统的编程对于互联网来说都显得过于臃肿庞大,你最需要的其实就是一个能代替你编写HTML的一个智能程序,所以,为什么要把程序编得象计算机的代码呢?为什么不能使它更象HTML本身?
编写互联网应用程序最现代的方法产生于最近的几年。这些编程方法起源于基于用户端的HTML,或者叫.shtml,其概念强大之处在于将编程代码嵌入HTML文件。一些比较流行的例子如下:

Active Server Pages (.asp文件), 这种程序应用于微软的IIS网络服务器。ASP文件可以用几种比特的脚本编写引擎例如VBScript, JavaScript,和PerlScript启动。
Allaire Cold Fusion,这是一种非常方便的商用互联网开发环境。尽管它最初只能用于Windows NT,但后来它也开发出了适用于UNIX的版本。
Meta-HTML, 这种"免费软件"适用于UNIX 系统,它支持ODBC以及本地化的mSQL接口,它可以提供用于Netscape和Apache网络服务器的插件软件。
本文中我不具体谈这些工具,但我打算谈一下Ralf Engelschall的ePerl,这种应用程序使你能将Perl源代码嵌入到文本文件中。它还集成了mod_perl/Apache,这些事项以前我们需要在Apache的设置中完成。mod_perl/Apache的集成强调速度及解决CGI编程中对服务器-内程序访问的失败,而ePerl则处理标准编程语言在生成HTML时的臃肿和罗嗦。



vb技巧之59-网络数据库教程八
下面,编写一些SQL代码,并将其放入变量。例如,在我昨天的例子中:

$SQL = <<"EOT"; select title, released from albums
     where artist="Genesis" order by released EOT
这个变量是用户端光标查询(cursor)的核心。光标查询 (cursor)是一种先进的SQL查询方法,它执行逐行查询功能。该查询功能实际上在同时全部执行,但我们的Perl查询只能一行一行地获得查询结果,所以它感觉上象是针对应用程序的光标。用户端光标查询的语句及执行代码如下:

     $cursor = $dbh->prepare($SQL);

     $cursor->execute;
现在我们逐行进行查询:

     while ( @columns = $cursor->fetchrow ) {

         print ( ( map { "[$_]" } @columns ) , "\n");

     }
这行Perl代码用于打印出列序列中的每一条数据-其数值利用 $cursor-> fetchrow方法从$cursor行中提取出来。其数值用[ ]包围。很显然,我可以将任何内容放在while循环内,而不只是打印语句。

最后,实现系统资源的回收和断开连接。我们关闭光标查询和数据库处理器。

     $cursor->finish;

     $dbh->disconnect;
如果某个你想执行的SQ指令不是select语句,你不需要使用while ( $cursor->fetchrow ) { ... } 循环,因为你实际并不需要发布会任何信息,你不需要循环查询各行。

假如在昨天的例子中,我没有从album数据库中删除my Genesis信息,我将利用今天所学的方法将其变成一个可以应用于互联网的ePerl程序。

     <?

         use DBI;    # 假如你没有startup.perl文件则需要假如该行代码

     

         my $dbh = DBI->connect('DBI:mysql:test:localhost', '','')

                   or die $DBI::errstr;

         my $SQL = <<"EOT";

     select title, released

     from   albums

     where  artist = 'Genesis'

     order  by released

     EOT

     

         my $cursor = $dbh->prepare($SQL);

         $cursor->execute;

     !>//

     <HTML>

     <HEAD><TITLE>ePerl/DBI/HTML Integration

     Example</TITLE></HEAD>

     <BODY>

     
     &lt>

     有关Genesis albums的数据库程序结果为 ...

     
     <HR>

     <TABLE BORDER>

     <TR><TH COLSPAN=2>Albums by Genesis</TH></TR>

     <TR><TH>Title</TH><TH>Release

     Date</TH></TR>

     <?

         my @columns;

         while ( @columns = $cursor->fetchrow ) {

              print ( "<TR>",( map { "<TD>$_</TD>" }

        @columns ) , "</TR>\n");

         }

     !>//

     </TABLE>

     <HR>

     

     <P>

     ... and that's it!

     

     </BODY>

     </HTML>

     <?

         $cursor->finish;

         $dbh->disconnect;

     !>//
你可以查看该程序执行的结果。

Albums by Genesis
Title Release Date
Selling England By The Pound 1973-01-01
Trespass 1974-01-01
A Trick of the Tale 1976-01-01
Wind & Wuthering 1976-01-01
Duke 1980-01-01
We Can't Dance 1990-01-01

四、 前景 ..

我们已经学习了网络数据库编程的基本知识,在第5天的课程中,我们将编写一个系统演示编写网络数据库将遇到的各种情况。

在生成该数据库之前还有一些细节问题需要研究。而且我们也不能忘记我们向数据库存取信息的基本途径:HTML表单。我将用到另外一个有用的Perl 模块,CGI.pm。

网络数据库教程-第5日
浏览: 344 次
一 必不可少的CGI.pm
二 数据库转义序列
三 在Here-Document字符串内嵌入引用表达式
四 嵌入子程序
五 用SQL设置表单- selection.iphtml
六 用CGI.pm - receive.iphtml处理表单结果



vb技巧之60-网络数据库教程九
一、 必不可少的CGI.pm

在过去的几天里我们已经谈了许多重要的事项。当然谈得都不是太深入。今天我将用一个实例比较细致地阐述一下过去几天所学的概念。而且几天还会涉及一些新的问题。

在各种有关Perl CGI编程的讨论中常常会提到Lincoln Stein的CGI.pm 。总体来说,CGI.pm 所用的编程理念和我在本教程中所倡导的完全相反。

从一开始,我就在试图帮助你们建立互动、动态生成的网页。这也是嵌入式HTML编程的初衷,而且它也能使网站的编码和组织更简便快捷。

而CGI.pm的观点是将网络编程分离出来,它给你一种感觉仿佛你是在用CGI.pm搭建一个网页,例:

    #!/usr/bin/perl

     use CGI;

     $query = new CGI;

     

     print $query->header(),

           $query->start_html(-title=>'Made with CGI.pm'),

           'This is what I mean by ',

           $query->b('abstracted'),

           '.',

           $query->end_html();

     exit 0;
该程序的执行结果是一个简单的HTTP头,一个起始HTML块(包括一个<TITLE> ),几行文字,以及标准的HTML结束块。注意所有这些都是用CGI的$query 对象以及与其相关的方法编制的:

Content-type: text/html <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <HTML><HEAD><TITLE>Made with CGI.pm</TITLE> </HEAD><BODY>This is what I mean by <B>abstracted</B>.</BODY></HTML>

我总是尽量避免使用这种编程方法,但是我也不得不承认这种方法有时候
用起来很顺手。

CGI.pm的优点不在于它的抽象性,而在于它所提供的工具。CGI.pm有一个非常强大的cookie处理器以及表单参数解码方法。

我们都了解表单,它是HTML,而且它具有很多用途。

View the page source to see how I put this one together.

作为一个网络程序员,表单是从用户处收集的只要方法。当一个用户点击递交(Submit)按钮时,浏览器将用户输入的信息打包编码然后发送给你的CGI程序进行处理。而CGI程序的职责就是要解包,解码和使用表单中的内容。

这个过程很烦琐,为什么不让CGI.pm帮你处理这些事情呢?表单参数可以用param方法提取:

 

    #!/usr/bin/perl

     #

     # BAR.cgi is a simple Perl CGI program using CGI.pm.

     #

     # A Web page with a form containing the FOO textarea

     # is meant to submit to BAR.cgi (pay attention to

     # the "param" method).

     #

     use CGI;

     $query = new CGI;

     

     print $query->header(),

           $query->start_html(-title=>'Test of the param method'),

           'The value of the FOO parameter is: ',

           $query->param('FOO'),

           $query->end_html();

     exit 0;
这就是用CGI.pm解决这个问题的方法。在以后的某些ePerl代码中我还将用到CGI.pm,但只是为了利用其param方法的优势。

二、 数据库转义序列

在第3天的教程中我用做了一个唱片数据库,其中有一张唱片叫做"We Can't Dance",这一项不能作为字符串利用mysql程序插入到数据库中-因为MySQL将符号'作为字符串的限位符。

变通方法是通过加入反斜杠将该限位符“转义”:

     mysql> insert into albums(title,artist,released)

              -> values('We Can\'t Dance','Genesis','1991-01-01');
当然在为了数据库上下文中处理这些细节比较令人头疼。

当你想在数据库中插入项目时,通常会直接使用表单参数。你的ePerl代码可能如下:

     $foo = $query->param('foo');

     $foo =~ s/'/\\'/g; # this Perl command will substitute ' with \'

     

     $SQL = <<"EOT";

     insert into my_table(my_column)

     values ('$foo')

     EOT
这种设置方法不好,因为:

MySQL用反斜杠"转义"字符,但其他的某些数据库程序则可能使用不同的转义序列,所以用反斜杠硬性“转义”会影响程序的可移植性另外,该转义符在此处只转义了单引号 ' -还有其他的字符也需要转义。

需要转义的其他字符在不同的数据库中会有所区别。

你不需要记忆文献中所述的细节。用$dbh->quote记忆可以帮你实现上述目的。

     $foo = $dbh->quote($query->param('foo'));
$query->param('foo')将返回表单文字区输入的foo的值,并且$dbh->quote将根据和你的数据库相应的DBD转义必要的字符。

$dbh->quote还在这个字符串外添加引号,这样就省得你在键盘输入引号了。



vb技巧之61-网络数据库教程十
三、 在Here-Document字符串内嵌入引用表达式

here-document字符串的语法如下:

     $string = <<"HERE_DOCUMENT";

     You can type all sorts of stuff in here....

     You can also $interpolate variables right into your h-d string.

     The here-document string will quit when it runs into the label

     given at its outset.

     HERE_DOCUMENT
here_document非常方便,特别是在编制传递给$dbh以生成客户端$cursor光标查询的 $SQL字符串时。

看一下我们如何在上面的$dbh->quote例子生成$SQL。 我必须生成一个中介变量$foo插入实际生成$SQL的here-document字符串。但这样也不是很理想。我们可以做得更好。

问题是,当$dbh->quote返回一个字符串标量值时,它不是字符串标量值,它是一个函数(实际上是一个方法),这个问题可以在here-documents中变通解决。例如,下面的代码就不能执行:

     $SQL = <<"EOT";

     insert into my_table(my_column)

     values ($dbh->quote($query->param('foo')))

     EOT
我在here-document做一些变通 (变通方法用加重体字显示)

     $SQL = <<"EOT";

     insert into my_table(my_column)

     values (${ \($dbh->quote($query->param('foo'))) })

     EOT
\ 对$dbh->quote所提供的值作了一个引用。${ ... }取消该引用。语法看起来不好看,但是,据我所知,从来也没有人认为Perl 是一种漂亮的语言。

四、 嵌入子程序

尽管ePerl可以让你在HTML中任意嵌入Perl,但有时候在你的.iphtml文件中
使用子程序能使你的程序显得简洁明了。

例:

     <HTML>
     <HEAD><TITLE>Embedding a Subroutine</TITLE></HEAD>
     <BODY>
     
     <P>
     Here's an HTML calendar for the current month:
     <B><?=${ \(`cal| head -1`) }!></B>
     
     <P>
     <?=${ \( calendar_table() ) }!>//
     
     </BODY>
     </HTML>
     <?
     
     sub calendar_table {
     
     #
     # I make copious use of the Unix "cal" command here.
     # This won't work on DOS-derivative machines.
     #

         my @cal = `cal`; # fill the cal array with the
                  output of a shelled cal command
         my $return = '';
     
         shift @cal; # junk the first line... it's not needed
     
         $return .= "<TABLE BORDER>\n";
         $return .= "<TR>";
     # I dedicate the following line to my fellow Perl junkies
everywhere
         $return .= join('', map { s/\W//g; "<TH>$_</TH>" }
                    unpack("A2A3A3A3A3A3A3", shift @cal));
         $return .=  "</TR>\n";
     
         foreach ( @cal ) {
             $return .= "<TR>\n";
             $return .= join('', map { s/\W//g; "<TD>$_</TD>" }
                        unpack("A2A3A3A3A3A3A3",$_));
             $return .= "</TR>\n";
         }
     
         $return .= "</TABLE>\n"; # the value of this line is
returned
     
     }
     
     !>//
这里是该程序执行的结果(如下)。 注意如果子程序非常大的话可能会给内存造成麻烦(因为$return的体积会很大),但是当我们遇到这个问题时我们会用相应的办法解决。

Su Mo Tu We Th Fr Sa
  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 30        



vb技巧之62-网络数据库教程十一
五、 用SQL设置表单 - selection.iphtml

这里是我所用到的例子,它包括两个程序selection.iphtml和receive.iphtml。

首先调用selection.iphtml - 它将提供一个表单。用户填完表单后,表单将被
递交给receive.iphtml。当它列表显示结果后,你将回到selection中。

但是我不能在这里演示插入、更新或删除SQL语句,因为我不能公开该数据库的
内容。

     <?

         my $dbh = DBI->connect('DBI:mysql:test:localhost', '','',

                                { PrintError => 0}) || die $DBI::
errstr;

     !>//

     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">

     

     <HTML>

       <HEAD>

         <TITLE>An ePerl Database Example: Fiddling with
Albums</TITLE>

       </HEAD>

       <BODY>

     

     <P>

     Use the following form to query the contents of an
(admittedly limited)

     database of CD albums of mine.

     

     <TABLE>

     <TR>

     <TD><?=${ \( search_by_band ( \$dbh ) ) }!></TD>

     <TD><?=${ \( search_by_year ( \$dbh ) ) }!></TD>

     </TR>

     </TABLE>

     

     <FORM ACTION=receive.iphtml METHOD=POST>

     <B>Or, type in a title:</B> <INPUT NAME=title SIZE=20>

     (for all titles, just put the cursor in this field
and hit ENTER)

     </FORM>

     

       </BODY>

     </HTML>

     <?

     

     $dbh->disconnect;

     

     !>//

     <?

     

     sub search_by_band {

     

     #

     # Note that I passed a reference to the database handle dbh.

     # This means that, in order to reference it within this

     # subroutine, I'll have to refer to it as $$dbh.

     #

         my $dbh = shift;

         my $return = '';

     

     #

     # The "distinct" keyword in SQL will only return one row for
a set of

     # identical matches.  "Order by" will sort the
     # returned set alphabetically.

     #

     

         my $SQL = <<"EOT";

     select distinct artist

     from   albums

     order by artist

     EOT

     

         my $cursor = $$dbh->prepare($SQL);

         $cursor->execute;

     

         $return .= "<FORM ACTION=receive.iphtml METHOD=POST>\n";

         $return .= "<B>Pick an artist:</B><BR>\n";

         $return .= "<SELECT NAME=artist>\n";

     

         my @fields;

         while ( @fields = $cursor->fetchrow ) {

             $return .= "<OPTION>$fields[0]\n";

         }

         $return .= "</SELECT><BR>\n";

         $return .= "<INPUT TYPE=SUBMIT NAME=artist_submit
                     VALUE=\"Go Search on This Artist!\">\n";

         $return .= "</FORM>\n";

     }

     

     sub search_by_year {

     

         my $dbh = shift;

         my $return = '';

     

     #

     # If COLUMN is defined as a date datum, then year(COLUMN)
will return only

     # the year portion of the data in the column. "Order by
COLUMN desc"

     # will reverse the usual sort order.

     #
vb技巧之63-网络数据库教程十二
my $SQL = <<"EOT";

     select distinct year(released)

     from   albums

     order by released desc

     EOT

     

         my $cursor = $$dbh->prepare($SQL);

         $cursor->execute;

     

         $return .= "<FORM ACTION=receive.iphtml METHOD=POST>\n";

         $return .= "<B>Or, pick a year:</B><BR>\n";

         $return .= "<SELECT NAME=year>\n";

     

         my @fields;

         while ( @fields = $cursor->fetchrow ) {

             $return .= "<OPTION>$fields[0]\n";

         }

         $cursor->finish;

     

         $return .= "</SELECT><BR>\n";

         $return .= "<INPUT TYPE=SUBMIT NAME=year_submit
                    VALUE=\"Go Search on This Year!\">\n";

         $return .= "</FORM>\n";

     }

     

     !>//
 

六、 用CGI.pm - receive.iphtml处理表单结果

     <?

         my $cgi = new CGI; # 利用 "param" 解码方法的优势

     

         my $dbh = DBI->connect('DBI:mysql:test:localhost', '','',

                                { PrintError => 0}) || die $DBI::errstr;

     !>//

     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">

     

     <HTML>

       <HEAD>

         <TITLE>Results from the Database Search</TITLE>

       </HEAD>

       <BODY>

     

     <P>

     <?=${\( display_query_results(\$dbh, \$cgi) )}!>//

     

     <P>

     <A HREF=selection.iphtml>Return to the query page</A>

     

       </BODY>

     </HTML>

     <?

     

     $dbh->disconnect;

     

     !>//

     <?

     

     sub display_query_results {

     

     #

     # 注意我将引用传递给数据库处理器dbh和
     # cgi对象 - 这意味着要想在子程序中引用他们

     # 我必须使用$$dbh和$$cgi.

     #

         my $dbh = shift;

         my $cgi = shift;

     

         my $return = '';

         my $SQL;

     

         if ( defined($$cgi->param('title')) ) {

     

             my $SQL = <<"EOT";

     select title, artist, year(released)

     from   albums

     where  ucase(title) like ${ \($$dbh->quote(uc($$cgi->
            param('title')) . '%') ) }

     order by title, artist

     EOT

     

     #

     # 在上述语句中我使用了更复杂的SQL。SQL不会
     # 自动将返回的结果排序,但是利用

     # "order by" 语句可以很容易地实现排序 - 只需设定你希望显示的列数

     # 以及它们,的顺序优先级,"Like"可以匹配子程序 -

     # 如果你提供了标题 "abc," 则所有标题以"abc"开头的唱片

     # 都会被返回。为了消除这种现象,我
     # 在SQL中使用ucase(title),以及uc($$cgi->param('title'),
         将两个字符串都大写显示。

     # %字符是一个通配符,很象UNIX中的*
vb技巧之64-网络数据库教程十三
# 文件名globbing.

     #

             my $cursor = $$dbh->prepare($SQL);

             $cursor->execute;

     

             $return .= "<TABLE BORDER>\n<TR><TH COLSPAN=3>";

             $return .= "<B>Matches on the title search for:
               <TT><I>${ \($$cgi->param('title') )}</I></TT></B></TH></TR>";

     

             $return .= "<TR><TH>Title</TH><TH>Artist</TH><TH>
                        Year of Release</TH></TR>\n";

     

             my @fields;

             while ( @fields = $cursor->fetchrow ) {

                 $return .= "<TR><TD>$fields[0]</TD><TD>$fields[1]
                            </TD><TD>$fields[2]</TD></TR>\n";

             }

             $cursor->finish;

     

             $return .= "</TABLE>\n";

     

         } else {

     

             if ( defined($$cgi->param('artist_submit')) ) {

     

                 $SQL = <<"EOT";

     select title, year(released)

     from   albums

     where  artist = ${ \($$dbh->quote($$cgi->param('artist'))) }

     order by released desc, title

     EOT

     

             } elsif ( defined($$cgi->param('year_submit')) ) {

     

                 $SQL = <<"EOT";

     select artist, title

     from   albums

     where  year(released) = ${ \($$dbh->quote($$cgi->param('year'))) }

     order by artist, title

     EOT

     

             }

     

        my $cursor = $$dbh->prepare($SQL);
        $cursor->execute;

        $return .= "<TABLE BORDER>\n<TR><TH COLSPAN=2>";
        $return .= (defined($$cgi->param('artist_submit'))?
                    ("<B>Artist: <TT><I>".
                     "${ \($$cgi->param('artist')) }</I>".
                     "</TT></B></TH></TR>\n<TR>".
                     "<TH>Album Title</TH>".
                     "<TH>Year of Release</TH></TR>\n"):
                    ("<B>Year of Release: <TT><I>".
                     "${ \($$cgi->param('year')) }</I>".
                     "</TT></B></TH></TR>\n<TR>".
                     "<TH>Artist</TH><TH>Album Title</TH>".
                     "</TR>\n"));

        my @fields;
        while ( @fields = $cursor->fetchrow ) {
            $return .= "<TR><TD>$fields[0]</TD>";
            $return .= "<TD>$fields[1]</TD></TR>\n";
        }
        $cursor->finish;
        $return .= "</TABLE>\n";
    }

    $return;
}

!>//

本教程到此就结束了,但是它只是为了数据库编程的入门,而不是结束。我希望该教程能对你有所帮助。
 楼主| 发表于 2005-5-11 08:32:04 | 显示全部楼层 来自 山东青岛

Re:[推荐]vb技巧集

声名:以上文章都属于转载。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Simapps系列直播

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-11-2 01:23 , Processed in 0.070325 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表