Ole Automation - passing parameters by reference
Giles R. Chamberlin -- GRC@langley.softwright.co.uk
Wednesday, October 23, 1996
Environment: VC++ 4.1, Win 95
I've successfully created a variety of automation methods which allow me
to pass parameters in to an automation function. OK so all I did was
click Class Wizard buttons, but it made me feel happy.
Now the tricky bit. I'm trying to implement a function which in a pure
C++ world would like:
BOOL Next(CString& strText);
ie on return strText has something useful in it. Having CString as the
return type is not one of the options I'm after.
So, moving in to OLE, I used ClassWizard to generate my method and hand
edited the odl file to add [out] to the parameter definition:
[ uuid(AD3901A0-2747-11D0-AB3C-0020AF71E433) ]
dispinterface ISPageNames
{
properties:
// NOTE - ClassWizard will maintain property information here.
// Use extreme caution when editing this section.
//{{AFX_ODL_PROP(SPageNames)
//}}AFX_ODL_PROP
methods:
// NOTE - ClassWizard will maintain method information here.
// Use extreme caution when editing this section.
//{{AFX_ODL_METHOD(SPageNames)
[id(1)] void Reset();
[id(2)] boolean Next([out] BSTR* pbstrPageName); // hand editing here
//}}AFX_ODL_METHOD
};
and coded the function itself as:
BOOL SPageNames::Auto_Next(BSTR* pbstrPageName)
{
if(m_posCurrent == NULL)
return FALSE;
CString strName = m_strlist.GetNext(m_posCurrent);
BSTR bstrName = strName.AllocSysString();
pbstrPageName = &bstrName;
return TRUE;
}
I then call this function from a simple test App (Class wizard generated
Class from TypeLib to wrap the IDispatch) and the following code to
exercise the function.
ASSERT(pDisp != NULL);
ISPageNames names;
names.AttachDispatch(pDisp);
BSTR bstrName;
names.Next(&bstrName);
CString strName = OLE2T(bstrName);
::SysFreeString(bstrName);
The problem:
the BSTR returned by names.Next is valid but empty, even though tracing
through the code of SPageNames::Auto_Next shows that a valid, non-empty
string is being assigned.
By a valid BSTR, I mean that the assignment to strName passes off without
a hitch. Unfortunately the value of strname is an unhelpful "";
So, how should I go about passing back information in one of the
parameters of an automation method?
Giles Chamberlin
Softwright
Ibsen -- iramos@geographix.com
Thursday, October 24, 1996
[Mini-digest: 5 responses]
Ok Mr. Giles....
This is what I did.....From my main app:
-------------------------------------------------------------------------
--------
CString strText;
IMyInterface myOleApp;
myOleApp.CreateDispatch("CmyOleApp.App");
myOleApp.myMethod((BSTR*)&strText);
-------------------------------------------------------------------------
--------
from my ole app (mine consist of a dialog box that I can input some
text):
-------------------------------------------------------------------------
--------
CMyDialog* m_pMyDialog; // I save the pointer to the dialog in the
constructor
CMyDialog* GetMyDialog {return m_pMyDialog;}
CString* m_pMyString;
void SetMyString(CString* pString) {m_pMyString = pString;}
in the interface
BOOL CMyInterface::myMethod(BSTR FAR* pString)
{
((CmyOleApp*)AfxGetApp())->GetMyDialog()->SetMyString((CString*)pString)
;
}
So whenever I set the text using m_pMyString, is always pointing to the
strText variable in my main app............ I did it this way and it
works for me, I'm not sure if this is what you're looking for. Let me
know if it worked......
>----------
>From: Giles R. Chamberlin[SMTP:GRC@langley.softwright.co.uk]
>Sent: Wednesday, October 23, 1996 10:29 AM
>To: mfc-l
>Subject: Ole Automation - passing parameters by reference
>
>
>Environment: VC++ 4.1, Win 95
>
>I've successfully created a variety of automation methods which allow
>me to pass parameters in to an automation function. OK so all I did
>was click Class Wizard buttons, but it made me feel happy.
>
>Now the tricky bit. I'm trying to implement a function which in a pure
>C++ world would like:
>BOOL Next(CString& strText);
>
>ie on return strText has something useful in it. Having CString as the
>return type is not one of the options I'm after.
>
>So, moving in to OLE, I used ClassWizard to generate my method and hand
>edited the odl file to add [out] to the parameter definition:
>
> [ uuid(AD3901A0-2747-11D0-AB3C-0020AF71E433) ]
>dispinterface ISPageNames
>{
> properties:
> // NOTE - ClassWizard will maintain property information here.
> // Use extreme caution when editing this section.
> //{{AFX_ODL_PROP(SPageNames)
> //}}AFX_ODL_PROP
> methods:
> // NOTE - ClassWizard will maintain method information here.
> // Use extreme caution when editing this section.
> //{{AFX_ODL_METHOD(SPageNames)
> [id(1)] void Reset();
> [id(2)] boolean Next([out] BSTR* pbstrPageName); // hand editing here
> //}}AFX_ODL_METHOD
>};
>
>
>and coded the function itself as:
>
>BOOL SPageNames::Auto_Next(BSTR* pbstrPageName)
>{
> if(m_posCurrent == NULL)
> return FALSE;
>
> CString strName = m_strlist.GetNext(m_posCurrent);
> BSTR bstrName = strName.AllocSysString();
> pbstrPageName = &bstrName;
> return TRUE;
>}
>
>
>I then call this function from a simple test App (Class wizard
>generated Class from TypeLib to wrap the IDispatch) and the following
>code to exercise the function.
>
>
> ASSERT(pDisp != NULL);
> ISPageNames names;
> names.AttachDispatch(pDisp);
> BSTR bstrName;
> names.Next(&bstrName);
> CString strName = OLE2T(bstrName);
> ::SysFreeString(bstrName);
>
>
>The problem:
>the BSTR returned by names.Next is valid but empty, even though tracing
>through the code of SPageNames::Auto_Next shows that a valid, non-empty
>string is being assigned.
>By a valid BSTR, I mean that the assignment to strName passes off
>without a hitch. Unfortunately the value of strname is an unhelpful
>"";
>
>So, how should I go about passing back information in one of the
>parameters of an automation method?
>
>
>Giles Chamberlin
>Softwright
>
-----From: "Siu-Wang Leung"
Hi:
If you code like the following:
CString strName = m_strlist.GetNext(m_posCurrent);
*pbstrPageName = strName.AllocSysString();
the code will work.
Siu-Wang Leung
-----From: Ian Pepper
Hi Giles
Try the following,
BOOL SPageNames::Auto_Next(BSTR* pbstrPageName)
{
if(m_posCurrent == NULL)
return FALSE;
CString strName = m_strlist.GetNext(m_posCurrent);
*pbstrPageName = strName.AllocSysString();
return TRUE;
}
The problem appears to be in the temporary varaiables assignment
Ian
ian@flexicom.ie
-----From: "Michael J. Morel"
ClassWizard provides you with an option to make a parameter of type =
BSTR*. I'd use that, and not hand-edit anything. Here is a sample =
function that passes a string back to VB via a parameter:
#include
...
BOOL CTestDoc::GetString(BSTR FAR* pbstr)=20
{
USES_CONVERSION;
SysReAllocString(pbstr, T2OLE("Hey!"));
return TRUE;
}
In VB 4.0, my complex processing looks like this:
Dim o As Object
Dim s As String
Dim b As Boolean
Set o =3D CreateObject("Test.Document")
b =3D o.GetString(s)
MsgBox (s)
This works for me. I'm VC 4.2, but that shouldn't matter.
Mike Morel
Mushroom Software
Home of MFC For Yourself
http://www.mushroomsoft.com/mushroom
-----From: "Doug Brubacher"
I think the problem with Giles' code is he is modifying the pointer
pbstrPageName itself, rather then the address it is pointing at.
I've being experimenting with Automation objects and I created a test
method that does almost exactly what he wants, here's my
implementation:
STDMETHODIMP CBlamo::get_Item(long Index, BSTR* pbstr)
{
CString sString;
sString.Format( "Index: %i", Index );
AfxMessageBox( sString );
if (pbstr == NULL)
return E_POINTER;
*pbstr = sString.AllocSysString();
return S_OK;
}
and the IDL definition:
HRESULT Item([in] long Index, [out, retval] BSTR* pbstr);
and here's a snippet from the calling function:
BSTR bsString;
...
hRes = pBlamo->get_Item( iIndex, &bsString );
if ( S_OK == hRes )
{
CString sString( bsString );
plblString->SetWindowText( sString );
}
...
I also do not call SysFreeString. I presume the destructor handles
this automatically when the BSTR goes out of scope, at any rate VC++
does not report any leaks when I run the program.
Regards
Doug Brubacher
| Вернуться в корень Архива
|