vba - programación - propiedades de visual basic definicion
Tipo definido por el usuario(UDT) como parámetro en Sub pública en módulo de clase(VB6) (7)
He intentado resolver este problema, pero no puedo encontrar ninguna solución. Tengo un UDT definido en un módulo normal y quería usarlo como parámetro en un Public Sub
en un Módulo de clase. Entonces me sale un error de compilación:
Solo los tipos públicos definidos por el usuario definidos en módulos de objetos públicos pueden usarse como parámetros o tipo de devolución para procedimientos públicos de módulos de clase o como campos de tipos públicos definidos por el usuario
Luego trato de mover mi UDT en la clase, declarado como Private
. Me sale este error de compilación:
Los tipos de Enum privado y definidos por el usuario no se pueden usar como parámetros o tipos de devolución para procedimientos públicos, miembros de datos públicos o campos de tipos públicos definidos por el usuario.
Finalmente trato de declararlo como Public
en la clase y obtengo este error de compilación:
No se puede definir un tipo público definido por el usuario dentro de un módulo de objeto privado.
Entonces, ¿hay alguna manera de que un UDT público se use como un parámetro en un sub público en una clase?
Entonces, ¿hay alguna manera de que un UDT público se use como un parámetro en un sub público en una clase?
En una palabra, no. Lo más cercano que puede venir con solo el código VB clásico sería crear una clase que replique el UDT y usarlo en su lugar. Definitivamente, hay ventajas allí, pero tiene una idea si necesita pasar eso a, digamos, una API también.
Otra opción es definir el UDT en una biblioteca de tipos. Si lo hace, puede usarse como un parámetro para un método público.
Defina UDF (tipo público) en un módulo:
Public Type TPVArticulo
Referencia As String
Descripcion As String
PVP As Double
Dto As Double
End Type
y usar Friend
in class, module o frm:
Friend Function GetArticulo() As TPVArticulo
El UDT debe ser declarado en un Objeto Público, como:
Public Class Sample
Public Strucutre UDT
Dim Value As Object
End Structure
End Class
Ok, aquí está cómo hacerlo, si puedo hacer que mi gato me deje solo, eso es.
En Form1 (con un botón de comando en él):
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
En form2 (no se necesitan controles). (Esto podría haber sido tan fácilmente un objeto creado con una clase.):
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
Y finalmente, esto va en un archivo de módulo (BAS).
Option Explicit
''
'' This is just the UDT that is used for the example.
Public Type MyUdtType
l As Long
End Type
''
Simplemente pase el UDT como parámetro de referencia y funcionará. :)
''method in the class
Public Sub CreateFile(ByRef udt1 As UdtTest)
End Sub
Solo define el sub como alcance de Friend
. Esto compila bien para mí en una clase de VB6.
Private Type testtype
x As String
End Type
Friend Sub testmethod(y As testtype)
End Sub
De tus mensajes de error parece que tu clase es privada. Si desea que su clase sea pública (es decir, está creando un archivo ActiveX exe o DLL y desea que los clientes puedan acceder al subproyecto), entonces haga que ambos sean del tipo y del subpublic.
Tuve el mismo mensaje de error y después de verificar la aplicación, encontré que en la ventana de propiedades para la clase, la configuración de "Instancia" se estableció en "1 - Privado" para el objeto referenciado. Lo cambié a "5 - MultiUse" y obtuve el mismo mensaje de error. Luego volví a una versión del módulo del proyecto antes de agregar el objeto al que se hace referencia y volver a agregar el proyecto, que de manera predeterminada es "1 - Privado". Lo cambié a "5 - MultiUse" antes de hacer cualquier otra cosa y cerré el proyecto para que se actualice antes de compilar. Volví a abrir el proyecto, verifiqué que aún estaba configurado en "5 - MultiUse", luego compilé el proyecto y lo compilé limpiamente sin el mensaje de error.
Cuando el mensaje de error decía que no permitía hacer referencia a un objeto privado, el objeto era realmente privado. Una vez que lo declaré no privado, y el módulo del proyecto aceptó esa nueva configuración, compiló limpiamente.