Error: Expected function or variable - c#-4.0

I am writing a small utility in VB6 which is calling the C#.Net class (which brings list of printers) but while calling the C# method, it is throwing below error and I am not able to compile/run the application. Can someone please help on this?
VB6 Code:
Dim retval As Integer
Dim tbp As NamespaceXYZ.CGETList
Dim a As String
Dim col As New Collection
Set tbp = New CGETList
retval = tbp.GetDefaultPrinterAndList(col, a)
C# definition for the method.
public void GetDefaultPrinterAndList(ref Microsoft.VisualBasic.Collection vntPrinterList, ref string defaultPrinter)
{
error:

You declared tbp, but forgot to initialise it.
Dim tbp As NamespaceXYZ.CGETList
'tbp value is currently Nothing
Set tbp = New NamespaceXYZ.CGETList
'now it's something.
Note that the above assumes that the NamespaceXYZ.CGETList class has a default constructor i.e. you can create a new object just using New. Some classes don't have this; they require you to create objects in other ways.

Related

Unable to find a way to store data into an array inside a class module

I've been wrestling with this problem for a while. My problem is that I have a bunch of JSON data and I want to represent it as objects.
Arrays are problematic.
I create a class module such as FancyCat with a public Name as String for its name.
Then I can set this with
Dim MyFancyCat as FancyCat
Set MyFancyCat = new FancyCat
FancyCat.Name = JSONData("Name")
I've typed that from memory but I think it's correct. Anyhoo, it works fine.
The problem is that a fancy cat has several pairs of socks. The number of socks is variable.
In vba you cannot for some reason have a public array. So this code is illegal:
public Socks() as FancySock 'Illegal
Looking on SO I found two solutions, one, to make it private and use a property to access it, and the other, to declare it as Variant and then stick an array into it later.
My approach to populating this array, is to examine the JSON array to get the Count, and then to ReDim the array to match and then populate it.
The problem is my ReDim statement refuses to work.
It seems I cannot redim a property, I get an error. And I also get an error trying to redim the public variant field. My ReDim works OK if I declare a local array and redim it, so potentially I could do that and then assign it to the property... but it just seems bizarre that I can't redim it directly.
Any idea why it's not working?
With the Variant approach above my code is:
ReDim MyFancyCat.Socks(socksLength) As FancySocks
And in the FancyCat class module:
public Socks As Variant
I get Method or Data Member Not Found.
The error for the other approach was different but I rejigged all my code to try the second approach so I am not sure what it was.
Edit: I'm gonna explain what I am trying to do a bit more clearly. I have some JSON data coming in, and I want to store it as an object hierarchy.
In C# I would do this (pseudo code without linq shortcuts):
var myData = ReadJsonData(); // Produces a kind of dictionary
var myFancyCat = new FancyCat();
myFancyCat.Name = myData["Name"];
myFancyCat.Age = myData["Age"];
myFancyCat.Socks = new List<FancySock>();
foreach (var sock in myData["Socks"])
{
myFancyCat.Socks.Add(sock);
}
In excel I want to do the same thing.
So I make a class module for FancyCat and FancySock and give FancyCat public members for Name, Age etc but then I also want an array of socks that my cat owns. I wanted to do this with strongly typed references, e.g. my c# code above I can do:
myFancyCat.Socks[0].Colour // Intellisense works, shows colour as a property
However it seems in excel you can't have publicly declared arrays. So you can get around this according to the comments by declaring it as variant and then sticking an array in anyway, but you would lose the intellisense. Or you can use a get/let property which kinda works but is more fiddly as it seems you can't actually expose an array using a get/let you have to have it take an index and expose elements individually.
So at this point I am thinking forget the strongly typed it's not happening, perhaps use a collection?
The FancySock class may have further nested arrays within it. I've read that there's no ByRef for arrays (at least, not completely - I think you can get an array ByRef but not set one?). I am not sure if that would create problems with trying to set it.
But ultimately, I just want to end up with my JSON data represented easily in an OO way, so that in my excel ultimately I can just do
myFancyCat.Name or myFancyCat.Socks.Count or myFancyCat.Socks(1).Colour etc
It seems much harder than it looks to simply deserialise JSON into 'objects' in vba.
Please, try the next way:
Insert a class module, name it FancyCat and copy the next code:
Option Explicit
Private arrL As Object
Public myName As String, myAge As Long
Public Sub Class_Initialize()
Set arrL = CreateObject("System.Collections.ArrayList")
End Sub
Public Property Let Name(strName As String)
myName = strName
End Property
Public Property Let Age(lngAge As String)
myAge = lngAge
End Property
Public Property Let SocksAdd(sMember)
arrL.Add sMember
End Property
Public Property Get Socks() As Variant
Socks = arrL.toarray()
End Property
Use it in the next testing Sub:
Sub testClassDictListArray()
Dim myFancyCat As New FancyCat, myData As Object
Dim arrSocks, sock
Set myData = CreateObject("Scripting.Dictionary") 'this should be the dictionary returned by ParseJSON
myData.Add "Name", "John Doe": myData.Add "Age", 35
myData.Add "Socks", Array("Blue", "White", "Red", "Green", "Yellow")
myFancyCat.Name = myData("Name")
myFancyCat.Age = myData("Age")
For Each sock In myData("Socks")
myFancyCat.SocksAdd = sock
Next sock
arrSocks = myFancyCat.Socks
Debug.Print Join(arrSocks, "|")
End Sub
I am not sure I perfectly understand the scenario you try putting in discussion...
If you want to benefit of instellisense suggestions, I will tell you what references to be added. Even, I will send two pieces of code to automatically add the necessary references (I mean, Scripting.Dictionary and ArrayList`).
Please, test it and send some feedback.
In your class:
Private m_Name As String
Private m_Socks() As String
Public Property Let Name(Name As String)
m_Name = Name
End Property
Public Property Get Name() As String
Name = m_Name
End Property
Public Sub SetSize(Quantity As Long)
ReDim m_Socks(1 To Quantity)
End Sub
Public Property Let Socks(Index As Long, Sock As String)
m_Socks(Index) = Sock
End Property
Public Property Get Socks(Index As Long) As String
Socks = m_Socks(Index)
End Property
In a regular module:
Sub UseFancyCat()
Dim MyFancyCat As FancyCat
Set MyFancyCat = New FancyCat
MyFancyCat.Name = "Fancy Name"
MyFancyCat.SetSize 2
MyFancyCat.Socks(1) = "Sock1"
MyFancyCat.Socks(2) = "Sock2"
Debug.Print MyFancyCat.Name
Debug.Print MyFancyCat.Socks(1)
Debug.Print MyFancyCat.Socks(2)
End Sub

Can't see created objects

I've created some simple classes in excel and I'm trying to create new objects from these classes. It works fine and let's me create them and I can also access the variables given to the object. I can't see the object in the local window though and I don't really understand why. Is it not created correctly because you are supposed to see your objects there I understand?
Here is the code for the class
Option Explicit
'Teams
Public Name As String
Public Group As String
Public GF As Integer
Public GA As Integer
Public Points As Integer
'Public Players(25) As String
Private Sub class_initialize()
Points = 5
End Sub
and here is the code where I try to create an object
Sub TestTeams()
Dim Madagaskar As Object
Set Madagaskar = New ETeam
MsgBox (Madagaskar.Points)
End Sub
If you put Stop on the line after the MsgBox call and run TestTeams, you will see the object in the locals window.
It will only be there while Madagaskar is in scope and you're in break mode.

Call a method object with arguments that returns variable

How can I call a method passing multiple parameters returning a variable?
I have a class called cExcelTable. Inside I have a method:
Public Function GetColumnNumberByColumnName(strColumnName As String)
Dim resultColumnFound As Integer
'... Here i have the code which find the right column
'... then i return the result as an integer
GetColumnNumberByColumnName = resutColumnFound
End Function
How can I call this method and get the returning value?
I want the equivalent of this:
Dim myTable As New cExcelTable
Dim i as Integer
myTable.Workbook = "file.xlsx"
myTable.Sheet = "TestingSheet"
myTable.Table = "TabDatas"
'... And here is my bug that i don't know how to solve
i = myTable.GetColumnNumberByColumnName("TOTAL")
I know that for a method not have returning values I must use Call but what about a method that return a value?
SOLVED
Thanks to PeterT and Domenic in comments i found after a night sleep that my mistake was not the calling of the method but misspelled of two variables inside my method and adding the type it should return
So for a new one who go inside this post the answer is
Inside the method you should use this
'Add the type the method it should return "As Integer"
Public Function nameOfTheMethod(parameterNumber1 As String) As Integer
Dim resultColumnFound As Integer
'... type your code
'... then return the result with the correct spelling
GetColumnNumberByColumnName = resultColumnFound
End Function
And then inside your code you can call your method like this
Dim myObject As New cMyClass 'cMyClass is the name of your class and myObject is the name of your object you are creating
Dim i as Integer
i = myObject.nameOfTheMethod("test")

List the properties of a class in VBA 2003

I've searched all over to see if there is an easy answer to this question, but there doesn't seem to be...
I'm using Excel VBA 2003 (yes, I know it's out-of date, but I can't change this), and all I want to do is list the names and values of all the readable properties in a given custom class.
I'd like to do something like this:
Class definition (for class entitled cFooBar)
Option Explicit
Private pFoo As String
Private pBar As String
Public Property Get Foo() As String
Foo=pFoo
End Property
Public Property Get Bar() As String
Bar=pBar
End Property
Calling code
Dim myFooBar as cFooBar, P as Property
myFooBar=new cFooBar
For Each P in myFooBar.Properties
Debug.Print P.Name, P.Value
Next
Of course, this doesn't work because there doesn't seem to be a "Properties" collection member for custom classes (or at least not one that you can get at), and there isn't a "Property" type either.
Does anybody know a way around this?
TIA,
Campbell
As John mentions above, reflection is not supported in VBA. Here is a hack that I have used before. Basically you can create a Collection or Dictionary object to store your "properties" by name.
Option Explicit
Private pProperties As Object
Public Property Get Properties() As Object
Set Properties=pProperties
End Property
Public Property Let Properties(p as Object)
Set pProperties = p
End Property
Sub Class_Initialize()
Set pProperties = CreateObject("Scripting.Dictionary")
'Add/instantiate your properties here
pProperties("foo") = "this is foo"
pProperties("bar") = "this is bar"
End Sub
Calling code
Dim myFooBar As New cFooBar, P As Variant
For Each P In myFooBar.Properties.Keys()
Debug.Print P, myFooBar.Properties(P)
Next

Only user-defined type defined in public object modules can be coerced when trying to call an external VBA function

I am trying to call an Access function from Excel and get this error:
Compile Error: Only user-defined types defined in public object
modules can be coerced to or from a variant or passed to late-bound
functions.
I tried to adopt this solution I found, but with no luck. Here is my code:
In the Excel Module ExternalStatistics
Option Explicit
Public Type MyExternalStatistics
esMyInvites As Single
esMyInvitePerTalk As Single
End Type
Public MyExtRecStats As MyExternalStatistics
In the Sheet1(A-Crunched Numbers) object:
Option Explicit
Public appRecruitingAccess As Access.Application
Public Sub Worksheet_Activate()
Dim MyExtRecStats As MyExternalStatistics
Dim RecruitWindow As Integer
Dim test As String
Set appRecruitingAccess = New Access.Application
With appRecruitingAccess
.Visible = False
.OpenCurrentDatabase "C:\Dropbox\RECRUITING\Remote0\Recruiting 0.accdb"
RecruitWindow = DateDiff("d", Format(Date, Worksheets("ActivityAndIncentive").Range("IncentiveStart").Value), Format(Date, Worksheets("ActivityAndIncentive").Range("IncentiveEnd").Value))
RecruitWindow = DateDiff("d", Format(Date, Worksheets("ActivityAndIncentive").Range("IncentiveStart").Value), Format(Date, Worksheets("ActivityAndIncentive").Range("IncentiveEnd").Value))
MyExtRecStats = .Run("ExternalRecruitingStats", RecruitWindow) '*** ERROR HERE ***
.CloseCurrentDatabase
.Quit
End With
Set appRecruitingAccess = Nothing
End Sub
In the Access Module ExternalStatistics
Option Compare Database
Option Explicit
Public Type MyExternalStatistics
esMyInvites As Single
esMyInvitePerTalk As Single
end Type
Public Function ExternalRecruitingStats(StatWindow As Integer) As MyExternalStatistics
Dim MyRecStats As MyExternalStatistics
Dim Invites As Integer, Talks As Integer
Invites = 1
Talks = 2
With MyRecStats
.esMyInvites = CSng(Invites)
.esMyInvitesPerTalk = CSng(Invites/Talks)
End With
ExternalRecruitingStats = MyRecStats 'return a single structure
End Function
It does not like the MyExtRecStats = .Run("ExternalRecruitingStats", RecruitWindow) statement. I would like to eventually assign several set in the Access function and bring them all back with one object. Then I can place those values where they should be in the spreadsheet.
Type definitions in VBA are very local and they don't work well when you try to use them with objects that may not have access to the exact definition of the Type (which is probably the case here).
Sometimes, using a Class may work. You would need to make the class public and instantiate it before passing it around, but I have some doubts that it will actually work (for the same reason that the class definition won't be visible from one app to the other).
Another simple solution would be to use a simple Collection object instead, where you add your values as items to the collection. Of course the exact order of how you add/retrieve items is important.
There are a few interesting answers to a similar issue in User Defined Type (UDT) As Parameter In Public Sub In Class Module. It's about VB6 but it should also apply in great part to VBA.
Having said all this, you may be able to resolve all your issues by importing your Access code into Excel instead.
You can use DAO or ADO from Excel and manipulate Access databases just as if you were in Excel, for instance:
Connecting to Microsoft Access Database from Excel VBA, using DAO Object Model
Using Excel VBA to Export data to Ms.Access Table

Resources