Определяемый пользователем тип (UDT) в качестве параметра в общедоступном Sub в модуле класса (VB6) - PullRequest
16 голосов
/ 10 июня 2009

Я пытался решить эту проблему, но не могу найти решение. У меня есть UDT, определенный в обычном модуле, и я хотел использовать его как параметр в Public Sub в модуле класса. Затем я получаю ошибку компиляции:

Только общедоступные пользовательские типы, определенные в общедоступных объектных модулях, могут использоваться в качестве параметров или типа возврата для общедоступных процедур модулей классов или в качестве полей общедоступных пользовательских типов

Затем я пытаюсь переместить свой UDT в класс, объявленный как Private. Я получаю эту ошибку компиляции:

Частные типы Enum и пользовательские типы нельзя использовать в качестве параметров или типов возврата для открытых процедур, открытых элементов данных или полей открытых пользовательских типов.

Наконец, я пытаюсь объявить его как Public в классе, и получаю эту ошибку компиляции:

Невозможно определить пользовательский тип Public в модуле закрытых объектов.

Так есть ли способ использовать общедоступный UDT в качестве параметра в общедоступной подпрограмме в классе?

Ответы [ 7 ]

18 голосов
/ 10 июня 2009

Просто определите подпрограмму как Friend scope. Это хорошо для меня в классе VB6.

Private Type testtype
  x As String
End Type


Friend Sub testmethod(y As testtype)

End Sub

Судя по вашим сообщениям об ошибках, ваш класс закрыт. Если вы хотите, чтобы ваш класс был общедоступным - то есть вы делаете exe-файл ActiveX или DLL и хотите, чтобы клиенты имели доступ к подпрограмме, - тогда просто сделайте и тип, и подпрограмму Public.

10 голосов
/ 11 июня 2009

Так есть ли способ иметь общественное UDT, используемый в качестве параметра в публичном саб в классе?

Одним словом, нет. Самое близкое, что вы можете получить только с классическим кодом VB, - это создать класс, который будет копировать UDT и использовать его вместо этого. В этом, безусловно, есть свои преимущества, но вам не терпится, если вам нужно передать это, скажем, и API.

Другой вариант - определить UDT в библиотеке типов. Если вы сделаете это, его можно будет использовать в качестве параметра для публичного метода.

9 голосов
/ 27 февраля 2010

Хорошо, вот как это сделать, если я смогу заставить свою кошку оставить меня в покое, то есть.

В Form1 (с одной кнопкой на нем):

Option Explicit
'
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal dst As Long, ByVal src As Long, ByVal nBytes As Long)
'

Private Sub Command1_Click()
' Okay, this is what won't work in VB6:
'     Dim MyUdt1 As MyUdtType   ' Declare a variable with a publicly defined UDT (no problem).
'     Form2.Show                ' We could have created some object with a class.  This was just easier for the demo.
'           INSIDE OF FORM2:
'               Public Sub MySub(MyUdt2 As MyUdtType)   ' It won't even let you compile this.
'                   Msgbox MyUdt2.l
'                   MyUdt2.l = 5
'               End Sub
'     Form2.MySub MyUdt1                                ' You'll never get this far.
'     Unload Form2
'     Msgbox MyUdt1.l
'
' The following is a way to get it done:
'
Dim MyUdt1 As MyUdtType         ' Declare a variable with a publicly defined UDT (no problem).
Dim ReturnUdtPtr As Long        ' Declare a variable for a return pointer.
MyUdt1.l = 3                    ' Give the variable of our UDT some value.
Form2.Show                      ' Create our other object.
'
' Now we're ready to call our procedure in the object.
' This is all we really wanted to do all along.
' Notice that the VarPtr of the UDT is passed and not the actual UDT.
' This allows us to circumvent the no passing of UDTs to objects.
ReturnUdtPtr = Form2.MyFunction(VarPtr(MyUdt1))
'
' If we don't want anything back, we could have just used a SUB procedure.
' However, I wanted to give an example of how to go both directions.
' All of this would be exactly the same even if we had started out in a module (BAS).
CopyMemory VarPtr(MyUdt1), ReturnUdtPtr, Len(MyUdt1)
'
' We can now kill our other object (Unload Form2).
' We probably shouldn't kill it until we've copied our UDT data
' because the lifetime of our UDT will be technically ended when we do.
Unload Form2                    ' Kill the other object.  We're done with it.
MsgBox MyUdt1.l                 ' Make sure we got the UDT data back.
End Sub

В форме 2 (контроль не требуется). (Это мог бы быть объект, созданный с помощью класса.):

    Option Explicit
'
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal dst As Long, ByVal src As Long, ByVal nBytes As Long)
'

Public Function MyFunction(ArgUdtPtr As Long) As Long
' Ok, this is how we get it done.
' There are a couple of things to notice right off the bat.
' First, the POINTER to the UDT is passed (using VarPtr) rather than the actual UDT.
' This way, we can circumvent the restriction of UDT not passed into objects.
' Second, the following MyUdt2 is declared as STATIC.
' This second point is important because the lifetime of MyUdt2 technically ends
' when we return from this function if it is just DIMmed.
' If we want to pass changes back to our caller, we will want to have a slightly longer lifetime.
Static MyUdt2 As MyUdtType
' Ok, we're here, so now we move the argument's UDT's data into our local UDT.
CopyMemory VarPtr(MyUdt2), ArgUdtPtr, Len(MyUdt2)
' Let's see if we got it.
MsgBox MyUdt2.l
' Now we might want to change it, and then pass back our changes.
MyUdt2.l = 5
' Once again, we pass back the pointer, because we can't get the actual UDT back.
' This is where the MyUdt2 being declared as Static becomes important.
MyFunction = VarPtr(MyUdt2)
End Function

И, наконец, это идет в файле модуля (BAS).

    Option Explicit
'
' This is just the UDT that is used for the example.
Public Type MyUdtType
    l As Long
End Type
'
2 голосов
/ 27 июля 2010

Просто передайте UDT как опорный параметр, и он будет работать. :)

'method in the class

Public Sub CreateFile(ByRef udt1 As UdtTest)

End Sub
1 голос
/ 27 июля 2015

У меня было то же сообщение об ошибке, и после проверки приложения я обнаружил, что в окне свойств для класса для параметра "Instancing" было установлено значение "1 - Private" для ссылочного объекта. Я изменил его на «5 - MultiUse» и получил то же сообщение об ошибке. Затем я вернулся к версии модуля проекта до того момента, когда я добавил этот объект, на который ссылаются, и снова добавил его в проект - по умолчанию он был «1 - Частный». Я изменил его на «5 - MultiUse», прежде чем делать что-либо еще, и закрыл проект, чтобы он мог обновляться перед компиляцией. Я заново открыл проект, проверил, что он по-прежнему установлен на «5 - MultiUse», затем скомпилировал проект, и он был скомпилирован без ошибок.

Когда в сообщении об ошибке говорилось, что оно не позволяет ссылаться на частный объект, объект действительно был закрытым. Как только я объявил, что он не является частным, и модуль проекта принял эту новую настройку, он скомпилирован чисто.

0 голосов
/ 13 ноября 2015

Определить UDF (открытый тип) в модуле:

Public Type TPVArticulo
    Referencia As String
    Descripcion As String
    PVP As Double
    Dto As Double
End Type

и используйте Friend в классе, модуль o:

Friend Function GetArticulo() As TPVArticulo
0 голосов
/ 10 июня 2009

UDT должен быть объявлен в публичном объекте, например:

Public Class Sample

    Public Strucutre UDT
       Dim Value As Object
    End Structure

End Class
...