各位老大,现在,我写了一个DLL,这个DLL有多个实例,每个实例开了多个FORM,并且每个FORM是隐藏的,我给每个FORM的TAG付了一个唯一值,现在我要在其中一个实例中根据不同的TAG值来关闭这些FORM,请问该怎么做?要根据TAG关闭指定的FORM,听说有findwindow的API,怎么使用呢?或者可以不根据TAG来关闭,但要可以选择关闭指定的FORM。还有这个findwindow的API怎么声明,谢谢各位!初级问题,别见笑!

解决方案 »

  1.   

    For i = Forms.Count - 1 To 1 Step -1
                    If Forms(i).tag="指定值" then Unload Forms(i)
                Next
    不知道这样行不行,你可以试一下findwindows声明
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
      

  2.   

    Findwindow说明
    寻找窗口列表中第一个符合指定条件的顶级窗口(在vb里使用:FindWindow最常见的一个用途是获得ThunderRTMain类的隐藏窗口的句柄;该类是所有运行中vb执行程序的一部分。获得句柄后,可用api函数GetWindowText取得这个窗口的名称;该名也是应用程序的标题)返回值
    Long,找到窗口的句柄。如未找到相符窗口,则返回零。会设置GetLastError参数表
      lpClassName ----  String,指向包含了窗口类名的空中止(C语言)字串的指针;或设为零,表示接收任何类  lpWindowName ---  String,指向包含了窗口文本(或标签)的空中止(C语言)字串的指针;或设为零,表示接收任何窗口标题
      

  3.   

    用FindWindow来查找,得到的是窗体句柄,而且只能根据窗体类型和窗体的标题来查,不是用窗体的tag来查的
      

  4.   

    比较简单的这样做:
    Private Sub Command1_Click()
        Dim frm As Form
        For Each frm In Forms
            If frm.Tag = "某个值" Then Unload frm
        Next
    End Sub
      

  5.   

    谢谢各位了,你们说的从集合来判断关闭我试过,只能关闭同一实例的窗口,不能关闭这个DLL的其它实例所创建的窗口,我可以给窗口付唯一标题。
    我想问下findwindow的这个参数:
     lpClassName ----  String,指向包含了窗口类名的空中止(C语言)字串的指针;或设为零,表示接收任何类
    这是什么意思啊?
    是我DLL的名字还是DLL中类的名字呢?
      

  6.   

    我怀疑你的思路有问题//现在我要在其中一个实例中根据不同的TAG值来关闭这些FORM
    你详细说一下你要关闭哪些form?是把实例中所有已经加载的form都关闭吗?还是有选择的关闭?
      

  7.   

    //谢谢各位了,你们说的从集合来判断关闭我试过,只能关闭同一实例的窗口,不能关闭这个DLL的其它实例所创建的窗口,我可以给窗口付唯一标题。其它的实例也是你的程序产生的吗?
    //我想问下findwindow的这个参数:
     lpClassName ----  String,指向包含了窗口类名的空中止(C语言)字串的指针;或设为零,表示接收任何类
    这是什么意思啊?
    是我DLL的名字还是DLL中类的名字呢?都不是,是窗口的类名,如果你的窗体是普通的vb窗体的话,这个类名应该是:ThunderFormDC
      

  8.   

    即然可以赋于每个窗口不同的caption,那就不如直接保存窗口的hwnd,就不必用FindWindows来找窗口了,直接发消息关闭它就行了。
      

  9.   

    各位,谢谢了,这些窗口都是同一个DLL的不同实例所创建的,这些实例都是我程序所创建的,我要有选择的关闭,当然也可以一次性全关闭。
    ===========================================================================
    //即然可以赋于每个窗口不同的caption,那就不如直接保存窗口的hwnd,就不必用FindWindows来找窗口了,直接发消息关闭它就行了。
    ===================================================================
    这个怎么来实现?可以说得仔细点吗?我是做WEB开发的,对于这些不懂,谢谢!
      

  10.   

    OK,OK,老大
    是这样子的,执行一次DLL的这个方法就会产生一个窗口
    Set sForm(FCount) = New TimerForm
    sForm(FCount).Tag = ConditionID
    Load sForm(FCount)
    这个SForm()是我定义的一个动态数组
    窗口是用来作为Timer的载体的,是隐藏的。
    关闭时根据页面上传进来的ConditionID来选择关闭,或者同时关闭所有的。可以把这个conditionid付给Caption
      

  11.   

    关闭sForm数组里的所有的Form:
    For i = 0 To UBound(sForm)
        If Not TypeName(sForm(i)) = "Nothing" Then Unload sForm(i)
    Next
      

  12.   

    获得窗口的句柄后,可以用SendMessage发送消息来关闭它
      

  13.   

    如果只是因为加载一个定时器就开一个窗口的话,那么我建议就不要这样了,再做个dll就行了,应该可以节省更多的资源。
      

  14.   

    //请问不用Timer怎么定时?
    用SetTimer这个api函数
    声明:
    Private Declare Function SetTimer Lib "user32" Alias "SetTimer" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long例子
    模块:
    'In a module
    Public Const DT_CENTER = &H1
    Public Const DT_WORDBREAK = &H10
    Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
    End Type
    Declare Function DrawTextEx Lib "user32" Alias "DrawTextExA" (ByVal hDC As Long, ByVal lpsz As String, ByVal n As Long, lpRect As RECT, ByVal un As Long, ByVal lpDrawTextParams As Any) As Long
    Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
    Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Declare Function SetRect Lib "user32" (lpRect As RECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
    Global Cnt As Long, sSave As String, sOld As String, Ret As String
    Dim Tel As Long
    Function GetPressedKey() As String
        For Cnt = 32 To 128
            'Get the keystate of a specified key
            If GetAsyncKeyState(Cnt) <> 0 Then
                GetPressedKey = Chr$(Cnt)
                Exit For
            End If
        Next Cnt
    End Function
    Sub TimerProc(ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long)
        Ret = GetPressedKey
        If Ret <> sOld Then
            sOld = Ret
            sSave = sSave + sOld
        End If
    End Sub'窗体
    'In a form
    Private Sub Form_Load()
        'KPD-Team 1999
        'URL: http://www.allapi.net/
        'E-Mail: [email protected]
        Me.Caption = "Key Spy"
        'Create an API-timer
        SetTimer Me.hwnd, 0, 1, AddressOf TimerProc
    End Sub
    Private Sub Form_Paint()
        Dim R As RECT
        Const mStr = "Start this project, go to another application, type something, switch back to this application and unload the form. If you unload the form, a messagebox with all the typed keys will be shown."
        'Clear the form
        Me.Cls
        'API uses pixels
        Me.ScaleMode = vbPixels
        'Set the rectangle's values
        SetRect R, 0, 0, Me.ScaleWidth, Me.ScaleHeight
        'Draw the text on the form
        DrawTextEx Me.hDC, mStr, Len(mStr), R, DT_WORDBREAK Or DT_CENTER, ByVal 0&
    End Sub
    Private Sub Form_Resize()
        Form_Paint
    End Sub
    Private Sub Form_Unload(Cancel As Integer)
        'Kill our API-timer
        KillTimer Me.hwnd, 0
        'Show all the typed keys
        MsgBox sSave
    End Sub
      

  15.   

    //如果只是因为加载一个定时器就开一个窗口的话,那么我建议就不要这样了,再做个dll就行了,应该可以节省更多的资源。事实上,我同意这个意见
      

  16.   

    //再问一下,获得窗口的句柄后,怎么关闭啊?呵呵用sendmessage发送wm_close消息即可事实上,你的问题比较复杂,还要考虑进程并发的情况,就是说,不管用怎样的方法关闭窗口,都要把有关数据记录下来,如果进程并发时就要把这个数据保存到每个进程都可以访问的地方,这就需要内存共享(尽管可以保存到文件,但是这样效率太低)这么一来,工作量就大了另外,一个实例创建了一个窗口,就要由这个实例负责销毁(尽管可以用sendmessage发送wm_close消息或其它手段销毁,但在销毁的同时就会产生安全问题),所以说你的想法是不可取的.最后,问一个问题,你用了那么多定时器干什么?
      

  17.   

    真是高手啊!太谢谢了!正考虑改写。
    还有点疑问,既然都问了,那就搞个清楚。
    我刚才用findwindow去捕获句柄的时候
    类名用:ThunderRTMain捕获不到,用ThunderFormDC可以捕获到句柄,但是关闭不了
    代码如下: 
    Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As String) As Long
    Const WM_CLOSE = &H10
    Const WM_QUIT = &H12
    Dim Handle As LongHandle = FindWindow("类名", sss)
    PostMessage Handle, WM_CLOSE, 0, 0
    其中sss为窗体标题变量但是我在声明API的时候把类名的类型改为ANY,然后类名不要,改为0&,就可以关闭窗口
    请问是怎么回事?
      

  18.   

    如果老大“rainstormmaster(暴风雨 v2.0) ”也同意我的意思,那么你就用下面的代码吧:类模块XTimer中的代码:Option Explicit
    '===============================================
    ' 注意!当调试这个工程时不要按“结束”按钮!
    '   请参阅在 XTimerSupport 模块(XTimerS.bas)
    '   顶部的解释。
    '===============================================' XTimer 属性的私有存储体:
    Private mlngTimerID As Long
    Private mlngInterval As Long
    Private mblnEnabled As Boolean' XTimer的唯一事件是 Tick。XTimer 的 Tick 事件
    '   没有任何参数(排除参数可以加速
    '   事件的苗条性),但它不能成为您希望
    '   提供但没有提供参数的原因。
    Event Tick()' TimerID property 被 EndTimer 过程所要求,
    ' ----------------   其目的是在活动的计时器
    '   的支持模块数组中快速定位计时器。
    '
    ' 对于客户来说,使用这个属性没有意义,
    '   索引它被声明为 Friend 而非 Public。
    '
    Friend Property Get TimerID() As Long
        TimerID = mlngTimerID
    End Property' Enabled 属性打开和关闭计时器。它通过
    ' -----------  去除系统的计时器来实现,
    '   因为没有办法暂停系统计时器。
    '   如果他们存在,则正在运行。
    '
    Public Property Get Enabled() As Boolean
        Enabled = mblnEnabled
    End Property
    '
    Public Property Let Enabled(ByVal NewValue As Boolean)
        ' 如果对属性的状态没有进行更改,
        '   则退出。这个避免了当已经
        '   有一个系统计时器正在运行时,
        '   启动第二个系统计时器,等等。
        If NewValue = mblnEnabled Then Exit Property
        '
        ' 保存新的属性设置。
        mblnEnabled = NewValue
        '
        ' 如果间隔为零,则计时器已经
        '   停止。不要启动它。
        If mlngInterval = 0 Then Exit Property
        '
        ' 打开和关闭计时器。
        If mblnEnabled Then
            Debug.Assert mlngTimerID = 0
            mlngTimerID = BeginTimer(Me, mlngInterval)
        Else
            ' 下列的代码是必须的,因为
            '   XTimer 可以通过两个方法
            '   关闭系统计时器:Enabled = False,
            '   或者 Interval = 0。
            If mlngTimerID <> 0 Then
                Call EndTimer(Me)
                mlngTimerID = 0
            End If
        End If
    End Property' Interval 属性需要做很多事情除了设置
    ' -----------------   计时器的间隔。如果 XTimer
    '   是 enabled,并且间隔被从零到非零进行了更改
    '   那么系统计时器必须被启动。
    '   同样地,如果间隔被更改为零,
    '   系统计时器必须被停止。
    '
    ' 无论间隔是否更改此属性让过程
    '   都停止一个系统计时器并且启动另一个系统计时器。
    '   这是因为无法更改一个系统计时器的间隔。
    '
    Public Property Get Interval() As Long
        Interval = mlngInterval
    End Property
    '
    Public Property Let Interval(ByVal NewInterval As Long)
        ' 如果新的间隔值与旧的一致,
        '   没有必要做任何工作。
        If NewInterval = mlngInterval Then Exit Property
        '
        ' 保存新的值。
        mlngInterval = NewInterval
        '
        ' 如果 XTimer 是活动的,mlngTimerID 为非零。
        '   在这种情况下,旧的系统计时器必须在新的
        '   启动之前终止。
        If mlngTimerID <> 0 Then
            Call EndTimer(Me)
            mlngTimerID = 0
        End If
        '
        ' 如果新的间隔为零,那么 XTimer
        '   成为非活动的,不管当前的
        '   Enabled 属性为何值。如果新的间隔
        '   不为零,并且 Enabled 属性为 True,
        '   那么一个新的系统计时器被启动,并且
        '   它的 ID 被存储在 mlngTimerID 中。
        If (NewInterval <> 0) And mblnEnabled Then
            mlngTimerID = BeginTimer(Me, NewInterval)
        End If
    End Property' RaiseTick 被所支持的模块所调用,当
    ' ----------------   系统计时器事件为
    '   这个 XTimer 对象的系统计时器产生的时侯。
    '
    ' 实现的细节:您可能期待声明这个
    '   方法为 Friend 代替 Public,因为不
    '   需要让客户来调用 RaiseTick。然而,
    '   RaiseTick 被决定声明为 Public,
    '   因为 XTimer 在 Tick 事件然被处理时
    '   可能被释放。当对象的一个公有方法在堆栈中时,
    '   它不能被终止,但是在堆栈中的它的
    '   Friend 方法可以被终止。如果此对象
    '   在 Friend 方法返回之前终止 (如果
    '   客户在 XTimer 的 Tick 事件中执行大量
    '   代码,这种情况可能会发生),结果是产生一个 GPF 。
    '   (注意这个高度的不寻常情景取决于外部的事件;
    '   它在一般的使用 Friend 函数中不会发生。)
    '
    Public Sub RaiseTick()
        RaiseEvent Tick
    End SubPrivate Sub Class_Terminate()
        ' 当客户释放它的最后一个对 XTimer 对象的引用时
        '   它将离开 -- 但仅仅当
        '   XTimer 的 Enabled 属性为 False 的时侯,
        '   或者它的 Interval 属性为 True!
        '
        ' 这是因为当 XTimer 的系统计时器
        '   正在运行时,XTimerSupport 模块
        '   为了产生它的 Tick 事件,
        '   不得不使用一个到 XTimer 的引用。
        '   那么客户在释放 XTimer 对象前
        '   禁用它们,将削弱系统计时器!
        '
        ' 这些削弱的系统计时器直到
        '   XTimers 部件关闭时才能被恢复
        '   -- 那就是说,当客户使用的
        '   DLL 关闭时,此 DLL 将不被
        '   卸载直到所有 XTimer 对象被释放。
        '   因为对公有对象的引用 (在这种
        '   情况下,它们被 XTimerSupport 所保存)
        '   将阻止 DLL 的卸载。
        '
        ' 那么为什么要麻烦地清除终止事件中的系统
        '   计时器呢?因为当
        '   DLL 被关闭后,所有到
        '   XTimer 对象的引用将被清除
        '   -- 并且 XTimer 将获得它的终止
        '   事件。系统计时器在此时将被破坏。
        On Error Resume Next
        If mlngTimerID <> 0 Then KillTimer 0, mlngTimerID
        '
        ' 下列工作是 XTimer 将要做的如果
        '   它非要释放关闭的 DLL 的优先级
        'If mlngTimerID <> 0 Then Call EndTimer(Me)
    End Sub
      

  19.   

    标准模块XTimerSupport中的代码:
    Option Explicit
    '================================================
    ' 注意!当调试此工程时不要按结束按钮!
    '   在中断模式时,不要对工程进行编辑,
    '   那样将导致工程被重置!
    '
    ' 这个模块具有危险性因为它使用
    '   SetTimer API 和 AddressOf 操作符
    '   来设置一个代码计时器。一旦这样
    '   计时器被设置,此系统在您返回到
    '   设计时之后将继续调用 TimerProc 函数事件。
    '
    ' 因为 TimerProc 在设计时不可用,
    '   这个程序在 Visual Basic 中将
    '   产生一个程序故障。
    '
    ' 当调试这个模块时,您需要确定
    '   在返回到设计时之前所有的系统
    '   计时器都已经停止(使用 KillTimer)。
    '   您可以从立即窗口中调用
    '   SCRUB 来完成此操作。
    '
    ' 回调计时器具有固有的危险性。
    '   使用计时器控件对于您多数的开发进程
    '   将更加的安全,只有到最后才切换到
    '   回调计时器。
    '==================================================' 当使用更多的计时器时,数组 maxti
    '   的合计尺寸将增大。(参阅下面的 'MoreRoom:' 代码。)
    Const MAXTIMERINCREMEMT = 5Private Type XTIMERINFO   ' Hungarian xti
        xt As XTimer
        id As Long
        blnReentered As Boolean
    End TypeDeclare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerProc As Long) As Long
    Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long' maxti 是一个活动的 XTimer 对象的数组。使用用户
    ' -----   定义类型的数组来代替一个集合对象
    '   的原因是当我们产生 XTimer 对象的 Tick
    '   事件时获得早期绑定。
    Private maxti() As XTIMERINFO
    '
    ' mintMaxTimers 告诉我们在任何给定的时间时
    ' -------------   数组 maxti 由多大。
    Private mintMaxTimers As Integer' BeginTimer function 当 XTimer 的间隔属性被
    ' -------------------   设置成一个新的非零值时
    '   被一个 XTimer 对象所调用。
    '
    ' 此函数使 API 调用产生一个请求来设置
    '   计时器。如果计时器被成功的创建,
    '   此函数放置到 XTimer 对象的引用到
    '   数组 maxti。这个引用将用于调用
    '   产生 XTimer 的 Tick 事件的方法。
    '
    Public Function BeginTimer(ByVal xt As XTimer, ByVal Interval As Long)
        Dim lngTimerID As Long
        Dim intTimerNumber As Integer
        
        lngTimerID = SetTimer(0, 0, Interval, AddressOf TimerProc)
        ' 成功的条件时从 SetTimer 返回一个非零值。如果我们不能
        '   获得一个计时器,则产生一个错误。
        If lngTimerID = 0 Then Err.Raise vbObjectError + 31013, , "没有可用的计时器"
        
        ' 下面的循环在数组 maxti 中定位出第一个
        '   可用的空位。如果超过了上一级绑定,
        '   产生错误并且将数组加大。(如果
        '   您编译这个 DLL 为本地代码,不要关闭
        '   绑定检查!)
        For intTimerNumber = 1 To mintMaxTimers
            If maxti(intTimerNumber).id = 0 Then Exit For
        Next
        '
        ' 如果没有找到空位,增加数组的尺寸。
        If intTimerNumber > mintMaxTimers Then
            mintMaxTimers = mintMaxTimers + MAXTIMERINCREMEMT
            ReDim Preserve maxti(1 To mintMaxTimers)
        End If
        '
        ' 当产生 XTimer 对象的 Tick 事件时,
        '   保存一个到使用的引用。
        Set maxti(intTimerNumber).xt = xt
        '
        ' 保存 SetTimer API 返回的的计时器 id ,
        '   并且返回到 XTimer 对象的值。
        maxti(intTimerNumber).id = lngTimerID
        maxti(intTimerNumber).blnReentered = False
        BeginTimer = lngTimerID
    End Function' TimerProc 是计时器过程,在您的某个计时器关闭时
    ' ---------   系统将调用它。
    '
    ' 重要信息 -- 因为这个过程必须在标准模块中,
    '   您的所有计时器对象都必须可以共享它。
    '   这意味着过程必须标识出哪一个计时器
    '   已经关闭。这个操作通过查找数组
    '   maxti 的计时器 ID 来完成(idEvent)。
    '
    ' 如果这个子过程声明错误,将产生程序故障!
    '   这是使用要求回调函数的 API
    '   的危险处之一。
    '
    Public Sub TimerProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal lngSysTime As Long)
        Dim intCt As Integer    For intCt = 1 To mintMaxTimers
            If maxti(intCt).id = idEvent Then
                ' 如果这个事件的一个早期实例
                '   仍然在进行时,不要产生此事件。
                If maxti(intCt).blnReentered Then Exit Sub
                ' blnReentered 标志将阻塞这个
                '   事件的未来实例直到
                '   当前的事例完成。
                maxti(intCt).blnReentered = True
                On Error Resume Next
                ' 为适当的 XTimer 对象产生一个 Tick 事件。
                maxti(intCt).xt.RaiseTick
                If Err.Number <> 0 Then
                    ' 如果发生错误,XTimer
                    '   将负责终止除第一个运行的
                    '   外的所有计时器。清除
                    '   孤立计时器,来防止
                    '   以后产生 GP 故障。
                    KillTimer 0, idEvent
                    maxti(intCt).id = 0
                    '
                    ' 释放到 XTimer 对象的引用。
                    Set maxti(intCt).xt = Nothing
                End If
                '
                ' 允许这个事件再次进入 TimerProc。
                maxti(intCt).blnReentered = False
                Exit Sub
            End If
        Next
        ' 下面的代码行是一个失败的保护,
        '   在 XTimer 无故被释放而 Windows
        '   系统计时器还没有将它铲除。
        '
        ' 执行也可能到达这个点因为一个
        '   已知的 NT 3.51 的错误,因此您可能
        '   在执行了 KillTimer API 后收到
        '   一个外部的计时器事件。
        KillTimer 0, idEvent
    End Sub' EndTimer 过程被 XTimer 调用,每当
    ' ------------------   Enabled 属性被设置为
    '   False,以及当需要一个新的计时器间隔。
    '   没有办法来重新设置系统计时器,所以更改
    '   间隔的唯一方法是铲除现存的计时器并且
    '   调用 BeginTimer 来启动一个新的计时器。
    '
    Public Sub EndTimer(ByVal xt As XTimer)
        Dim lngTimerID As Long
        Dim intCt As Integer
        
        ' 询问 XTimer 的 TimerID,以至我们可以查找
        '   有关正确的 XTIMERINFO 的数组。(您可以
        '   查找 XTimer 自身的引用,使用
        '   Is 操作符来同带有 maxti(intCt).xt 的 xt 进行
        '   比较,但那样将降低速度。)
        lngTimerID = xt.TimerID
        '
        ' 如果计时器 ID 是零,EndTimer 调用将出错。
        If lngTimerID = 0 Then Exit Sub
        '
        For intCt = 1 To mintMaxTimers
            If maxti(intCt).id = lngTimerID Then
                ' 铲除系统计时器。
                KillTimer 0, lngTimerID
                '
                ' 释放对 XTimer 对象的引用。
                Set maxti(intCt).xt = Nothing
                '
                ' 清除 ID,释放空位以备新的活动的计时器使用。
                maxti(intCt).id = 0
                Exit Sub
            End If
        Next
    End Sub' Scrub 过程是一个仅仅为了调试目的的安全的阀:
    ' ---------------   如果当 XTimer 对象活动时,
    '   您不得不结束这个工程,从立即窗口中调用 Scrub 。
    '   这将调用  KillTimer 来铲除所有的系统计时器,
    '   使开发环境可以安全地放回到设计模式。
    '
    Public Sub Scrub()
        Dim intCt As Integer
        ' 铲除仍然活动的计时器。
        For intCt = 1 To mintMaxTimers
            If maxti(intCt).id <> 0 Then KillTimer 0, maxti(intCt).id
        Next
    End Sub
      

  20.   

    上面的代码看起来好象很长,但实际代码并不多,大多都是非常详尽的注释。可以看一下,这是MSDN中的一个Dll示例程序。
      

  21.   

    呵呵,是这样子的,客户单位有多个操作员来执行一项任务,这个任务的执行是根据条件来执行的,而且是要在服务器上定时执行,每个操作员负责几个条件。
    每个操作员会启动其负责的所有条件的任务,自动在服务器上定时执行,但是这个启动可能不是同时的,可能会是多次的,我们的系统是B/S的,ASP的,所以在操作员进入到启动页面的时候就会产生一个实例,启动后,可能机会退出系统,在某个时候再登录系统进行停止工作,可能会停止所有的,可能会停止其中一个或某个。
    几位高手的回帖上我受益非浅啊!非常感谢!
      

  22.   

    Handle = FindWindow("ThunderFormDC", sss)'任何一个参数想用0的时候,不用改声明,用vbnullstring表示0就可以了
    PostMessage Handle, WM_CLOSE, 0, 0