473,761 Members | 1,808 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

How to? COM class library Property pass-by-reference for TypeLib [propput] ?

TJ
In C# how do you achieve pass-by-reference property declarations in the Type
Library?

I am writing a COM Class Library that must mimick an existing library for
which the only information is the TypeLib. I'm using Visual Studio .NET
2003.

The original library provides simple authentication services, from Access
and MS-SQL OLEDB providers. The enhancement I'm creating provides support
for ODBC and will be a drop-in replacement.

The original library was written in Visual Basic 6, and declares an
interface with property setter methods that take pointers as arguments, as
this extract shows:

dispinterface _DBLink {
methods:
[id(0x60030006)] VARIANT_BOOL CheckUser([in, out] BSTR* User, [in, out]
BSTR* Password);
[id(0x68030008), propput] void LoginClassField ([in, out] BSTR* rhs);

I've created an identical COM Class Library in C#, but the arguments to the
property setter methods are passed-by-value, and it isn't possible to use
the C# "ref" or "out" modifier on Properties.

dispinterface _DBLink {
methods:
[id(0x60020006)] VARIANT_BOOL CheckUser([in, out] BSTR* User, [in, out]
BSTR* Password);
[id(0x60020008), propput] void LoginClassField ([in] BSTR rhs);

[id(0x60020009)] void set_LoginClassF ield([in, out] BSTR* value);

code:
public interface _DBLink {
bool CheckUser(ref string User, ref string Password);
string LoginPassField { set; }

void set_LoginClassF ield(ref string value);

// ... rest of code
}

As you can see, although I can define the Property setters as methods, the
TypeLib would then no longer declare them as "propput".

Any ideas?

TJ.
Nov 17 '05 #1
7 3898
TJ,

Why not use the TLBIMP utility and then reference that from your
project? I'm not too sure if the propput attribute in IDL is supported, but
if it is, TLBIMP should be able to create the correct managed assembly.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard. caspershouse.co m

"TJ" <mi************ ***@tjworld.org > wrote in message
news:eS******** ******@TK2MSFTN GP14.phx.gbl...
In C# how do you achieve pass-by-reference property declarations in the
Type Library?

I am writing a COM Class Library that must mimick an existing library for
which the only information is the TypeLib. I'm using Visual Studio .NET
2003.

The original library provides simple authentication services, from Access
and MS-SQL OLEDB providers. The enhancement I'm creating provides support
for ODBC and will be a drop-in replacement.

The original library was written in Visual Basic 6, and declares an
interface with property setter methods that take pointers as arguments, as
this extract shows:

dispinterface _DBLink {
methods:
[id(0x60030006)] VARIANT_BOOL CheckUser([in, out] BSTR* User, [in, out]
BSTR* Password);
[id(0x68030008), propput] void LoginClassField ([in, out] BSTR* rhs);

I've created an identical COM Class Library in C#, but the arguments to
the property setter methods are passed-by-value, and it isn't possible to
use the C# "ref" or "out" modifier on Properties.

dispinterface _DBLink {
methods:
[id(0x60020006)] VARIANT_BOOL CheckUser([in, out] BSTR* User, [in, out]
BSTR* Password);
[id(0x60020008), propput] void LoginClassField ([in] BSTR rhs);

[id(0x60020009)] void set_LoginClassF ield([in, out] BSTR* value);

code:
public interface _DBLink {
bool CheckUser(ref string User, ref string Password);
string LoginPassField { set; }

void set_LoginClassF ield(ref string value);

// ... rest of code
}

As you can see, although I can define the Property setters as methods, the
TypeLib would then no longer declare them as "propput".

Any ideas?

TJ.

Nov 17 '05 #2
TJ
Nicholas, thanks for that suggestion, it offers some progress but further
confusion. I have further questions if anyone can help?

I'd been using Object Viewer stand-alone so it wasn't showing me C# specific
code matching the VB6 COM Type Library. As soon as I added the external
COM's TLB to my C# solution and ran Object Viewer on it, it showed:

IDL: [id(0x68030008), propput] void LoginClassField ([in, out] BSTR* rhs);
C# prototype: public abstract new System.IntPtr LoginClassField [ set ]

I didn't know about the IntPtr structure. I've now redefined my Interface
this way:

public interface _DBLink
{
[DispId(0x680300 08)] IntPtr LoginClassField { set; }
// ...
}
public class DBLink : _DBLink {
public IntPtr LoginClassField {
set {
_LoginClassFiel d = Marshal.PtrToSt ringBSTR(value) ;
Marshal.FreeBST R(value);
}
}
// ...
}

Now I'm concerned that when viewed in Object Viewer the IDL looks different
in other ways:

public System.IntPtr LoginClassField [ set ]

and when used to view the resulting Type Library (from the build) shows:
[id(0x68030008), propput] void LoginClassField ([in] long rhs);

So although the C# property declaration seems to match, the IDL looks
further away than it was. I've now got a long instead of a BSTR*

I tried to use [MarshalAs(Unman agedType.LPStr)] as per the documentation,
but as for many things Property-related, the compiler won't accept it.

[DispId(0x680300 08), MarshalAs(Unman agedType.LPStr)] IntPtr
LoginClassField { set; }

Is it possible to manually apply the propputref attribute to a C# method so
I could do something along the lines of this ?

[ BindAs( BindFlags.PutRe fDispProperty ) ] public void
set_LoginClassF ield(ref string value)

which, if there is a way to control the Bind, would result in something like
this in the IDL:

[propputref] void LoginClassField ( [in, out] BSTR* value)
Nov 17 '05 #3
TJ,

I think Nicholas misunderstood your problem. It looks like he thought you
were trying to IMPORT a COM dll. If I now understand you correctly, you're
trying to EXPORT a .NET class as a COM interface to emulate an older VB6
component you had (i.e. you've re-written this component in C#, but you want
it to appear to clients as essentially the same interface, right)?

I've had to do similar things in my job recently. I've encountered a
situation similar to yours, though not exactly the same.

What I had to do is manually create my own IDL and my own TLB and, after
calling regasm /tlb, swap out the regasm-generated TLB with my homebrew TLB.

This is some complicated brain surgery, but in many cases, it's the only
thing you can do.

I've written several blog posts about doing this kind of stuff. Sorry for
the poor grammar and spelling, these were all written after midnight after a
long day. I need to re-write them, but I'm too lazy :)

Part 1: (poorly) explaining some of the concepts involved in exporting .NET
types to COM:
http://blog.chadmyers.com/chad/archi...10/06/166.aspx

Part 2: Explaining problems with Tlbexp/TypeLibExporter and how to hack
together your own homebrew IDL:
http://blog.chadmyers.com/chad/archi...10/07/167.aspx

Part 3: Handling ComVisible(true ), default, reference-type properties in C#:
http://blog.chadmyers.com/chad/archi...10/07/168.aspx
Part 3 is what my specific deal-breaker situation was. It's similar to your
situation. If you can find no other solution, you may have to follow some of
the steps in my Part 2 article to hack together your own IDL.

I've encountered a few other problems along the way that required IDL
manipulation, but I, sadly, haven't had time to blog about them.

I'd be happy to walk you through some of them once you've given everything
else a good try and studied up on IDL hacking.

I *STRONGLY* urge you to purchase, borrow, or otherwise acquire the book
".NET and COM The Complete Interoperabilit y Guide" by Adam Nathan. This book
explains almost everything I did in those 3 articles. You may have to dig
around a little, but the information is all there.

One other thing, if you've had to deal with optional parameters in your COM
interface (i.e. the VB6 had some optional arguments, and now you have to
simulate that in the C# interface), check out:
http://blog.chadmyers.com/chad/archi...02/10/145.aspx

Hope this helps.

-Chad
"TJ" <mi************ ***@tjworld.org > wrote in message
news:eX******** ******@TK2MSFTN GP15.phx.gbl...
Nicholas, thanks for that suggestion, it offers some progress but further
confusion. I have further questions if anyone can help?

I'd been using Object Viewer stand-alone so it wasn't showing me C#
specific code matching the VB6 COM Type Library. As soon as I added the
external COM's TLB to my C# solution and ran Object Viewer on it, it
showed:

IDL: [id(0x68030008), propput] void LoginClassField ([in, out] BSTR* rhs);
C# prototype: public abstract new System.IntPtr LoginClassField [ set ]

I didn't know about the IntPtr structure. I've now redefined my Interface
this way:

public interface _DBLink
{
[DispId(0x680300 08)] IntPtr LoginClassField { set; }
// ...
}
public class DBLink : _DBLink {
public IntPtr LoginClassField {
set {
_LoginClassFiel d = Marshal.PtrToSt ringBSTR(value) ;
Marshal.FreeBST R(value);
}
}
// ...
}

Now I'm concerned that when viewed in Object Viewer the IDL looks
different in other ways:

public System.IntPtr LoginClassField [ set ]

and when used to view the resulting Type Library (from the build) shows:
[id(0x68030008), propput] void LoginClassField ([in] long rhs);

So although the C# property declaration seems to match, the IDL looks
further away than it was. I've now got a long instead of a BSTR*

I tried to use [MarshalAs(Unman agedType.LPStr)] as per the documentation,
but as for many things Property-related, the compiler won't accept it.

[DispId(0x680300 08), MarshalAs(Unman agedType.LPStr)] IntPtr
LoginClassField { set; }

Is it possible to manually apply the propputref attribute to a C# method
so I could do something along the lines of this ?

[ BindAs( BindFlags.PutRe fDispProperty ) ] public void
set_LoginClassF ield(ref string value)

which, if there is a way to control the Bind, would result in something
like this in the IDL:

[propputref] void LoginClassField ( [in, out] BSTR* value)

Nov 17 '05 #4
TJ
Thanks Chad, your articles have moved me on somewhat.

Working out what was wrong with the syntax of the Object Viewer IDL was a
pain, but then I had yet more joy solving "cl.exe not found" and "oaidl.idl
not found" errors from MIDL, along with others.

Solutions were to add to the environmental variables for the location of
midl.exe, cl.exe (wasn't even in the Visual Studio 2003 .Net folder
structure), and the library .tbl files used by MIDL.

PATH=%PATH%;C:\ Program Files\Microsoft \Visual Studio .NET 2003\Common7\ID E;
PATH=%PATH%;C:\ Program Files\Microsoft \Visual Studio .NET 2003\Vc7\bin;
INCLUDE=C:\Prog ram Files\Microsoft \SDK\include\

*Note: I always edit my Microsoft applications install folder to be
"\Program Files\Microsoft \<application> " rather than "\Program
Files\Microsoft <application> " so as to stop the multiplication of
"Microsoft. .." folders in the "Program Files" folder.

In the revised class IDL file express the full path for the importlib()
statement:

// TLib : // TLib : Common Language Runtime Library :
{BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("C:\W INDOWS\Microsof t.NET\Framework \v1.1.4322\msco rlib.tlb");

HOWEVER, having got this far I've now convinced myself I've taken the wrong
route, since the COM object I'm creating needs to be a drop-in replacement
for an existing COM object, and may be deployed on systems that don't have
the .Net framework installed.

What a pain, as the code in the library itself is complete!

I was investigating [ ComRegisterFunc tionAttribute ] & [
ComUnregisterFu nctionAttribute ] thinking I could create a component that
would work in a .Net and classic environment, but I think maybe I
misunderstood the documentation and that my component will only work in the
..Net environment, even when called by a classic COM client.

Thinking of switching to C++, but it seems that Visual Studio .Net 2003
won't let me create a classic COM library, only a .net assembly!
Investigating Visual Basic (*spits!) it looks like that still allows the
creation of classic COM libraries - grrr!!

I'll be glad when I've got this finished and can go back to Java and Eclipse
IDE! I only started on this C# / Microsoft programming 2 days ago to provide
ODBC functionality to the application that uses DBLink, so it can share a
common user database with a J2EE web application.

TJ.
Nov 17 '05 #5
Re: Minor problems with midl:

Oh yeah, forgot to mention all the nitpicky stuff, but it's not that hard to
figure out or work through.

But then you said something that confused me...

HOWEVER, having got this far I've now convinced myself I've taken the
wrong route, since the COM object I'm creating needs to be a drop-in
replacement for an existing COM object, and may be deployed on
systems that don't have the .Net framework installed.
How do you plan on deploying, and running, a .NET/C# component on a system
without the .NET Framework installed? Isn't the whole point of this
excercise to replace a VB6 component with a C# component?
Thinking of switching to C++, but it seems that Visual Studio .Net 2003
won't let me create a classic COM library, only a .net assembly!
123456789112345 678921234567893 123456789412345 678951234567896 123456789712 I'll be glad when I've got this finished and can go back to Java and
Eclipse IDE! I only started on this C# / Microsoft programming 2 days
ago to provide ODBC functionality to the application that uses DBLink,
so it can share a common user database with a J2EE web application.
Ah, I see the problem. You are very confused. C# and VB.NET and Managed
Extensions for C++ are all .NET-framework based. Imagine if the JVM
supported multiple languages besides Java. That's what .NET essentially is.

You can create unmanaged components from VS.NET 2003, but only in C++
without the /clr compiler switch.

C# is a .NET-only language, you cannot create unmanaged code. You can create
a .NET component which exposes a COM interface, but you cannot create
non-.NET components from VS.NET 2003 if you're not using C++ [sans /clr].

Good luck on your efforts and I'm sorry you have to use Java/Eclipse ;)

-c

"TJ" <mi************ ***@tjworld.org > wrote in message
news:Oy******** ********@tk2msf tngp13.phx.gbl. .. Thanks Chad, your articles have moved me on somewhat.

Working out what was wrong with the syntax of the Object Viewer IDL was a
pain, but then I had yet more joy solving "cl.exe not found" and
"oaidl.idl not found" errors from MIDL, along with others.

Solutions were to add to the environmental variables for the location of
midl.exe, cl.exe (wasn't even in the Visual Studio 2003 .Net folder
structure), and the library .tbl files used by MIDL.

PATH=%PATH%;C:\ Program Files\Microsoft \Visual Studio .NET
2003\Common7\ID E;
PATH=%PATH%;C:\ Program Files\Microsoft \Visual Studio .NET 2003\Vc7\bin;
INCLUDE=C:\Prog ram Files\Microsoft \SDK\include\

*Note: I always edit my Microsoft applications install folder to be
"\Program Files\Microsoft \<application> " rather than "\Program
Files\Microsoft <application> " so as to stop the multiplication of
"Microsoft. .." folders in the "Program Files" folder.

In the revised class IDL file express the full path for the importlib()
statement:

// TLib : // TLib : Common Language Runtime Library :
{BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("C:\W INDOWS\Microsof t.NET\Framework \v1.1.4322\msco rlib.tlb");

HOWEVER, having got this far I've now convinced myself I've taken the
wrong route, since the COM object I'm creating needs to be a drop-in
replacement for an existing COM object, and may be deployed on systems
that don't have the .Net framework installed.

What a pain, as the code in the library itself is complete!

I was investigating [ ComRegisterFunc tionAttribute ] & [
ComUnregisterFu nctionAttribute ] thinking I could create a component that
would work in a .Net and classic environment, but I think maybe I
misunderstood the documentation and that my component will only work in
the .Net environment, even when called by a classic COM client.

Thinking of switching to C++, but it seems that Visual Studio .Net 2003
won't let me create a classic COM library, only a .net assembly!
Investigating Visual Basic (*spits!) it looks like that still allows the
creation of classic COM libraries - grrr!!

I'll be glad when I've got this finished and can go back to Java and
Eclipse IDE! I only started on this C# / Microsoft programming 2 days ago
to provide ODBC functionality to the application that uses DBLink, so it
can share a common user database with a J2EE web application.

TJ.

Nov 17 '05 #6
TJ
The primary issue is, the COM DLL I'm "extending" is an optional part of a
Windows IRC server (IRCXPro), so for operators that want to use my ODBC
version of DBLink I can't dictate that they install the .Net Framework if it
isn't already there - a severe case of overkill I feel.

Assuming for the moment I continue with the current C# (how nice is it is to
see microsoft providing something so close to Java - the reason I was able
to get up to speed so quick)...

As I understand it, my managed-code replacement DLL can simply replace the
existing DLL, but am I correct in thinking the TLB would need to be added to
the DLL's resources? (I don't want to confuse users by shipping more than
the one file).

If thats the case, how is one supposed to add a resource to the DLL? I tried
to follow the destructions in the help files but I seem to hit a brick wall
no matter what approach I take - where the hell has the lovely ole Resource
Workshop gone for doing stuff like string-tables, icons, bitmaps, version
info, and raw RC_data?

Because the original DLL is set to OLESelfRegister does this have
implications for me? Do i need to implement the [
ComRegisterFunc tionAttribute ] etc static methods and make entries in the
registry of the server the component is installed on?

Do I need to create an install package that simply makes the component
register itself, or is that handled the first time the DLL is called?

Because the finished component will use the same GUIDs as the original, in
theory it shouldn't need to register itself because all the settings will be
there already, but I just want to be clear.

Many thanks for your help on this; It's been an intense learning experience
and tiring on the eyes 8-)

TJ.
Nov 17 '05 #7
TJ
I thought I'd complete this thread with my latest experiences.

This article began as an appeal for help, but in the course of writing it I
appear to have solved the specific issue so check the article on my blog for
details.

When loading a VB6 application that delay-loads a database-access DLL
written in C# I'm seeing the error dialog
--------------------------------
Two different copies of MSCOREE.DLL have been loaded.
First copy:
<Unknown>
Second copy:
C:\Windows\Micr osoft.NET\Frame work\v1.1.4322\ mscorwks.dll
This is typically caused by having a registered MSCOREE.DLL that is
different from one that is statically linked with the application.
------------------------

It is a 3rd-party application that recently added support for user
authentication via MS Access and MS SQL Server databases using a
delay-loaded DLL.

The DLL exposes its interfaces via COM and its TLB is in the resource
section of the DLL. I used OLE/COM Viewer to extract the IDL and wrote my
own C# component that supports ODBC datasources, with an identical type
library so it can be used as a drop-in replacement for the application's own
database-access DLL.

http://blog.tjworld.net/blog/page/TJ...ies_of_mscoree

Nov 17 '05 #8

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

Similar topics

32
3344
by: Kalle Anke | last post by:
I'm coming to Python from other programming languages. I like to hide all attributes of a class and to only provide access to them via methods. Some of these languages allows me to write something similar to this int age( ) { return theAge }
15
4390
by: | last post by:
Hi, I want to do things this way: I have a bunch of stuff that I want to keep track of while a user is connected to the site. Maybe 50 little peices of information. So I know I can make 50 session variables , or an store an array in a session variable, but what I wanna do is store it all in a class so I can use property get and property let.
5
2073
by: Laszlo Zsolt Nagy | last post by:
Hughes, Chad O wrote: > Is there any way to create a class method? I can create a class > variable like this: > Hmm, seeing this post, I have decided to implement a 'classproperty' descriptor. But I could not. This is what I imagined: class A(object):
2
1482
by: Andrea Williams | last post by:
I need to expose the properties of an User Object to all other classes, but hide the operations (functions) from all but the Business layer of my app? The goal is to load up this USER object and pass it from app Layer to bus layer to Data layer and then back once data has been handled. All requests to the data layer from the business layer, so that it can validate the data before Insertion, update, etc. I've read up on Interfaces......
2
2120
by: Venu | last post by:
Hi Everyone, I'm very new to C# and I have the following problem - please help. I have a Windows Forms application called 'FunApp' which has a status bar. I also have a separate class library called FunTx compiled as a DLL. What I want to do is update the status bar from within a FunTx method - and I used delegates to try this. Here's what I did.
2
2349
by: Steve | last post by:
I'm in a weird situation where I'm using ComboBox's in a DataGrid. When the ComboBox selection changes, I'm currently storing the SelectedValue object into the DataSource of the DataGrid cell. This is not what I want. I want to bind a string to the datagrid, then bind the string and value of a lookup table to the combo box. When the combobox lookup is changed, I wanted to store the value in a different, unbound property of the bound...
12
3795
by: Michael Maes | last post by:
Hello, I have a BaseClass and many Classes which all inherit (directly) from the BaseClass. One of the functions in the BaseClass is to (de)serialize the (inherited) Class to/from disk. 1. The Deserialization goes like: #Region " Load "
6
1568
by: alainpoint | last post by:
Hello, I have got a problem that i can't readily solve. I want the following: I want to create a supertuple that behaves both as a tuple and as a class. It should do the following: Point=superTuple("x","y","z") # this is a class factory p=Point(4,7,9) assert p.x==p
5
2178
by: Len Weltman | last post by:
I am trying to pass a NumericUpDown object into a class method using Visual Studio 2005, but the control type is not found in Intellisense and the type declaration is flagged as an error. Here is a code sample (which doesn't work): *** Begin code ***
5
1910
by: John Wright | last post by:
I want to create a method in my class where I can pass in a property name and have it reset the property to the previous value. I have the method that stores the properties last value, now I need the class that can interate through the properties and reset the value. Something like this Private Sub UndoChange (PropertyName as string) 'Get the old value dim drProperty as DataRow = propertyChanges.Rows.Find(PropertyName)
0
9554
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9377
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10136
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9925
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8814
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7358
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 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 a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6640
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5266
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5405
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?

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.