1、VB怎样实现多线程,请给出调用CreateThread的代码!2、怎样动态创建控件?谢谢!

解决方案 »

  1.   

    呵呵,我也准备写一个多线程的DLL
      

  2.   

    以前再csdn看到的'请将该部分数据保存为 FORM1.frm 文件 
    VERSION 5.00 
    Begin VB.Form Form1 
      Caption       =   "多线程" 
       ClientHeight    = 3195 
       ClientLeft      =   60 
       ClientTop      = 345 
       ClientWidth     = 6450 
       LinkTopic      =   "Form1" 
       ScaleHeight     = 3195 
       ScaleWidth      = 6450 
       StartUpPosition =   3  '窗口缺省 
       Begin VB.TextBox Text1 
        Height        = 270 
      Left        = 960 
          TabIndex     = 2 
      Text        = "2" 
      Top        = 2760 
       Width        = 2415 
      End 
       Begin VB.CommandButton Command2 
         Caption       =   "返回" 
        Height        = 255 
      Left        = 3480 
          TabIndex     = 1 
      Top        = 2760 
       Width        = 1455 
      End 
       Begin VB.CommandButton Command1 
         Caption       =   "Start Count" 
        Height        = 255 
      Left        = 3480 
          TabIndex     = 0 
      Top        = 240 
       Width        = 1455 
      End 
       Begin VB.Label Label1 
          AutoSize    =   -1 'True 
         Caption       =   "主线程执行结果测试:" 
        Height        = 180 
      Left        = 600 
          TabIndex     = 3 
      Top        = 2400 
       Width        = 1710 
       End 
    End 
    Attribute VB_Name = "Form1" 
    Attribute VB_GlobalNameSpace = False 
    Attribute VB_Creatable = False 
    Attribute VB_PredeclaredId = True 
    Attribute VB_Exposed = False  '下载地址:http://www.bssoft.com.cn/vbThread.rar Private Sub Command1_Click() 
    '声明了线程ID 
        Dim threadid1 As Long 
        Dim threadid2 As Long '参数一,lpThreadAttributes 线程安全属性,传递为NULL 
    '参数二,dwStackSize ,线程堆栈大小,可以为0,表示堆栈和此应用堆栈相同 
    '参数三,lpstartAddress ,执行函数地址,用AddressOf 获取 
    '参数四,lpParameter ,执行函数的参数地址,可以是一个记录或者是别的类型,用VarPtr获取参数地址(varptr为未公开函数)!! 
    '参数五,dwCreationFlags ,表示线程创建后的状态!,0表示立即运行,create_SUSPENDED表示线程挂起 
    '参数六,lpThreadID 表示分配给线程的线程号 
        Call CreateThread(Null, ByVal O&, AddressOf Module1.OutText1, VarPtr(0), ByVal 0&, threadid1) 
        Call CreateThread(Null, ByVal 0&, AddressOf Module1.OutText2, VarPtr(0), ByVal 0&, threadid2) 
        
    End Sub Private Sub Command2_Click() 
    '该事件运行于主线程! 
        Dim i As Long 
        i = CLng(Text1.Text) 
        Text1.Text = CStr(i * i)  '不要点击次数太多,LONG 类型会溢出 
    End Sub Private Sub Form_Load() 
    '保存窗体句柄全局变量,用于在form 上绘图 
        formhandle = Form1.hwnd 
    End Sub 
    ---------------------------------- 
    '请将该部分数据保存为 Module1.bas 文件 
    Attribute VB_Name = "Module1" '线程安全属性数据结构; 
    Public Type SECURITY_ATTRIBUTES 
           nLength As Long 
            lpSecurityDescriptor As Long 
            bInheritHandle As Long 
    End Type '这个是用于多线程访问临界资源同步Api的数据结构 
    Public Type CRITICAL_SECTION 
        dummy As Long 
    End Type 
    '为什么用GDI 函数绘图?原因等下再讲 
    Public Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long 
    Public Declare Function SetBkColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long 
    Public Declare Function TextOut Lib "gdi32" Alias "TextOutA" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal lpString As String, ByVal nCount As Long) As Long 
    Public Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long 
    '请注意;createThread APi声明已被我修改过,修改的地方请自行参照APIView复制的内容 
    Public Declare Function CreateThread Lib "kernel32" (lpThreadAttributes As Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long 
    '这个是sleep,作用就是让两个线程绘图频率不一致,效果才明显。 
    Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 
    Public Declare Sub EnterCriticalSection Lib "kernel32" (lpCriticalSection As CRITICAL_SECTION)  '进入临界区 
    Public Declare Sub LeaveCriticalSection Lib "kernel32" (lpCriticalSection As CRITICAL_SECTION)  '离开临界区 '几个重要的函数举例 
    'ObjPtr:返回对象实例私有域的地址。 
    'StrPtr:返回字符串第一个字的地址。 
    'VarPtr:返回变量的地址。 '全局的form的句柄! 
    Public formhandle As Long 
    '临界数据结构 
    Public sect As CRITICAL_SECTION Sub OutText1()  '过程一 
    Dim i As Long 
    Dim dc As Long 
    Dim s As String 
        dc = GetDC(formhandle) '获取窗体句柄的DC 
       For i = 1 To 100000 
            s = CStr(i) 
            Call SetBkColor(dc, &HF0F0F0)  '设置绘制区域的背景色,也起清除作用 
            Call TextOut(dc, 10, 10, s, Len(s)) '输出文本! 
            Call Sleep(40) '等待 
      Next 
        Call ReleaseDC(formhandle, dc)  '释放资源! 
       ' Call EnterCriticalSection(sect) 
       ' 上下表示该处为临界区,如果要对工程全局变量做操作,最好在该区域内 
       ' 否则线程同步过程中,非常容易让程序崩溃 
       ' Call LeaveCriticalSection(sect) 
    End Sub Sub OutText2()  '和过程一类似 
    Dim i As Long 
    Dim dc As Long 
    Dim s As String 
        dc = GetDC(formhandle) 
       For i = 1 To 100000 
            s = CStr(i) 
            Call SetBkColor(dc, &HF0F0F0) 
            Call TextOut(dc, 10, 80, s, Len(s))  '文本位置改变了 
            Call Sleep(20) '延时改变了 
      Next 
        Call ReleaseDC(formhandle, dc) 
       ' Call EnterCriticalSection(sect) 
      '  Call LeaveCriticalSection(sect) 
    End Sub 
    '关于为何使用gdi 函数输出文本,这是一个很重要的内容; 
    '程序在记数时用了难用的TextOut 函数,而没有使用标签控件,这是因为 
    'vb的组件不都是线程安全的,当多线程访问不是线程安全的组件,那么会 
    '产生严重错误。 'mailto:[email protected] 
    '作者:萧寒(410000)
      

  3.   

    VB中动态创建控件 
    作者:未知  创建数据驱动窗体所谓数据驱动窗体就是根据所请求的数据的不同生成相应的窗体。举例来讲,假设你现在有一个数据库,其中有些字段必须根据登录者的身份加以显示,授权级别高的用户可以浏览并修改这些字段的内容;授权级别一般的用户只能浏览这些字段中的数据;授权级别低的用户则不能浏览这些字段中的内容。要做到这一点就得利用VB动态添加控件的功能。动态创建控件无论你想要创建何种类型的数据驱动窗体,你必须知道如何在运行时动态地创建控件。你可以通过控件数组做到这一点,但VB6的Controls集合所提供的Add方法,功能更强大,灵活性更高。使用该方法,你不需要在设计时将控件的实例放在窗体上。实际上,用Add方法你甚至可以创建程序在编译时根本不存在的控件。这种方法的用法也很简单:' 声明一个窗体级的变量
    Dim WithEvents txtTotal As TextBoxSub CreateTextbox()
    ' 创建新的Textbox控件
    Set txtTotal = Controls.Add("VB.TextBox", "txtTotal")
    ' 将控件移动到你所需要的地方
    txtTotal.Move 1000, 800, 1200, 300
    ' 创建时,所有的控件都是不可见的
    txtTotal.Visible = True
    End Sub
    请注意Add方法的第二个参数:分配给控件的名称。从代码可读性出发,这个名称一般都与变量名相同。你可以用这个名称从Controls集合中获取相应的控件或移除该控件。例如:Controls.Remove "txtTotal"在变量声明时加上WithEvents关键字,即使在设计时窗体不存在该控件,你也可以为该控件的事件编写代码。上面所讲的方法只适合解决VB内置的控件。例如,当你要添加一个TreeView控件时,VB会要求你证明你已经得到了合法的授权来创建该控件的实例。换句话说,VB要证明这个控件是买来的,而不是从其它附有该控件的程序中借来的。要证明你经过了合法的授权有下面几种方法:在窗体上放置一个控件。这也是最简单的方法。你完全没有必要将这个窗体显示出来。 
    将相关的控件添加到工具箱中,然后在“工程属性”对话框的“生成”标签页中取消选择“删除有关未使用的ActiveX控件的信息”这一项。 
    向Licenses集合添加一个元素。例如:Debug.Print Licenses.Add("MSMask.MaskedEdBox") 
    仅仅创建了控件并不足够要创建一个数据驱动窗体,仅仅知道动态创建控件还不够。例如:现在你要创建一个能根据数据库中表的不同字段自动生成控件的窗体。该窗体可能会创建单行文本框,其长度随字段长度不同而不同;也可能会创建单选按钮或复选按钮以显示布尔型字段;甚至可能创建一个多行文本框显示备注型字段。你需要解决的第一个问题是:文本框控件的Multiline属性在运行时是只读的,只在设计时可用。幸好,微软的Microsoft Windowless Controls 6.0可以解决这个问题。这组控件集包括了轻量级的TextBox,ComboBox,ListBox,CheckBox,OptionButton,CommandButton和两个scrollbar控件。这些控件与VB内置的相应的控件最大的区别在于:这些控件的所有属性在运行时是可读写的。在VB的安装光盘中的Common\Tools\VB\WinLess文件夹中可以找到这个控件组。用下面的代码可以创建一个多行文本框:Dim WithEvents txtEditor AsMSWLess.WLTextPrivate Sub CreateEditor()
    Set txtEditor = Controls.Add( "MSWLess.WLText", "txtEditor")
    txtEditor.Move 0, 0, 4000, 4000
    txtEditor.MultiLine = True
    txtEditor.ScrollBars = wlBoth
    txtEditor.Visible = True
    End Sub
    另外一个问题比较复杂:在事先不知道要创建多少个控件的情况下,如何给每个对新创建的控件的引用分配唯一的带WithEvents关键字的变量。换句话说就是要对新创建的控件的事件进行编程,前提是你在设计时不知道程序会创建多少个控件。使用对象数组显然不行,因为不能用WithEvents关键字声明一个对象数组;更坏的情况是,资一个变量定义为As Control或As Object也不行,因为还是不能用WithEvents。问题源自于我们无法在运行时捕获一个对象数组事件。所以我们只能采取曲线救国的办法。所要的编写的代码可能比你想象的多,不过这个解决方法很有趣,值得我们这样去做。我们需要两个辅助类模块来捕获事件,分别取名为ControlItems和ControlItem。ControlItems是一个集合类,其中保存了ControlItem对象及其数量。该数量等于你所要对之编程的控件的数量。ControlItem类的每一份实例捕获控件产生的事件,然后调用在其所属的ControlItems集合类中的过程,最后由ControlItems在窗体中触发事件并执行事件中的代码。整个过程如下图所示:捕获多个控件的事件为简单起见,假设你要捕获来自所有的动态添加到窗体上去的控件的Validate事件。为完成这个工作,ControlItems集合类必须向父窗体展示该事件,并随时准备接收来自其子ControlItem类的通知以触发事件。代码如下:Event Validate(CtrlItem As ControlItem, Cancel As Boolean)
    Private m_ControlItems As New Collection' 向集合中添加一个新的ControlItem项目
    Function Add(ctrl As Control) As ControlItem
    Dim newItem As New ControlItem
    newItem.Init ctrl, Me
    ' 添加到私有类
    m_ControlItems.Add newItem
    ' 返回新项目给调用者
    Set Add = newItem
    End FunctionFriend Sub Notify_Validate(Item As ControlItem, Cancel As Boolean)
    RaiseEvent Validate(Item, Cancel)
    End Sub
    ControlItem类必须捕获来自动态添加到窗体中的控件的事件,并通知其所属的ControlItems集合类。很显然,ControlItem类必须有一个用WithEvents关键字定义的变量来引用真正的控件。这意味着你不能将变量声明为As Control或As Object。如果你决定在窗体中所动态添加的控件不使用VB内置的控件的话,这个问题的解决办法相当的简单。你只需要将变量声明为VBControlExtender类型就行了。对于创建数据驱动窗体来讲,不使用VB内置的控件并不是一件大不了的事。将变量声明为VBControlExtender,并加上WithEvents关键字,你就能直接捕获Validate,GotFocus,LostFocus,DragDrop和DragOver这几个事件了。如果要捕获其它更多的事件,你可以使用ObjectEvent。下面是ControlItem类模块中的代码:Public WithEvents Ctrl As VBControlExtender
    ' 所属的ControlItems对象
    Dim m_Parent As ControlItemsSub Init(ctl As Object, parnt As ControlItems)
    Set Ctrl = ctl
    Set m_Parent = parnt
    End SubPrivate Sub Ctrl_Validate(Cancel As Boolean)
    ' 通知所属的ControlItems类
    m_Parent.Notify_Validate Me, Cancel
    End Sub
    将下面的代码放入窗体中,就可以捕获动态添加的控件所产生的事件了:Dim WithEvents CtrlItems As New ControlItemsPrivate Sub cmdCreateControls_Click()
    Dim ctrl As Control
    ' 创建两个文本框并将它们添加到ControlItems集合?Set ctrl = Controls.Add("MSWLess.WLText", "One")
    ctrl.Move 100, 200, 1000, 300
    ctrl.Visible = True
    CtrlItems.Add ctrl
    ' 注意你可以使用同一个变量
    Set ctrl = Controls.Add("MSWLess.WLText", "Two")
    ctrl.Move 100, 800, 1000, 300
    ctrl.Visible = True
    CtrlItems.Add ctrl
    End SubPrivate Sub CtrlItems_Validate( CtrlItem As ControlItem, Cancel As Boolean)
    ' 拒绝空字符串 - 注意如何引用控件的属?If CtrlItem.Ctrl.Text = "" 
    Then Cancel=True
    End Sub
      

  4.   

    现在解决了最困难的部分,要创建一个数据驱动窗体就变得简单了**************************************************************
    ****************************************************************
    动态添加控件VB6有一个新功能,可以动态添加控件,不用控件数组:object.Add (ProgID, name, container)
    参数说明Object 必需的。一个对象表达式,其值是“应用于”列表中的一个对象。
    ProgID 必需的。一个标识控件的字符串。大多数控件的 ProgID 都可通过查看对象浏览器来决定。控件的 ProgID 是由控件的库和类组成的。
    例如,CommandButton 控件的 ProgID 是 VB.CommandButton。在ProgID 与对象浏览器中所显示的不一样的情况下,Visual Basic
    将显示一个包括正确 ProgId 的错误信息。
    name 必要的。一个字符串,用来标识集合的成员。
    container 可选的。一个对象引用,它指定控件的容器。如果没有指定或为NULL,缺省值为 Controls 集合所属的容器。通过指定该参数,可以把一个控件放置在任何现存的容器控件(如 Frame 控件)中。用户控件或 ActiveX 文档也可以作为一个容器。
      
    举例: //在picture1上面添加一个commandbutton
    Private Sub Form_Load()
    Form1.Controls.Add "VB.CommandButton", "cmdOk", Picture1
    With Form1!cmdOk
    .Visible = True
    .Width = 500
    .Caption = "确认(&Y)"
    End With
    End Sub  
      重点:当您添加一个未引用的需要许可证的控件到一个现存的(已部署好的)应用程序时,在使用 Add 方法之前您必须也添加这个控件的许可证关键字。在运行时添加未引用的控件:
      您也可以利用 Add 方法来动态添加一个在工程中没有被引用的控件。(“未引用的”控件是不出现在 Toolbox 中的控件)。为此,您必须也把控件的License 关键字添加到 Licenses 集合中。下面的示例中在添加控件本身之前添加了控件的许可证关键字:Option Explicit
    Private WithEvents extCtl As VBControlExtenderPrivate Sub Form_Load()
    Licenses.Add "prjWeeks.WeeksCtl", "xydsfasfjewfe"
    Set extCtl = Form1.Controls.Add("prjWeeks.WeeksCtl", "ctl1")
    extCtl.Visible = True ' The control is invisible by default.
    End Sub  但是,为了编程这样一个未引用控件的事件,您必须使用 WithEvents 关键字声明一个对象变量为VBControlExtender 对象(如上),并且设置该对象变量到Add 方法返回的引用上。然后,利用VBControlExtender 对象的 ObjectEvent事件来编程该控件的事件。下面是一个简单的例子。Option Explicit
    Dim WithEvents objExt As VBControlExtender '声明 Extender 变量Private Sub LoadControl()
    Licenses.Add "Project1.Control1", "xydsfasfjewfe"
    Set objExt = Controls.Add("Project1.Control1", "myCtl")
    objExt.Visible = True
    End SubPrivate Sub extObj_ObjectEvent(Info As EventInfo)
    '使用 Select Case 编程控件的事件。
    Select Case Info.Name
    Case "Click"
    '这里处理 Click 事件。
    '现在显示其他的 case
    Case Else '未知事件
    '这里处理未知事件。
    End Select
    End SubNote: 不能把一个固有的控件指定给这个 VBControlExtender 变量; 任何这种试图将引起类型不匹配错误。  但是,您也可以通过使用 WithEvents 关键字声明一个对象变量,并且设置该方法返回的引用为该变量,从而编程一个动态添加控件的事件,如下所示。Option Explicit
    '声明对象变量为 CommandButton 。
    Private WithEvents cmdObject As CommandButtonPrivate Sub Form_Load()
    Set cmdObject = Form1.Controls.Add("VB.CommandButton", "cmdOne")
    cmdObject.Visible = True
    cmdObject.Caption = "Dynamic CommandButton"
    End SubPrivate Sub cmdObject_Click()
    Print "This is a dynamically added control"
    End Sub
      如果希望添加一个用户控件或任何 ActiveX 控件到您的窗体,必须或者把这个控件添加到“工具箱”,或者把控件的 License 关键字添加到 Licenses集合中。有关详细信息请参阅“增加方法 (Licenses 集合)”。  注意:如果您添加一个 ActiveX 或用户控件到您的工程,但是没有在窗体中使用它,您也必须不要选定“工程属性”对话框的“生成” 选项卡上的“删除有关未使用的 ActiveX 控件”选项。如果您的应用程序试图添加该控件,那么该 Add 方法将失败,因为必需的信息已经被丢弃。  
      

  5.   

    Option Explicit
    Dim WithEvents sock As Winsock
    Private Sub Form_Load()
      Set sock = Controls.Add("VB.Winsock", "sock")
    End Sub再请问:VB中Winsock的ProgID是什么,我写VB.Winsock是错误的。马上结贴!谢谢
      

  6.   

    谢谢,好像是MSWinsocklib.winsock呦结贴