473,461 Members | 1,349 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

accessing COM from C# with an IStream** parameter

Hallo,

I'm trying to call a COM function from C#.
The function has a parameter from the type array of IStream* (IStream**).
The COM component (out-proc-server (.exe)) has the following code:

(C++)

STDMETHODIMP CIntf::SendFiles(int noOfStreams, IUnknown** dataStreams)
{
for(int i = 0; i < noOfStreams; i++)
{
if(*(dataStreams + i))
{
IStream* iStream;
hr = (*(dataStreams + i))->QueryInterface(IID_IStream,
(void**)&iStream);
... ...
}
}
}

I can't change the code of the COM component.
If I'm calling the function from C# I get an E_NOINTERFACE error from
QueryInterface in the COM component.
Does anyone has an idea about the problem in my C# code?

I asked the same in the german newsgroup, but I got no answer. I hope you
are better here.

Best reguards
Ralf Beckers

(C#)

public void SendFiles(string file)
{

FileStream fs = new FileStream(file, FileMode.Open);
StreamReader sr = new StreamReader(fs, Encoding.Default);
string trc = sr.ReadToEnd();
sr.Close();
fs.Close();

byte[] data = Encoding.Default.GetBytes(trc);

IStorage storage;
ComTypes.IStream stream;

int err = StgCreateDocfile(null,
STGM.CREATE | STGM.READWRITE | STGM.TRANSACTED |
STGM.SHARE_EXCLUSIVE | STGM.DELETEONRELEASE,
0, out storage);

storage.CreateStream("TRTFiles.trt", (uint)(STGM.READWRITE |
STGM.SHARE_EXCLUSIVE), 0,0, out stream);
stream.Write(data, data.Length, IntPtr.Zero);
stream.Commit((int)STGC.OVERWRITE);

storage.Commit((int)STGC.OVERWRITE);
IntPtr ptr = Marshal.GetIUnknownForObject(stream);
IntPtr[] arr = { ptr };
IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( typeof(IntPtr ))
* arr.Length );
Marshal.Copy(arr, 0, buffer, arr.Length );

object obj = buffer;
this.intf.SendFiles(1, ref obj);
Marshal.FreeCoTaskMem((IntPtr)buffer);
}
[DllImport("ole32.dll")]
static extern int StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)]string
pwcsName, STGM grfMode, uint reserved, out IStorage ppstgOpen);

[Flags]
public enum CSMFlags : short
{
NONE = 0,
EVENT_EN = 0x0100,
POLLED_EVENTS = 0x0001
}
[Flags]
public enum CSMFilterType : byte
{
ENABLE_MSG = 0x00,
BLOCK_MSG = 0x01,
NO_FILTER = 0x02
}
[Flags]
internal enum STGC : int
{
DEFAULT = 0,
OVERWRITE = 1,
ONLYIFCURRENT = 2,
DANGEROUSLYCOMMITMERELYTODISKCACHE = 4,
CONSOLIDATE = 8
}
[Flags]
internal enum STGM : int
{
DIRECT = 0x00000000,
TRANSACTED = 0x00010000,
SIMPLE = 0x08000000,
READ = 0x00000000,
WRITE = 0x00000001,
READWRITE = 0x00000002,
SHARE_DENY_NONE = 0x00000040,
SHARE_DENY_READ = 0x00000030,
SHARE_DENY_WRITE= 0x00000020,
SHARE_EXCLUSIVE = 0x00000010,
PRIORITY = 0x00040000,
DELETEONRELEASE = 0x04000000,
NOSCRATCH = 0x00100000,
CREATE = 0x00001000,
CONVERT = 0x00020000,
FAILIFTHERE = 0x00000000,
NOSNAPSHOT = 0x00200000,
DIRECT_SWMR = 0x00400000
}

[ComImport]
[Guid("0000000b-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown )]
interface IStorage
{
void CreateStream(
/* [string][in] */ string pwcsName,
/* [in] */ uint grfMode,
/* [in] */ uint reserved1,
/* [in] */ uint reserved2,
/* [out] */ out ComTypes.IStream ppstm);
void OpenStream(
/* [string][in] */ string pwcsName,
/* [unique][in] */ IntPtr reserved1,
/* [in] */ uint grfMode,
/* [in] */ uint reserved2,
/* [out] */ out ComTypes.IStream ppstm);
void CreateStorage(
/* [string][in] */ string pwcsName,
/* [in] */ uint grfMode,
/* [in] */ uint reserved1,
/* [in] */ uint reserved2,
/* [out] */ out IStorage ppstg);
void OpenStorage(
/* [string][unique][in] */ string pwcsName,
/* [unique][in] */ IStorage pstgPriority,
/* [in] */ uint grfMode,
/* [unique][in] */ IntPtr snbExclude,
/* [in] */ uint reserved,
/* [out] */ out IStorage ppstg);
void CopyTo(
/* [in] */ uint ciidExclude,
/* [size_is][unique][in] */ Guid rgiidExclude, // should this be an array?
/* [unique][in] */ IntPtr snbExclude,
/* [unique][in] */ IStorage pstgDest);
void MoveElementTo(
/* [string][in] */ string pwcsName,
/* [unique][in] */ IStorage pstgDest,
/* [string][in] */ string pwcsNewName,
/* [in] */ uint grfFlags);
void Commit(
/* [in] */ uint grfCommitFlags);
void Revert();
void EnumElements(
/* [in] */ uint reserved1,
/* [size_is][unique][in] */ IntPtr reserved2,
/* [in] */ uint reserved3,
/* [out] */ out IEnumSTATSTG ppenum);
void DestroyElement(
/* [string][in] */ string pwcsName);
void RenameElement(
/* [string][in] */ string pwcsOldName,
/* [string][in] */ string pwcsNewName);
void SetElementTimes(
/* [string][unique][in] */ string pwcsName,
/* [unique][in] */ ComTypes.FILETIME pctime,
/* [unique][in] */ ComTypes.FILETIME patime,
/* [unique][in] */ ComTypes.FILETIME pmtime);
void SetClass(
/* [in] */ Guid clsid);
void SetStateBits(
/* [in] */ uint grfStateBits,
/* [in] */ uint grfMask);
void Stat(
/* [out] */ out ComTypes.STATSTG pstatstg,
/* [in] */ uint grfStatFlag);
}

[ComImport]
[Guid("0000000d-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown )]
public interface IEnumSTATSTG
{
// The user needs to allocate an STATSTG array whose size is celt.
[PreserveSig]
uint
Next(
uint celt,
[MarshalAs(UnmanagedType.LPArray), Out]
ComTypes.STATSTG[] rgelt,
out uint pceltFetched
);
void Skip(uint celt);
void Reset();
[return:MarshalAs(UnmanagedType.Interface)]
IEnumSTATSTG Clone();
}

Jan 16 '08 #1
4 8066
Hi Ralf,

Based on my understanding, you are trying to pass an array of interface
pointers to a COM component, right?

To pass array in COM, you need SAFEARRAY.

Here's some key steps:

1) In your IDL:

[id(3), helpstring("method SendFiles2")] HRESULT SendFiles2([in,out]
SAFEARRAY(IUnknown*)* m);

2) Here's some example code on how to retrieve the element in a SAFEARRAY
with index 0:

STDMETHODIMP CSimpleObject::SendFiles2(SAFEARRAY ** m)
{
IUnknown* punk;
long elementNumber = 0;
HRESULT hr = S_OK;
hr = SafeArrayGetElement(*m, &elementNumber, &punk);
if (SUCCEEDED(hr)) {
IStream* pstream;
hr = punk->QueryInterface(IID_IStream, (void**)&pstream);
}
...

3) In C#, after you re-adding the reference, you should see this method now
has signature (ref Array). To call this method:

Array T = Array.CreateInstance(typeof(IStream), 1);
T.SetValue(stream, 0);
intf.SendFiles2(ref T);
Hope this helps.

Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Jan 17 '08 #2
Hi Walter,

thanx for your answer.
But as I wrote in my question, I can't change anything at the interface of
the C++ COM component.
I need a way to use the existing interface without any modifications.

The interface is described in the IDL file as:

[
object,
uuid(A0926B7C-D57F-4F5E-9115-8F6ADB890DC1),
dual,
helpstring("IIntf Interface"),
pointer_default(unique)
]
interface IIntf : IDispatch
{
[id(21), helpstring("method SendFiles")]
HRESULT SendFiles(
[in] INT num,
[in, ref, size_is(num)] IUnknown** arr);

and my DevStudio generates:
using System;
using System.Runtime.InteropServices;

[ClassInterface(0)]
[TypeLibType(2)]
[Guid("A0926B7C-D57F-4F5E-9115-8F6ADB890DC1")]
public class CIntfClass :IIntf , CIntf
{
public CIntfClass ();
[DispId(1)]
public virtual void SendFiles(int num, ref object arr);
}

Regards
Ralf
""Walter Wang [MSFT]"" <wa****@online.microsoft.comschrieb im Newsbeitrag
news:mP**************@TK2MSFTNGHUB02.phx.gbl...
Hi Ralf,

Based on my understanding, you are trying to pass an array of interface
pointers to a COM component, right?

To pass array in COM, you need SAFEARRAY.

Here's some key steps:

1) In your IDL:

[id(3), helpstring("method SendFiles2")] HRESULT SendFiles2([in,out]
SAFEARRAY(IUnknown*)* m);

2) Here's some example code on how to retrieve the element in a SAFEARRAY
with index 0:

STDMETHODIMP CSimpleObject::SendFiles2(SAFEARRAY ** m)
{
IUnknown* punk;
long elementNumber = 0;
HRESULT hr = S_OK;
hr = SafeArrayGetElement(*m, &elementNumber, &punk);
if (SUCCEEDED(hr)) {
IStream* pstream;
hr = punk->QueryInterface(IID_IStream, (void**)&pstream);
}
..

3) In C#, after you re-adding the reference, you should see this method
now
has signature (ref Array). To call this method:

Array T = Array.CreateInstance(typeof(IStream), 1);
T.SetValue(stream, 0);
intf.SendFiles2(ref T);
Hope this helps.

Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no
rights.
Jan 17 '08 #3
Hi Ralf,

I'm not sure if we could do that from .NET side but I will do some further
research.

Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Jan 19 '08 #4
Hi Ralf,

I'm writing to check the status of this post. Please feel free to let me
know if there's anything else I can help. Thanks.
Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Jan 25 '08 #5

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

Similar topics

4
by: Thomas Matthews | last post by:
Hi, In some threads, some people mentioned that variable initialization is best performed in an initialization list. Is there a way to initialize a variable from an istream in an...
7
by: ragi | last post by:
Short version of my program: ifstream File; File.open("test.txt"); if(!File.good()) return; Func(File); <--cannot convert parametr 1 from 'std::ifstream' to 'std::istream'
13
by: Peteroid | last post by:
These don't work (I'm using VS C++.NET 2005 Express with clr:/pure syntax): ostream& operator <<( ostream& output, String^ str ) { output << str ; //compile error return output ; } ...
13
by: Randy | last post by:
Is there any way to do this? I've tried tellg() followed by seekg(), inserting the stream buffer to an ostringstream (ala os << is.rdbuf()), read(), and having no luck. The problem is, all of...
5
by: Gunnar Liknes | last post by:
Hi, I am trying to access COM component - method that takes a IStream (ByRef) parameter from ASP (Not ASP.NET). So far I have had no luck and google drowns my search with ASP.NET examples......
3
by: KWienhold | last post by:
I'm currently writing an application (using Visual Studio 2003 SP1 and C#) that stores files and additional information in a single compound file using IStorage/IStream. Since files in a compound...
21
by: Peter Larsen [] | last post by:
Hi, I have a problem using System.Runtime.InteropServices.ComTypes.IStream. Sample using the Read() method: if (IStreamObject != null) { IntPtr readBytes = IntPtr.Zero;...
2
by: Colonel | last post by:
It seems that the problems have something to do with the overloading of istream operator ">>", but I just can't find the exact problem. // the declaration friend std::istream &...
3
by: Kourosh | last post by:
Hi all, I'm trying to call a COM function from C# The function gets a paramter of type IStream in C++. I've found the type System.Runtime.InteropServices.ComTypes.IStream, however I'm not sure...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
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
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
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
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...
0
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.