
ATL ActiveX Control hosting code fails to initialize ActiveX Controls on Win9x
Hello!
Take a look at the following items:
First is an extract from the MSDN Library regarding the WM_CREATE message:
--------------------------------------------------------------------------------
WM_CREATE
The WM_CREATE message is sent when an application requests that a window be created by calling the CreateWindowEx or CreateWindow function. (The message is sent before the function returns.) The window procedure of the new window receives this message after the window is created, but before the window becomes visible.
A window receives this message through its WindowProc function.
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_CREATE
WPARAM wParam, // not used
LPARAM lParam // creation data (LPCREATESTRUCT)
);
Parameters
wParam
This parameter is not used.
lParam
Pointer to a CREATESTRUCT structure that contains information about the window being created.
Return Values
If an application processes this message, it should return zero to continue creation of the window. If the application returns -1, the window is destroyed and the CreateWindowEx or CreateWindow function returns a NULL handle.
Requirements
Windows NT/2000: Requires Windows NT 3.1 or later.
Windows 95/98: Requires Windows 95 or later.
Windows CE: Requires version 1.0 or later.
Header: Declared in winuser.h; include windows.h.
See Also
Windows Overview, Window Messages, CreateWindow, CreateWindowEx, CREATESTRUCT, WM_NCCREATE
Built on Wednesday, August 18, 1999
Requirements
Windows NT/2000: Requires Windows NT 3.1 or later.
Windows 95/98: Requires Windows 95 or later.
Windows CE: Requires version 1.0 or later.
Header: Declared in winuser.h; include windows.h.
See Also
--------------------------------------------------------------------------------
Following the link to CREATESTRUCT you end up in the following text:
--------------------------------------------------------------------------------
CREATESTRUCT
The CREATESTRUCT structure defines the initialization parameters passed to the window procedure of an application. These members are identical to the parameters of the CreateWindowEx function.
typedef struct tagCREATESTRUCT {
LPVOID lpCreateParams;
HINSTANCE hInstance;
HMENU hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPCTSTR lpszName;
LPCTSTR lpszClass;
DWORD dwExStyle;
Quote:
} CREATESTRUCT, *LPCREATESTRUCT;
Members
lpCreateParams
Contains additional data which may be used to create the window. If the window is being created as a result of a call to the CreateWindow or CreateWindowEx function, this member contains the value of the lpParam parameter specified in the function call.
If the window being created is an MDI window, this member contains a pointer to an MDICREATESTRUCT structure.
Windows NT/2000: If the window is being created from a dialog template, this member is the address of a SHORT value that specifies the size, in bytes, of the window creation data. The value is immediately followed by the creation data. For more information, see the following Remarks section.
hInstance
Handle to the module that owns the new window.
hMenu
Handle to the menu to be used by the new window.
hwndParent
Handle to the parent window, if the window is a child window. If the window is owned, this member identifies the owner window. If the window is not a child or owned window, this member is NULL.
cy
Specifies the height of the new window, in pixels.
cx
Specifies the width of the new window, in pixels.
y
Specifies the y-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.
x
Specifies the x-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.
style
Specifies the style for the new window.
lpszName
Pointer to a null-terminated string that specifies the name of the new window.
lpszClass
Pointer to a null-terminated string that specifies the class name of the new window.
dwExStyle
Specifies the extended window style for the new window.
Remarks
Windows NT/2000: You should access the data represented by the lpCreateParams member using a pointer that has been declared using the UNALIGNED type, because the pointer may not be DWORD aligned. This is demonstrated in the following example:
typedef struct tagMyData
{
// Define creation data here.
Quote:
} MYDATA;
typedef struct tagMyDlgData
{
SHORT cbExtra;
MYDATA myData;
Quote:
} MYDLGDATA, UNALIGNED *PMYDLGDATA;
PMYDLGDATA pMyDlgdata =
(PMYDLGDATA) (((LPCREATESTRUCT) lParam)->lpCreateParams);
Requirements
Windows NT/2000: Requires Windows NT 3.1 or later.
Windows 95/98: Requires Windows 95 or later.
Windows CE: Requires version 1.0 or later.
Header: Declared in winuser.h; include windows.h.
Unicode: Declared as Unicode and ANSI structures.
See Also
Windows Overview, Window Structures, CreateWindow, CreateWindowEx, MDICREATESTRUCT
Built on Wednesday, August 18, 1999
Requirements
Windows NT/2000: Requires Windows NT 3.1 or later.
Windows 95/98: Requires Windows 95 or later.
Windows CE: Requires version 1.0 or later.
Header: Declared in winuser.h; include windows.h.
Unicode: Declared as Unicode and ANSI structures.
See Also
Windows Overview, Window Structures, CreateWindow, CreateWindowEx, MDICREATESTRUCT
--------------------------------------------------------------------------------
Note carefully the text about Win2000/NT in the paragraph about the lpCreateParams item. So on Win9x this item directly points at the creation data, but on NT this item points 2 bytes before the creation data.
Now, consider the following code taken from ATL 3.0 Visual Studo 6.0 SP3 file ATLHOST.H:
static LRESULT CALLBACK AtlAxWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
// create control from a PROGID in the title
// This is to make sure drag drop works
::OleInitialize(NULL);
CREATESTRUCT* lpCreate = (CREATESTRUCT*)lParam;
int nLen = ::GetWindowTextLength(hWnd);
LPTSTR lpstrName = (LPTSTR)_alloca((nLen + 1) * sizeof(TCHAR));
::GetWindowText(hWnd, lpstrName, nLen + 1);
::SetWindowText(hWnd, _T(""));
IAxWinHostWindow* pAxWindow = NULL;
int nCreateSize = 0;
if (lpCreate && lpCreate->lpCreateParams)
nCreateSize = *((WORD*)lpCreate->lpCreateParams);
HGLOBAL h = GlobalAlloc(GHND, nCreateSize);
CComPtr<IStream> spStream;
if (h && nCreateSize)
{
BYTE* pBytes = (BYTE*) GlobalLock(h);
BYTE* pSource = ((BYTE*)(lpCreate->lpCreateParams)) + sizeof(WORD);
// Align to DWORD
// pSource += (((~((DWORD)pSource)) + 1) & 3);
memcpy(pBytes, pSource, nCreateSize);
GlobalUnlock(h);
CreateStreamOnHGlobal(h, TRUE, &spStream);
}
USES_CONVERSION;
CComPtr<IUnknown> spUnk;
The red marked code indicates that this code only works on NT. The code always assumes that the creation data is preceeded by a WORD. Instead the following code, or something similar should be used:
...
// Determine current operation system platform
OSVERSIONINFO os;
ZeroMemory(&os, sizeof(os));
os.dwOSVersionInfoSize = sizeof(os);
::GetVersionEx(&os);
if(os.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
// NT: pCreationData points at the size of the creation data
BYTE* pSource = ((BYTE*)(lpCreate->lpCreateParams)) + sizeof(WORD);
}
else
{
// Win9x: pCreationData points directly at the creation data
BYTE* pSource = ((BYTE*)(lpCreate->lpCreateParams));
}
...
Patrik Pettersson
Caesar Business Systems AB