不明白??
是 Timer1_timer() 吗???以后提问要写清楚点哦。

解决方案 »

  1.   

    使用API函数TimerSetEvent,如何在动态库利触发一个事件?
      

  2.   

    我没有找到这个API,我只有SetTimer,KillTimer
    是用来设置定时触发事件和接触设置定时的。
        SetTimer hwnd, g_idEvent, lng_Time, AddressOf TimerProc
        KillTimer hwnd, g_idEvent
    lng_Time:是定时触发事件的时间片长(单位:毫秒)
    TimerProc:定时触发事件的函数(地址),要写在模块中(BAS),并且要为PUBLIC
      

  3.   

    例子:
    1、窗体中(一个TEXTBOX,两个COMMANDBUTTON)
    Option ExplicitPrivate Sub Command1_Click()
        SetTimer Me.hwnd, myTimerId, 1000, AddressOf myTimerProc
    End SubPrivate Sub Command2_Click()
        KillTimer Me.hwnd, myTimerId
    End Sub2、模块中:
    Option ExplicitPublic Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Public Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As LongPublic Const myTimerId As Long = 1Public Sub myTimerProc(ByVal hwnd&, ByVal uMsg&, ByVal idEvent&, ByVal dwTime&)
        Select Case idEvent
            Case myTimerId
                Form1.Text1.Text = Now
        End Select
    End Sub
      

  4.   

    有这个函数适用于多媒体精确计时的。你在MSDN可以找到。可惜我想在调用
    它是独立线程的。
    Public Declare Function timeSetEvent Lib "winmm.dll" _
                                        (ByVal uDelay As Long, ByVal _
                                        uResolution As Long, _
                                        ByVal lpFunction As Long, _
                                        ByVal dwUser As Long, _
                                        ByVal uFlags As Long) As Long
    Public Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
      

  5.   

    用Settimer 我也用过。不过也不能触发事件(RaiseEvent) ,我看MSDN说timeSetEvent可以出发事件,不知怎么用?它很好用的,独立线程,精确计时。好吸引人哦,大家研究研究
      

  6.   

    VB高精度计时器编程的讨论VB记时器编程的讨论 在很多场合下编程(例如工业控制、游戏)中需要比较精确的记时器,本文讨论的是在VB下实现记时器的若干方法以及它们的精度控制问题。 在VB中最常用的是Timer控件,它的设置和使用都非常方便,理论上它的记时精度可以达到1ms(毫秒)。但是众所周知的,实际上Timer在记时间隔小于50ms之下是精度是十分差的。它只适用于对于精度要求不太高的场合。 这里作者要介绍的是两中利用Windows API函数实现精确记时的方法。第一中方法是利用高性能频率记数(作者本人的称呼)法。利用这种方法要使用两个API函数QueryPerformanceFrequency和QueryPerformanceCounter。QueryPerformanceFrequency函数获得高性能频率记数器的震荡频率,该函数的定义如下: Private Declare Function QueryPerformanceFrequency Lib "kernel32" _
                  (lpFrequency As LARGE_INTEGER) As Long
    函数中的数据结构LARGE_INTEGER定义如下:
    Type LARGE_INTEGER
        lowpart As Long
        highpart As Long
    End Type调用该函数后,函数会将系统频率记数器的震荡频率保存到lpPerformanceCount中,其中低位保存到lowpart中,高位保存到highpart中。但是现在的Windows没有使用到hightpart(系统频率记数器的震荡频率与计算机的主频无关,我在几台机上做过验证,都是lowpart为1193180,highpart为0)。
    QueryPerformanceCounter函数获得系统频率记数器的震荡次数,函数的定义如下Private Declare Function QueryPerformanceCounter Lib "kernel32" _
            (lpPerformanceCount As LARGE_INTEGER) As Long获得记时器震荡次数保存在lpPerformanceCount中。
    显然,如果首先获得利用QueryPerformanceFrequency函数获得频率记数器的震荡频率,然后在执行某个程序段之前调用QueryPerformanceCounter函数获得频率记数器的震荡次数,在程序段结束再调用QueryPerformanceCounter函数获得频率记数器的震荡次数,将两次获得的震荡次数相减后再除以震荡频率就获得的了两次间隔之间的时间(以秒为单位)。如果在程序中建立一个循环,在循环中不停的调用QueryPerformanceCounter获得频率记数器的震荡次数并同先前的频率记数器的震荡次数相减,将结果除以频率记数器的震荡频率,如果达到一定的时间就执行某个任务,这样就实现了一个比较精确的记时器的功能。另外的一种精确记时器的功能是利用多媒体记时器函数(这也是作者的定义,因为这个系列的函数是在Winmm.dll中定义并且是为媒体播放服务的)。
    实现多媒体记时器首先要定义timeSetEvent函数,该函数的定义如下:Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal _
            uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, _
            ByVal uFlags As Long) As Long函数定义中参数uDelay定义延迟时间,以毫秒为单位,该参数相当于Timer控件的Interval属性。参数uResolution定义记时精度,如果要求尽可能高的精度,要将该参数设置为0;参数lpFunction定义了timeSetEvent函数的回调函数的地址。参数dwUser定义用户自定义的回调值,该值将传递给回调函数。参数uFlags定义定时类型,如果定义为Time_OneShot,则只会在当达到uDelay定义的时间后调用回调函数一次,如果定义为TIME_PERIODIC,则在每次达到定时时间后调用回调函数。
    如果函数调用成功,在系统中建立了一个多媒体记时器对象,每当经过一个uDelay时间后lpFunction指定的函数都会被调用。同时函数返回一个对象标识,如果不再需要记时器则必须要使用timeKillEvent函数删除记时器对象。
    由于Windows是一个多任务的操作系统,因此基于API调用的记时器的精度都会受到其它很多因素的干扰。到底这两中记时器的精度如何,我们来使用以下的程序进行验证:
    设置三种记时器(Timer控件、高性能频率记数、多媒体记时器)。将它们的定时间隔设置为10毫秒,让它们不停工作直到达到一个比较长的时间(比如60秒),这样记时器的误差会被累计下来,然后同实际经过的时间相比较,就可以得到它们的精度。
    下面是具体的检测程序。
    首先建立一个工程文件,在Form1中加入一个Timer控件,两个CommandButton控件和三个TextBox控件,然后在Form1的代码窗口中加入以下代码
    Option ExplicitPrivate Sub Command1_Click()
        Dim lagTick1 As LARGE_INTEGER
        Dim lagTick2 As LARGE_INTEGER
        Dim lTen As Long
        
        Command2.Enabled = True
        Command1.Enabled = False
        iCountStart = 60
        lmmCount = 60
        TimerCount = 60
        actTime1 = GetTickCount
        lTimeID = timeSetEvent(10, 0, AddressOf TimeProc, 1, 1)
        Timer1.Enabled = True
        
        lTen = 10 * lMSFreq
        Call QueryPerformanceCounter(lagTick1)
        lagTick2 = lagTick1
        While iCountStart > 0
            Call QueryPerformanceCounter(lagTick2)
            '如果时钟震动次数超过10毫秒的次数则刷新Text1的显示
            If lagTick2.lowpart - lagTick1.lowpart > lTen Then
                lagTick1 = lagTick2
                iCountStart = iCountStart - 0.01
                Text1.Text = Format$(iCountStart, "00.00")
            End If
            DoEvents
        Wend
    End SubPrivate Sub Command2_Click()
        EndCount
    End SubPrivate Sub Form_Load()
        Dim lim As LARGE_INTEGER
        
        Text1.Text = "60.00"
        Text2.Text = "60.00"
        Text3.Text = "60.00"
        Command1.Caption = "开始倒记时"
        Command2.Caption = "停止记时"
        Command2.Enabled = False
        
        '获得系统板上时钟频率
        QueryPerformanceFrequency lim
        
        '将频率除以1000就的出时钟1毫秒震动的次数
        lMSFreq = (lim.highpart * 2 ^ 16) \ 1000 + lim.lowpart \ 1000
        Timer1.Interval = 10
        Timer1.Enabled = False
    End SubPrivate Sub Timer1_Timer()
        TimerCount = TimerCount - 0.01
        Text3.Text = Format$(TimerCount, "00.00")
        If TimerCount <= 0 Then
            Timer1.Enabled = False
        End If
    End Sub
    在Project中加入一个Module,然后在其中加入以下代码:
    Option ExplicitType LARGE_INTEGER
        lowpart As Long
        highpart As Long
    End TypePublic Declare Function QueryPerformanceCounter Lib "kernel32" _
            (lpPerformanceCount As LARGE_INTEGER) As Long
    Public Declare Function QueryPerformanceFrequency Lib "kernel32" _
            (lpFrequency As LARGE_INTEGER) As Long
    Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal _
            uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, _
            ByVal uFlags As Long) As Long
    Public Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
    Public Declare Function GetTickCount Lib "kernel32" () As LongPublic lMSFreq As Long
    Public TimerCount As Single
    Public lmmCount As Single
    Public lTimeID As Long
    Public actTime1 As Long
    Public actTime2 As Long
    Public iCountStart As SingleDim iCount As Single'timeSetEvent的回调函数
    Sub TimeProc(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, _
        ByVal dw1 As Long, ByVal dw2 As Long)
        
        Form1.Text2.Text = Format$(lmmCount, "00.00")
        lmmCount = lmmCount - 0.01
        If lmmCount <= 0 Then
            iCountStart = 60
            lmmCount = 60
            TimerCount = 60
            EndCount
        End If
    End Sub
    Sub EndCount()
        iCount = iCountStart
        iCountStart = 0
        timeKillEvent lTimeID
        actTime2 = GetTickCount - actTime1
        With Form1
            .Command1.Enabled = True
            .Command2.Enabled = False
            .Timer1.Enabled = False
            
            .Text1 = "计数器记时" + Format$((60 - iCount), "00.00") + "  " _
                    + "实际经过时间" + Format$((actTime2 / 1000), "00.00")
            .Text2 = "计数器记时" + Format$((60 - lmmCount), "00.00") + "  " _
                    + "实际经过时间" + Format$((actTime2 / 1000), "00.00")
            .Text3 = "计数器记时" + Format$((60 - TimerCount), "00.00") + "  " _
                    + "实际经过时间" + Format$((actTime2 / 1000), "00.00")
        End With
    End Sub
    运行程序,点击“开始倒记时”按钮开始倒记时,可以看到两种API记时器工作基本正常,文本框中的倒记时显示流畅,而Timer控件的时间显示相比之下却不堪重负,十分缓慢。按“停止记时”按钮就可以停止倒记时,由图1可以看到,两种API记时器的累计误差在2‰以下,考虑到系统原因和处理记时显示的时间,这个误差基本是可以接受的,而且经过作者的多次检测,误差都在3‰以下。而Timer控件的误差简直是无法接受的。图 三种不同的记时器记时结果
    在运行程序时作者还发现一个问题,如果在倒记时时拖动窗口,文本框中的显示都会停止,而当停止窗口拖放后,多媒体记时器显示会跳过这段时间记时,而其它两种记时器显示倒记时却还是从原来的时间倒数。这说明多媒体记时器是在独立的线程中运行的,不会受到程序的影响。
    综合上面的介绍和范例,我们可以看到,如果要建立高精度的记时器,使用多媒体记时器是比较好的选择。而高性能频率记数法比较适合计算某个耗时十分短的过程所消耗的时间(例如分
      

  7.   

    这文章我也看过。不符合我的要求,实际上它说的我早会了。只是我想每次计时,能够RaiseEvent,而不是只是使用回调函数。因为我是要做一个ActiceX的动态库。大家明白了吗?
      

  8.   

    我不要这样的文章,这样我文章我有一大箩。我只想知道在我做的ActiveX动态库里如何利用它 RaiseEven,回调函数我也会,问题它不能RaiseEvent
      

  9.   

    在类模块中:
    public event myevent(byval ......)在TIMERSETEVENT函数中所调用的进程地址函数中触发该事件RaiseEvent myevent(byval ....)
    这样不行吗???
      

  10.   

    回调函数只能写在标准模块里,模块里不能用RaiseEvent
      

  11.   

    在类里面写一个函数专门用来掉RaiseEvent的,然后在标准模块中(回调函数)中调用这个函数不就行了么。我写过一个自画菜单的DLL,就是这样来处理回调函数中的RaiseEvent的。
      

  12.   

    写个例子给你吧:
    FORM1中:一个TEXTBOX,两个COMMANDBUTTONOption ExplicitPrivate WithEvents evTest As Class1Private Sub Command1_Click()
        SetTimer Me.hwnd, myTimerId, 1000, AddressOf myTimerProc
    End SubPrivate Sub Command2_Click()
        KillTimer Me.hwnd, myTimerId
    End SubPrivate Sub evTest_MenuHelp(ByVal str1 As String)
        Me.Text1.Text = str1
    End SubPrivate Sub Form_Load()
        Set evTest = New Class1
        gCol.Add evTest, "Test"
    End SubMODULE1中:Option ExplicitPublic Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Public Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As LongPublic Const myTimerId As Long = 1
    Public gCol As New CollectionPublic Sub myTimerProc(ByVal hwnd&, ByVal uMsg&, ByVal idEvent&, ByVal dwTime&)
        Select Case idEvent
            Case myTimerId
                gCol("Test").RaiseHelpEvent (Now)
        End Select
    End SubCLASS1中:Option ExplicitPublic Event MenuHelp(ByVal str1 As String)Public Sub RaiseHelpEvent(ByVal str1 As String)
      RaiseEvent MenuHelp(str1)
    End Sub
    '======================================
    '可以了吧,明白了吧!!!
      

  13.   

    你可在要求用户初始化你的类时传入一个带WITHEVENTS的类到你的初始化函数中,你在DLL中就把它帮定到COLLECTION中。
    如:我的自化菜单就是这样让用户调用的。2、声明类
    Dim c as New clsBpMenu
    Dim WithEvents d as HelpCallBack
    3、初始化菜单
    set d = new helpcallback
    call c.fun_install(窗体句柄,d,图像列表框名称)'这时传入d,就是用于把它帮定到我DLL中的COLLECTION中去,这样就可以RASIEEVENT了。UNDERSTAND??!!
    4、添加事件(可选)
    Private Sub d_MenuHelp(ByVal MenuText As String, ByVal MenuHelp As String, ByVal Enabled As Boolean)
         if enable then
    txtCaption=menutext
    txtHelp=menuhelp
    else
    txtCaption=""
    txtHelp=""
    endif
    End Sub
    5、销毁菜单
    c.fun_uninstall(窗体句柄)
    set d=nothing
      

  14.   

    天啊,我不用Timer控件就是因为我不想用Form ,我要做的是无界面动态库。你这种方式我以前用来做过通讯协议。可惜对我不适用。
    不过还是谢谢你。
      

  15.   

    我写的就是没有界面的啊。
    我说的FORM中的,只是你在外面程序调用你的DLL时用的啊。你还是没有明白。
      

  16.   

    看来你还是不明白怎么做动态库,你是在Form里调用SetTimer啊老兄。而我要的是在类里面调用SetTimer。你现在做的只是用外部的Timer调用类模块的方法,然后由类模块来触发事件。还不如我直接用Timer,你说呢?因为这样做已经失去动态库的封装和多线程的意义了。而且你做动态库时是应该先做动态库里的代码,然后才添加工程,写测试工程的代码。这样才能测试动态库能不能正常运作。
      

  17.   

    不难,我就用它做了一个精确计时的 Timer 控件,关键是要把类的指针(ObjPtr)传递到模块里面,再根据构造类,就可以使用类的相关属性和方法了.
      

  18.   

    如果你不相信,你给个MAIL,我发个例子给你,何如??哈哈哈
      

  19.   

    我知道你是什么意思,但你想想,你的代码里:
    Private Sub Form_Load()
        Set evTest = New Class1
        gCol.Add evTest, "Test"
    End Sub对象gCol能够调出来吗?(如果你的模块MODULE1是封装在动态库里的话)
    但如果MODULE1不是封装在动态库里的话就不符合我的要求了。
      

  20.   

    你留个MAIL吧,我发给你例子,ok?
      

  21.   

    写ACTIVEX DLL时,如何在回调函数中改变DLL的一些私有变量的值,并触发用户事件?请看例子:
    两个类模块
    clsTimer:
    公有类,用于输出
    clsSendMessage:
    私有类,用于中转,便于触发公有类的事件
    一个标准模块
    modTime:
    回调函数所在的模块原代码:clsTimer:
    Option Explicit
    Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
    Private m_lngTimerHandle As Long
    Private WithEvents m_oMessage As clsSendMessage
    Public Event Timer() Public Sub StartTick()
    m_lngTimerHandle = SetTimer(0, 0, 1000, AddressOf TimerFunc)
    End Sub Public Sub StopTick()
    KillTimer 0, m_lngTimerHandle
    m_lngTimerHandle = 0
    End Sub Private Sub Class_Initialize()
    Set m_oMessage = g_oMessage
    End Sub Private Sub Class_Terminate()
    KillTimer 0, m_lngTimerHandle
    End Sub Private Sub m_oMessage_MessageArrval()
    WriteClick
    RaiseEvent Timer
    End Sub Private Sub WriteClick()
    Debug.Print "a tick"
    End SubclsSendMessage:
    Option Explicit Public Event MessageArrval() Public Sub SendMessage()
    RaiseEvent MessageArrval
    End SubmodTime:
    Option Explicit Public g_oMessage As New clsSendMessage
    Public Sub TimerFunc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    g_oMessage.SendMessage
    End Sub