VisualCpp.org Collection of Visual C++ Stuffs

15Apr/100

Careful to allocate BSTRs using ::SysAllocString().

Note that code like the following :

BSTR bstr = L"My BSTR";

does not allocate a BSTR.

To allocate a BSTR, you must use ::SysAllocString() :
BSTR bstr = ::SysAllocString(L"My BSTR");

Verify this with a call to ::SysStringByteLen() :
UINT uiLen = ::SysStringByteLen(bstr);

In the first case (using merely L), we get uiLen == 0.

In the second case, (using ::SysAllocString()), we get uiLen == 14 (the size of the string "My BSTR" in unicode.

This is because creating a BSTR via ::SysAllocString() generates a proper BSTR with a preceding 4 byte length indicator placed in the memory location just preceding the actual BSTR data.

Code like L"My BSTR" only creates in memory a Unicode string without any preceding 4 byte length indicator.

- Bio.

28Feb/100

Default and Customized Constructors

  1. A default (no-parameter) constructor is for creating an object with default state.

1.1.    That is, with member data set to default values.

1.2.    The principle behind this is that (by design) such objects can be used immediately after creation.

1.3.   Note that it must make sense to construct an object with default state.

1.4.    There are 2 points to note about code like the following :

  1. some_class instance;

2.1.   This indicates that we want to create an object "instance" of type "some_class" and that "instance" should have default state.

2.2.   If it is deemed acceptable that a "some_class" object, in default state, has member data that can be set to default values, then it does make sense to have "instance" in default state.

2.3.   The compiler requires the definition of a default constructor in order to successfully compile code like the above.

  1. If there are no constructor functions at all for "some_class", it means that we want the compiler to create the default constructor for us. This is not always a good idea because an unsatisfactory constructor may be created for our code.
  2.  If we have at least one non-default constructor for "some_class", but no default constructor for the class, e.g. :

some_class(int i);

This indicates the following :

4.1.   That by design a "some_class" object has no default state.

4.2.   That in order to be constructed properly, parameters must be given in order to sensibly initialize the state of the object.

4.3.   In the case of "some_class", it means that parameter "i" is used to somehow initialize an instance to a meaningful state.

4.4.   In this case, the compiler will not generate any default constructor for "some_class" because by design the class must not have one.

27Feb/100

COM Objects that are created via tags

The following is advise from Brian Muth MVP, taken from the MSDN Forum for Visual C++ Language :

To use the <OBJECT> tag (to create a COM object), the ATL COM object needs to implement the IObjectWithSite interface. This can be done quite trivially, since ATL gives you the IObjectWithSiteImpl<> template. Just add the following line to your list of inherited classes:

public IObjectWithSiteImpl<CMyIeObj>,

and to the BEGIN_COM_MAP table, add:

COM_INTERFACE_ENTRY(IObjectWithSite)

21Feb/100

Internet Explorer with Tabs : Debugging a COM Object or an ActiveX inside a Web Page

The following advise is for Internet Explorers that features tabs :

In order to debug a web page for the purpose of stepping into a COM object or an ActiveX created within HTML code, it is not sufficient to simply start iexplore.exe.

This is because the main IE process may spawn additional iexplore.exe for every tab.

Hence one way to debug into a HTML page is as follows :

  1.  Start IE.
  2.  Load the web page.
  3.  Determine the Process ID (PID) of the iexplore.exe that is hosting the web page.
  4.  Debug into the running process of that iexplore.exe by using the "Attach To Process" facility.
  5.  Refresh the web page.

- Bio.

21Feb/100

The Significance of the "CLSID:" Symbol for the OBJECT Tag's CLASSID Attribute

According to the Web Design Group's web page for the "OBJECT" tag (help) :

The CLASSID attribute may be used to specify an implementation for the object. Java applets, Python applets, and ActiveX controls all provide implementations for the embedded object, and so are specified with the CLASSID attribute...

Some examples of the use of the CLASSID attribute are also listed :

CLASSID="yahtzee.py"
CLASSID="java:Yahtzee.class"

Hence, the string value contained inside a CLASSID attribute need not always specify an ActiveX. It may be anything that can be interpreted by the browser. For example, the "CLSID:" prepending string is interpreted by the IE browser to expect the GUID of an ActiveX control to follow.

20Feb/100

Cool use of the #import inject_statement() attribute

A potentially useful #import attribute is the inject_statement() attribute.

This attribute can be used to insert various statements inside a generated .TLH file.

For example, I was trying to import the EXCEL type library embededd inside EXCEL.EXE. However, this type library required several declarations from MSO.DLL.

What I did was to import both EXCEL.EXE and MSO.DLL and inserted an "#include" statement in the generated EXCEL.TLH file. This was what I did :

#include <windows.h>
#import "C:\Program Files\Common Files\Microsoft Shared\Office10\MSO.DLL"

#import "C:\Program Files\Microsoft Office\Office10\EXCEL.EXE" inject_statement("#include \"MSO.tlh\"") exclude("IRange", "IDummy") raw_interfaces_only

The "inject_statement" attribute led to the following being generated inside EXCEL.TLH :

namespace Excel {

//
// User-injected statements
//

#include "MSO.tlh"
}

Note the comment "User-injected statements" and the #include "MSO.tlh".

Cool.

- Bio.

11Feb/100

Failure of javascript usage of MFC ActiveX Control – Part 4

The following is a continuation of Bio's reply :

Hello Anand,

As promised, the following is my long answer :

Long Answer

1. Unless the value of the CLSID attribute of the OBJECT tag in your HTML code contains the symbol "CLSID:" as in :

<OBJECT classid="CLSID:2D0B18FB-673F-4B90-865F-3EC067C9DEA9" id="a"></OBJECT>

The CLASSID attribute remains invalid and so your ActiveX will not get created.

2. Next, comes the problem with "myobject" :

myobject = new ActiveXObject("SAMPLEACTIVEX.sampleActiveXCtrl.1");

The issue has to do with the calling of the IPersistPropertyBag::InitNew() method of your MFC ActiveX Control. This interface method is called by the MSHTML.DLL code within IExplorer.exe.

3. The IPersistPropertyBag::InitNew() method is implemented for you by MFC via the COleControl::XPersistPropertyBag::InitNew() method. Your MFC class would have been derived from COleControl and so this function is already embedded within your MFC class.

3. Inside COleControl::XPersistPropertyBag::InitNew(), you will notice a call to set COleControl::m_bInitialized to TRUE. This is important as we will see later.

4. Now, when any of your control's methods is called, the JScript engine will first get MSHTML to obtain the ID of your method. This is the essence of late binding. Hence, if MyAdd() is to be invoked, JScript will need to know the ID of the MyAdd() function which in your ActiveX control would be DISPID_MYADD.

5. MSHTML will inquire of your ActiveX the ID of MyAdd() by calling your ActiveX control's IDispatch::GetIDsOfNames() method. This is implemented for you by MFC with the function : COleDispatchImpl::GetIDsOfNames().

6. After obtaining this ID, the IDispatch::Invoke() method will be called. The IDispatch::Invoke() method is implemented for your ActiveX by the COleDispatchImpl::Invoke() method. It is here that your MyAdd() function should get called. However, there is a line within COleDispatchImpl::Invoke() that goes like this :

// allow subclass to disable Invoke

if (!pThis-&gt;IsInvokeAllowed(dispid))

return E_UNEXPECTED;

This is the function COleControl::IsInvokeAllowed() and it is the "archilles tendon" of your problem.

7. Examining COleControl::IsInvokeAllowed() :

BOOL COleControl::IsInvokeAllowed(DISPID)

{

return m_bInitialized;

}

We will note that the state of the COleControl::m_bInitialized, if FALSE, will result in the premature conclusion of the COleDispatchImpl::Invoke() method, resulting in the return of the E_UNEXPECTED HRESULT. This is the cause of the exception in your Javascript.

8. In summary, adding "CLSID:" to the CLASSID attribute of the OBJECT tag is not sufficient. You must use the ActiveX control as declared by the OBJECT tag whose id is "a". The use of the ActiveXObject() function is meant to create and return a COM interface. There are 2 problems with the use of the ActiveXObject() function in relation to your Javascript :

8.1 By declaring "myobject" and then setting it to a new ActiveXObject(), a brand new instance of your ActiveX control will be created. The "a" object will remain but it will not be used. The calling of IPersists* interface methods of your ActiveX control will not be called.

8.2 "myobject" will end up without its COleControl::XPersistPropertyBag::InitNew() ever being called which will result in its COleControl::m_bInitialized remaining FALSE. This results in the COleDispatchImpl::Invoke() function returning E_UNEXPECTED.

Hence my recommendation that you use the "a" object and remove the declaration and use of "myobject".

I hope the above rather long explanation helps.

- Bio.