山山红叶飞吧 关注:1,716贴子:12,513
  • 5回复贴,共1

VB编程技巧①

只看楼主收藏回复

一、怎样用VB编写.DLL动态链接库文件  

  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 


IP属地:北京1楼2006-05-02 20:45回复
    1. 一般不要使用多线程。曾经有一段时间,我很喜欢使用多线程编程,确实,多线程提供了更好的性能,不过在新版动态链接库上出错的事实让人丧气,想来是因为没有进行互斥操作的原因,不过 VB 的主线程由 VB 内部调用,很难加入我们关于互斥的代码,所以想一想,很多任务其实使用单线程也同样好用,至少把单线程作为一种可选项是一个不错的选择。很多需要异步操作的工作可以使用“PostMessage”函数进行处理,也很不错。 

    2. 在单线程的时候,MsgBox(InputBox)可能会引起问题,因为其它的窗体即使使用模式显示,也同样不会阻止其它窗体的运行,唯有 MsgBox (InputBox)在显示时阻止本线程的一切操作,等待它的返回,则对于实时性要求比较高的系统就不行了,所以我们可以设计自己的 MsgBox(InputBox),不止可以解决这个问题,而且可以增加一些功能,实现更好的接口,不过一般前面的函数参数要和 MsgBox 相同,以便兼容。因为有多态性,所以我们可以在一个标准模块里实现自己的 MsgBox 函数,而程序里调用 MsgBox 的地方都会改成调用此函数,而如果需要调用原函数的话,使用“VBA.Interaction.MsgBox”。同样的,为了避免 LoadPicture 函数返回空值,也可以重载 LoadPicture ,以便其它的地方处理图片时不需要都做空值判断。 

    3. 另一方面,在单线程的时候,也只有 MsgBox(InputBox)会使程序真的完全停下来等候输入,如果我们希望我们自制的模式窗体也具有这种能力,倒也颇为费事。一种方法是跟踪 MsgBox ,看它是怎么实现这一功能的,不过可能完成起来很有难度;另一种方法是使用窗口子类化的方式,把窗体的消息循环定义到自己的处理函数中,这样,在我们显示模式窗体的时候,可以让消息处理函数什么也不做,也不把消息传给其它函数,这样,因为收不到消息,其它函数也就停止下来等待模式窗体的关闭了。 

    4. 条件编译的使用。条件编译一般用于调试,在调试阶段加入了很多的调试代码之后,如果不使用条件编译,在生成最终的可执行文件的时候就会很麻烦,使用条件编译后,只需要修改一下条件编译的常数声明就可以了,而且这样可以保证最终的程序没有冗余代码。 

    Option Explicit 

    Private Sub Form_Load() 
    #If test1 Then 
     MsgBox "test1 Ok." 
    #End If 
    #If test2 Then 
     MsgBox "test2 ok." 
    #End If 
    End Sub 

    如果没有加入 #Const 的话,不会有任何显示,所以要加入“#Const test1 = True: #Const test2 = True”,不过,不能定义“#Public Const”,所以如果需要全局的条件编译的话,要加在菜单“工程 - 属性 - 生成 - 条件编译参数”里,不过注意,不能写 #Const ,而且不能写“True、False”之类的数据,只能使用整数,所以应该写成“test1 = 1 : test2 = 1”。 

    5. 字体设置和属性的缺省值的问题。VB 有缺省值,控件也是,所以我们在我们的系统上编程的时候会看到窗体使用“宋体,9”,以为编译出来的程序必然使用“宋体,9”显示,错!虽然在属性框里显示,不过缺省值是不存盘的,这样有好处,不过需要建立在所有控件的不同版本的属性缺省值相同的基础上,很可惜,据我所知,很多控件的中英文版都有一些属性的缺省值不同,具体有哪些,需要各位在实践中测试,而我这一次只说“宋体,9”的问题。首先窗体中的控件如果没有设置字体的话,就会使用窗体设置的字体,所以如果需要修改窗体中所有控件的字体为统一的格式,只需要修改窗体的字体就可以了,不过如前所述,窗体在创建时是没有字体的,虽然你看到字体栏里显示“宋体”,也同样需要在选择一次才行。另外,VB 有一个比较奇怪的问题,如果运行库“Msvbvbx?0.dll”和程序在同一目录下,虽然编程是选择的是“宋体,9”,显示的却是“宋体,8”,对于这个问题,我找到的解决方法是,使用其它的编辑器(如 Notepad)打开窗体文件 *.frm ,找到字体大小的设置,把 9 改成 9.25 ,这样就没有这种问题了,不过不方便,如果各位有更好的解决方法,希望可以通知我。 

    6. 联等的问题。这个问题比较有趣,不过却应该在编程的时候避免的。请看一下如下的程序(注意,VB6 中调用 Join 函数和我这里的参数格式可能不同): 

    Option Explicit 

    Sub Main() 
     Dim a, b, c, d 
     d = "abcd" 
     c = 100 
     a = b = c = d 
     MsgBox Join(":", a, b, c, d) 
    End Sub 

    如果在 C 语言里,a=b=c=d 的结果应该是使这四个变量都是“abcd”,也就是 MsgBox 出来的应该是“abcd:abcd:abcd:abcd”,但是在 VB 里就不同了,结果是“False::100:abcd”,为什么呢?这样看:a = ((b = c) = d),首先比较 b = c 吗?则 (b = c) 为 False ,然后比较 False = d 吗?,仍然是 False ,最后把 False 赋给 a : 

     a = ((b = c) = d) 
    => a = (False = d) 
    => a = False 

    也就是说,这里实际上进行了两次比较,然后进行了一次赋值,虽然不建议使用,但是有时候这样的写法确实能简化程序,不过最好加上括号,否则怕只是令人头晕而已了。 

    另外,像 a = b > c > d 这样的式子也同样可以使用这样的结合法:a = ((b > c) > d) ,只需要注意,在 VB 中,True 等于 -1 ,False 等于 0 ,而进行比较的时候使用的是整数的形式。


    IP属地:北京2楼2006-05-02 20:48
    回复
      2025-06-15 11:08:55
      广告
      Private Declare Function MakeSureDirectoryPathExists Lib "imagehlp.dll" (ByVal lpPath As String) As Long
      '创建指定的目录(可以是多级目录)
       
      Private Function CreateDirectory(ByVal sDirectory As String) As Boolean
      '创建指定的目录(可以是多级目录),sDirectory:要创建的文件夹
       On Error GoTo ErrHandle
       Dim lngResult As Long
       sDirectory = checkpath(sDirectory)
       lngResult = MakeSureDirectoryPathExists(sDirectory)
       CreateDirectory = IIf(lngResult = 0, False, True)
      ErrHandle:
       If Err <> 0 Then
       CreateDirectory = False
       End If
      End Function

      Private Function checkpath(ByVal sPath As String) As String
       If Right$(sPath, 1) = "\" Then
       checkpath = sPath
       Else
       checkpath = sPath & "\"
       End If
      End Function

      Private Sub Command1_Click()
       CreateDirectory "c:\abc\def\ghi"
      End Sub


      IP属地:北京4楼2006-05-04 15:12
      回复
        在VB中如何判断文件、文件夹是否存在

         在VB中编程中,经常需要判断一个文件是否存在,以便执行相应的操作,这可用下列语句进行判断
         
        Dir([pathname],[Attributes as VbFileAttribute=vbNormal]) As String 
        解释: pathname:文件的绝对路径; 
         Attributes:文件的属性。 
         “[]”内为可选项。dir(file)=""表示文件不存在,dir(file)<>""表示文件存在。 
         例如判断c:wpswinwps.exe是否存在,如存在,就调用它,可用下列语句: 
        if dir("c:wpswinwps.exe")<>"" then
        shell "c:wpswinwps.exe"
        end if
         
        但如果判断的文件是隐藏文件,上面的语句则无法判断出来,这时就需要加上后面的可选项目,例如 
         判断C盘根目录下是否有隐藏文件command.com,就用下面的源代码: 
         if dir("c:command.com,vbhidden")<>"" then
        msgbox"Found c:command.com" 
        end if
         
         判断文件夹是否存在,可用下列语句: 
         dir(文件夹路径, vbDirectory) <>"" 
         例如,要判断文件夹c:aaa是否正在,则代码如下: 
         if Dir("c:aaa", vbDirectory) <>"" then 
          msgbox"文件夹:c:aaa 存在!" 
         end if


        IP属地:北京5楼2006-05-07 23:40
        回复
           
            在编程时经常会用到判断文件是否存在,比如对文件做读写操作前,或是判断密钥文件是否存在等。判断的方法有很多,有些方法虽很实用,但有点繁琐。其实还可以有更简单的方法,就是使用vb 6.0提供的filesystemobject对象。

            filesystemobject对象不是vb内置对象,使用前必须首先选择[工程]→[引用],在出现的窗口中选择“microsoft scripting runtime”,然后利用filesystemobject的fileexists方法来判断文件是否存在。示例程序代码如下:

            private sub command1_click()

             ′引用filesystemobject对象

             dim fs as new filesystemobject

             ′利用filesystemobject对象的fileexists

             ′方法判断文件是否存在

             if fs.fileexists(〃c:\*.gif〃) then

             msgbox 〃文件存在〃

             else

             msgbox 〃文件不存在〃

             end if

            end sub

            灵活运用filesystemobject对象可以解决与文件操作有关的大部分问题。


          IP属地:北京6楼2006-05-07 23:45
          回复
            声明: 
            Declare Function mciSendString Lib "winmm.dll" Alias _ 
            "mciSendStringA" (ByVal lpstrCommand As String, ByVal _ 
            lpstrReturnString As String, ByVal uReturnLength As Long, _ 
            ByVal hwndCallback As Long) As Long 
            使用: 
            '打开 
            retvalue = mcisendstring("set CDAudio door open", returnstring, 127, 0) 
            '关闭 
            retvalue = mcisendstring("set CDAudio door closed", returnstring, 127, 0)


            IP属地:北京7楼2006-05-11 21:17
            回复