I'm using a VB6 library in my VB.NET application.
This library has a function that retrieves report records (as structures).
One of the structures in this library contains 105 public Boolean members that indicate to the function which "types" of records should be included while running a report.
The report record structures retrieved by the function contain this report type structure in order to indicate the"type" of record retrieved. You are able to tell which type of record it is by finding the single Boolean member is set to True in the record type structure.
Is there a way to loop through the VB6 Structure members?
Please note that the 105 Booleans are not Properties...they are simply publicly exposed Booleans. (So the System.Reflection PropertyInfo won't work)
Thanks for your time,
-Frinny
18 6732
Hey Frinny...
Have you tried looking at the FieldInfo?
VB - Dim t As Type = GetType(MyType)
-
Dim f As FieldInfo() = t.GetFields(BindingFlags.ExactBinding
C# - type t = GetType(MyType);
-
FieldInfo[] f = t.GetFields(BindingFlags.ExactBinding);
I can't be 100% sure this will work with VB6 structures, however, you can reference fields in regular .NET classes (the same as you can with properties). I haven't tried it with any VB6 classes - and I don't have VB6 any more so I can't even knock up a dummy library to test the theory sadly...
Does this help any? - public struct MyStruct
-
{
-
public bool item1;
-
public bool item2;
-
public bool item3;
-
public bool item4;
-
public bool item5;
-
-
public MyStruct(bool item1, bool item2, bool item3, bool item4, bool item5)
-
{
-
this.item1 = item1;
-
this.item2 = item2;
-
this.item3 = item3;
-
this.item4 = item4;
-
this.item5 = item5;
-
}
-
-
}
-
-
class Program
-
{
-
static void Main(string[] args)
-
{
-
MyStruct m = new MyStruct(true, true, false, false, true);
-
-
Type t = typeof(MyStruct);
-
FieldInfo[] f = t.GetFields();
-
FieldInfo[] selected = Array.FindAll(f, item => (bool)item.GetValue(m) );
-
-
foreach (FieldInfo item in selected)
-
{
-
Console.WriteLine(String.Format("{0}: {1}", item.Name, item.GetValue(m)));
-
}
-
-
Console.ReadKey();
-
}
-
}
What is item in the following code? -
-
FieldInfo[] selected = Array.FindAll(f, item => (bool)item.GetValue(m) == true );
-
-
Ok, hold on a second....I see...I'm looking up Lambda expressions / functions.
:)
What is item in the following code? -
-
FieldInfo[] selected = Array.FindAll(f, item => (bool)item.GetValue(m) == true );
-
-
Okay, this uses lambda functions... a new concept that was introduced in .NET 3.0/3.5.
I don't know of your understanding of delegates, function pointers or callbacks but basically it's declared in a somewhat similar manner as a callback...
So what's going on here is FindAll grabs "f" which is our array of FieldInfo and for every item in the array it runs the lambda function defined on the right side of the comma.
"item" is an arbitrary name I used to reference the current item that is being reviewed in the array. I could have called this, n, k, s, foo... it's just arbitrary. FindAll passes the current item in the array into this variable (just the same way you'd pass into another method).
The lambda function then takes this value as a FieldInfo and uses item.GetValue(m) (where m is our structure instance) to check if the field that matches the signature specified by "item" in object m is set to true and returns an implicit boolean back to the FindAll method.
If True is returned to FindAll then the current field is added to the return list. Once FindAll has iterated through all items in the list it returns the list which is stored in the variable Selected.
Think of the following code which would do the same kind of thing: - public FieldInfo[] FindAll(MyStruct inst, FieldInfo[] fieldList)
-
{
-
List<FieldInfo> matches = new List<FieldInfo>;
-
foreach(FieldInfo item in fieldList)
-
{
-
if (item.GetValue(inst) == true)
-
matches.Add(item.Name);
-
}
-
return matches.ToArray();
-
}
I've got a post on my blog that covers this: Predicates/List.FindAll()
So I ended up learning a lot about the Delegates, Lambda Expressions / Functions, and the Array.Find methods. -
Private Function RetrieveRecordName(ByVal retrievedRecordType As RecordType) As String
-
Dim recordName As String = ""
-
-
Dim rType As Type = GetType(RecordType)
-
Dim recordTypeMembers() As FieldInfo = rType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
-
-
'Method 1
-
'Using Lambda Expression with the Array.FindAll method to retrieve all the selected record types
-
-
'Dim selectedMembers() As FieldInfo = Array.FindAll(recordTypeMembers, Function(x As FieldInfo) CType(x.GetValue(retrievedRecordType), Boolean) = True)
-
'If selectedMembers IsNot Nothing Then
-
' recordName = selectedMembers(0).Name
-
'End If
-
-
'Method 2
-
'Using Lambda Expression with Array.Find method to retrieve the first selected record type
-
Dim selectedMember As FieldInfo = Array.Find(recordTypeMembers, Function(x As FieldInfo) CType(x.GetValue(retrievedRecordType), Boolean) = True)
-
If selectedMember IsNot Nothing Then
-
recordName = selectedMember.Name
-
End If
-
-
'Method 3
-
'Not using the Array.Find methods nor Lambda Expressions to find the first selected item
-
'Dim selectedMember As FieldInfo = Nothing
-
'For Each item In recordTypeMembers
-
' If CType(item.GetValue(retrievedRecordType ), Boolean) Then
-
' selectedMember = item
-
' Exit For
-
' End If
-
'Next
-
'If selectedMember IsNot Nothing Then
-
' recordName = selectedMember.Name
-
'End If
-
-
Return recordName
-
End Function
-
-
-
I still haven't totally figured out how to find the Array.Find method with a delegate to solve this problem...yet...I'm still working on it.
Thanks for all your help!
-Frinny
All looks good - just a pointer, it might not seem like much but you might consider using DirectCast instead of CType.
We're not actually converting the objects to boolean, we're telling the code that these objects should be interpreted as boolean - because while they are passed as a "typeless" object, they are really boolean. Thus DirectCast should perform better than CType in this situation. Syntactically, the two methods are the same (other than their obviously different names)...
If we were to pass 0 or the string literal "false" but wish to interpret it as boolean, then we'd use CType.
All looks good - just a pointer, it might not seem like much but you might consider using DirectCast instead of CType.
We're not actually converting the objects to boolean, we're telling the code that these objects should be interpreted as boolean - because while they are passed as a "typeless" object, they are really boolean. Thus DirectCast should perform better than CType in this situation. Syntactically, the two methods are the same (other than their obviously different names)...
If we were to pass 0 or the string literal "false" but wish to interpret it as boolean, then we'd use CType.
Good point :)
I didn't mention that, because of how the .NET Interop treats the structure, the Booleans are actually shorts.
Good point :)
I didn't mention that, because of how the .NET Interop treats the structure, the Booleans are actually shorts.
ah, gotcha - I guess it's okay the way it is then...
I still haven't totally figured out how to find the Array.Find method with a delegate to solve this problem...yet...I'm still working on it.
I never did get this to work.
The Find method requires a reference to a function that takes 1 parameter...I need there to be 2 parameters.
The Lambda Function gets around that requirement very nicely!
I'm starting to really understand how powerful Lambda Functions are.
Aside from that...
I am now attempting to use the System.Reflection.FieldInfo class to set values in my type with the following code: -
Dim rec As New RecordType
-
Dim recType As Type = GetType(RecordType)
-
Dim recordTypeMembers() As FieldInfo = kTransactionType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
-
For Each item In recordTypeMembers
-
Dim x As Short = -1
-
item.SetValue(rec, x)
-
Next
-
Despite what I try the values are not changed.
According to this article on the FieldInfo.SetValue(obj,value) Method:
This method will assign value to the field reflected by this instance on object obj. If the field is static, obj will be ignored.
My field is not static (note the GetFields(BindingFlags.Instance Or BindingFlags.Public) returns public instance fields) but this still isn't working.
Sometimes I'm an idiot.
The SetValue method requires an Object as the parameter.
I'm not passing it an Object, I'm passing it a Structure.
I think this is the source of my problem.
It is strange that the GetValue method still works when I pass the method a Structure though...
<edit>
Wouldn't you know, there's a thread here on the bytes about the SetValue method not working with Structures ...too bad the link doesn't work.</edit>
I never did get this to work.
The Find method requires a reference to a function that takes 1 parameter...I need there to be 2 parameters.
There's no nice way to get around this - you have to use a class level field to transfer the value into your delegate - it's ugly as sin, I hate that. So yes, Lambda expressions nicely sidesteps that oversight.
As for not being able to set your value... this appears to be an issue with the fact that the object is a structure. I had a play and the only way I could get around it was to change MyStruct from a structure to a class.
I'm not guessing that's too much help... I did some checking and it was reported a while back to Microsoft to fix - they closed it stating that this was by design!
I'm wondering if they really checked it out though - it seems the guy who reported it was trying to pass the structure as an argument into another method byval instead of byref which doesn't really apply in this case.
There's no nice way to get around this - you have to use a class level field to transfer the value into your delegate - it's ugly as sin, I hate that. So yes, Lambda expressions nicely sidesteps that oversight.
As for not being able to set your value... this appears to be an issue with the fact that the object is a structure. I had a play and the only way I could get around it was to change MyStruct from a structure to a class.
I'm not guessing that's too much help... I did some checking and it was reported a while back to Microsoft to fix - they closed it stating that this was by design!
I'm wondering if they really checked it out though - it seems the guy who reported it was trying to pass the structure as an argument into another method byval instead of byref which doesn't really apply in this case.
I came across that same information.
The best explanation I've found as to why this wont work is in this article.
There are a few other forums where people have linked to "solutions" to this problem but all of the links are not working. It almost feels as if someone's trying to hide the answer from me.
I've been working on trying to trick the SetValue function by wrapping my structure in an Object.....
Seeing as this is an example application (for other developers) I'm really looking for a simple way to do this................................
This is anything but simple.
Ha! Got it!
C# - public static void setValue(object var, string fieldName, string newValue)
-
{
-
Type t = var.GetType();
-
FieldInfo f = t.GetField(fieldName);
-
if (t.IsValueType)
-
{
-
ValueType vt = (ValueType)var;
-
f.SetValue(vt, newValue);
-
}
-
else
-
{
-
f.SetValue(var, newValue);
-
}
-
}
-
-
static void Main(string[] args)
-
{
-
MyStruct m = new MyStruct();
-
m.item1 = "Old Value";
-
-
Type t = typeof(MyStruct);
-
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
-
FieldInfo f = t.GetField("item1", flags);
-
-
Console.WriteLine(f.GetValue(m));
-
setValue(m, f.Name, "New Value");
-
Console.WriteLine(f.GetValue(m));
-
-
Console.ReadKey();
-
}
We can apply this to our situation just trading up the boolean values for the strings...
It's because Structures are referenced differently than Classes... we need to tell reflection to update a ByVal object and not a ByRef object. Structures are treated in the same way as regular variables - albeit complex variables. Classes are treated as objects and as such the two are referenced slightly differently.
Maybe I spoke too soon - I thought I had it...
What we have to do is pass it byval to a function that will then pass it back out as the return value: - Public Sub SetValue(ByVal var As Object, _
-
ByVal FieldName As String, _
-
ByVal NewValue As Boolean)
-
-
Dim t As Type = var.GetType()
-
Dim f As FieldInfo = t.GetField(fieldName)
-
If t.IsValueType Then
-
Dim vt As ValueType = DirectCast(var, ValueType)
-
f.SetValue(vt, NewValue)
-
Else
-
f.SetValue(var, NewValue)
-
End If
-
Return var
-
-
End Sub
-
-
'Then you'd need to call this method to do the set...
-
myStructInstance = DirectCast(SetValue(passVal, item.Name, false), MyStruct)
I have to say it's not the prettiest code in the world... but it'll do the job...
VB.NET Version -
Private Sub setValue(ByRef var As Object, ByVal fieldName As String, ByVal newValue As Short)
-
Dim t As Type = var.GetType
-
Dim fi As FieldInfo = t.GetField(fieldName)
-
If (t.IsValueType) Then
-
Dim vt As ValueType = CType(var, ValueType)
-
fi.SetValue(vt, newValue)
-
Else
-
fi.SetValue(var, newValue)
-
End If
-
End Sub
-
Maybe I spoke too soon - I thought I had it...
What we have to do is pass it byval to a function that will then pass it back out as the return value:
I have to say it's not the prettiest code in the world... but it'll do the job...
I passed ByRef....
-Frinny
I passed ByRef....
-Frinny
Hmm... I tried that and it failed - but then, I was using C# and it freaked out when I tried to pass a "value" object byref. I guess with VBs ByRef/ByVal keywords you can force the issue and it'll work just nicely...
Glad we got there in the end :)
Sign in to post your reply or Sign up for a free account.
Similar topics
by: kazack |
last post by:
I am a little confused with code I am looking at. My c++ book does not go
into passing a structure to a function so I pulled out a c book which does.
and I do not understand the prototype verses...
|
by: brett valjalo |
last post by:
Hey Gang!
SORRY ABOUT THE LENGTH!
Nice to see some of the same faces around this place from way back
when ... Whatta buncha CDMA addicts some o' y'all are ;)
Don't get me wrong, I...
|
by: John |
last post by:
In the course of an assignment, I learned the hard way that I shouldn't try
to free a malloc'd member of a malloc'd structure after having freed that
structure (i.e., free( structure ); free(...
|
by: damian birchler |
last post by:
Hi
I'm wondering of what type a structure is. Of course, it is a
_structure_, but an array isn't an _array_ either. So of what type is
a structure? I'd say a pointer, am I right?
|
by: Madhav |
last post by:
Hi all,
I was going through a piece of code which had a very
interesting format. There were two files: one was a .h file, and the
other was a .c file. The .c file had a structure defined in it...
|
by: sandeep |
last post by:
Hi
why we cannot have static as a structure member?
& also is there any way to achive data hiding in C at this level( i.e.
access only selected structure member )
following code gives syntax...
|
by: Kavya |
last post by:
Here is the code
int main(){
struct node{
int a;
int b;
int c;
};
struct node s={3,5,6};
struct node *ptr=&s;
|
by: cman |
last post by:
I do not understand the use of a period to define structure members,
one sees this frequently in kernel code. Please explain. Here is the
structure:
static struct file_system_type ext2_fs_type =...
|
by: =?Utf-8?B?QXlrdXQgRXJnaW4=?= |
last post by:
Hi Willy,
Thank you very much for your work.
C++ code doesnot make any serialization.
So at runtime C# code gives an serialization error at
"msg_file_s sa = (msg_file_s) bf.Deserialize(ms);"...
|
by: ryjfgjl |
last post by:
ExcelToDatabase: batch import excel into database automatically...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, we are pleased to welcome back...
|
by: Vimpel783 |
last post by:
Hello!
Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
|
by: jfyes |
last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
|
by: ArrayDB |
last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
|
by: CloudSolutions |
last post by:
Introduction:
For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
|
by: Defcon1945 |
last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
|
by: Faith0G |
last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome former...
| |