• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 843
  • Last Modified:

MFC ActiveX Control, Trying to Pass String By Reference

Hello All,

I am writing an ActiveX Control in MFC I use the easiest method of class wizard for adding methods to COM Interface, anyway, I want to pass a string byref from my VB.net app to MFC ActiveX Control method.

I would like to know how can I accomplish this I can very easily pass integers and other variables but not Strings by ref, I achieved passing Strings by Val by using BSTR as a method typem but when using BSTR* it says Type Mismatch, I tried using VARIANT Type the MFC Method do recieved the value but when I try to modify it, it doesnt return the modified value, now I tried VARIANT* and that also gives type mismatch.

I need help. Moreover if u can tell me how to convert WCHAR to BSTR I have fixed length WCHAR array and I want to convert it to BSTR.

If any one of you knows about a resource which would be helpful in letting me know about all possible types going to MFC ActiveX from VB and viceversa I would be very thankful again.

Regards,
Rizwan
0
syedrizwanm
Asked:
syedrizwanm
  • 11
  • 7
1 Solution
 
nonubikCommented:
>Moreover if u can tell me how to convert WCHAR to BSTR

BSTR mybstr = ::SysAllocString(mywchar);

> but when using BSTR* it says Type Mismatch
Where does it say? Please post both the ActiveX COM method and the VB call.
0
 
syedrizwanmAuthor Commented:
the method is declared in ActiveX com as: testString(BSTR* aString){} it is same in the Header File and the IDL file as well.

when I call it from my vb.net application it is like:
Dim devID as string
dp2.testString(devID) <<--- this is where it gives type mismatch. If I change the testString Parameter to BSTR aString it works.
0
 
syedrizwanmAuthor Commented:
This is the MFC Class Code:

void CcustStringTestCtrl::testMethod(BSTR* aString)
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState());

      // TODO: Add your dispatch handler code here
}

This is the Dispatch MAP for this method
DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_EMPTY, VTS_PBSTR)

This is the IDL Declaration:
[id(2), helpstring("method testMethod")] void testMethod(BSTR* aString);

this is the VB CODE:

Dim xp As String
xp = "Rizwan"
dp2.testMethod (xp) 'dp2 is the object Name for the ActiveX Control also this line causes the error Type Mismatch

Any ideas?

Regards,
Rizwan
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
nonubikCommented:
Try this:

In IDL
 [id(2), helpstring("method testMethod")] void testMethod([in] BSTR inString, [out, retval] BSTR* outString);

So, in VB the function will be
 Public Function testMethod (inString AS String) As String

And you can pass the inString to COM, it will modify it and retunr it as the outString

Dim xp As String
xp = "Rizwan"
xp = dp2.testMethod (xp)
0
 
syedrizwanmAuthor Commented:
Should I also make any changes to the CPP, Header and IDL file for that method? I mean the signature, or should I leave them as it is and change only the IDL file, u sure that I dont even need to modify the dispatch map?
0
 
nonubikCommented:
Of course, you need to modify all accordingly:

//.cpp

void CcustStringTestCtrl::testMethod(BSTR inString, BSTR* outString)
{
     AFX_MANAGE_STATE(AfxGetStaticModuleState());

     //*outString = inString;
}

//.h

void testMethod(BSTR, BSTR *);

..etc
0
 
syedrizwanmAuthor Commented:
What about the Dispatch MAP how to modify it?

This is the Dispatch MAP for this method
DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_EMPTY, VTS_PBSTR)

Thanx
0
 
nonubikCommented:
Try:
DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_EMPTY, VTS_BSTR VTS_PBSTR)
0
 
syedrizwanmAuthor Commented:
not working it says argument not optional. and when I tried it with VTS_PBSTR it shows garbae in the message box which I have placed in the method and displayes an error that IDispatch.... failed I guess this is coz of the lines accessing outString.

THisi s the new Code:
void CcustStringTestCtrl::testMethod(BSTR inString,BSTR *outString)
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState());
USES_CONVERSION;
      // TODO: Add your dispatch handler code here
      MessageBox (OLE2T(inString));
      CComBSTR tmp = ::SysAllocString(L"Hello World");
      outString=(BSTR *)tmp.Detach ();
}

It was atleast displaying the inString value in the message box when I modified only the IDL and didnt modify the Implementation or Declarator
0
 
nonubikCommented:
VTS_BSTR VTS_PBSTR

This is a space-separated list of values of VTS_ constants. One or more of these values separated by spaces (not commas) specifies the function's parameter list
0
 
syedrizwanmAuthor Commented:
yeah I did that already its not working it is saying Argument not Optional when I call it from VB even though the VB Intellisense shows only one parameter i.e. inString
0
 
nonubikCommented:
DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_BSTR, VTS_BSTR) ?
0
 
syedrizwanmAuthor Commented:
its like this right now: DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_EMPTY, VTS_PBSTR)
and it is displaying garbase on messagebox and an error after that

when I modified that line to: DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_EMPTY, VTS_BSTR VTS_PBSTR)

it gave me the error Argument not optional when I called it from VB.

0
 
syedrizwanmAuthor Commented:
// custStringTestCtrl.cpp : Implementation of the CcustStringTestCtrl ActiveX Control class.

#include "stdafx.h"
#include "custStringTest.h"
#include "custStringTestCtrl.h"
#include "custStringTestPpg.h"
#include ".\custstringtestctrl.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


IMPLEMENT_DYNCREATE(CcustStringTestCtrl, COleControl)



// Message map

BEGIN_MESSAGE_MAP(CcustStringTestCtrl, COleControl)
      ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()



// Dispatch map

BEGIN_DISPATCH_MAP(CcustStringTestCtrl, COleControl)
      DISP_FUNCTION_ID(CcustStringTestCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
      DISP_FUNCTION_ID(CcustStringTestCtrl, "testString", dispidtestString, testString, VT_EMPTY, VTS_BSTR)
      DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_EMPTY, VTS_BSTR VTS_PBSTR)
      //DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_BSTR, VTS_BSTR)
END_DISPATCH_MAP()



// Event map

BEGIN_EVENT_MAP(CcustStringTestCtrl, COleControl)
END_EVENT_MAP()



// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CcustStringTestCtrl, 1)
      PROPPAGEID(CcustStringTestPropPage::guid)
END_PROPPAGEIDS(CcustStringTestCtrl)



// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CcustStringTestCtrl, "CUSTSTRINGTEST.custStringTestCtrl.1",
      0xdecf8aa8, 0x9a0b, 0x4a6b, 0x94, 0xab, 0x96, 0xec, 0x4, 0xc, 0x64, 0x80)



// Type library ID and version

IMPLEMENT_OLETYPELIB(CcustStringTestCtrl, _tlid, _wVerMajor, _wVerMinor)



// Interface IDs

const IID BASED_CODE IID_DcustStringTest =
            { 0x215693B7, 0x8D5A, 0x48CC, { 0x85, 0xD3, 0x38, 0x49, 0xFA, 0xF5, 0x6C, 0x63 } };
const IID BASED_CODE IID_DcustStringTestEvents =
            { 0x3ECE0E28, 0x3682, 0x4B1C, { 0x92, 0x44, 0x78, 0x40, 0xDE, 0x7B, 0xA2, 0xAD } };



// Control type information

static const DWORD BASED_CODE _dwcustStringTestOleMisc =
      OLEMISC_ACTIVATEWHENVISIBLE |
      OLEMISC_SETCLIENTSITEFIRST |
      OLEMISC_INSIDEOUT |
      OLEMISC_CANTLINKINSIDE |
      OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CcustStringTestCtrl, IDS_CUSTSTRINGTEST, _dwcustStringTestOleMisc)



// CcustStringTestCtrl::CcustStringTestCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CcustStringTestCtrl

BOOL CcustStringTestCtrl::CcustStringTestCtrlFactory::UpdateRegistry(BOOL bRegister)
{
      // TODO: Verify that your control follows apartment-model threading rules.
      // Refer to MFC TechNote 64 for more information.
      // If your control does not conform to the apartment-model rules, then
      // you must modify the code below, changing the 6th parameter from
      // afxRegApartmentThreading to 0.

      if (bRegister)
            return AfxOleRegisterControlClass(
                  AfxGetInstanceHandle(),
                  m_clsid,
                  m_lpszProgID,
                  IDS_CUSTSTRINGTEST,
                  IDB_CUSTSTRINGTEST,
                  afxRegApartmentThreading,
                  _dwcustStringTestOleMisc,
                  _tlid,
                  _wVerMajor,
                  _wVerMinor);
      else
            return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}



// CcustStringTestCtrl::CcustStringTestCtrl - Constructor

CcustStringTestCtrl::CcustStringTestCtrl()
{
      InitializeIIDs(&IID_DcustStringTest, &IID_DcustStringTestEvents);
      // TODO: Initialize your control's instance data here.
}



// CcustStringTestCtrl::~CcustStringTestCtrl - Destructor

CcustStringTestCtrl::~CcustStringTestCtrl()
{
      // TODO: Cleanup your control's instance data here.
}



// CcustStringTestCtrl::OnDraw - Drawing function

void CcustStringTestCtrl::OnDraw(
                  CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
      if (!pdc)
            return;

      // TODO: Replace the following code with your own drawing code.
      pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
      pdc->Ellipse(rcBounds);
}



// CcustStringTestCtrl::DoPropExchange - Persistence support

void CcustStringTestCtrl::DoPropExchange(CPropExchange* pPX)
{
      ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
      COleControl::DoPropExchange(pPX);

      // TODO: Call PX_ functions for each persistent custom property.
}



// CcustStringTestCtrl::OnResetState - Reset control to default state

void CcustStringTestCtrl::OnResetState()
{
      COleControl::OnResetState();  // Resets defaults found in DoPropExchange

      // TODO: Reset any other control state here.
}



// CcustStringTestCtrl::AboutBox - Display an "About" box to the user

void CcustStringTestCtrl::AboutBox()
{
      CDialog dlgAbout(IDD_ABOUTBOX_CUSTSTRINGTEST);
      dlgAbout.DoModal();
}



// CcustStringTestCtrl message handlers

void CcustStringTestCtrl::testString(LPCTSTR aString)
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState());

      // TODO: Add your dispatch handler code here
      MessageBox(aString);
}

void CcustStringTestCtrl::testMethod(BSTR inString,BSTR *outString)
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState());
USES_CONVERSION;
      // TODO: Add your dispatch handler code here
      MessageBox (OLE2T(inString));
      CComBSTR tmp = ::SysAllocString(L"Hello World");
      outString=(BSTR *)tmp.Detach ();
}

#pragma once

// custStringTestCtrl.h : Declaration of the CcustStringTestCtrl ActiveX Control class.


// CcustStringTestCtrl : See custStringTestCtrl.cpp for implementation.

class CcustStringTestCtrl : public COleControl
{
      DECLARE_DYNCREATE(CcustStringTestCtrl)

// Constructor
public:
      CcustStringTestCtrl();

// Overrides
public:
      virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
      virtual void DoPropExchange(CPropExchange* pPX);
      virtual void OnResetState();

// Implementation
protected:
      ~CcustStringTestCtrl();

      DECLARE_OLECREATE_EX(CcustStringTestCtrl)    // Class factory and guid
      DECLARE_OLETYPELIB(CcustStringTestCtrl)      // GetTypeInfo
      DECLARE_PROPPAGEIDS(CcustStringTestCtrl)     // Property page IDs
      DECLARE_OLECTLTYPE(CcustStringTestCtrl)            // Type name and misc status

// Message maps
      DECLARE_MESSAGE_MAP()

// Dispatch maps
      DECLARE_DISPATCH_MAP()

      afx_msg void AboutBox();

// Event maps
      DECLARE_EVENT_MAP()

// Dispatch and event IDs
public:
      enum {
            dispidtestMethod = 2L,            dispidtestString = 1L
      };
protected:
      void testString(LPCTSTR aString);
      void testMethod(BSTR inString,BSTR *outString);
};

// custStringTest.idl : type library source for ActiveX Control project.

// This file will be processed by the MIDL compiler tool to
// produce the type library (custStringTest.tlb) that will become a resource in
// custStringTest.ocx.

#include <olectl.h>
#include <idispids.h>

[ uuid(61F35562-C36E-4117-8B68-3BA7F8D10056), version(1.0),
  helpfile("custStringTest.hlp"),
  helpstring("custStringTest ActiveX Control module"),
  control ]
library custStringTestLib
{
      importlib(STDOLE_TLB);

      //  Primary dispatch interface for CcustStringTestCtrl

      [ uuid(215693B7-8D5A-48CC-85D3-3849FAF56C63),
        helpstring("Dispatch interface for custStringTest Control")]
      dispinterface _DcustStringTest
      {
            properties:
            methods:

                  [id(DISPID_ABOUTBOX)] void AboutBox();
                  [id(1), helpstring("method testString")] void testString(BSTR aString);
                  [id(2), helpstring("method testMethod")] void testMethod([in] BSTR inString, [out, retval] BSTR* outString);
      };

      //  Event dispatch interface for CcustStringTestCtrl

      [ uuid(3ECE0E28-3682-4B1C-9244-7840DE7BA2AD),
        helpstring("Event interface for custStringTest Control") ]
      dispinterface _DcustStringTestEvents
      {
            properties:
                  //  Event interface has no properties

            methods:
      };

      //  Class information for CcustStringTestCtrl

      [ uuid(DECF8AA8-9A0B-4A6B-94AB-96EC040C6480),
        helpstring("custStringTest Control"), control ]
      coclass custStringTest
      {
            [default] dispinterface _DcustStringTest;
            [default, source] dispinterface _DcustStringTestEvents;
      };

};

Private Sub Form_Load()
Dim xp As String
xp = "asdasd"
dp2.testMethod xp
MsgBox xp
End Sub

Now tell me what needs a change?
0
 
nonubikCommented:
Obviously there's something wrong on the VB side, the VC++ side looks very fine.

But I'm not skilled in VB, so let's try to make the method receive one BSTR param end return another.

[id(2), helpstring("method testMethod")] BSTR testMethod([in] BSTR inString); //idl

DISP_FUNCTION_ID(CcustStringTestCtrl, "testMethod", dispidtestMethod, testMethod, VT_BSTR, VTS_BSTR)

BSTR CcustStringTestCtrl::testMethod(BSTR inString) //cpp
{
...

BSTR testMethod(BSTR); //h
0
 
syedrizwanmAuthor Commented:
yup the recieving and sending stuff works fine I generated new methods to test it and its is working A OK:

Private Sub Form_Load()
Dim xp As String
xp = "Rizwan"
MsgBox dp2.testReturnString(xp)

End Sub

BSTR CcustStringTestCtrl::testReturnString(LPCTSTR aString)
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState());

      CString *strResult=new CString(aString);

      // TODO: Add your dispatch handler code here

      return strResult->AllocSysString();
}

DISP_FUNCTION_ID(CcustStringTestCtrl, "testReturnString", dispidtestReturnString, testReturnString, VT_BSTR, VTS_BSTR)

[id(3), helpstring("method testReturnString")] BSTR testReturnString(BSTR aString);

its working good.

But I want to return by Ref, as I said that passing in is working fine, I actually have methods which return ErrorCodes on return and I need to pass a name of a device to VB Now I am seriously thinking to pass it as an Array of Int32.
0
 
syedrizwanmAuthor Commented:
OK, tellme one thing when taking the String as Input it gives LPCTSTR aString
which means I can access aString[0]='X'; cant I? if I can then what if I make modifications using this method. I can pass a fixed string empty buffer from VB. and modify each item like that Would it work?
0
 
syedrizwanmAuthor Commented:
Success at last, found a solution at MS Knowledgebase but that wasnt complete either so if any one else is looking for a solution to this problem they must look forward to doing this:

void CcustStringTestCtrl::testVP(VARIANT* str)
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState());
USES_CONVERSION;
      // TODO: Add your dispatch handler code here
      str->vt=VT_BSTR;
      str->bstrVal=::SysAllocString(L"Hello World");
      MessageBox(OLE2T(str->bstrVal ));
}

Private Sub Form_Load()
Dim xp 'As String Do no declare the variable with type string otherwise you will recieve a nice Type Mismatch error
xp = "klasdhfklhaskldfhklahdfklahsklfhakl"
dp2.testVP xp
MsgBox xp
End Sub
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 11
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now