473,395 Members | 2,423 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Implementing collection for VB script in C#

I have created a "collection" in C# like this:

namespace ClassLibrary1
{
public class X {}

public class Class1
{
public ArrayList objs
{
get
{
return new ArrayList(new object[] { new X(), new X(),
new X() } );
}
}
}
}

Then I am trying to use this collection from VB script like this:

Set c = CreateObject("ClassLibrary1.Class1")
Set x = c.objs.Item(1) ' works
Set x = c.objs(1) ' does not work - here is the problem
(*)

At the same time, similar thing works just fine with Excel (for
example):

Set e = CreateObject("Excel.Application")
e.Workbooks.Add
Set x = e.Worksheets(1) ' Works

How do I make (*) work?
Kind regards.
Dec 26 '07 #1
5 3593
Did you try adding the 'this[ ]' indexer and setting that as your
default property by decorating it with DefaultPropertyAttribute?

On the other hand, I'm surprised this 'almost' worked since the
VBA.CreateObject() method call is explicitly used for COM objects, and
by the looks of your code, it doesn't appear to be exposed to COM. The
reason it works for Excel is because Excel is a COM object.

regards,

Greg

Nikolay Belyh wrote:
I have created a "collection" in C# like this:

namespace ClassLibrary1
{
public class X {}

public class Class1
{
public ArrayList objs
{
get
{
return new ArrayList(new object[] { new X(), new X(),
new X() } );
}
}
}
}

Then I am trying to use this collection from VB script like this:

Set c = CreateObject("ClassLibrary1.Class1")
Set x = c.objs.Item(1) ' works
Set x = c.objs(1) ' does not work - here is the problem
(*)

At the same time, similar thing works just fine with Excel (for
example):

Set e = CreateObject("Excel.Application")
e.Workbooks.Add
Set x = e.Worksheets(1) ' Works

How do I make (*) work?
Kind regards.
Dec 26 '07 #2
On 27 ÄÅË, 05:10, Greg <gcad...@gmail.comwrote:

Greg, thank you for reply.
Did you try adding the 'this[ ]' indexer and setting that as your
default property by decorating it with DefaultPropertyAttribute?
I did not try DefaultPropertyAttribute, since AFAIK it is unrelated to
COM after all.. But now I did :-)
Still no luck. What I did try before is trying to use [DispId(0)]
attribute on indexer. Withe the same (negative) result though..
On the other hand, I'm surprised this 'almost' worked since the
VBA.CreateObject() method call is explicitly used for COM objects, and
by the looks of your code, it doesn't appear to be exposed to COM. The
reason it works for Excel is because Excel is a COM object.
The assembly is made visible for COM using project settings. I mean, 2
chekcboxes
"Make assembly COM-visible" and "Register for COM interop" in project
settings.

I have also tried to make the COM type library for the assembly look
exactly as Excel's one
in the part of enumerator implementation. Though it did not work
either, below is the code I tried:

using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace ClassLibrary2
{
public interface IMyColl
{
[DispId(-4)]
object _NewEnum
{
[return: MarshalAs(UnmanagedType.IUnknown)]
get;
}

[DispId(0)]
[IndexerName("_Default")]
object this[int index]
{
get;
}
}

public class X {}

[ComDefaultInterface(typeof(IMyColl))]
[ClassInterface(ClassInterfaceType.None)]
public class MyColl : IMyColl
{
ArrayList items;

public MyColl()
{
items = new ArrayList(new object[] { new X(), new X(), new
X() });
}

public object _NewEnum
{
get { return items.GetEnumerator(); }
}

public object this[int index]
{
get
{
return items[index];
}
}
}

public interface IMyClass
{
MyColl objs { get; }
}

[ComDefaultInterface(typeof(IMyClass))]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : IMyClass
{
public MyColl objs
{
get { return new MyColl(); }
}
}
}

This way it works when target environment sees the type library (from
Excel VBA for example)
But it still does not work from the script.
Dec 27 '07 #3
"Nikolay Belyh" <nb****@gmail.comwrote in message
news:11**********************************@t1g2000p ra.googlegroups.com...
On 27 ÄÅË, 05:10, Greg <gcad...@gmail.comwrote:

Greg, thank you for reply.
Did you try adding the 'this[ ]' indexer and setting that as your
default property by decorating it with DefaultPropertyAttribute?
I did not try DefaultPropertyAttribute, since AFAIK it is unrelated to
COM after all.. But now I did :-)
Still no luck. What I did try before is trying to use [DispId(0)]
attribute on indexer. Withe the same (negative) result though..
On the other hand, I'm surprised this 'almost' worked since the
VBA.CreateObject() method call is explicitly used for COM objects, and
by the looks of your code, it doesn't appear to be exposed to COM. The
reason it works for Excel is because Excel is a COM object.
The assembly is made visible for COM using project settings. I mean, 2
chekcboxes
"Make assembly COM-visible" and "Register for COM interop" in project
settings.

I have also tried to make the COM type library for the assembly look
exactly as Excel's one
in the part of enumerator implementation. Though it did not work
either, below is the code I tried:

using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace ClassLibrary2
{
public interface IMyColl
{
[DispId(-4)]
object _NewEnum
{
[return: MarshalAs(UnmanagedType.IUnknown)]
get;
}

[DispId(0)]
[IndexerName("_Default")]
object this[int index]
{
get;
}
}

public class X {}

[ComDefaultInterface(typeof(IMyColl))]
[ClassInterface(ClassInterfaceType.None)]
public class MyColl : IMyColl
{
ArrayList items;

public MyColl()
{
items = new ArrayList(new object[] { new X(), new X(), new
X() });
}

public object _NewEnum
{
get { return items.GetEnumerator(); }
}

public object this[int index]
{
get
{
return items[index];
}
}
}

public interface IMyClass
{
MyColl objs { get; }
}

[ComDefaultInterface(typeof(IMyClass))]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : IMyClass
{
public MyColl objs
{
get { return new MyColl(); }
}
}
}

This way it works when target environment sees the type library (from
Excel VBA for example)
But it still does not work from the script.

You won't be able to use the indexer syntax on a .NET collection like you do
on a COM collection without some hand code interface trickery. Note that
..NET collections are not exactly like COM collections, for instance the
default lower bound is 0, while it's 1 for COM (try Worksheets(0)).

If you change your code a bit like this:

using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace ClassLibrary2
{
public interface IMyColl : IEnumerable // (1)
{
[DispId(-4)]
new IEnumerator GetEnumerator(); // (2)
[DispId(1)] // (3)
int Count
{
get;
}
[DispId(0)]
object this[int index]
{
get;
}
}
public class X { // (4)
int _val;
public int Val
{
get
{
return _val;
}
}
}

[ComDefaultInterface(typeof(IMyColl))]
[ClassInterface(ClassInterfaceType.None)]
public class MyColl : IMyColl
{
ArrayList items;

public MyColl()
{
items = new ArrayList(new object[] { new X(), new X(), new
X() });
}
public IEnumerator GetEnumerator()
{
return items.GetEnumerator();
}
public int Count
{
get { return items.Count;}
}
public object this[int index]
{
get
{
return items[index];
}
}
}

public interface IMyClass
{
MyColl objs { get; }
}

[ComDefaultInterface(typeof(IMyClass))]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : IMyClass
{
public MyColl objs
{
get { return new MyColl(); }
}
}
}
You will be able to use this class from VBscript like this:

Dim obj, x
Set obj = Wscript.CreateObject("ClassLibrary2.Class1")
Set coll = obj.objs
For Each v in coll
WScript.Echo v.Val
Next
WScript.Echo coll.Count
For i = 0 To coll.Count - 1 'lower bound is 0!!
WScript.Echo x(i).Val
Next

Note that I set coll to obj.objs which is exposed as an IEnumVARIANT by the
COM Interop layer(wrapped in a VARIANT by the scripting engine).
You can use indexing syntax on the coll object to get a specific object from
the collection, while you can also For ... Each over the collection

Willy.

Dec 27 '07 #4
"Nikolay Belyh" <nb****@gmail.comwrote in message
news:ea**********************************@a35g2000 prf.googlegroups.com...
Willy, thank you for reply.

My aim is to achieve the excel syntax, the rest of the collection
stuff is not a problem.

Why? What don't you like about this pattern:
Set coll = mycoll.objs
Set entry = mycoll(1)
....

Keeping in mind that mycoll(1) does not refer to the first entry in the
collection like it's the case when calling into COM.

Anyway, it looks like none of the (2) CLR's internal IDispatch handlers
handle the indexer syntax correctly. All you can try to do about this is to
implement a custom IDispatch marshaler and use this one instead, but I'm not
sure that even then, you will be able to overcome this issue.

Willy.
Dec 28 '07 #5
Why? What don't you like about this pattern:
*Set coll = mycoll.objs
*Set entry = mycoll(1)
There is no particular reason, actually.
I was jsut curious, why that syntax did not work, and how to make it
work...
You know, that kind of curiosity when a kid breaks a toy into 17
pieces to see what's in there.. :-)
Anyway, it looks like none of the (2) CLR's internal IDispatch handlers
handle the indexer syntax correctly. All you can try to do about this is to
implement a custom IDispatch marshaler and use this one instead, but I'm not
sure that even then, you will be able to overcome this issue.
But I have already bet $20 this can be done... So I just can't give up
that easily :-)

Kind regards, Nikolay.
Dec 28 '07 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: zaw | last post by:
Hi I am working on implementing this script to shopping cart. Basically, it copies fill the shipping address from billing automatically. I believe one or more syntax is not netscape compatible....
1
by: Dan H. | last post by:
Hello, I have an application that requires a collection that is sorted by a double field first, and then by a long field. So, lets say I have an class that has 2 fields called time, priority. I...
7
by: Pete Davis | last post by:
A different question this time. I have a DataGrid bound to a collection. Is there any way for me to allow sorting? The DataGrid.AllowSorting=true doesn't work, but that's probably because it can't...
3
by: ad | last post by:
Hi, When I studied CSharp, I am confuse by IList, Collection and Array. What is the relationships between them?
3
by: TJS | last post by:
from a code class, a] how does one dimension a collection and then b] after it is created, reassign it in the page ? I'm getting only errors on line of code in the page....
4
by: WStoreyII | last post by:
I am Making a Collection for categories There will be three fields Category Major And Minor For the Category i need to know what Type it is Expense/income for the major i need to know the cat...
2
by: ern | last post by:
My command-line application must be able to run text scripts (macros). The scripts have commands, comments, and flags. Comments are ignored (maybe they are any line beginning with " ; ") Commands...
4
by: haplobaaz | last post by:
I've just had a look at your fading opacity script. As I'm new to programming and I'm amazed by the script could I ask for some hints how to implement it in a site with a mouseover, mouseout events...
158
by: pushpakulkar | last post by:
Hi all, Is garbage collection possible in C++. It doesn't come as part of language support. Is there any specific reason for the same due to the way the language is designed. Or it is...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.