Visual Basic COM基础讲座之(三)

来源:互联网 发布:mac画流程图软件 编辑:程序博客网 时间:2024/05/01 04:25

 VB COM基础讲座之建立测试程序

这里我们直接创建一个应用程序来测试一下前面生成的ActiveX EXE文件监视组件:

  新建一个"Standard EXE"工程;
下面需要添加一个引用到我们的新的文件组件中去,然后添加少量的代码作尝试:

  选择"Project"->"References"菜单;

  选中"File"组件选项,然后单击[OK]按钮;

  在表单的通用声明部分添加下列代码:

  Dim WithEvents MyFileObject As FileCheck

  从"Object"下拉列表中选择"MyFileObject";

  确保插入符在FileFound事件程序中;

  键入下列代码:

  MsgBox "Found: " & Filename

  在表单Form1中添加一个命令按钮;

  在该按钮中添加下列代码:

  Set MyFileObject = New FileCheck

  MyFileObject.MonitorFile ("c:/test.txt")

  这里,我们是将MyFileObject定义成FileCheck的一个新实例,然后用c:/test.txt参数运行MonitorFile方法。这时,程序在后台中启用计时器,且每隔60秒都来检测一次这个文件。

  由于,我们的计算机中还没有这个文件,所以什么也没有发生。现在,我们用Notepad(记事本)在C盘中创建一个名为test.txt的文件。

  则在60秒内,弹出一个消息对话框用来表示我们的文件被找到。这就是我们刚刚创建的ActiveX EXE!

  对于上述这样的组件,使用异步处理是没有太大的必要的。正如我们以前讨论的那样,ActiveX EXE是有自己的进程空间的。因此,当计时器启用并检测文件的存在性时,它不会使其它程序暂停。而如果使用的是DLL,那么就可以使用异步处理了。

  即使这样,你能在计时器中放入任何代码吗?是能放入创建大型报表的程序、复杂的计算代码,还是其他?

  至此,我们构造了一些实际的常规组件,但我们还没有来得及讨论它们的发布问题,这将在下一节中进行。

VB COM基础讲座之全面测试

这一次,我们不用Visual Basic来测试前面的程序,而是先来编译:

  选择"File"->"Make Project1.exe"菜单;

  择要保存的文件夹,单击[OK]按钮;



  退出Visual Basic;

  运行刚才编译过的.EXE文件;

  当表单出现时,试试打开一个customer,然后对其修改并单击[OK]按钮。再打开刚才的customer,看看其资料是否被修改?结果应该是这样,因为ActiveX DLL会自动将结果保存在数据库中。

  现在,让我们静下来想一想刚才做过的事件。我们只用了几条简单的语句就建立了一个自己的数据库应用程序,虽然这里只使用了COM一点功能,但却使得应用程序变得如此容易。

  关闭已测试完的应用程序;

  如果上述过程比较顺利的话,那么我们再做这样的测试:

  打开Northwind工程;

  假如对Northwind工程作了某些修改,那么还需要重新编译:

  选择"File"->"Compile Northwind.dll"菜单;

  选择和上次保存Northwind.dll相同的文件夹,以便覆盖原来的文件,单击[OK]按钮;

  需要说明的是,如果编译时出现错误,那肯定在程序中有一些不对的地方。关闭所有正在运行的程序,然后再重新试一试。

  编译后,退出Visual Basic;

  再次运行Project1.exe;

  天啦,居然会有错误信息,类已不再支持原来接口。

  这就是我们做的一种测试,当重新编译ActiveX工程时,使用它的程序就会被支解。

  解决上述问题的一种办法是将Project1文件打开并重新编译。但是假如工作组中有两百个员工,这就是说,我们得把重新编译好的工程和新的DLL分发到这两百个员工手上。

  你能受得了吗?

  不,不能这样做。我们必须搞清楚错误产生的原因,以及弄明白为什么我们的工程不能和最新的DLL一起工作,难道是兼容性的问题吗?本教程的最后一部分将详细探讨这些内容。

 

Visual Basic COM基础讲座之兼容性

在本教程第二部分的最后,我们遇到一个小问题,但确切地说,那实际上是一个大问题。如果有时间的话,这个问题应该值得我们花大精力去研究。

  还记得我们是怎样遇到那个问题吗?当时,我们先编译ActiveX DLL,然后编译使用该DLL的测试程序。接着,我们重新编译DLL,那是因为假设DLL中的内容需要修改。然而,再运行测试程序时,却出现错误!



  虽然,我们可以重新编译测试程序,以便该程序能正确运行。但是,如果这里不是VB程序,而是Excel数据表或是C++统计程序在使用该DLL,那么是不是每次对ActiveX DLL进行小小的修改后都要重新编译这些程序呢?

  是的,肯定不能这样。

  因为经验告诉我们,这是一个兼容性问题。所以,可以这样处理:

  启动Visual Basic,打开Northwind工程;

  选择"Project"->"Northwind Properties"菜单;

  单击"Component"标签;

  浏览一下"Version Compatibility"的页面内容,可以发现有三个选项。现解释一下:

  No Compatibility —— 每次编译时,用户COM组件都被标有一个新的标记,这就意味着程序只能使用旧标记(以前版本)的DLL。

  Project Compatibility —— 每次编译时,用户COM组件不是总会被标有一个新的标记。如果是的话,任何当前使用的应用程序都会失败。事实上,只有当当前工程和已经编译过的DLL工程有较大不同时才会这样。

  Binary Compatibility —— 每次编译时,应用程序总试图保存前一个编译过的DLL标记,这样就确保了使用的应用程序不会出现蓝屏的死机现象。但是,若当前将要编译的DLL和以前编译过的DLL区别太大,则新的标记就会被标上。

  让我们测试一下上述论点:

  打开本教程上一部分的测试程序;

  重新编译一下;

  试运行一下,应该能正常工作;

  打开ActiveX DLL工程;

  将其属性设置为Binary Compatibility;

  重新编译一下该DLL;

  试运行一下测试程序,应该能正常工作。

  好了,看起来似乎解决了问题。但当重新编译DLL后,大多数开发人员将会陷入另一种不兼容的境地。

  难道就没有更好的解决办法吗?我们暂时将这个问题放到一边!



VB COM基础讲座之ActiveX EXEs

到现在为止,本教程一直讨论基于ActiveX DLLs中的类的内容,但是没有一本教程不说明与DLL相似的ActiveX EXEs。

  所以,想在这里实际编写一个ActiveX EXE工程。事实上,它和ActiveX DLL没有太大的区别,甚至没有区别。在启动Visual Basic后选择"ActiveX EXE"就可创建,然后像以前一样构造自己的类。



  但这里不想再作更详细的讨论,因为ActiveX EXE和ActiveX DLL除了在运行时有一些微小区别外,其他都相同。

  它们的区别首先表现在它们的"进程空间"的不同。所谓"进程空间"是用于运行、处理和存取的一块计算机内存。任何Windows程序,如Microsoft Word等,都有自己的"进程空间",它很像程序的桌面那样。

  当使用ActiveX DLLs工程运行时,DLL是在使用它的程序的进程空间中运行的,而ActiveX EXE是在进程空间外面工作的。但是,ActiveX EXE还有自己的"桌面"。这究竟如何理解呢?

  假如,ActiveX DLL变得不稳定或意外受损时,使用它的应用程序常常出现蓝屏的死机现象,而在EXEs中却不会发生,因为它有自己的"进程空间",即使被破坏,也仅仅是桌面受损,当然用户程序应该很好地去修复它。

  其次,它们的区别还表现在装载的速度上。由于DLL是直接装载到已存在的进程空间,所以它的速度非常快。而EXEs由于还要分配自己的进程空间,所以速度上相对慢一点。

  上述两点区别可以说是它们真正的区别。

  总之,如果使用不同的Windows工具来实现相应的ActiveX组件,那么相应的工程类型就应该有所不同。例如,若使用MTS,则应创建DLL工程,若使用DCOM,则应创建EXE工程。当然,即使现在不理解这此缩写字母的含义,我们也不必担心。因为它们是针对高级用户的,并用于COM远程的工具组件。以后有机会再来给出相应的教程。

  这里再来分析第二点的区别。

  如果现在需要创建这样的一个程序,它不断地检测一个数据库是否有什么改变。那么我们想到的是在程序中使用一些"timer"(计时器),每隔10分钟激发一次并检测该数据库。但问题来了,在该进程空间的其他所有代码都要被停止运行直至数据库检测完毕。

  而ActiveX EXEs伟大之处,就在于它有自己的进程空间。所以在其中添加的计时器也只会工作在自己的进程空间中而不会影响其他使用它的程序。也就是说,对于前面的工程来说,若使用ActiveX EXE来检测数据库,则不会停止其他使用它的程序的运行;即使需要从其他程序中返回一个消息,也可以通过其他事件而获得。

  需要说明的是,运行代码远离正规程序而通过事件与使用的应用程序会话的方法称为"异步处理"。通常当需要对e-mail或数据库作定期检查时,或当运行一个长的报表以及计算大的统计数据时,我们就需使用这种异步处理方式。

  不怕你惊讶的话,我们可以将前面论述的内容总结成这样的一句话:

  "ActiveX DLLs是在进程内运行,而ActiveX EXEs是在进程外运行"。

  好了,下一节将创建并测试一个自己的ActiveX EXE工程,并使用大家还不太熟悉的"异步处理"技巧。然后,提出一个称为"实例"的有意义的概念,最后指明怎样获得更多的COM知识使自己达到一个新的水平。

 

VB COM基础讲座之测试ActiveX EXEs

示例中将使用这样一个组件,它是一个有效的文件探测器。大约每隔60秒检测指定文件的存在性。如何该文件存在,该组件激发一个事件来调用应用程序,如果不存在,则另作处理。



  当然,如果将所有代码写到ActiveX DLL工程,则运行时程序代码将被挂起直到文件检测代码运行完毕为止。由于ActiveX EXE工程拥有自己的进程空间,代码运行时会自我协调、异步处理,从而不会使其他程序代码停顿。

  下面就来创建:

  新建一个"ActiveX EXE"工程;

  工程名设为"File";

  添加的类名为"FileCheck";

  下一步,我们需要构造一些用于每隔1分钟左右检测文件的代码。这里将在ActiveX EXE工程插入一个带有计时器的表单。但该表单不会被显示,因为我们只是使用上面的计时器控件每隔1分钟左右来检测文件,如果相应的文件被检测到,则激发一个事件。

  选择"Project"->"Add Form";

  在表单Form1中添加一个计时器;

  在表单代码中添加下列变量的声明:

Public Filename As String
  
  该变量用于保存被监视的文件名。

  在表单代码中添加下列事件的声明:

Public Event FileFound()
  
  该事件只有当前面的文件发现后才被激发。

  在Timer1代码中添加下列语句:

  Private Sub Timer1_Timer()

   If Dir(Filename) <> "" Then

    RaiseEvent FileFound

    Timer1.Interval = 0

   End If

  End Sub

  代码中,首先简单地检测文件,若存在则激发FileFound事件,然后将Timer1的时间间隔设为0,停止以后的检测。

  打开FileCheck类;

  在通用声明处添加下列对象的声明:

Dim WithEvents objFileCheck As Form1
  
  这就是Form1的代码,它通知Visual Basic上述定义的对象是用来保存表单的。关键词WithEvents表示该类可以接收传送来的事件,如前面的FileFound等。

  本节将创建并测试自己的ActiveX EXE程序。

  示例中将使用这样一个组件,它是一个有效的文件探测器。大约每隔60秒检测指定文件的存在性。如何该文件存在,该组件激发一个事件来调用应用程序,如果不存在,则另作处理。

  当然,如果将所有代码写到ActiveX DLL工程,则运行时程序代码将被挂起直到文件检测代码运行完毕为止。由于ActiveX EXE工程拥有自己的进程空间,代码运行时会自我协调、异步处理,从而不会使其他程序代码停顿。

  下面就来创建:

  新建一个"ActiveX EXE"工程;

  工程名设为"File";

  添加的类名为"FileCheck";

  下一步,我们需要构造一些用于每隔1分钟左右检测文件的代码。这里将在ActiveX EXE工程插入一个带有计时器的表单。但该表单不会被显示,因为我们只是使用上面的计时器控件每隔1分钟左右来检测文件,如果相应的文件被检测到,则激发一个事件。

  选择"Project"->"Add Form";

  在表单Form1中添加一个计时器;

  在表单代码中添加下列变量的声明:

Public Filename As String
 
  该变量用于保存被监视的文件名。

  在表单代码中添加下列事件的声明:

  Public Event FileFound()

  该事件只有当前面的文件发现后才被激发。

  在Timer1代码中添加下列语句:

  Private Sub Timer1_Timer()

   If Dir(Filename) <> "" Then

    RaiseEvent FileFound

    Timer1.Interval = 0

   End If

  End Sub

  代码中,首先简单地检测文件,若存在则激发FileFound事件,然后将Timer1的时间间隔设为0,停止以后的检测。

  打开FileCheck类;

  在通用声明处添加下列对象的声明:

Dim WithEvents objFileCheck As Form1

  这就是Form1的代码,它通知Visual Basic上述定义的对象是用来保存表单的。关键词WithEvents表示该类可以接收传送来的事件,如前面的FileFound等。
从"Object"下拉列表框中选择"Class";

  再从"Procedure"下拉列表框中选择"Initialize";

  在Class_Initialize事件中添加下列代码:

  Private Sub Class_Initialize()

   Set objFileCheck = New Form1

  End Sub

  该代码简单地使objFileCheck等于Form1的新的一个实例。之后,我们将使用在Form1中添加的功能。接下来,我们编写一个子过程用来监视一个文件。

  在FileCheck中添加下列代码:

  Public Sub MonitorFile(Filename As String)

   objFileCheck.Filename = Filename

   objFileCheck.Timer1.Interval = 60000

  End Sub

  当我们调用此过程时,需要给出文件名参数。这时,表单的Filename变量保存该文件名,然后将计时器的时间间隔属性设置为60,000毫秒并激活该计时器。

  至此,我们构造了用于监视文件的所有代码。但是当文件检测到时,我们需要通过激发FileFound事件通知程序正在使用ActiveX EXE。

  在通用声明部分添加下列事件声明:

Public Event FileFound(Filename As String)

  该代码只是简单地定义一个FileFound事件,下一步该事件的相应代码。

  从"Object"下拉列表框中选择"objFileCheck";

  再从"Procedure"下拉列表框中选择"FileFound";

  Private Sub objFileCheck_FileFound ( )

   RaiseEvent FileFound ( objFileCheck.Filename)

  End Sub  

  显然,当文件检测到时,这里的FileFound事件就被激发。但我们还需要在使用EXE程序中添加这个事件的添加代码。

  在objFileCheck_FileFound事件中添加下列代码:

  RaiseEvent FileFound(objFileCheck.Filename)

  这就是我们的全部代码。

  当程序员使用该类时,都可以文件名为参数调用MonitorFile方法,然后表单中的计时器被引发,每隔60秒钟检测一下文件,若该文件被查找到,则激发FileCheck类中的事件,该事件又激发相关的应用程序中的另一个事件,用来通知程序员,该文件已被找到。

  明白了吗?让我们试试看吧!