vb On Error里面的if条件excel len函数数好像有问题,但是具体哪儿错了不知道

一个关于函数的问题,vb的,在vb文件中的vb函数好像不能执行
[问题点数:100分,结帖人bzscs]
一个关于函数的问题,vb的,在vb文件中的vb函数好像不能执行
[问题点数:100分,结帖人bzscs]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
2005年4月 .NET技术大版内专家分月排行榜第二
2005年6月 .NET技术大版内专家分月排行榜第三
2005年4月 .NET技术大版内专家分月排行榜第二
2005年6月 .NET技术大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。VBS脚本编程简明教程_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
50页免费31页免费44页免费188页免费80页1下载券 28页1下载券16页免费9页免费19页1下载券9页4下载券
VBS脚本编程简明教程|
把文档贴到Blog、BBS或个人站等:
普通尺寸(450*500pix)
较大尺寸(630*500pix)
你可能喜欢&&&您需要以后才能回答,未注册用户请先。本人有一个问题想问,请VB编程高手帮个忙!急_百度知道
本人有一个问题想问,请VB编程高手帮个忙!急
如何能让一个程序一运行,就把程序复制到c盘下呢???是把被运行的程序复制到C盘下.请问如何能用VB实现??????本人很爱好VB编程,希望高手加我QQ:
本人找VB编程高手做师傅,交学费就免了!
(一) COPY文件复制命令 1.功能:拷贝一个或多个文件到指定盘上。 2.类型:内部命令 3.格式:COPY [源盘][路径]〈源文件名〉[目标盘][路径][目标文件名] 4.使用说明: (1)COPY是文件对文件的方式复制数据,复制前目标盘必须已经格式化; (2)复制过程中,目标盘上相同文件名称的旧文件会被源文件取代; (3)复制文件时,必须先确定目标般有足够的空间,否则会出现;insufficient的错误信息,提示磁盘空间不够; (4)文件名中允许使用通配举“*”“?”,可同时复制多个文件; (5)COPY命令中源文件名必须指出,不可以省略。 (6)复制时,目标文件名可以与源文件名相同,称作“同名拷贝”此时目标文件名可以省略; (7)复制时,目标文件名也可以与源文件名不相同,称作“异名拷贝”,此时,目标文件名不能省略; (8)复制时,还可以将几个文件合并为一个文件,称为“合并拷贝”,格式如下:COPY;[源盘][路径]〈源文件名1〉〈源文件名2〉…[目标盘][路径]〈目标文件名〉; (9)利用COPY命令,还可以从键盘上输入数据建立文件,格式如下:COPY CON [盘符:][路径]〈文件名〉; (10)注意:COPY命令的使用格式,源文件名与目标文件名之间必须有空格! DOS时代,Copy命令恐怕是最受欢迎也最常用一个DOS内部命令,但在Windows横行的今天,它渐渐被用户遗忘,似乎变得可有可无。其实这个命令远远不止“拷贝”这么简单,好好利用它,会收到意想不到的效果。 用Copy实现远程上传和下载 用Copy命令拷贝文件大家肯定都知道,但你知道吗?Copy还支持远程文件的拷贝!比如Copy C:\SRV.EXE \\210.***.***.***\ADMIN$可以把程序SRV.EXE“上传”到对方的ADMIN$共享目录下,当然反过来也可以,这样就成“下载”了:Copy \\210.***.***.***\ADMIN$\SRV.EXE C:\就能把对方的ADMIN$共享目录下的SRV.EXE文件下载到本地的C盘中。 用Copy将秘密藏在别人肚子里 DOS的Copy命令可以将几个同类型的文件合并成一个文件,比如:多个.txt文件,其实通过它还能将一个文本文件合并到一个非文本文件中,实现隐藏秘密的效果。比如你在D盘根目录有一个重要的文本文件:001.txt,想对其进行隐藏。 找一个MP3歌曲,体积最好不要太大(500KB左右为宜),比如:wanfei.mp3(假设也放在D盘根目录),输入:Copy wanfei.mp3/b + 001.txt/a wanfei-1.mp3,这样会生成一个新文件wanfei-1.mp3。用Winamp打开它,歌曲没有变化。按住Shift键右击wanfei-1.mp3,选择“打开方式”并选择EmEditor之类的文本编辑器打开该文件,看到什么了?一堆乱码?但如果按下Ctrl+End组合键将光标移至文件的尾部,是不是001.txt文件中的内容? 小提示:其中参数/b指定以二进制格式复制、合并文件;参数/a指定以ASCII格式复制、合并文件。这里要注意文件的顺序,二进制格式的文件应放在加号前,文本格式的文件放在加号后。有一点要提醒大家:就是这个文本文件的前面最好至少空3行,这样它头部的内容就不易丢失。 同样道理,你可以把文件藏进图片、WAV声音文件,甚至还能在Word、Excel等文档中藏进秘密,比如: Copy wanfei.jpg/b + 001.txt/a wanfei-1.jpg(把001.txt藏进wanfei-1.jpg图片) Copy wanfei.doc/b + 001.txt/a wanfei-1.doc(把001.txt藏进wanfei-1.doc文档) Copy wanfei.wav/b + 001.txt/a wanfei-1.wav(把001.txt藏进wanfei-1.wav文件) Copy wanfei.exe/b+ 001.txt/a wanfei-1.exe(把001.txt藏进wanfei-1.exe文件)★ShellExecute函数和Shell函数:打开外部程序ShellExecute函数'声明Private Declare Function ShellExecute Lib &shell32.dll& Alias &ShellExecuteA& _(ByVal hWnd As Long, ByVal lpOperation As String, _ ByVal lpFile As String, ByVal lpParameters As String, _ ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long'命令语句Private Sub Command1_Click() Dim lR As LonglR = ShellExecute(Me.hWnd, &Open&, sFile, &&, &&, vbNormalFocus)End Sub本函数还可以用来连接到网页:ShellExecute 0&, vbNullString, &&, vbNullString, vbNullString, vbNormalFocus 或者这样写来发送Email:ShellExecute me.hwnd, &open&, &mailto:&, vbNullString, vbNullString, SW_SHOW另外有ShellExecute的替代用法,更加简单实用,不用API,一句Shell搞定!连接到网页:
Shell &rundll32.exe url.dll,FileProtocolHandler &打开文件:
Shell &rundll32.exe url.dll,FileProtocolHandler & & App.Path & &\SHELLTST.TXT& Shell函数 运行一个可执行程序,并且如果该程序仍然在运行,则返回一个包含该程序的进程 ID 的整数。 Public Function Shell( _ ByVal Pathname As String, _ Optional ByVal Style As AppWinStyle = AppWinStyle.MinimizedFocus, _ Optional ByVal Wait As Boolean = False, _ Optional ByVal Timeout As Integer = -1 _ ) As Integer格式:Shell(Pathname, Style As AppWinStyle, Wait, Timeout)参数:△Pathname 必选项。字符串。要执行的程序名以及任何需要的参数和命令行开关。Pathname 还可以包括驱动器和目录路径或文件夹。 △Style 可选项。AppWinStyle。从 AppWinStyle 枚举中选择的值,该枚举与要在其中运行程序的窗口样式相对应。如果省略 Style,则 Shell 使用 AppWinStyle.MinimizedFocus,这将使程序以最小化启动并具有焦点。 Style 参数可以有以下设置之一:
AppWinStyle.Hide 隐藏窗口并为隐藏的窗口提供焦点。
AppWinStyle.NormalFocus 为窗口提供焦点,并以最近的大小和位置显示窗口。
AppWinStyle.MinimizedFocus 为窗口提供焦点,并以图标的形式显示窗口。
AppWinStyle.MaximizedFocus 为窗口提供焦点,并以全屏方式显示窗口。
AppWinStyle.NormalNoFocus 将窗口设置为最近的大小和位置。当前活动窗口保持焦点。
AppWinStyle.MinimizedNoFocus 以图标的形式显示窗口。当前活动窗口保持焦点。 △Wait 可选项。Boolean。指示 Shell 函数是否应等待程序完成的值。如果省略 Wait,则 Shell 使用 False。 △Timeout 可选项。Integer。Wait 为 True 时等待完成的毫秒数。如果省略 Timeout,则 Shell 使用 -1,表示没有超时,Shell 直到程序完成时才返回。因此,如果省略 Timeout 或将它设置为 -1,则 Shell 可能永远不会将控制返回给程序。异常/错误 异常类型 错误号 条件 ArgumentException 5 Style 不在 0 到 9(包含 0 和 9)范围内。 FileNotFoundException 53 Shell 无法启动指定的程序。 备注 Shell 函数的返回值取决于 Pathname 中指定的程序在 Shell 返回时是否仍在执行。如果将 Wait 设置为 True 并且程序在超时过期前结束,Shell 返回零。如果超时过期或者省略 Wait 或将它设置为 False,则 Shell 返回程序的进程 ID。进程 ID 是标识正在运行的程序的唯一数字。 如果 Shell 函数无法启动指定的程序,则出现 System.IO.FileNotFoundException 错误。例如,当试图从使用 System.Windows.Forms 的应用程序运行 16 位程序(如 )时,可能会发生这种情况。解决办法是运行将调用所需的 16 位程序的 32 位程序。如果是 ,则可以将运行 cmd.exe 作为另一种选择。 默认情况下,Shell 函数异步运行程序。这意味着用 Shell 函数启动的程序在 Shell 函数后面的语句执行前可能没有结束执行。如果想等待程序结束后再继续,请将 Wait 设置为 True。 整个路径和文件规范应该始终用引号引起来,如以下示例所示: ID = Shell(&&&C:\Program Files\MyFile.exe&& -a -q&, , True, 100000) 字符串内每对相邻的双引号 (&&) 被解释为字符串中的一个双引号字符。因此,前面的示例表示 Shell 函数的下列字符串: &C:\Program Files\MyFile.exe& -a -q 如果路径没有用引号引起来,Windows 就会在 C:\ 目录中查找名为 Program.exe 的文件,而不是在 C:\Program Files 目录中查找 MyFile.exe 文件。 安全说明 如果路径和文件规范没有用引号引起来,那么当文件名或路径节点包含空格时,就会出现安全风险。在上面的示例中,路径节点 \Program Files 包含一个空格。如果规范不在引号中,并且名为 Program.exe 的程序(例如通过非法的破坏)安装在 C:\ 中,Windows 就会执行 Program.exe 程序而不是 MyFile.exe。 安全说明 Shell 函数需要非托管代码权限,这可能会对它在部分信任情况下的执行产生影响。有关更多信息,请参见 SecurityPermission 类和代码访问权限。 示例 本示例使用 Shell 函数运行一个用户指定的应用程序。通过将 AppWinStyle.NormalFocus 指定为第二个参数,以正常大小打开应用程序并为它提供焦点。 Dim ProcID As Integer ' Run Calculator. ProcID = Shell(&C:\Windows\system32\calc.exe&, AppWinStyle.NormalFocus) ' The preceding path is for Windows XP; ' The Windows 2000 path is C:\WINNT\system32\calc.exe.另,shell函数无须声明,例: Option Explicit Private Sub Command1_Click() Shell (&D:\Program Files\WinRAR\winrar.exe&) End Sub调用Shell函数可以执行外部可执行文件,其扩展名如.exe 、.com、.bat或.pif,缺省扩展名为.exe。不能执行操作系统内部命令及所有非执行文件(如文档),否则将显示出错信息 VB 中,常以Shell指令来执行外部程式,然而它在Create该外部process 后,立刻就会回到vb 的下一行程式,无法做到等待该Process结束时,才执行下一行指令,或是说,无法得知该Process是否已结束,甚者,该Process执行到一半,又该如何中止其执行等等,这些都不是Shell指令所能控制的,因此我们需使API的帮助来完成。
第一个问题,如何等待shell所Create的process结束后才往后执行vb的程式。
首先要知道的是,每个Process有唯一的一个ProcessID,这是OS给定的,用来区别每个 Process,这个Process ID(PID)主要可用来取得该Process相对应的一些资讯,然而要对该Process的控制,却大多透过 Process Handle(hProcess)。VB Shell指令的传回值是PID,而非hProcess,所以我们需透过OpenProcess这个API来取得 hProcess而OpenProcess()的第一个参数,指的是所取得的hProcess所具有的
能力,像 PROCESS_QUERY_INFORMATION 便是让GetExitCode()可取得hProcess所指的process之状态,而PROCESS_TERMINATE,便是让TerminateProcess(hProcess..)的指令能够生效,也就是说,不同参数设定,使hProcess所具有的权限、能力有所不同。取得 hProcess后便可以使用WaitForSingleObject()来等待hProcess状态的改变,也就是说,它会等待 hProcess所指的process执行完,这个指令才结束,它
第二个参数所指的是 WaitForSingleObject()所要等待的时间(in milliseconds ),如果超过所指的时间,就TimeOut而结束WaitForSingleObject()的等待。若要它无限的等下去,就设定为INFINITE。pid = Shell(&C:\tools\spe3\pe2.exe&, vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) ExitEvent = WaitForSingleObject(hProcess, INFINITE) Call CloseHandle(hProcess)
上例会无限等待shell指令create之process结束后,才再做后面的vb指令。有时觉得那会等太久,所以有第二个解决方式:等process结束时再通知vb 就好,即:设定一个公用变数(isDone),当它变成True时代表Shell所Create的Process已结束。当Process还在执行时,GetExitCodeProcess会传&H103给其第二个参数,直到结束时才传另外的数值,如果程式正常结束,那Exitcode = 0,否则就得看它如何
结束了。或许有人在其他地方看到 loop的地方是Loop while Exitcode && 0,那有一点危险,如果以这个例子来看,您不是用F4来离开pe2而是用右上方 X 的结束dos window那麽,会因为ExitCode的值永远不会是0,而进入无穷的回圈。 Dim pid As Long pid = Shell(&C:\tools\spe3\pe2.exe&, vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) isDone = False Do Call GetExitCodeProcess(hProcess, ExitCode) Debug.Print ExitCode DoEvents Loop While ExitCode = STILL_ALIVE Call CloseHandle(hProcess) isDone = True
另外,如果您的shell所Create的程式,有视窗且为立刻Focus者,可另外用以下的方式Dim pid As Long Dim hwnd5 As Long pid = Shell(&c:\tools\spe3\pe2.exe&, vbNormalFocus) hwnd5 = GetForegroundWindow() isDone = False Do While IsWindow(hwnd5) DoEvents Loop isDone = True
而如何强迫shell所Create的process结束呢,那便是Dim aa As Long If hProcess && 0 Then aa = TerminateProcess(hProcess, 3838) End IfhProcess便是先前的例子中所取得的那个Process Handle, 3838所指的是传给GetExitCodeProcess()中的第二参数,这是我们任意给的,但最好不要是0,因为0一般是代表正常结束,当然这样设也不会有错。当然不可设&H103,以这个例子来看,如果程式正处於以下的LOOPDoCall GetExitCodeProcess(hProcess, ExitCode) Debug.Print ExitCode DoEvents Loop While ExitCode = STILL_ALIVE Debug.print ExitCode
而执行了 TerminateProcess(hProcess, 3838)那会看到ExitCode = 3838。然而,这个方式在win95没问题,在NT中,可能您要在OpenProcess()的第一个参数要更改成 PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE 这样才能Work。不过良心的建议,非到最后关头,不要使用TerminateProcess(),因不正常的结束,往往许多程式结束前所要做的事都没有做,可能造成Resource的浪费,甚者,下次再执行某些程式时会有问题,例如:本人常使用MS-dos Shell Link 的方式执行一程式,透过Com port与大电脑的联结,如果Ms-dos Shell Link 不正常结束,下次再想Link时,会发现too Many Opens,这便是一例。
另外,有人使用Shell来执行.bat档,即:pid = Shell(&c:\aa.bat&, vbNormalFocus)
可是却遇上aa.bat结束了,但ms-dos的Window却仍活着,那可以用以下的方式来做pid = Shell(&c:&# /c c:\aa.bat&, vbNormalFocus)
那是执行,而指定执行c:\aa.bat 而且结束时自动Close 所有程式如下:Private Declare Function OpenProcess Lib &kernel32& (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long,ByVal dwProcessId As Long) As Long Private Declare Function WaitForSingleObject Lib &kernel32&(ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Private Declare Function CloseHandle Lib &kernel32&(ByVal hObject As Long) As Long Private Declare Function GetExitCodeProcess Lib &kernel32&(ByVal hProcess As Long, lpExitCode As Long) As Long Private Declare Function TerminateProcess Lib &kernel32& (ByVal hProcess As Long, ByVal uExitCode As Long) As Long Private Declare Function GetForegroundWindow Lib &user32& () As Long Private Declare Function IsWindow Lib &user32& (ByVal hwnd As Long) As Long Const PROCESS_QUERY_INFORMATION = &H400 Const STILL_ALIVE = &H103 Const INFINITE = &HFFFF Private ExitCode As Long Private hProcess As Long Private isDone As Long Private Sub Command1_Click() Dim pid As Long pid = Shell(&C:\tools\spe3\pe2.exe&, vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) isDone = False Do Call GetExitCodeProcess(hProcess, ExitCode) Debug.Print ExitCode DoEvents Loop While ExitCode = STILL_ALIVE Call CloseHandle(hProcess) isDone = True End Sub Private Sub Command2_Click() Dim pid As Long Dim ExitEvent As Long pid = Shell(&C:\tools\spe3\pe2.exe&, vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) ExitEvent = WaitForSingleObject(hProcess, INFINITE) Call CloseHandle(hProcess) End Sub Private Sub Command3_Click() If hProcess && 0 Then
TerminateProcessh Process, 3838 End If End Sub Private Sub Command4_Click() Dim pid As Long Dim hwnd5 As Long pid = Shell(&c:\tools\spe3\pe2.exe&, vbNormalFocus) hwnd5 = GetForegroundWindow() isDone = False Do While IsWindow(hwnd5) DoEvents Loop isDone = True End Sub Private Sub Command5_Click() Shell &c:&# /c c:\aa.bat&, vbNormalFocus ' vbHide)End Sub
其他类似问题
vb编程的相关知识
按默认排序
其他5条回答
Private Sub Form_Load()
Dim sFile As String
If Len(App.Path) = 3 Then
sFile = App.Path & App.EXEName & &.exe&
sFile = App.Path & &\& & App.EXEName & &.exe&
FileCopy sFile, &C:\& & App.EXEName & &.exe&End Sub
这个太EASY了!看代码:private sub form_load() ON ERROR RESUME NEXT '除错处理If mid(App.Path,len(app.path),1) = &\& Then '假如当前位置末字符为&\&时,则当前应用程序的路径为 'App.Path & App.EXEName & &.exe& FileCopy
App.Path & App.EXEName & &.exe& , &C:\& & App.EXEName & &.exe&end if If mid(App.Path,len(app.path),1) && &\& Then
'假如当前位置末字符不为&\&时,则当前应用程序的路径为 'App.Path &&\& & App.EXEName & &.exe& FileCopy App.Path &&\& & App.EXEName & &.exe& ,&C:\& & App.EXEName & &.exe&End If End Sub'其实上面那位仁兄的做法更好,在这里判断末字符是否为&\&是为了防止错误出现,比如说假如你的应用程序在D盘,那么使用app.path返回的值为&D:\&后边再加上一个&\&就成了&D:\\&,那么就会出现错误了,假如应用程序不在根目录使用APP.PATH返回的路径后面就没有&\&,这时再加上一个&\&才正确!
用SHELL函数和DOS的批处理命令,批处理命令用DS的COPY方式。
'既然你知道别人做法好,怎么就没有看出别人已经对程序是否在根目录做了判断呢?请看以下代码:If Len(App.Path) = 3 Then
'路径长度等于3即在根目录sFile = App.Path & App.EXEName & &.exe& Else sFile = App.Path & &\& & App.EXEName & &.exe& End If
楼上的很长细................
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁1612人阅读
有关于 VB&&&&Visual Basic 已经变得像 C 一样结构化,像 Pascal 一样灵活,像 FORTRAN 一样适于科学工作,比 COBOL 更适用于商业工作,比 Xbase 更适于操作数据,甚至可能像 Smalltalk 一样面向对象,像 LISP 一样长于列表处理。 &&援引自《Visual Basic 5.0 核心技术》 一 几件小事Visual Basic 是强大的,但是我想在开始时先说一些小事。虽是小事,但有时却会令人头疼不已,所以先说。 如果你也经常将工程命名为中文长文件名,可能你也在启动 VB5 时遇到过&未知的错误&提示,这时运行&RegEdit&,打开&HKEY_CURRENT_USER/Software/Microsoft/Visual Basic/5.0/RecentFiles&键,将名为&1&的字符串值删掉,VB5 又可正常运行了,但&打开&中的&最新&就被清空了。 打开&要求变量声明&选项。不要求变量声明在很多情况下也可正常,但是如果程序里有拼写错误,你将对程序的莫名其妙的错误白白浪费许多时间。另外,我一般将&自动语法检测&关掉,因为它非常讨厌,而且关掉后,语法错误的程序一样以&红色显示&(缺省),足以提示了。 系统颜色的使用。Windows 可以自定义系统颜色,也就是说,按钮表面不一定是灰色,按钮文本也不一定是黑色,所以一幅灰色背景的图并不一定会和窗体背景融合。也有些人也把窗体背景色也硬性定义为灰色,但是边框却还是用户定义的颜色!所以还是要注意。 尽量多用常数。VB 定义了很多常数,比如,vbCr 是回车,vbLf 是换行,vbCrLf 是回车换行。 删除图标按 Del 键。我看过一篇文章说,要除去 Icon ,需在 Form_Load 里加入 Set Me.Icon=LoadPicture(&&) ,首先,LoadPicture(&&) 返回 Nothing ,故可写作 Set Me.Icon=Nothing ;其次,如前所述,这条语句也属多余。 多用热键。比如,Ctrl+J 显示 属性/方法 列表, Ctrl+Shift+J 显示常数列表,Ctrl+I 显示快速信息,Ctrl+Shift+I 显示参数信息。(VB 不能自定义热键颇为可恶。) 全编译执行程序。大多数情况下,执行程序即可,但全编译执行可以帮你迅速排除一些低级错误,特别应该用于 API 回调函数等不能中断的程序调试时。 Dim 时,每个变量皆应声明。用过其它语言如 C、Pascal 等,在 VB 中一般会这样定义变量: Dim i,j As Integer ,自以为定义了 i、j 两个整数,其实是定义了一个变体变量 i 和一个整数 j 。正确的方法应是 Dim i As Integer,j As Integer 。 预定义对象和集合的使用。如 App、Err、Screen 等对象,Forms、Controls 等集合。也许我们千方百计不能达到的目的就在这些对象和集合中有异常简单的解决方法。 各种属性的搜刮。比如早期我编俄罗斯方块对 PictureBox 的键盘事件编程,需要时时防止焦点离开,后发现窗体有 KeyPreview 属性,所以现在不需时刻提防,程序却更稳定了。 注意参数的传递方式。比如,开始我并不知道如何控制文本框的输入,后来才知道可以通过给 KeyAscii 赋值来控制,这才发现 KeyAscii 是按指针传递的。其实,VB 提供的事件的参数只要是按指针传递的,基本可以肯定通过改变此参数的值可以控制此事件过后 VB 的行为。 Sub 的调用方法。习惯了 C 或 Pascal 中调用函数的方法,在 VB 中也会这样调用过程:Test (x) ,函数名和括号之间的那个空格使它和正常调用过程不同;如果是函数而不关心其返回值的话,也有人这样写:temp=Test(x) 。其实正确的调用方法是 Test x 或 Call Test(x) ,当然,像前面的写法并不一定会出错,但要指出,我以前在使用 Test (x) 这样的语法时曾出过错。 数组从 0 开始。Dim x(10) 其实和 Dim x(0 To 10) 的结果一样,你得到的是十一个元素,而不是十个。特别的,ReDim x(0) 等同于 ReDim x(0 To 0) ,并非删除了所有的数组元素,而是有一个元素,一定要注意(要删除动态数组的所有元素,用&Erase&)。 True False 的值。VB 中 True 的值是 -1 ,False 的值是 0 ,用 If 语句直接判断时和 C 并无差别,但是如果用了等号或 Not 等操作符,也许结果就事与愿违了。 二 中文函数名、变量名、控件名以及窗体名使用 VB5 及其以上版本,不论中英文版,都可以使用中文函数名、变量名、控件名以及窗体名。每次引用时都输入中文当然有些力不从心,所以我现在最熟练的操作是&Ctrl + C&、&Ctrl + X&、&Ctrl + V&。 :) 我曾在多种语言上试验,只有 VB 允许这样做。Visual FoxPro 应该也可以,但我把它看作 VB 的同类,其它如 VC、Dephi、C++ Builder、Perl,甚至于 JavaScript、VbScript,都不能这样做。 最近听到一种说法,以为用中文函数名、变量名、控件名以及窗体名可能兼容性不好。好吧,让我们看看结果如何:将有中文函数名、变量名、控件名以及窗体名的工程编译,再在编译好的程序里查找中文函数名、变量名&&找不到,再查找控件名、窗体名&&找到了。如此,我们能确定函数名和变量名被编译成了地址的形式,所以找不到;那么找到了控件名和窗体名是否说明控件和窗体是用名字调用的呢?非也,非也,之所以找到控件名和窗体名是因为你可能在程序里访问控件和窗体的&Name&属性&&&岂予所欲哉!予不得已也&。 当然,是否使用中文编程是由各位自己决定的。我曾数次 Mail 给&网络蚂蚁&的作者,希望他将界面改为中文而终不可得,更何逞用中文编程乎?三 函数式调用对话框VB 中有 MsgBox 和 InputBox 两个函数用来进行最常用的输入输出操作,但有时却不够我们的需求,而且 MsgBox 和 InputBox 在执行时就暂停了程序,大部分情况下正是我们所要的,但是有些情况下,我们却希望在执行这一类输入输出时不不暂停程序,而是能在后台仍执行程序,用模式对话框可以实现,但又失去了 MsgBox 和 InputBox 的快捷和方便,这时函数式调用对话框便成为首选方案。 当然,这只需在标准模块里定义函数原型,再在此函数里调用&自定义的窗体.Show vbModal&即可。在这里最重要的问题是:返回值如何返回? 首先,可以定义全局变量,在&自定义的窗体&卸载以后检测这些变量,从而得知作了哪些改变。这种方法并不差,我也常用,但是它有问题:使用了全局变量。全局变量的使用过多,会造成程序混乱,一有可能自己也记不清此变量的用处,二有可能在其它地方调用变量时不经意的使用了同一个名字,从而造成错误,另外,也许你从以前编的几个程序里各取一部分加入新的工程,却发现许多变量同名,又不得不重改变量名。 其次,可以使用我介绍的下一种方法。 在&自定义的窗体&里定义一个 Public 类型的&自定义函数&,在其中加入初始化代码,然后调用&Me.Show vbModal&,然后&自定义函数=返回值&、&Unload Me&,在卸载窗体时令其不卸载,只隐藏,然后在标准模块定义的函数里调用&自定义的窗体.自定义函数&,如下:Option Explicit
Private 返回值 As String
Public Function 自定义函数() As String
Me.Show vbModal
自定义函数 = 返回值
End Function
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
If UnloadMode = vbFormControlMenu Then
Cancel = True
取消_Click
Private Sub 取消_Click()
返回值 = &&
Private Sub 确定_Click()
返回值 = 输入值
最后,我想说一下,因为模式窗体并不阻止程序运行,就有可能此函数被调用多次,从而在&Me.Show vbModal&时产生&运行时错误&,如果不希望出现多个窗体,应该避免出现这种情况;如果希望出现多个窗体,在标准模块的函数里应该用&New&产生新的&自定义的窗体&,然后调用,如下:Public Function 自定义函数() As String
Dim 新窗体 As New 自定义的窗体
自定义函数=新窗体.自定义函数
End Function
也许有人对窗体是否真的被卸载表示怀疑,很好,你可以用&Forms&集合自己检测。四 数组的应用数组其实能完成一些本来看似不应由数组完成的任务,我当然不是吃饱了没事干,它使有些程序看来更舒服&&至少我这么认为。 比如,VB 的 WeekDay 返回一个 Integer 值,我们显示时却希望显示字符串,Format 函数返回的是英文字符串,于是我们需要自己完成转换:Private Function 询问星期(ByVal 星期几 As Integer) As String
Select Case 星期几
Case vbSunday
询问星期 = &星期日&
Case vbMonday
询问星期 = &星期一&
Case vbTuesday
询问星期 = &星期二&
Case vbWednesday
询问星期 = &星期三&
Case vbThursday
询问星期 = &星期四&
Case vbFriday
询问星期 = &星期五&
Case vbSaturday
询问星期 = &星期六&
End Select
End Function
如果使用数组的话,可以写成:Private Function 询问星期(ByVal 星期几 As Integer) As String
星期 = Array(&日&, &一&, &二&, &三&, &四&, &五&, &六&)
询问星期 = &星期& & 星期(星期几 - vbSunday)
End Function
具体选用那种方法当然由你决定。我要说的是这种方法也可用于其它语言,不过要注意,数组毕竟不是 Select Case ,后者所能完成的大多数任务不能由数组替代,事实上,VB 的 Select Case 几乎是所有语言中最强大的,善用 Select Case 将精简大量代码。不过 VB 中的数组还有一些其它的特性,使得它的用途也是十分广泛,关于这方面的一些情况,请参见我的下一篇文章&&。 五 事件的应用在 VB5 的面向对象编程时,我们不只可以自定义属性,方法,还有非常强大的&自定义事件&。 在类模块中定义事件,然后在适当的时候,用 RaiseEvent 产生事件即可,本没有更多可说的,但我在编一个 Socket 通信的程序时,却发现事件的功能比我想象的大。 就以 Socket 通信为例,我所要做到的是:不同的 Socket 字符串送给不同的窗体。我做了一个类,用来分析 Socket 字符串,并分别产生不同的事件,问题是只能有一个 Socket 控件接收 Socket 信息,所以由此类产生的对象只能和 Socket 控件同在&主窗体&中,那么,此类所产生的事件是否也只是发向这个&主窗体&呢? 开始我以为是的。于是我在&主窗体&里对每一个事件编程,在事件里调用不同窗体的 Public 类型的函数。但有一个问题:我所调的窗体可能还没有加载,而且我也不希望它现在加载。我用&窗体.Visible&检测窗体加载与否,极不理想。 后来我发现可以这么作:将&主窗体&里产生的对象定义为 Public ,比如类名为&协议&,如下:Option Explicit
Public WithEvents 分析员 As 协议
Private Sub Form_Load()
Set 分析员 = New 协议
Socket控件.Connect
Private Sub Socket控件_DataArrival(ByVal bytesTotal As Long)
Dim Temp As String
Socket控件.GetData Temp
分析员.分析信息 Temp
在需要事件的窗体里,这样定义:Option Explicit
Public WithEvents 事件发生器 As 协议
Private Sub Form_Load()
Set 事件发生器 = 主窗体.分析员
Private Sub 事件发生器_狼来了()
Me.Caption = &快逃啊!&
这样,用这种方法完成了这一操作。你可以在所有窗体里对此事件编程,也可以只对几个窗体编程,从而可以用简单的方法完成复杂的任务。六 Image 控件与 PictureBox 控件的比较PictureBox 控件功能强大,但占资源较多;Image 控件功能不强,但占资源较少。但是还有另一面:感觉。 因为 PictureBox 控件是真正意义上的控件:有窗口类衍生而来;Image 控件却不是。这一点可用 Spy++ 检测得知。 由此,我们知道了 Image 控件事实上是在其父窗体上画出的,虽然它占用资源确实很少,但是在刷新控件时,即使不是刷新了整个父窗体,也是在刷新时在整个父窗体范围内关闭了鼠标。这样,在频繁刷新的情况下(如进度条),只要鼠标在父窗体范围内,就会不停的闪动,这时用 PictureBox 控件代替 Image 控件,闪动就只在控件内部了。( 2 色鼠标光标一般肉眼看不出闪动,256 色鼠标光标就非常明显了。)七 控件数组动态增删控件数组并非真正的数组,所以它的动态增删与普通数组也是不同的。 新增一个控件数组的元素,使用的是&Load 控件(n)&;删除一个控件数组的元素,使用的是&Unload 控件(n)&;n 自增;但是这样反复几次后会发现控件数组中出现了&空洞&,虽然可以用&For Each&来访问每一项,但却为以后的增删产生了麻烦。 本来,如果控件索引是&Long&型,&空洞&问题也不怎么严重。因为有
个数可选,即使一秒钟产生一个&空洞&,也需要 136 年才会有重复的可能性。在这些年里,即使我们不被微软强迫升级 Windows , Windows 自身也会先于我们的软件崩溃的。只是可惜,控件索引是&Integer&,也就是只有 65535 个数可选,也就是说如果一秒钟产生一个&空洞&,18 个小时后就会产生重复的数,从而产生错误。 比如我在编 Socket 服务器时是这样解决的:Private Sub 连接_ConnectionRequest(Index As Integer, ByVal requestID As Long)
If Index = 0 Then
Dim 连接数 As Long
连接数 = 空余
Load 连接(连接数)
连接(连接数).LocalPort = 0
连接(连接数).Accept requestID
新增连接 连接数, &未知&, 0, 连接(连接数).RemoteHost,
连接(连接数).RemoteHostIP, &无操作&
Private Function 空余() As Long
Dim i As Long, Temp As Long
On Error GoTo 完成
For i = 连接.LBound To 连接.UBound
Temp = 连接(i).LocalPort
End Function
Private Sub 新增连接(连接数 As Long, 用户名 As String, 级别 As Long,
主机名 As String, IP As String, 操作 As String)
Dim Item As ListItem
Set Item = 用户列表.ListItems.Add(, &U& & 连接数, 用户名)
Item.SubItems(1) = 级别
Item.SubItems(2) = 主机名
Item.SubItems(3) = IP
Item.SubItems(4) = 操作
因为&空洞&并不影响数组控件的索引值,所以删除较为简单:Private Sub 连接_Close(Index As Integer)
删除连接 Index
Private Sub 连接_Error(Index As Integer, ByVal Number As Integer,
Description As String, ByVal Scode As Long,
ByVal Source As String, ByVal HelpFile As String,
ByVal HelpContext As Long, CancelDisplay As Boolean)
ShowError &连接& & Index & &发生错误:& & Description
CancelDisplay = True
删除连接 Index
Private Sub 删除连接(ByVal Index As Long)
If 索引 &= Index Then 索引 = 索引 - 1
Unload 连接(Index)
用户列表.ListItems.Remove &U& & Index
Private Sub ShowError(详情 As String)
Me.Caption = 详情
最后我说一下,VB5 的 Socket 控件在调用&Close&方法后,连接却并不一定&Close&掉了,据说需要做一个&Do&循环不断检测&State&属性,直到真的&Close&掉了为止,我甚觉其可恶,所以现在一般用 VB6 的 Socket 控件。八 TextBox 的输入控制TextBox 的 KeyPress 事件的参数 KeyAscii 是以指针的方式传递(准确的说是按引用传递的)的,所以能通过对它的赋值起到控制其输入的目的:Private Sub 输入框_KeyPress(KeyAscii As Integer)
If KeyAscii & vbKey9 Or KeyAscii & vbKey0 Then
KeyAscii = 0
如果有多个 TextBox 需要控制,可以这样在 KeyPress 事件中调用过程:Private Sub 输入框_KeyPress(KeyAscii As Integer)
字符过滤 KeyAscii
如果将需要控制的 TextBox 定义为控件数组,会更方便,只是有一些限制。&字符过滤&在标准模块中定义:Option Explicit
Private Const vbKeyDot = 46
Public Enum 过滤方式
只留十六进制
Public Sub 字符过滤(字符 As Integer, Optional 方式 As 过滤方式 = 只留整数)
If 字符 & 26 Then
Select Case 方式
Case 只留整数
If 字符 & vbKey9 Or 字符 & vbKey0 Then
Case 只留数字 '可能输入多个小数点
If (字符 & vbKey9 Or 字符 & vbKey0) And 字符 && vbKeyDot Then
Case 只留十六进制
Select Case 字符
Case vbKey0 To vbKey9, vbKeyA To vbKeyF, 97 To 102
End Select
End Select
可能你已经注意到了我先检测&If 字符 & 26&,那么,&字符 & 26&是什么呢?原来是&Ctrl + 字母&。比如:&Ctrl + V&时,&字符&的值为 22 ,这时将&字符&赋值为 0 ,就使&粘贴&操作不被执行,这样,几乎所有的 TextBox 操作都能控制了。九 调用 API 时的字符串返回值说明 API 中的字符串时将字符串定义为&ByVal&就可以在 API 中用字符串了:Declare Function GetClassName Lib &user32& Alias &GetClassNameA& _
(ByVal hwnd As Long, ByVal lpClassName As String, _
ByVal nMaxCount As Long) As Long
而要取得字符串返回值可以用这样的函数:Public Function 窗体类名(ByVal 句柄 As Long) As String
Dim 类名 As String * 256, 类名长度 As Integer
类名长度 = GetClassName(句柄, 类名, 255)
窗体类名 = Mid$(类名, 1, 类名长度)
End Function
还可以用这样的函数:Public Function 窗体类名(ByVal 句柄 As Long) As String
窗体类名 = Space$(256)
GetClassName 句柄, 窗体类名, 255
窗体类名 = Api字符串还原(窗体类名)
End Function
Public Function Api字符串还原(原字符串 As String) As String
Dim 长度 As Long
长度 = InStr(1, 原字符串, vbNullChar) - 1
If 长度 & 0 Then
Api字符串还原 = 原字符串
Api字符串还原 = Left$(原字符串, 长度)
End Function
第二种方法比较通用,第一种方法比较简单,具体使用悉听尊便。不过我想说一说,我以前喜欢用定长字符串调用 API (第一种),现在却喜欢用变长字符串(第二种),定长字符串的问题在于首先定义&Dim 类名 As String * 256&,调完 API 后,执行&类名 = Mid$(类名, 1, 类名长度)&,这时&类名&并非真正的类名,而是&真正的类名 + Space$(256 - Len(真正的类名)&,非&我所欲也&。十 产生错误适时地产生&运行时错误&,不仅有利于调试程序,在有些情况下,也能起到简化编程的目的。 首先应该知道,&On Error&语句有很强的包容性,比如在一个函数里有&On Error Goto 出错&,而在这个函数中调用了另一个函数,这&另一个函数&产生了&运行时错误&,也会同样&Goto 出错&的。 正因为如此,我们可以在&另一个函数&产生&运行时错误&,而在原函数里统一用&On Error&处理错误,从而简化编程。Private Function 执行MCI命令(命令 As String) As String
Dim 返回 As String, 执行情况 As Long
返回 = Space(256)
执行情况 = mciSendString(命令, 返回, 255, 0)
If 执行情况 = 0 Then
执行MCI命令 = Api字符串还原(返回)
Err.Raise vbObjectError + 1, , _
&执行 MCI 命令出错:& & vbCrLf & _
命令 & vbCrLf & &返回:& & 执行情况
End Function
&Goto&语句曾倍受奚落,因为它不是结构化的,但是在 VB 作了一些手脚后,&Goto&也很好用,且不容易出错了:VB 的行号是过程内有效的。这也就是说,在不同的函数里,可以定义同为&出错&的行号,而不会出错,这样&Goto&好像也有些&结构化&了。 :)十一 随机数的问题产生随机数也是一个简单的问题:首先用&Randomize&初始化随机数发生器,然后就可以用&Rnd&产生随机数了。(需要初始化的原因是随机数其实并非真的随机,初始化的值如果确定,则产生的随机数序列也是确定的,所以一般用当前时间初始化随机数发生器,不过我在这里就不详细讨论了。) 我在这里想说的是另一个问题。 比如 WinAmp 的随机播放,只是简单的调用了随机数发生器,所以有可能刚听完这一首歌,随机数发生器又产生这个数,就要再听一遍这一首歌,而有可能有些歌在全部循环几遍之后才能播放一次。 简单的调用随机数发生器,更严重的问题会出现在&挖雷&上:我们自定义 10&10 的方阵,99 颗雷,越往后越难产生正确的雷的位置了。 所以我在&俄罗斯方块&里这样产生&随机&的&底图&:Dim i As Long, j As Long, n As Long
n = 文件过滤器.listcount - 1
If listcount(随机控制) && (n + 1) Then
If n &= 0 Then
ReDim 随机控制(0 To n)
If 图号 & 文件过滤器.listcount Then
随机控制(图号) = True
For j = 0 To n
If 随机控制(j) = False Then i = i + 1
If i = 0 Then
ReDim 随机控制(0 To n)
If 图号 & 文件过滤器.listcount Then
随机控制(图号) = True
i = Int(Rnd * i)
For j = 0 To n
If 随机控制(j) = False Then
If i = -1 Then
随机控制(j) = True
Set 选择的图像 = LoadPicture(文件过滤器.List(图号))
程序很罗嗦,但效果良好,即使只有两幅&底图&,也不会连续两次得到同一幅&底图&了。十二 回调函数我并不是要说&回调函数&的全部,这个题目太大,不只版面不允许,我的能力也不允许。所以我要说的是&回调函数&的一些零碎的问题。 我很喜欢类模块的封装性,但是&回调函数&却必须有一个标准模块,因为 AdressOf 只能取得标准模块中的函数地址,但是问题是,我在标准模块里怎么令类模块产生&事件&呢? 从我收集的源代码来看,有一种是直接调用确定窗体的函数,不免有失通用性;另一种是用&CopyMemary&作了一些奇怪的操作来完成的,让人不敢放心,而且我见的例子只在编控件时有效,在类模块时不正常。这真是让人难以愉快啊! 后来,我发现&正统&的方法应该是这样的:(标准模块)Option Explicit
Public PrevWndProc As Long
Private 系统栏对象 As New Collection
Public Function SubWndProc(ByVal hwnd As Long, _
ByVal Msg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
On Error Resume Next
Select Case Msg
Case TRAY_CALLBACK
Dim CurTray As 系统栏
Set CurTray = 系统栏对象.Item(&H& & hwnd)
CurTray.SendEvent lParam, wParam
End Select
SubWndProc = CallWindowProc(PrevWndProc, hwnd, Msg, wParam, lParam)
End Function
Public Sub 注册新对象(新对象 As 系统栏, H窗口 As Long)
系统栏对象.add Item:=新对象, Key:=&H& & H窗口
Public Sub 注销对象(H窗口 As Long)
系统栏对象.Remove &H& & H窗口
名为&系统栏&的类模块:(部分)Public Sub 初始化(hwnd As Long, Icon As StdPicture, _
Optional Tip As String = defTrayTip)
gInTray = defInTray
gAddedToTray = False
gTrayId = 0
gTrayHwnd = hwnd
InTray = defInTray
TrayTip = Tip
Set TrayIcon = Icon
注册新对象 Me, hwnd
Private Sub Class_Terminate()
If InTray Then InTray = False
注销对象 gTrayHwnd
Friend Sub SendEvent(MouseEvent As Long, Id As Long)
Select Case MouseEvent
Case WM_MOUSEMOVE
RaiseEvent MouseMove(Id)
Case WM_LBUTTONDOWN
RaiseEvent MouseDown(vbLeftButton, Id)
Case WM_LBUTTONUP
RaiseEvent MouseUp(vbLeftButton, Id)
Case WM_LBUTTONDBLCLK
RaiseEvent MouseDblClick(vbLeftButton, Id)
Case WM_RBUTTONDOWN
RaiseEvent MouseDown(vbRightButton, Id)
Case WM_RBUTTONUP
RaiseEvent MouseUp(vbRightButton, Id)
Case WM_RBUTTONDBLCLK
RaiseEvent MouseDblClick(vbRightButton, Id)
End Select
这样,几近完美的完成了&事件&的产生,既保持了比较好的封装性,又有很好的通用性。 在&回调函数&中,还有这样一个问题:超时。比如精确定时函数&timeSetEvent&,你可以定义一毫秒产生一次回调,但是这样你就必须在一毫秒内完成所有操作,如果不然,你就需付出死机的代价。 面对这种情况,也有几种解决办法。比如,你可以在&回调函数&中使一个全局变量自增,而在主程序的一个死循环中检测这个变量用以决定操作,这种方法其实也很好,只是改变了事件驱动的编程方式,但换来了比较好的响应度和稳定性。 我更喜欢事件驱动的编程方式,并且偏执的认为事件驱动的效率更高,所以我用下面的方法:Option Explicit
Private m_TID As Long
Public TimeEnabled As Boolean
Private CurdwUser As Long
Public Sub TimeProc(ByVal uID As Long, _
ByVal uMsg As Long, ByVal dwUser As Long, _
ByVal dw1 As Long, ByVal dw2 As Long)
If TimeEnabled = True Then
If m_TID = uID Then
If CurdwUser = dwUser Then
If 主窗体.Visible = True Then
PostMessage 主窗体.HWND, WM_KEYDOWN, 1, 0
Public Sub AddTimer(ByVal dwInt As Long, _
Optional ByVal dwUser As Long = 0)
CurdwUser = dwUser
m_TID = timeSetEvent(dwInt, 0, _
AddressOf TimeProc, dwUser, TIME_PERIODIC)
If m_TID = 0 Then 主窗体.Caption = &创建时间函数失败&
Public Sub RemoveTimer()
If m_TID & 0 Then timeKillEvent m_TID
本来应该&PostMessage&一个自定义消息的,但是那样又需完成另一个&回调函数&,故不取,而令&PostMessage&产生一个 KeyDown 消息,送出&1&(在键盘上是无法键入 AscII 值为&1&的键值的),这样就可以利用&主窗体_KeyDown&事件完成这个操作了。 好了,我不妨也自高自大一回,说一句&程序本天成,妙手偶得之&(此句剽窃而来)。十三 关于帮助最后,我要说 VB 的帮助是非常全面的,经常查一下帮助(包括联机手册),平常所遇到的问题一般能迎刃而解。但是,迷信其帮助也是不行的,让我们来看一看这个&令人心碎、绝望和徒劳无功的小故事&:&&&&WritePrivateProfileString 过去是一个是流行的函数,因为它允许你在任务之间保存数据,这是 Visual Basic 很早就应该提供而直到版本 4 才提供的功能。每一个人都想使用这个函数。每一个人都从 API 声明文件中粘贴其声明部分。每一个人在使用它时都遇到了麻烦。然后每一个人都寻求 Microsoft 产品支持,或者如果他们在 Microsoft 工作,则发送电子邮件到内部 Visual Basic 编程部门。我过去至少每一个月看到一次关于 WritePrivateProfileString 的这种查询。 &&援引自《Visual Basic 5.0 核心技术》 而且对于一些高级问题,可能 VB 的帮助有点力不从心,这时需要一本关于 VB 的好书,不过好书实在不多,我所见的只《Visual Basic 5.0 核心技术》值得推荐一下。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:522881次
积分:8374
积分:8374
排名:第676名
原创:308篇
转载:39篇
评论:180条
(1)(3)(2)(1)(4)(1)(3)(1)(1)(2)(2)(4)(1)(1)(5)(4)(3)(2)(8)(2)(1)(4)(1)(4)(8)(4)(3)(5)(2)(2)(4)(2)(1)(2)(3)(8)(10)(7)(3)(4)(7)(5)(11)(1)(7)(5)(8)(23)(14)(7)(3)(8)(6)(3)(1)(11)(2)(5)(7)(1)(10)(6)(18)(12)(20)(18)}

我要回帖

更多关于 excel中len函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信