Private Property Get IField_ControlIdx() As Integer
IField_ControlIdx = m_intControlIdx
End Property
Private Property Let IField_ControlIdx(p_intControlIdx As Integer)
m_intControlIdx = p_intControlIdx
End Property
IField_ControlIdx = m_intControlIdx
End Property
Private Property Let IField_ControlIdx(p_intControlIdx As Integer)
m_intControlIdx = p_intControlIdx
End Property
When implemented in VB.Net, that (should) look like this:
Public Property ControlIdx() As Short Implements ...
Get
returns m_intControlIdx
End Get
Set(ByRef value As Short)
m_controlIdx = value
End Set
End Property
Get
returns m_intControlIdx
End Get
Set(ByRef value As Short)
m_controlIdx = value
End Set
End Property
Unfortunately, that doesn't compile, instead giving the following error: 'Set' parameter cannot be declared 'ByRef'. Changing 'ByRef' to 'ByVal' makes the property valid, but not the class, which gives the following compile error: [PropertyName] cannot implement [Propertyname] because there is no matching property on interface [Interface]. Stuck.
Microsoft has the following article on this issue: http://support.microsoft.com/kb/316581
Their solution? "To resolve this bug, rebuild the COM library so that it passes arguments to property procedures by value instead of by reference." Well sure, of course THAT would work, but that comes with its own issues...in our case, the fact that it would mean roughly 50 VB6 classes that would require updating and testing. Our interface is shared with our windows application, which is well past the point of a core change, so this wasn't an option.
Fortunately, there is another solution: C#.
Because the parameters are passed by reference, the C# interpreter sees the set properties as methods:
public void set_ControlIdx(ref short value)
Alternatively, you can implement the interface explicitly:
void [InterfaceName].set_ControlIdx(ref short value)
This is how we handled it. By implementing the interface explicitly, we were able to create our own, valid public properties, while hiding the ugly ByRef versions. To keep things consistent, we had the explicit methods reference the cleaner, public methods, keeping the logic in the same place.
public short ControlIdx
{
get { return m_controlIdx; }
set { m_controlIdx = value; }
}
short [Interface].get_controlIdx()
{
return this.ControlIdx;
}
void [Interface].set_controlIdx(ref short value)
{
this.ControlIdx = value;
}
{
get { return m_controlIdx; }
set { m_controlIdx = value; }
}
short [Interface].get_controlIdx()
{
return this.ControlIdx;
}
void [Interface].set_controlIdx(ref short value)
{
this.ControlIdx = value;
}
Hope that helps!
Additional note for VB developers:
We actually took an additional step in our C# classes. In order to keep the bulk of our logic in Visual Basic (I personally prefer C#, but this is a VB shop), we actually made our C# classes abstract, and our public properties are abstract as well.
Then, we created matching VB.Net classes which inherit from our C# classes and put the logic there. The result is an extra file, and an external class library, but we were able to implement our VB6 interface without changing it, and while still keeping the actual logic in VB.Net.