GetPrivateProfileString Return String Variable not set - vba

Im using getPrivateProfileString to read from an API. Here I call the method and get a store number
Rec = String(255, 0)
NC = GetPrivateProfileString("ConfigInfo", "store", "", Rec, 255, "C:\MyPath")
Now when I debug Rec has no value
However when I use Rec in a message box it shows its value as expected.
Why is the variable Rec an empty variable instead of holding my store number as expected? Why does Rec's value seem to be as expected in a message box?

Related

VBA: Using Let / Get Default Properties with Arrays

This is my first class with a default member and I'm still getting a feel for it. I have a let / get property data:
class ArrayClass
private D as variant
Property Get data() As Variant
data = D
End Property
Property Let data(arg1 As Variant)
D = arg1
End Property
I have added the following in my .cls file (using notepad) to make data the default parameter which looks like this:
Property Get data() As Variant
Attribute data.VB_UserMemId = 0
data = D
End Property
I'm just testing this to see how well this works using an array for "D":
Dim testArray As ArrayClass
Dim passArray(5, 1) As Variant
passArray(0, 0) = 1
passArray(1, 0) = 2
passArray(2, 0) = 3
passArray(3, 0) = 4
passArray(4, 0) = 5
passArray(5, 0) = 6
passArray(0, 1) = 7
passArray(1, 1) = 8
passArray(2, 1) = 9
passArray(3, 1) = 10
passArray(4, 1) = 11
passArray(5, 1) = 12
Set testArray = new ArrayClass
testArray = passArray
testArray(1, 1) = 5
Debug.Print testArray(2, 1)
It "mostly" works. The "testArray = passArray" calls the "Let Data" property, and assigns the passArray to parameter "D" inside the object.
Also, "Debug.Print testArray(2,1)" also works. That calls the "Get Data" property, and it returns the index values of 2,1 of the "D" parameter in the object.
My problem is the "testArray(1,1) = 5" instruction. The intent was to assign the 1,1 index to parameter D to the number 5. But what happens is it calls the "Get Data" property, instead of the "Let Data" property.
To be clear, I wasn't really expecting it to work because I'm not yet sure how to do it. But I'm at a loss on why its calling the "get property" instead of the "let property" being that the instruction is on the left side of the equal sign.
Anyone have any ideas on how to make it work? Thanks.
What you're experiencing is standard VBA behaviour.
The line testArray(1,1) = 5 first makes a copy of the of the D array (indeed calling Get) and then value 5 is assigned to the 1,1 index of the new/copy array.
You can only call Let to pass a single value as that's what you definition expects:
Property Let data(arg1 As Variant)
D = arg1
End Property
You can't call it with testArray(1,1) because that passes 2 values. Obviously, you made it clear that you intend to update just one member of the internal D array but that's simply not possible via that Let property.
What you could do is to define a new property that expects 3 parameters:
Property Let item(ByVal index1 As Long, ByVal index2 As Long, ByVal newValue As Variant)
D(index1, index2) = newValue
End Property
and call it with testArray.item(1, 1) = 5 or maybe define this new property as the default.
Consider declaring D as an array - as it currently stands, you can pass anything e.g. testArray = "test" which I don't think is what you want. So, maybe declare it as Private D() As Variant and then update the data properties to receive and return an array of Variant type:
Property Get data() As Variant()
data = D
End Property
Property Let data(arg1() As Variant)
D = arg1
End Property
I was able to figure out how to do this the way I want to do it. The secret is using the parameter arrays in the input fields of my Get / Let properties.
Property Let data(ParamArray sizes() As Variant, data As Variant)
end property
Property Get data(ParamArray sizes() As Variant) As Variant
Attribute data.VB_UserMemID = 0 'This line makes the data property the default property.
'It is Only visible/editable in .cls file opened in text editer
end property
So it turns out that the let property has two different types of input arguments a "arglist" and a value. The last argument in the list is your value (and is the number to the right of the equal sign). But since VBA (and all other languages to my knowledge) requires if you use an optional input, then all inputs to the right of it must also be optional, including the value input.
But if you use ParamArray, then VBA knows which parameters are the inputs, and which one is the value, thus enabling you to have optional inputs on your let property. All my inputs for these properties are optional. Then I just use if statements to map what I'm supposed to output based on the number of input values.
So now I can access my array parameter inside my class using the exact same syntax as an array outside my class:
passArray(0, 0) = 1
passArray(1, 0) = 2
passArray(2, 0) = 3
passArray(0, 1) = 4
passArray(1, 1) = 5
passArray(2, 1) = 6
testArray = passArray
Debug.Print testArray(2, 1) 'returns 6
testArray(2, 1) = 7.5
Debug.Print testArray(2, 1) 'returns 7.5

How to parameterise a object member in VB.NET for WSDL

I have some code that populates a SOAP request in VB.NET. I get the data from a SQL query and run through the objects members to populate each one. I'm trying to find a quick(ish) way to not provide the member when it is empty rather than checking each value before applying it. As the SQL data comes in from a pipe delimited file in the first place we never get NULL just empty cells which get sent in the SOAP request as "".
Is there a way to define an objects member using a variable rather than its literal name?
UpLB_request_Items.Spare8 = Convert.ToString(SourceDataSet.tables(0).Rows(i)(colSPARE8))
UpLB_request_Items.Spare9 = Convert.ToString(SourceDataSet.tables(0).Rows(i)(colSPARE9))
UpLB_request_Items.Spare10 = Convert.ToString(SourceDataSet.tables(0).Rows(i)(colSPARE10))
Call IterateObject(UpLB_request_Items)
So this populates each member with the value from the SQL data (SourceDataSet), then I could send the completed object down to a Sub to check each value before I actually send it to the webservice
Sub IterateObject(objName)
Dim CollName = ""
For Each m As System.Reflection.PropertyInfo In objName.GetType().GetProperties()
If m.CanRead Then
If m.PropertyType.Name = "String" Then
CollName = m.Name
Dim CollVal = CallByName(objName, CollName, CallType.Get)
If CollVal = "" Then
objName.CollName = Nothing 'this is the tricky bit
End If
End If
End If
Next
End Sub
The bit where it obviously breaks is objName.CollName = Nothing as it will then say that the object doesn't have a member called CollName and I'm not sure if there is a way to force the code to evaluate CollName to its value (e.g. SPARE8 rather than the string "CollName")
I went with this in the end
UpLB_request_Items.Spare4 = Strings.Replace(Convert.ToString(SourceDataSet.Tables(0).Rows(i)(colSPARE4)), "", Nothing)

Reference a variable using a string

I have a few variables called: _2sVal, _3sVal, _4sVal, etc
I want to change each of their values through a loop.
Like:
For i = 1 To 10
'set the value
Next
I've tried putting them in a dictionary like:
Dim varDict As New Dictionary(Of String, Integer)
varDict.Add("2sVal", _2sVal)
varDict.Add("3sVal", _3sVal)
varDict.Add("4sVal", _4sVal)
I can retrieve the value using
MsgBox(varDict(i.ToString & "sVal"))
But when I try to change it like
varDict(i.ToString & "sVal") = 5
It doesn't do anything. No errors or exceptions either, just the value stays unchanged
When you are using
varDict.Add("4sVal", _4sVal)
You are not putting the _4sVal variable inside the dictionary, but its value.
Then, changing the dictionary will not change the _4sVal, since there is no reference of it inside the dictionary.
What I mean is
varDict("4sVal") = 5
will change the value of dictionary but not the variable _4sVal itself.
I think the correct to do is define that variables as Properties, defined like:
Property _4sVal As Integer
Get
Return varDict("4sVal")
End Get
Set(value As Integer)
varDict("4sVal") = value
End Set
End Property
This way you will not have to change anything in the rest of your code. It will be transparent.

vba function which returns more than one value and so can be called in sql

I'm new to VBA and i need help.
I want to create vba function which takes table name as input, and distinct specific field from that table. I created function, and it works when i run it in vba immediate window (when i use debug.print command to display results). But when i call this function in sql, instead whole field values, it returns just last one. I'm not good at vba syntax so i need help to understand. Does function can return more than one value? If can, how, and if not what else to use? Here's my code:
Public Function TableInfo(tabela As String)
Dim db As Database
Dim rec As Recordset
Dim polje1 As Field, polje2 As Field
Dim sifMat As Field, pogon As Field, tipVred As Field
Set db = CurrentDb()
Set rec = db.OpenRecordset(tabela)
Set sifMat = rec.Fields("Field1")
Set pogon = rec.Fields("Field2")
Set tipVred = rec.Fields("Field3")
For Each polje1 In rec.Fields
For Each polje2 In rec.Fields
TableInfo = pogon.Value
rec.MoveNext
Next
Next
End Function
Any help is appreciated.
The problem is with this line probably:
TableInfo = pogon.Value
It runs inside the loop and returns the last value of the loop.
Instead of returning one value TableInfo, you may try to return something similar to a Collection or an Array.
Inside the loop, append values in the Collection and after the loop, return the Collection back from the function.
Edit:
I have re-written the code shared by you:
Public Function TableInfo(tabela As String) as String()
Dim db As Database
Dim rec As Recordset
Dim polje1 As Field, polje2 As Field
Dim sifMat As Field, pogon As Field, tipVred As Field
Dim returnValue() As String
Dim i as Integer
Set db = CurrentDb()
Set rec = db.OpenRecordset(tabela)
Set sifMat = rec.Fields("Field1")
Set pogon = rec.Fields("Field2")
Set tipVred = rec.Fields("Field3")
' I am not going to modify this but I think we can do away with two For Each loops.
' Just iterate over rec like
' For Each r In rec -> please use proper naming conventions and best practices
' and access each field as r("Field1") and r("Field2")
For Each polje1 In rec.Fields
For Each polje2 In rec.Fields
returnValue(i) = pogon.Value
i = i + 1
rec.MoveNext
Next
Next
TableInfo = returnValue
End Function
Please note: I have not tested this code but I assume this should work for you. Also, I have assumed that you want to return String() array. Please change the data type if you want to return some other type.
When you call the array (as posted in theghostofc's answer), you will need to do something like this:
Dim TableInfo() As String
For i = LBound(TableInfo) To UBound(TableInfo)
YourValue = TableInfo(i)
... Process some code that uses YourValue
Next i
If you're not looping through your array, you're not going to get each individual value out of it.

What does this line of code in CRUDOperations.vb do?

Here is some code from the CRUDOperations.vb file in Microsoft Dynamics CRM 2011 SDK:
' Retrieve the account containing several of its attributes.
Dim cols As New ColumnSet(New String() { "name", "address1_postalcode", "lastusedincampaign" })
Dim retrievedAccount As Account = CType(_service.Retrieve("account", _accountId, cols), Account)
Console.Write("retrieved, ")
' Update the postal code attribute.
retrievedAccount.Address1_PostalCode = "98052"
' The address 2 postal code was set accidentally, so set it to null.
retrievedAccount.Address2_PostalCode = Nothing
Now if I am understanding correctly, the following line:
Dim retrievedAccount As Account = CType(_service.Retrieve("account", _accountId, cols), Account)
Doesn't seem to actually do anything?
It calls _service.Retrieve("account", _accountId, cols)
It casts the return value to type Account.
It stores the return value in the variable retrievedAccount.
And then the subsequent lines modify the properties of the account that is referenced by retrievedAccount.