文章列表
 
您正在查看 "vb语言程序设计篇" 分类下的文章

2008-08-26 9:57

'引用 Microsoft WMI Scripting v1.1 Library

'添加 Command1


Private Sub Command1_Click()
   Dim cpuSet As SWbemObjectSet
   Dim cpu As SWbemObject
   Set cpuSet = GetObject("winmgmts:{impersonationLevel=impersonate}").InstancesOf("Win32_Processor")
   For Each cpu In cpuSet
      MsgBox "CPU系列号:" & cpu.ProcessorId           取得CPU序列号
   Next
End Sub

 
2008-07-12 9:51

          VB中的SCALEHIEGT,SCALEWIDTH,与窗体中的WIDTH,HEIGHT的区别及关系是许多VB初学者难以理解的。本人在学习DELPHI的过程中也曾经对这类似的概论搞不清楚,但通过这次对VB中这些类似概念的学习后,可以说是已掌握了这种概念及原理了。现在回头看DELPHI的相关知识点有豁然开朗的感觉,VB的确是可视化编程入门的最佳语言。


问题的提出
   在VB中默认的度量单位是缇,这是一种跟屏幕分辨率无关的一种度量单位,主要是用在打印机上的,大概是1缇=1/20磅。其它的一些单位请查看MSDN。使用缇就会给我们带来一些麻烦,因为我们都习惯于使用像素来度量窗体及控件的大小,并使用显示器当前的分辨率作参考物来确定窗体的适当大小,当我们想动态地改变窗体的大小的时候我们该如何确定正确的数值呢,想动态地移动窗体中的控件,该如何确定控件的位置呢?同时,在VB的窗体中同时存在着这样的一些属性:scaleWidth,scaleHeight,scaleLeft,scaleTop,scaleMode,Width,Height,他们之间是怎样的关系,是如何影响窗体中控件的大小的呢?通过下面的解说,我们就能解决上面所提到的问题。


预备知识
          其实在VB中的窗体内部(除去窗体边框及标标题栏的区域)有一个类似于画布的东西,它始终是占满整个窗体区域的,他有一个坐标系统,默认的是原点就是窗体的左上角,坐标是0,0 然后往左伸延的就是X轴,往下就是Y轴了,但是这个坐标的单位默认就是缇,当然我们是可以修改成其它类型的单位,要修改度量单位的话就要设定窗体的scaleMode属性。如:设为像素scaleMode=3 。这个坐标系统是用来确定要在什么位置上通过PRINT等方法来作图的,以及确定在这个容器中的什么位置上放置控件,以及跟窗体宽和高的比例情况。

scale类属性的作用
          清楚了窗体有这样一个画布及它的坐标后,我们再来看看有关这个坐标系统的属性。这些scale类型属性主要是用来设定画布坐标系统的数值跟窗体的高宽数值比例情况的。具体是怎样的关系及怎样影响在下面有论说。scaleLeft,scaleTop这两个属性是用来设定这个坐标系统的原点位置的,系统默认的scaleLeft,scaleTop是0,也就是说原点在窗体的左上角了,坐标系统只有大于0的那一块坐标,这样的好处是可以很直观地使用这个坐标系统因为参照点是0且是从窗体的左上角开始的。如果把这两个值设定为大于0的话,画布的坐标就有正负区域了,这样就更像我们数学上的坐标系统了。scaleMode用于设定坐标轴的度量单位。

width,Height的作用
          这两个属性是用于设定窗体的宽和高,他们的单位始终是缇,会直接影响到画布的大小及坐标的比例情况,要动态设置窗体的大小也只能通过这两个属性来设定。

这些属性的关系
          默认情况下,窗体的宽和高是跟窗体上的画布的宽和高是一样大小的,且画布的坐标原点就是窗体的左上角。也就是说,画布的宽和窗体的宽是1:1的关系,也就是说画布的1缇宽度相当于窗体的1缇宽度。那么当我们在窗体上用print.circle (500,500),200来画一个圆的时候,原点就是在距窗体顶部500个缇,左边500个缇,半径是200个缇。现在我们尝试把窗体上的scaleHeight,scaleWidth修改为原来的1/2,现在也是用同样的方法来画一个圆,对比这一下现在的圆跟修改前的圆,可以发现当前圆的半径比原来的扩大了一倍,而且圆心的位置也改变了。同样的参数为什么会有不一要结果呢?这就是scaleHeigh scaleWidth起的作用,假如窗体原本的width是1000缇,scaleWidth也是1000缇,也就是说他们是1:1的关系,我们用 print.circle (500,500),200在画布上画出来的圆所用的尺寸单位是1:1的,明确一点说就是在画布宽上所画的一缇就是窗体宽度的一缇,但修改了scaleWidth后,比如说是原来值的一半,情况就不一样了,画布跟窗体的比例就变成是1:2了,在画布看来,要用原来数值的一半来表示窗体的宽,那么只能是1个缇来表示窗体width的两个缇了,这样的话如果还是用原来参数来使用print方法来作圆的话,出来的圆就是原来的两倍了。情况就有点像要在一张白张上把整个中国地图画出来一样,张上的一毫米就相当于实际十万八千公里了。这就是scale属性跟窗体width,height之间或关系了。

缇跟像素的关系
我们可以通过VB的系统对像screen的twipPerPixersX及twipPerPixersX属性来返回当前分辨率下每一像素所占缇,默认情况下应该是15。但这个值是不是固定的呢?答案是不的,屏幕也是一个画布,同时也像窗体一样有高和宽,要返回15的前提条件是scaleWidth跟width是1:1,scaleHeight跟height也是1:1。

总结
          窗体上有一个画布,它的坐标系统默认是跟窗体一样的,但可以通过scale类属性可以去修改。通过这些scale类属性我们可以开发出一种具有图形放大缩小功能的程序,只要把作图的方法中参数保持不变,动态改变scale属性就可以达到目的,这种关系是成反比的,也就是说参数不变,scale减小的话图形就放大。这类程序的例子就像是股票分析软件中的成交量图。

          另:DELPHI也有类似的画布机制。原理是基本上一致的。

 
2008-01-02 15:53
VB中创建的DLL只是COM组件,无法作为输出函数的DLL,其实这只是个错误的说法。其实MS非常狡猾,如果你是个VB疯狂发烧友的话,应该早就狂试出这种可以创建输出函数的DLL的方法。
VB编译文件实际上采取了两次编译的方法,首先是调用C2.exe产生*.OBJ文件,然后调用Link.EXE连接。如果在LINK的时候添加EXPORT选项,实际上是可以输出函数的。但是,在VB的工程选项中将这些屏蔽了。而且过分的是:VB在Build完成后会将OBJ文件删除,这样就无法手动通过Link来创建我们需要的DLL了。不过我找到一个比较龌鹾的变通的方法,就是先创建一个Exe工程,在Form_Load事件里面写下面的语句:

Sub Main
If MsgBox("哈哈", vbOKCancel) = vbOK Then
Shell "link2.exe " & Command$
End If
End Sub

然后编译为LinkTemp.EXE,接下来将LINK.EXE改名为Link2.exe,将LinkTemp.EXE改名为Link.EXE。这样在VB调用Link.EXE时会弹出对话框,处理就会中断。这时就可以有机会将OBJ文件拷贝出来了。
然后我创建了一个ActiveX DLL工程,在这个工程里面添加一个Module并创建一个Public函数mathadd:

Public Function mathadd(ByVal a As Long, ByVal b As Long) As Long
mathadd = a + b
End Function

编译这个工程,在Link的时候就会中断。然后把创建的Class1.obj、Module1.obj、Project1.obj备份出来。
然后就可以调用Link2.exe连接OBJ到DLL了,我的连接代码是:

Link2.exe "e:\vbdll\Class1.obj" "e:\vbdll\Module1.obj" "e:\vbdll\Project1.obj" "E:\Program Files\Microsoft Visual Studio\VB98\VBAEXE6.LIB" /ENTRY:__vbaS /EXPORT:mathadd /OUT:"e:\vbdll\ProjectOK.dll" /BASE:0x11000000 /SUBSYSTEM:WINDOWS,4.0 /VERS

注意里面的/ENTRY和/EXPORT开关,/EXPORT开关声明了输出函数mathadd。这样就大功告成了,可以被其他语言引入,例如在VB中,只需要:

Private Declare Function mathadd Lib "e:\vbdll\ProjectOK.dll" (ByVal a As Long, ByVal b As Long) As Long
 
2008-01-02 10:22
1.新建一个ActiveX Dll,工程名字为vbmytestdll,类模块名字为mytestdll
2.类模块内容只有一个函数,主要返回DLL的HELLO WORLD
Public Function dlltest1() As String
dlltest1 = "HELLO WORLD"
End Function

3.保存,生成DLL,名字为

vbmytestdll.dll

4.新建一个EXE工程,在菜单: 工程---引用---浏览里找到vbmytestdll.dll,把它引用进来

5.EXE工程代码如下:

Option Explicit
Dim testdll As mytestdll'类模块名字

Private Sub Form_Load()
Set testdll = New mytestdll 'DLL的一个新实例
Me.Caption = testdll.dlltest1 '我的标题=返回DLL的HELLO WORLD
End Sub

OK,编译成EXE即可看到效果.
 
2008-01-01 17:53
VB的好处我就不多说了。VB初学者模仿能力很强,总希望自己的程序看起来专业一点,如用密码登录、制作限次版、限时版、强行启动等等,其实这些东西并不神秘,在VB里只要用少量代码就可实现。
  1.最简单的可执行文件密码登录:
  在程序启动时加入以下代码:
  Private Sub Form_Load()
  Dim a as Variant
  a=InputBox("请输入密码!")
  If a<>"****" Then MsgBox "密码错误,您不能使用本软件!": End 注释:****为预先设定的字符
  End Sub
  怎么样,能唬人吧。什么?太烂!
  2.在硬盘上建立一个文件用于存放密码,这样就可以读写修改了
  On Error GoTo sss
   注释:若文件不存在,则捕获该错误,建立密码
  Open ("c:\abc.abc") For Input As #1
  注释:文件存在,则打开文件
  Input #1,b 注释:将密码读入变量b
  Close #1
  a=InputBox("请输入密码!")
  If a<>b Then MsgBox "密码错误,您不能使用本软件!":End
  Exit Sub
  sss:
  a=InputBox("请建立密码!")
  Open("c:\abc.abc") For Output As #2 注释:在硬盘上建立存放密码的文件
  Print #2,a
  Close #2
  MsgBox "建立密码成功!"
  使用InputBox输入密码的缺点是密码被显示出来,大家可以另建一个窗体代替输入对话框,加入一TextBox并将其PasswordChar属性设为*就行了。文件abc.abc可用任何文本文件打开编辑,因此在你未学会加密算法之前可将文件命名为*.sys或*.dll,并放在windows或system目录下,甚至将其属性设为隐藏,哈哈,系统文件谁敢乱改!不过要小心不要覆盖真正的系统文件。
  用启动登录的方法加密会令用户反感,最好只用在软件中较重要的修改数据部分或用于多用户登录。如果你想制作共享软件,那就先试试限次版吧。
  3.软件限定使用次数说白了也是在硬盘中的某个地方作个标记,每启动一次就记数一次,当次数加到一定值时就不允许使用软件。以上代码稍加改动也能实现 :
  Private Sub Form_Load()
  On Error GoTo sss
  注释:若文件不存在,则建立文件
  Open("c:\abc.abc") For Input As #1
  注释:文件存在,则打开文件
  Input #1,b 注释:将数值读入变量b
  Close #1
  If b>100 Then MsgBox "对不起,您只能使用本软件100次!":End
  注释:提示用户使用次数并退出程序
  c=b+1 注释:计数器加1
  Open("c:\abc.abc") For Output As #3
  Print #3,c 注释:将加1后的数值写入文件
  Close #3
  Exit Sub
  sss:
  Open("c:\abc.abc") For Output As #2
  Print #2,1 注释:建立文件,并写入数值1
  Close #2
  End Sub
  4.大家一定对win.ini和system.ini文件很熟悉吧,它是一种专门用来保存应用程序初始化信息和运行环境信息的文本文件,Windows软件的初始化参数的获取与保存是通过读取扩展名为.ini的文本文件来实现的。目前很多软件干脆就把软件密码保存在自己的ini文件中。VB只要利用API的GetPrivateProfileString和WritePrivateProfileString两个函数就可以很方便地读写ini文件,从而可以保存、读出和验证密码。首先认识一下ini文件。
  ini文件的形式为:
  [section1]
  keyword1=value1
  keyword2=value2
  ……
  [section2]
  keyword1=value1
  keyword2=value2
  ……
  section是段名,keyword是关键字名,value为关键字对应的设定值
  首先用WritePrivateProfileSection创建新的段名和关键字名:
  Declare Function WritePrivateProfileSection Lib "kernel32" Alias "WritePrivateProfileSectionA" (ByVal lpAppName As String,ByVal lpString As String, ByVal lpFileName As String) As Long
  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
  A=WritePrivateProfileSection ("user","password","c:\windows\user.ini")
  在windows目录下的user.ini文件中创建新段名user及该段名下的关键字password,如果目录下没有user.ini文件,则创建该文件
  B=WritePrivateProfileString ("user","password","1234","c:\windows\user.ini"),设定关键字user的值为1234。这样在你的user.ini文件就会多出一段:
  [user]
  password=1234
  利用GetPrivateProfileString函数可以读出password的值:
  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
  Dim key as String*255
  c=GetPrivateProfileString("user","password","false",key,255,"c:\windows\user.ini")
  If key="false" then
  MsgBox"文件不存在或没有该字段"
  Else: Form1.Print"The password is ";key
  该函数将文件user.ini中password的值(即你设定的密码)赋予key,若发生错误(文件不存在或没有该段名)则key的值为“false”,注意一定要声明变量key的长度并与函数中的值一致。这样你就可以将key与登录密码进行对照或直接处理key的值来决定是否继续运行程序。
  使用ini文件存储密码还有一个好处,就是设计者可以建立几个段名来存储不同的密码,从而可实现多用户登录。
  5.在注册表中标记密码可能是保护你的劳动成果的最高境界了。主要方法是在注册表中创建一个键名,在键值里存放你的密码,以后运行时则取出该数据进行验证或处理,当满足条件时终止程序。可以认为注册表是"以乱取胜",只要你选择到一个隐蔽的位置做标记或存放数据,不用做任何加密算法的处理都应该是比较安全的。令人惊喜的是VB很容易利用API操作注册表。这里只简单介绍几个API函数,大家只要参照函数说明,正确引用变量传递数据,不需要任何技巧就可操作注册表。
  RegCreateKeyEx:创建关键字,如果关键字已存在,则将只简单地将它打开
  RegOpenKey:用于打开某键
  RegSetValueEx:打开某键后,用于设置其键值
  RegQueryValueEx:查询一个存在的值,如果此函数调用成功,会返回ERROR_SUCCESS标志
  制作限时版只要会用几个函数如day、month、year、date就行了。例如到了2001年就不能执行程序:
  a=Year(Date)
  if a>=2001 then MsgBox"对不起,该软件已过期":End
  你还可以用前面的方法使条件满足时在硬盘上作个标记,而用户通过修改系统时间、重新安装也不能再使用软件。
  怎么样?学会了对硬盘的简单读写操作,这些东东一点也不神秘了吧!虽然不是很高明,但很多软件都确实使用这种方法进行简单加密;随着解密手段越来越高明,单一加密方法已成为过去,一些软件同时在ini文件和注册表等地方做标记,当然不是简单的把你输入的保存起来,win9x拨号上网时如果选择保存密码也会在硬盘上生成user.pwl文件,不过该文件加了密,强行用文本编辑器打开时只会看到些乱码。哈哈,又心痒痒想学其他招数了吧!
 
2007-11-29 9:21
加入text1,text2,command1
Option Explicit
Public Function StringEnDeCodecn(strSource As String, MA) As String
'该函数只对中西文起到加密作用
'参数为:源文件,密码
On Error GoTo ErrEnDeCode
Dim X As Single
Dim CHARNUM As Long, RANDOMINTEGER As Integer
Dim SINGLECHAR As String * 1
Dim strTmp As String
Dim i As Integer

If MA < 0 Then
MA = MA * (-1)
End If

X = Rnd(-MA)

For i = 1 To Len(strSource) Step 1 '取单字节内容
SINGLECHAR = Mid(strSource, i, 1)
CHARNUM = Asc(SINGLECHAR)


While RANDOMINTEGER < 30 Or RANDOMINTEGER > 100
RANDOMINTEGER = Int(127 * Rnd)
Wend

CHARNUM = CHARNUM Xor RANDOMINTEGER

strTmp = strTmp & Chr(CHARNUM)
Next i
StringEnDeCodecn = strTmp
Exit Function
ErrEnDeCode:
StringEnDeCodecn = ""
MsgBox Err.Number & "\" & Err.Description
End Function

Private Sub Command1_Click()
Dim temp As String
temp = StringEnDeCodecn(Text2.Text, 75) 'temp为加密后的文字
Text1.Text = StringEnDeCodecn(temp, 75) '解密
End Sub  
 
2007-11-06 20:14
With 语句

在一个单一对象或一个用户定义类型上执行一系列的语句。

语法

With object
[statements]

End With

With 语句的语法具有以下几个部分:

部分 描述
object 必要参数。一个对象或用户自定义类型的名称。
statements 可选参数。要执行在 object 上的一条或多条语句。


说明

With 语句可以对某个对象执行一系列的语句,而不用重复指出对象的名称。例如,要改变一个对象的多个属性,可以在 With 控制结构中加上属性的赋值语句,这时候只是引用对象一次而不是在每个属性赋值时都要引用它。下面的例子显示了如何使用 With 语句来给同一个对象的几个属性赋值。

With MyLabel
.Height = 2000
.Width = 2000
.Caption = "This is MyLabel"
End With

注意 当程序一旦进入 With 块,object 就不能改变。因此不能用一个 With 语句来设置多个不同的对象。

可以将一个 With 块放在另一个之中,而产生嵌套的 With 语句。但是,由于外层 With 块成员会在内层的 With 块中被屏蔽住,所以必须在内层的 With 块中,使用完整的对象引用来指出在外层的 With 块中的对象成员。

重点 一般来说,建议您不要跳入或跳出 With 块。如果在 With 块中的语句被执行,但是 With 或 End With 语句并没有执行,则一个包含对该对象引用的临时变量将保留在内存中,直到您退出该过程。
 
2007-11-06 8:28

IIF() 函数:根据条件返回指定的值。 '光看这句话肯定不明白:-( ,接着往下看吧

IIF()语法:IIF( 逻辑表达式 , 表达式1 , 表达式2 )    '能明白点了吗?还不明白就再往下看

返值类型:表达式1、2是什么类型就是什么类型。 '越看越糊涂 &:-)

参数描述:

逻辑表达式 :如果此表达式为真,该函数就返回 表达式1 ,否则返回 表达式2 。

一个例子:

IIF(a=1,'正确','错误')

如果 a 等于1,就显示“正确”,否则就显示“错误”。 '这下明白了吧 ^o^

聪明的读者一定会想到,用下面这段程序也可以实现上面的功能:

if a=1 then '正确' else '错误' end if

但很显然用 iif() 函数简单得多,而且程序运行的速度也快。另外在有些地方它是不可替代的.

 
2007-11-01 15:15
利用Visual Basic开发应用程序时,常常会遇到这样的问题:生成的可执行文件在开发的机器上能够运行,复制到另一台机器上则无法运行,这种现象称之为应用程序与机器环境相关。造成这种现象主要有两个方面的原因:一是程序在运行过程中调用了一些文件,如数据库文件、文本文件和图片文件等,由于路径使用不当而无法定位;二是Visual Basic编译成的.EXE文件并不是实际意义上的EXE文件,Visual Basic系统中的标准控件和开发过程中用到的第三方控件,都没有包含在内。此现象可由图1形象地加以说明。

  因此要解决用VB开发的应用程序与机器环境的相关性,必须从两个方面入手,一是保证应用程序能调用到所用文件,二是应用程序发布时同时发布所有用到的控件和DLL文件。

  开发与路径无关的应用程序
  无论应用程序论开发得多么好,是否成功还取决于其能否在任何机器的任何目录下都能运行,这就要求应用程序要自成一体,不但要包含所有用到的文件,而且还应与路径无关。实现应用程序与路径无关可用两种方法:一是利用VB.APP对象的PATH属性;二是把调用文件放在光盘上,直接调用。

  1.利用VB.APP.PATH实现与路径无关

  该方法的主要思路是在调用文件时利用相对路径,由于VB中不支持与DOS类似的相对路径,如调用当前目录下的“hh1.bmp”文件,写成“hh1.bmp” 和 “.\hh1.bmp“将会出错。为解决该问题,VB提供一个VB.APP对象,该对象有个名为PATH的属性,它记下了执行文件所在的路径,可在运行时访问。

  用该方法创建与路径无关应用程序的要点如下:

  (1)为应用程序(项目)创建一个目录,用以存放建立的窗体或其它文件。

  (2)把应用程序所调用的文件放在该目录下或者放在该目录的子目录下。子目录最好按照引用文件的类型进行建立,如存放图片的子目录名为PIC,存放表的的目录为DBF等。

  (3)除包含在可执行文件中的文件(如在设计时图片框加载的图片)外的其它文件,调用一律采用相对路径而禁用绝对路径。

  这样在复制应用程序的时候,只要把应用程序目录下的所有文件(包括子目录)复制到任意目录下,应用程序都不会发生因找不到文件而产生的错误。

  以下是一个程序实例,该实例显示一系列的角度逐渐变化的地球图片,从而形成地球转动动画。用VB设计一个窗体,窗体上放置一个图片框,名为Image1(Strech=.T.),给窗体加一个定时器控件,控件名为Timer1(Interval=25,enabled=.t.),该项目存放在A:\exam下,图片文件存放在A:\EXAM1\PIC下面。

  使用绝对路径,程序代码如下:

  Dim t1 As Integer

  Private Sub Form_Load()

  t1 = 0 注释:t1 记录时钟事件发生的次数

  End Sub

  Private Sub Timer1_Timer()

  t1 = t1 + 1

  If t1 < 100 Then 注释:图片共显示100幅

  current = t1 Mod 8

  注释:current表示当前应该显示哪张图片

  FileName$ = "A:\exam\pic\earth" && current && ".jpg" 注释:图片文件名(绝对路径)

  Image1.Picture = LoadPicture(FileName$) 注释:显示图片

   Else

   End 注释:程序结束

   End If

  End Sub

  该程序使用绝对路径调用外部文件(earth0.jpg earth7.jpg),当把EXAM目录全部内容拷贝到其它机器上,抽出软盘后,运行程序将发生找不到文件错误。若采用VB.APP.PATH属性,把形成图片文件名的语句改写如下:

  FileName$ = VB.App.Path && "\pic\earth" && current && ".jpg" 注释:形成显示图片的文件名

  这样无论把exam目录完全复制到任何机器,程序均能运行。

  2.从光盘调用文件实现与路径无关

  把应用程序要调用文件放在光盘指定目录下,应用程序发行时和该光盘的拷贝一同发行。程序运行时,直接从光盘指定目录调用文件,故不会发生因找不到文件而出现的错误。由于不同机器上的光盘盘符不同,因此在开发时不能直接引用光盘的盘符,应用程序必须要先取得光盘盘符,然后再生成需要调用文件的完整文件名。

  取得光驱盘符可以使用API函数,也可以通过以下程序段来检测到光驱盘符:

  Private Declare Function GetDriveType Lib "kernel32"

  Alias "GetDriveTypeA" (ByVal nDrive As String) As Long 注释:声明 API函数

  Dim drive As String

  Dim a As Long

  For i = 0 To 25

   drive = Chr(65 + i) && ":\" 注释:形成盘符符号

   a = GetDriveType(drive)

  注释:得到盘符常数

   If a = 5 Then

   Exit For

  注释:如果是光驱则退出

   End If

   Next

   以上程序段放在需要检测光驱的地方,通常放在Form.load事件中,光驱盘符存放在Drive变量中。检测到光驱后,则可直接调用光盘上的文件,如上例中,若PIC目录下的图片文件存放在光盘上,形成文件名的语句则可以用以下语句代替:

  FileName$ = Drive && "exam\pic\earth" && current && ".jpg" 注释:形成显示图片的文件名

  这样,我们就实现了从光盘调用文件与路径无关了。

  包装应用程序实现与系统无关
  解决了与文件路径相关的问题后,生成的可执行文件在其它没有安装Visual Basic的机器中,依然无法执行。原因之一是Visual Basic具有21个标准控件,这些控件都保存在动态链接库中(扩展名为DLL),Visual Basic的可执行程序中并没有包含;原因之二是开发的应用程序可能包含了第三方控件,Visual Basic的可执行程序中也不包含它们。因此在其它机器上执行VB开发的应用程序,必须使该机器包含程序中所有用到的动态链接库和控件文件(OCX或VBX文件),并需要把它们在Windows中加以注册。

  为了减少拷贝和注册DLL、OCX和VBX给用户带来的麻烦,VB自带了一个包装程序,利用它给应用程序打包,生成安装盘。包中可以包含应用程序相关文件、DLL文件、OCX文件、VBX文件等。要把程序包安装到某台机器上时,只需在该机器上执行Setup程序即可,由Setup程序自动完成相应的DLL、OCX和VBX文件的拷贝和注册。

  应用程序与机器环境无关性测试方法
  要保证程序的机器环境的无关性,必须要进行严格测试。但由于在开发机器上,所有调用的文件都实际存在,DLL、OCX和VBX等文件存在并且已经注册,所以无法进行程序的机器环境无关性测试。测试只能在其它机器上进行,可以分成以下几步:

  (1)另找一台只安装了Windows系统而没有安装任何其它软件的机器,且只有Windows系统子目录。

  (2)在该机器上解包并执行程序。

  (3)若执行无误则进入下一步,否则该软件需根据提示进行修改。该步骤保证了调用DLL、OCX和VBX的正确性,但并不能保证与路径无关。

  (4)改变应用程序的安装目录再进一步验证路径无关性,若无误进入下一步,否则该软件需根据提示进行修改。该步骤保证软件自带文件的调用正确性。

  (5)另找一台只安装了Windows系统的机器,Windows系统子目录与前台机器不一样,然后重复以上步骤,若无误说明该软件已经达到了机器环境无关性的要求。否则该软件需根据提示进行修改。该步骤保证软件绝对没有调用任何没有自带的外部文件。

  应用程序的系统无关性是软件成败的一个重要因素,是程序设计中需要详细规划的一个重要方面,同时也是程序调试的一个重点内容。本文讨论的方法,稍加修改亦可适用于其它开发工具。
 
2007-11-01 14:40

VB中创建的DLL只是COM组件,无法作为输出函数的DLL,其实这只是个错误的说法。VB编译文件实际上采取了两次编译的方法,首先是调用C2.exe产生*.OBJ文件,然后调用Link.EXE连接。如果在LINK的时候添加 EXPORT选项,实际上是可以输出函数的。但是,在VB的工程选项中将这些屏蔽了。而且过分的是:VB在Build完成后会将OBJ文件删除,这样就无法手动通过Link来创建我们需要的DLL了。


不过有个比较龌鹾的变通方法,就是先创建一个exe工程,在Form_Load事件里面写下面的语句:

Sub Main
If MsgBox(“Test”, vbOKCancel) = vbOK Then
Shell “link2.exe “ & Command$
End If
End Sub

然后编译为LinkTemp.exe,接下来将LINK.exe改名为Link2.exe,将LinkTemp.exe改名为Link.exe。这样在VB调用Link.exe时会弹出对话框,处理就会中断。这时就可以有机会将OBJ文件拷贝出来了。

然后再创建了一个ActiveX DLL工程,在这个工程里面添加一个Module并创建一个Public函数mathadd:

Public Function mathadd(ByVal a As Long, ByVal b As Long) As Long
mathadd = a + b
End Function

编译这个工程,在Link的时候就会中断。然后把创建的Class1.obj、Module1.obj、Project1.obj备份出来。
然后就可以调用Link2.exe连接OBJ到DLL了,我的连接代码是:

Link2.exe "e:\vbdll\Class1.obj" "e:\vbdll\Module1.obj" "e:\vbdll\Project1.obj" "E:\Program Files\Microsoft Visual Studio\VB98\VBAEXE6.LIB" /ENTRY:__vbaS /EXPORT:mathadd /OUT:"e:\vbdll\ProjectOK.dll" /BASE:0x11000000 /SUBSYSTEM:WINDOWS,4.0 /VERSION:1.0 /Dll /INCREMENTAL:NO /OPT:REF /MERGE:.rdata=.text /IGNORE:4078

注意里面的/ENTRY和/EXPORT开关,/EXPORT开关声明了输出函数mathadd。这样就大功告成了,可以被其他语言引入。更详细地说明,可以参考Ron Petrusha写的Creating a Windows DLL with Visual Basic

 
   
 
 
文章存档
 
     
 
最新文章评论
  

谢谢啦,好用。。。
 

[表情]
 

谢谢,很有帮助!
 

怎么没有答案呢?
 

谢谢
   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu