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();
} 4 7928
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.
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.
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.
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. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
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...
|
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'
|
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 ;
}
...
|
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...
|
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......
|
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...
|
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;...
|
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 &...
|
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...
|
by: Rina0 |
last post by:
Cybersecurity engineering is a specialized field that focuses on the design, development, and implementation of systems, processes, and technologies that protect against cyber threats and...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: linyimin |
last post by:
Spring Startup Analyzer generates an interactive Spring application startup report that lets you understand what contributes to the application startup time and helps to optimize it. Support for...
|
by: erikbower65 |
last post by:
Here's a concise step-by-step guide for manually installing IntelliJ IDEA:
1. Download: Visit the official JetBrains website and download the IntelliJ IDEA Community or Ultimate edition based on...
|
by: kcodez |
last post by:
As a H5 game development enthusiast, I recently wrote a very interesting little game - Toy Claw ((http://claw.kjeek.com/))。Here I will summarize and share the development experience here, and hope it...
|
by: Taofi |
last post by:
I try to insert a new record but the error message says the number of query names and destination fields are not the same
This are my field names
ID, Budgeted, Actual, Status and Differences
...
|
by: DJRhino1175 |
last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this -
If...
|
by: Rina0 |
last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
|
by: lllomh |
last post by:
Define the method first
this.state = {
buttonBackgroundColor: 'green',
isBlinking: false, // A new status is added to identify whether the button is blinking or not
}
autoStart=()=>{
| |