类模块中不能用自定义结构么?我在标准模块中声明了如下结构:
'用于类间消息传递,指明涉及变动的细节ID
Public Type DETAIL
lngDetailId As Long
strDetailTable As String
End Type
然后在类模块中这样用:
Public Event ValueChangedD(udtDetail As DETAIL, sngIncreased As Single, udtCT As ChangeType) '由CDetailList发出'由CDetailList发出
Public Sub SendMessage_ValueChangedD(udtDetail As DETAIL, sngIncreased As Single, udtCT As ChangeType)
RaiseEvent ValueChangedD(udtDetail, sngIncreased, udtCT)
End Sub编译后出错,提示:只有在公共对象模块中定义的用户定义类型才可以与变体类型强制转换 或传递给后期绑定 late-bound 的函数。
出错在下面这句:
RaiseEvent ValueChangedD(udtDetail, sngIncreased, udtCT)“udtDetail”这个词高亮显示。这个raiseevent是后期绑定的函数么?如果是,像现在这种情况,我有什么办法传结构出去?
'用于类间消息传递,指明涉及变动的细节ID
Public Type DETAIL
lngDetailId As Long
strDetailTable As String
End Type
然后在类模块中这样用:
Public Event ValueChangedD(udtDetail As DETAIL, sngIncreased As Single, udtCT As ChangeType) '由CDetailList发出'由CDetailList发出
Public Sub SendMessage_ValueChangedD(udtDetail As DETAIL, sngIncreased As Single, udtCT As ChangeType)
RaiseEvent ValueChangedD(udtDetail, sngIncreased, udtCT)
End Sub编译后出错,提示:只有在公共对象模块中定义的用户定义类型才可以与变体类型强制转换 或传递给后期绑定 late-bound 的函数。
出错在下面这句:
RaiseEvent ValueChangedD(udtDetail, sngIncreased, udtCT)“udtDetail”这个词高亮显示。这个raiseevent是后期绑定的函数么?如果是,像现在这种情况,我有什么办法传结构出去?
解决方案 »
- vb引用总是丢失,需要手动重新引用
- 非常简单的问题,帮帮我吧
- 请问一下乍样用API对注册表进行操作啊!!!特急!!!
- 怎么把RecordSet中的数据绑定到DataGrid中啊?提示 类型不匹配
- 有段代码我怎么都看不明白,高手来帮帮我
- 困惑已久的问题:VB中的文本框和数据绑定以后,只可以新添加记录,或者修改记录,但是我想把已经赋值的记录置空就不行,各位有经验,帮我
- 用image控件,失去焦点后这个功能怎么写?
- 我的VB6.0属性框里picture属性不可以用,WHY
- 请问如何实现上标下标问题!就像2的3次方那样的
- 我在程序里对PictureBox得picture赋值,应该怎样写????急
- 鼠标按键的判断
- vb 用DataReport和DataEnvironment做报表,怎样修改显示顺序
但是,我试验的情况是:可以定义在模块中的结构作为公共类的参数类型,但就是不能用在raiseevent里。看下面的代码就可以通过编译:Public Sub SendMessage_ValueChangedD(udtDetail As DETAIL, sngIncreased As Single, udtCT As ChangeType)
udtDetail.lngDetailId = 0
' RaiseEvent ValueChangedD(udtDetail, sngIncreased, udtCT)
End Sub
Type 语句只能在模块级使用。使用 Type 语句声明了一个用户自定义类型后,就可以在该声明范围内的任何位置声明该类型的变量。可以使用 Dim、Private、Public、ReDim 或 Static 来声明用户自定义类型的变量。在标准模块中,用户自定义类型按缺省设置是公用的。可以使用 Private 关键字来改变其可见性。而在类模块中,用户自定义类型只能是私有的,且使用 Public 关键字也不能改变其可见性。
'用于DetailList维护细节数据
Public Type NODE_DETAIL
lngDetailId As Long
strName As String
sngValue As Single
bytRef As Byte
End Type在CDetailList类模块里用这个结构,既没有编译错误过也没有运行错误过:
Private m_udtDetails() As NODE_DETAILPublic Property Get Item(lngIndex As Long) As NODE_DETAIL
Item = m_udtDetails(lngIndex)
End PropertyPublic Sub Initialize(strDetailTable As String)
On Error GoTo Err_Initialize
Dim rstDetail As DAO.Recordset
Dim i As Long
Set m_cmm = GetCmm
Me.DetailTable = strDetailTable
'loadData
Set rstDetail = CurrentDb.OpenRecordset(m_strDetailTable)
With rstDetail
ReDim m_udtDetails(.RecordCount - 1)
i = 0
While Not .EOF
m_udtDetails(i).lngDetailId = .Fields("lngId")
m_udtDetails(i).strName = Nz(.Fields("strName"))
m_udtDetails(i).bytRef = .Fields("bytRef")
If m_blnBasic Then
m_udtDetails(i).sngValue = Nz(.Fields("sngValue"))
Else
m_udtDetails(i).sngValue = -1
End If
i = i + 1
.MoveNext
Wend
.Close
End With
Set rstDetail = Nothing
Exit Sub
Err_Initialize:
Stop
Debug.Print ERR.Description
Resume
End Sub
……
Private Sub m_cmm_ValueChangedS(udtDetail As DETAIL, sngNewValue As Single, udtCT As ChangeType)
Dim sngIncreased As Single
If udtDetail.strDetailTable <> m_strDetailTable Then Exit Sub
#If DEBUG_VERSION Then
gstrLog = gstrLog & "CDetailList:m_cmm_ValueChangedS "
#End If 'unfinished: sngIncreased尚未得到正确的值
Call m_cmm.SendMessage_ValueChangedD(udtDetail, sngIncreased, udtCT)
End Sub
对象模块中的用户定义类型不能为 Public。这个错误的起因与解决方法如下所示: 试图在对象模块中定义 Public 用户自定义类型。
将用户自定义类型的定义移到标准模块中,然后在对象模块或其它模块中声明该类型的变量。若只是要在它出现的模块中使用该类型,可以在对象模块中放入 Type...End Type 定义,并在定义之前加上 Private 关键字。
用的好好的,没出错啊。我在3楼的代码倒还没运行过,但是可以通过编译。这回是把自定义类型作为类模块函数的参数了。貌似与这段英文的说法都矛盾。
标准模块中
Public Type MyType
x As Single
y As Single
End Type类模块中Friend Sub setValue(v As MyType)
End Sub
Public Type DETAIL
lngDetailId As Long
strDetailTable As String
End Type
然后点“转换”,它怎么没反应啊?
其实有个简单的方案,不需要改什么代码
把Type改写成类模块
Public Type DETAIL
lngDetailId As Long
strDetailTable As String
End Type
'
'新建一个类模块,名为DETAIL
定义两个公共变量
Public lngDetailId As Long
Public strDetailTable As String
'把原来的Type删除
这时,只要在每个Dim X As DETAIL 后面加上一句Set X=New DETAIL
不考虑资源问题就用这个吧,LS很多方法都可以的,不过还是这个最方便..:)
而 RaiseEvent 走标准流程,无法保证事件接收者肯定是工程内对象,所以不能用私有 UDT。
lngDetailId As Long
strDetailTable As String
End Type用一个结构模拟类代替结构。
一、结构模拟类
类名:DETAIL。
代码:
public lngDetailId As Long
public strDetailTable As String
二、用户类模块:
Public Event ValueChangedD(udtDetail As DETAIL, sngIncreased As Single, udtCT As ChangeType) '由CDetailList发出dim m_udtCT as ChangeType
Private Sub Class_Initialize()
set m_udtCT=New ChangeType
End Sub
Private Sub Class_Terminate()
set m_udtCT=Nothing
End SubPublic Sub SendMessage_ValueChangedD(udtDetail As DETAIL, sngIncreased As Single, udtCT As ChangeType)
RaiseEvent ValueChangedD(udtDetail, sngIncreased, m_udtCT)
End Sub
三、用户类实例代码:
Dim WithEvents objUserClass As UserClass
Private Sub Form_Load()
Set objUserClass = New UserClass
End SubPrivate Sub objUserClass_ValueChangedD(udtDetail As Single, sngIncreased As Single, udtCT As ChangeType)
MsgBox udtCT.lngDetailId
End Sub
其它工程内的 Class 通过属性 Instancing 指定。
类模块内自定义数据类型不能直接在vb中以公用接口方法输出
除非将那个类型放到模块中,并标示成 global 或 public 状态
原因是com中类型是严谨的,你输出了一个只有自己才知道的数据类型,
而对于外面引用你的代码,他们无法得到关于这个数据类型的任何说明
对于vb,就强制的设置成不允许这样做
对于类,他是一个封闭的代码堆,是COM的一个特性
灵活的相对面就是不安全。
解决方法就是在工程外(tlb、dll)定义结构:
1)可以用 VC 的 idl 编译成 tlb。
2)也可以用《高级 Visual Basic 编程》附带的 EditTlb.exe 直接做成 tlb。
3)纯 VB 的方式就是在一个 ActiveX Dll 工程中定义结构。
这个类模块中,想要对外暴露的接口,在VB6里面被申请为PUBLIC类型,Private,Friend都被视为保护类型对外不暴露现在LZ的意思是,想在标准模块中,定义一个PUBLIC类型的结构体,然后在外部进程中对其进行使用,那么,回答是肯定的,
所有在标准模块中定义的PUBLIC类型,都被视为只能在进程内使用,不能被使用在外部进程中,这就是为什么同样是模块,
同样是定义了PUBLIC类型,一个可以在外部被使用,一个只能被进程内的类模块使用!至于说到C/C++,,那是个标准COM,那么在定义时,如果是公共类型那么不管是进程内还是时程外,只要将其内存地址复制出来
(也就是常说的用指针指到那个内存地址的开头位置),那么你就能用,但是在C/C++里面还有二种类型是不能被外部进程使用
的,一个是私有类型,还有一个好像叫友员吧(我记不大清楚了名字:) 报歉),其中私有类型和VB6一样只能在相同的子进程中
使用,而友员那就有点和VB6中在标准模块中PUBLIC一样,可以在进程内使用.呵呵,,乱说的,说的不好指出一下下!
也是可以通过copymemory 来实现大多数的c++功能的 只不过对象编程也有很多特性,对象虽然方便共享,但就对对象的实现方式来讲,
不同语言在实现对象的过程中,也有自己的方法或特殊的COM属性,所以并不一定能实现不同语言之间的共享
'class1Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long)Public Event ValueChangedD(ByVal udtDetail As Long, ByVal nCount As Long, ByVal sngIncreased As Single)
Friend Sub SendMessage_ValueChangedD(udtDetail As DETAIL, sngIncreased As Single)
Dim bytArr() As Byte
ReDim bytArr(LenB(udtDetail) - 1)
udtDetail.lngDetailId = 111
udtDetail.strDetailTable = "xxxxxxxxxxxxx"
CopyMemory bytArr(0), udtDetail, LenB(udtDetail)
RaiseEvent ValueChangedD(VarPtr(bytArr(0)), LenB(udtDetail), sngIncreased)
End Sub
'
'Module1
Option ExplicitPublic Type DETAIL
lngDetailId As Long
strDetailTable As String * 255 '需要用定长字符串,不定长得不到正确结果
End Type'FormOption ExplicitPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long)Dim WithEvents c As Class1
Private Sub c_ValueChangedD(ByVal udtDetail As Long, ByVal nCount As Long, ByVal sngIncreased As Single)
Dim d As DETAIL
CopyMemory d, ByVal udtDetail, nCount
Debug.Print d.lngDetailId, ":", d.strDetailTable
End SubPrivate Sub Command1_Click()
Dim d As DETAIL, s As Single
Set c = New Class1
d.lngDetailId = 12
d.strDetailTable = "asdf"
c.SendMessage_ValueChangedD d, s
End Sub
先问句溜边儿滴:你干嘛声明两次copymemory啊?在标准模块里声明一个public的CopyMemory不好么?
谢谢指教。你说的很好,VC俺不懂,你说的VB部分的内容和我最近学习到的知识相符。不过的话,我感觉你并没有看到俺的症结所在啊,呵呵。:其实我的问题的根源不在自定义结构在哪里定义,而是在哪里使用。我的所有自定义结构都是在标准模块里以public声明的,所以,其实它们都是不能被外部使用的,但是可被进程内的类模块使用,所以我以前在类模块里用自定义结构都没问题。但是这回我在进程内使用了raiseevent函数,由于这个函数的接受对象可能来自外部进程,所以它不能使用私有的自定义结构,所以这里编译不能通过。具体可见Tiger_Zhao在19楼和22楼的解释。
也就是我得在我的工程里引用这个定义了UDT的部件(.tlb 或 .dll),是吧?