Hi Brendan,
see inline
"Brendan Grant" <(E-Mail Removed)> wrote in message
news:F598B50E-5C36-4920-9432-(E-Mail Removed)...
> I've got a C# library that I've built into a COM component that will be
> used
> from a VC++ 6 application and while the creation of the COM object side of
> things seem to be working fine, using the object fully is another matter.
>
> On the C# side of things I've got an object defined like so:
>
> [ClassInterface(ClassInterfaceType.None)]
> public class PID : IPID
> {
<snip/>
> private PID[] pids;
<snip/>
> public PID[] PIDs
> {
> get { return pids;}
> set { pids = value;}
> }
What does the COM declaration in C++ code look like? Have a look at your tlh
file. Is the retval a VARIANT* or a SAFEARRAY* ?
What is the definition of the interface IPID?
What do you expect to return there anyways? You have a class PID which
exposes an array of PID instances, each exposing a PID array again?
I am astonished that you can return a PID[]? To my knowledge you cannot
expose a class as parameter type, just an interface. Is it really PID[] or
IPID[] what you are returning?
<snip/>
>
> I can instantiate an instance of this object in the MFC app with no
> problem... the problem is when I try to set the PIDs array to... anything
> but
> null really.
>
> The issue is that the C# array is viewed by the MFC app as pointer to a
> SAFEARRAY and all attempts to create an array of PID objects and assign
> them
> to the PIDs property fails.
>
> I've tried straight up (and cheesy) typecasting:
>
> IPIDPtr pPID1(__uuidof(PID));
> IPID *pid1 = pPID1;
When you take a raw interface pointer you should call AddRef and Release.
You get a little help here because pPID1 is a smartpointer so for its
lifetime pid1 is valid also. So why not you pPID1 directly and remove pid1.
> ...
> IPID *pidArray1[2];
> pidArray1[0] = pid2;
> pidArray1[1] = pid3;
> pid1->PIDs = (SAFEARRAY*)pidArray1;
What is pid1 and pid2? Have they been initialized?
> Which causes a friendly "User breakpoint called from code at 0x7c901230"
> and
> points to code I do not have the debug symbols for.
>
> I also tried explicitly creating a SAFEARRAY with SafeArrayCreate:
>
> SAFEARRAY * psa;
> SAFEARRAYBOUND rgsabound[1];
>
> rgsabound[0].lLbound = 0;
> rgsabound[0].cElements = 2;
>
> psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
>
> LONG index = 0;
> SafeArrayPutElement(psa, &index, &pid2);
> index = 1;
> SafeArrayPutElement(psa, &index, &pid3);
This looks the most promising. But you made some small mistakes:
I guess pid2 and pid3 are of type IPID*, correct? If so you must not use &,
just pass pid2 and pid3 as they are already pointers so they are valid for
void*.
BUT: void* ist used because you have absolutely no type safety. The compiler
trusts you, and infect you lied to him

You said: I want a safearray of VARIANTs. And later on you when you should
pass a VARIANT through void* you put an IPID* in there.
I guess you should setup two VARIANTs where you set the type to VT_UNKNOWN
and set punkVal to pid2 and pid3.
VARIANT v1, v2;
v1.vt = v2.vt = VT_UNKNOWN;
v1.punkVal = pid2; // I assume pid2 is AddReffed and you no longer use pid2
later on, so you transfer ownership to v1.
v2.punkVal = pid3; // same assumption
Now you call:
SafeArrayPutElements(psa, &index, &v1); // same for v2
> fi->PIDs = psa;
>
> In this example everything works fine up until we assign PIDs (but not
> when
> we set PIDs to null)... then we get an exception which reads:
>
> Unhandled exception at 0x7c81eb33 in MFCWSTestApp.exe: Microsoft C++
> exception: _com_error @ 0x0012f8c4.
>
> When the following line is called from the .tli wrapper:
>
> inline void IFileInformation::PutPIDs ( SAFEARRAY * _arg1 ) {
> _com_dispatch_method(this, 0x60020004, DISPATCH_PROPERTYPUT,
> VT_EMPTY, NULL,
> L"\x2009", _arg1);
> }
How comes IFileInformation into play? I thought we were using IPID?
>
>
> Thinking that I should be a little more explicit with regards to the size
> of
> the elements (and based on another example) I tried the following:
>
> SAFEARRAY *params = SafeArrayCreateVector(VT_R4, 0, 2);
Why do you create an array of doubles when you want to store interface
pointers?
>
> int paramMin = 0;
>
> SafeArrayAccessData(params, (void**)&pid1);
> memcpy(¶mMin, &pid1, sizeof(IPID));
> SafeArrayUnaccessData(params);
>
> paramMin = 1;
> SafeArrayAccessData(params, (void**)&pid2);
> memcpy(¶mMin, &pid2, sizeof(PID));
> SafeArrayUnaccessData(params);
Why do you copy values 0 and 1 at the adresses of pid1 and pid2. What type
are pid1 and pid2?
> This test behaves similarly to the previous one in that the bulk of the
> code
> executes without any error... but then an unhandled exception is thrown
> the
> moment we try to assign PIDs to anything... including null:
>
> Unhandled exception at 0x7c81eb33 in MFCWSTestApp.exe: Microsoft C++
> exception: _com_error @ 0x0012f894.
>
> Because of the far easier to use environment and debugger I have spent a
> fair amount of time trying to resolve this issue within the VC7.1
> environment, unfortunately both VC6 and VC7 have the exact same issues
> with
> the code in question.
>
> Aside from the obvious issue of trying to use VC6... does anyone see what
> I
> might be doing wrong here or have any ideas on how I could fix it?
--
SvenC