Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / September 2005

Tip: Looking for answers? Try searching our database.

Iterating through collection from VB6 gives error 424 Object requi

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Joe - 10 Sep 2005 17:52 GMT
See the example below.
I have a .Net class Customer which implements an interface ICustomer, and
which is stored in a collection CustomerCollection.
Both CustomerCollection and ICustomer are exposed to COM (ComVisible = true)
My Customer object is *not* exposed to COM (ComVisible = false), mainly
because I don't want my COM clients to be able to instantiate Customer
objects - only get them returned by methods of another class (in this example
returned by CustomerCollection's indexer).

When I attempt to access this from VB6, everything works fine, except that I
can't iterate through my CustomerCollection using "for each":

   Dim col As VB6Test.CustomerCollection
   Dim cust As VB6Test.ICustomer
   Set col = New VB6Test.CustomerCollection
   
   For Each cust In col
       Debug.Print cust.Name
   Next cust

The above VB6 code raises an error 424 'Object required' at the line "For
Each...".

Now if I modify my .NET Customer class to set ComVisible = true, the VB6
code works fine.  But I don't want this class to be visible to Com objects.

Can anyone explain this behavior and suggest a workaround?

Thanks,
Joe
============= ICustomer interface ===================
[
ComVisible(true),
GuidAttribute("16870d0c-213c-11da-9422-000bdb57d597")
]
public interface ICustomer
{
    string Name { get; set; }
}
============= Customer class ===================
[
ComVisible(false),
GuidAttribute("16870d0a-213c-11da-9422-000bdb57d597"),
]
public class Customer : ICustomer
{
    public Customer()
    {
    }

    public Customer(string name)
    {
        Name = name;
    }

    public string Name
    {
        get { return _name == null ? "" : _name; }
        set { _name = value; }
    }
    private string _name;
}
============= CustomerCollection class ===================
[
ComVisible(true),
GuidAttribute("16870d0b-213c-11da-9422-000bdb57d597"),
ClassInterface(ClassInterfaceType.AutoDual)
]
public class CustomerCollection : CollectionBase
{
    public CustomerCollection()
    {
        ((IList)this).Add(new Customer("Customer1"));
        ((IList)this).Add(new Customer("Customer2"));
    }

    public ICustomer this[int index]
    {
        get { return (ICustomer) InnerList[index]; }
        set { InnerList[index] = value; }
    }

}
Robert Jordan - 10 Sep 2005 18:11 GMT
> Now if I modify my .NET Customer class to set ComVisible = true, the VB6
> code works fine.  But I don't want this class to be visible to Com objects.
>
> Can anyone explain this behavior and suggest a workaround?

Either remove the default ctor from the Customer class or
make it internal or protected or both.

Rob
Joe - 10 Sep 2005 21:20 GMT
Robert,

Thanks for the response.

Making the default ctor internal has the effect I want for COM clients by
making the coclass noncreatable in the generated TLB.

However I need to be able to use the public default constructor for .NET
clients of my Customer class.   I tried adding the ComVisible attribute to
the default ctor, but ComVisible is not valid for a ctor.

I'm still struggling to understand why I should need to make my Customer
class ComVisible - COM only uses interfaces, right?  What I'm looking for is
a) an explanation as to why this is happening
b) a workaround which allows the default ctor to be visible to .NET clients
while either not generating the COM coclass or generating it as noncreatable.

> > Now if I modify my .NET Customer class to set ComVisible = true, the VB6
> > code works fine.  But I don't want this class to be visible to Com objects.
[quoted text clipped - 5 lines]
>
> Rob
Robert Jordan - 10 Sep 2005 21:50 GMT
Joe,

> Making the default ctor internal has the effect I want for COM clients by
> making the coclass noncreatable in the generated TLB.
[quoted text clipped - 6 lines]
> class ComVisible - COM only uses interfaces, right?  What I'm looking for is
> a) an explanation as to why this is happening

If a class is not ComVisible no CCW (COM callable wrapper) will
be created for that class. W/Out the CCW there is no way to access
the object from COM.

> b) a workaround which allows the default ctor to be visible to .NET clients
> while either not generating the COM coclass or generating it as noncreatable.

Apply [ClassInterface(ClassInterfaceType.None)] to Customer.
It probably helps too.

bye
Rob
Joe - 11 Sep 2005 10:13 GMT
> Joe,
>
[quoted text clipped - 12 lines]
> be created for that class. W/Out the CCW there is no way to access
> the object from COM.

But I *can* access it with ComVisible = false, via the ICustomer interface.
I can do everything with it I want except iterate using For Each.

> > b) a workaround which allows the default ctor to be visible to .NET clients
> > while either not generating the COM coclass or generating it as noncreatable.
>
> Apply [ClassInterface(ClassInterfaceType.None)] to Customer.
> It probably helps too.

No this doesn't help: with a public ctor and ClassInterfaceType.None I can
still create an instance of the object from a COM client

> bye
> Rob
Robert Jordan - 11 Sep 2005 13:17 GMT
>>>Making the default ctor internal has the effect I want for COM clients by
>>>making the coclass noncreatable in the generated TLB.
[quoted text clipped - 10 lines]
>>be created for that class. W/Out the CCW there is no way to access
>>the object from COM.

Correction: the CCW gets created for ComVisible(false) as well.

> But I *can* access it with ComVisible = false, via the ICustomer interface.
> I can do everything with it I want except iterate using For Each.

The problem is the automatic managed IEnumVARIANT wrapper that
probably checks the ComVisible flag of the items.

You can make the Customer class noncreatable by removing
its registry entries during the COM registration.

See the ComRegisterFunctionAttribute class docs.

Rob
Joe - 11 Sep 2005 19:09 GMT
Rob, thanks again.

> The problem is the automatic managed IEnumVARIANT wrapper that
> probably checks the ComVisible flag of the items.

So is this a bug in the IEnumVARIANT wrapper, or is it by design?  If it is
by design, what is the justification for this strange design?  .NET 2.0 Beta
2 has the same behaviour: should I raise a bug on the feedback center?

> You can make the Customer class noncreatable by removing
> its registry entries during the COM registration.
>
> See the ComRegisterFunctionAttribute class docs.

That's an interesting, if rather kludgey workaround.  I'll investigate this
week.

> Rob
Robert Jordan - 11 Sep 2005 20:16 GMT
Hi Joe,

>>The problem is the automatic managed IEnumVARIANT wrapper that
>>probably checks the ComVisible flag of the items.
>
> So is this a bug in the IEnumVARIANT wrapper, or is it by design?  If it is
> by design, what is the justification for this strange design?  .NET 2.0 Beta
> 2 has the same behaviour: should I raise a bug on the feedback center?

I'm not sure whether it's a bug. The doc of ComVisibleAttribute
states that a object whose type has ComVisible(false) won't
respond to QueryInterface. So I don't unterstand why you can
access a Customer object at all.

By any chance, can you clean up the registry and retry?
Or change the GUID of the Customer class? I'm supposing,
that your Customer is still registered with COM.

Rob
Joe - 13 Sep 2005 07:40 GMT
> I'm not sure whether it's a bug. The doc of ComVisibleAttribute
> states that a object whose type has ComVisible(false) won't
[quoted text clipped - 4 lines]
> Or change the GUID of the Customer class? I'm supposing,
> that your Customer is still registered with COM.

That's an excellent suggestion, I hadn't thought of that.  However, having
cleaned the registry, then rebuilt the project with ComVisible=false for the
Customer class, I am still getting the same behaviour:

- I can access the Customer object from VB6 via the ICustomer interface
without any problems.  For example, the following VB6 code works fine:

Dim col As CustomerCollection
Dim c As ICustomer
Set col = New CustomerCollection
Set c = col(1)
Debug.Print c.Name

- But I still can't iterate through the CustomerCollection using For Each

I think I'll raise a bug oin the product feedback center and see if they can
throw any light on this behaviour.

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.