Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CreateWindowEx AtlAxWin fails with last error 1407

486 views
Skip to first unread message

David Liebtag

unread,
Oct 26, 2007, 12:12:05 PM10/26/07
to
I do this:

LPCTSTR AtlClassName;
AtlAxWinInit();
AtlClassName = CAxWindow::GetWndClassName();
Control =
CreateWindowExA(ExStyle,AtlClassName,"MSCAL.Calendar",Style,x,y,cx,cy,Parent,Id,GetModuleHandle(NULL),CtlData);

CreateWindowEx returns zero and GetLastError returns
ERROR_CANNOT_FIND_WND_CLASS.

CAxWindow::GetWndClassName() returns "AtlAxWin71". I have tried hard coding
AtlAxWin, AtlAxWin7, AtlAxWin71, AtlAxWin8, and AtlAxWin80. They all yield
the same result.

I am using Microsoft Visual C++ .NET 69462-270-0000007-18234 on Windows XP
with service pack 2.

Can anyone explain why I'm getting window class not found?

Thanks a lot.

David Liebtag
IBM APL Products and Services


David Liebtag

unread,
Oct 26, 2007, 12:26:46 PM10/26/07
to
I discovered that the AtlAxWin71 window class is found if in the call to
CreateWindowEx I use the instance handle of the DLL from which I called
AtlAxWinInit and CAxWindow::GetWndClassName(). However, I then see these
error messages in my console window:

Control creation failed for 'MSCAL.Calendar'
Error code: 0x8007000e - Not enough storage is available to complete this
operation.

And CreateWindowEx then returns zero.

Can anyone suggest what I need to do to get this to work?

I'm trying to create an ATL container as a child of a normal Win32 dialog.
Should this work?

Igor Tandetnik

unread,
Oct 26, 2007, 4:37:12 PM10/26/07
to
David Liebtag <DavidL...@vermontel.net> wrote:
> LPCTSTR AtlClassName;
> AtlAxWinInit();
> AtlClassName = CAxWindow::GetWndClassName();
> Control =
> CreateWindowExA(ExStyle,AtlClassName,"MSCAL.Calendar",Style,x,y,cx,cy,Parent,Id,GetModuleHandle(NULL),CtlData);

Why don't you just use CAxWindow::Create? See also KB article KB218442
"How to add ActiveX controls to an ATL composite control
programmatically in Visual C++". Ignore "to composite control" part -
all you need is an HWND to serve as the parent window.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925


David Liebtag

unread,
Oct 29, 2007, 10:13:14 AM10/29/07
to
> Why don't you just use CAxWindow::Create?

Several reasons:

1) Because I am trying to add support for ActiveX to a program which already
uses CreateWindoEx for adding other types of controls to dialogs.
2) Because the portion of the program that adds controls is written in C
rather than C++
3) Because the documentation states either method should work
4) Because the technique you suggest doesn't work any better.

I tried using a simple program I found elsewhere on the web. Both
techniques hit an exception trying to read from address 000000. I attached
the program below.

I assume I must be doing something incorrectly, but I can't figure out what.
Can you?

David Liebtag

#include <windows.h>
#pragma comment(lib, "atl.lib")
#include <atlbase.h>
#include <atldef.h>
#include <atlhost.h>
#include <atlwin.h>
#define APP "My Class"
#define IDC_MYCTL 35
LRESULT CALLBACK MyWindowProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,PSTR sxCommand,int
iShow)
{
WNDCLASSEX myWindow;
myWindow.cbClsExtra = 0;
myWindow.cbSize = sizeof(myWindow);
myWindow.cbWndExtra = 0;
myWindow.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
myWindow.hCursor = LoadCursor(NULL,IDC_ARROW);
myWindow.hIcon = LoadIcon(NULL,IDI_APPLICATION);
myWindow.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
myWindow.hInstance = hInst;
myWindow.lpfnWndProc = MyWindowProc;
myWindow.lpszClassName = APP;
myWindow.lpszMenuName = NULL;
myWindow.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&myWindow);
AtlAxWinInit();
HWND hWnd;
hWnd = CreateWindow(APP,"AtlAxWin Test",WS_OVERLAPPEDWINDOW,0,0,640,480,
NULL,NULL,hInst,NULL);
if(hWnd)
{
CAxWindow wnd;
RECT rect = {10,10,400,300};
// hWnd is the composite control handle
// rect is the size of ActiveX control in client coordinates
wnd.Create(hWnd, rect, _T("MSCAL.Calendar"), WS_CHILD| WS_VISIBLE,
0,IDC_MYCTL) ;
#if FALSE
HWND hWndX = CreateWindow("AtlAxWin71","http://www.google.com"
,WS_CHILD|WS_VISIBLE ,0,0,50,50 ,hWnd,NULL,hInst,NULL );
if(hWndX == 0)
{
char Message[1024] ;
sprintf(Message,"CreateWindow AtlAxWin failed. Last error:
%li",GetLastError()) ;
MessageBox(hWnd,Message,"AtlTest Message",MB_OK) ;
}
else
#endif
{
ShowWindow(hWnd, iShow);
UpdateWindow(hWnd);

MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

AtlAxWinTerm();
return 0 ;
}

LRESULT CALLBACK MyWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
lParam)
{
switch(msg)
{
case WM_CREATE:
{
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
return 0;
}
case WM_SIZE:
{
RECT clientRect;
GetClientRect(hWnd, &clientRect);
SetWindowPos(hWndX,HWND_TOP,0,0,clientRect.right,clientRect.bottom,SWP_NOZORDER);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}


Igor Tandetnik

unread,
Oct 29, 2007, 1:09:25 PM10/29/07
to
David Liebtag <DavidL...@vermontel.net> wrote:
> I tried using a simple program I found elsewhere on the web. Both
> techniques hit an exception trying to read from address 000000. I
> attached the program below.
>
> I assume I must be doing something incorrectly, but I can't figure
> out what. Can you?

Add these two lines to any source file in your project:

class CDummyModule : public CAtlExeModuleT<CDummyModule> {};
CDummyModule _Module;

With these, your test program works (after a few small fixes to get it
to compile).

David Liebtag

unread,
Oct 29, 2007, 2:17:42 PM10/29/07
to
Thanks but,,,

When I add these two lines the wnd.Create technique does not hit an
exception, but the calendar control is not visible in the child container.

The CreateWindow technique returns zero with last error also zero when I use
MSCAL.Calendar as the control class. When I use a URL, I get a Debug
Assertion Failed message box that asks me if I forgot to pass LIBID to
CComModule::Init.

David Liebtag


Igor Tandetnik

unread,
Oct 29, 2007, 2:42:22 PM10/29/07
to
David Liebtag <DavidL...@vermontel.net> wrote:
> When I add these two lines the wnd.Create technique does not hit an
> exception, but the calendar control is not visible in the child
> container.

Works for me. Your WM_SIZE handler needed work (it referes to hWndX
variable that wasn't defined), but that fixed, I do see calendar control
in your test program.

> The CreateWindow technique returns zero with last error also zero
> when I use MSCAL.Calendar as the control class. When I use a URL, I
> get a Debug Assertion Failed message box that asks me if I forgot to
> pass LIBID to CComModule::Init.

Right, you need two more changes. First, call CoInitialize(0) somewhere
at the beginning of WinMain (and CoUninitialize at the end for
completeness). CAxWindow::Create happens to call it, so that's why it
works.

Second, change the module declaration to this:

class CDummyModule : public CAtlExeModuleT<CDummyModule> {

public:
DECLARE_LIBID(LIBID_ATLLib);
};
CDummyModule _Module;

With these changes, CreateWindow-based path works for me in your test,
both for Calendar and for WebBrowser.

David Liebtag

unread,
Oct 29, 2007, 8:19:22 PM10/29/07
to
Superb! Thank you Igor!

David Liebtag


David Liebtag

unread,
Oct 30, 2007, 4:51:44 PM10/30/07
to
Igor,

One more question please:

Am I correct that If I want to use AtlAxWin to host a licensed control, I
have to create the control myself? If so, does the approach in this
pseudocode seem reasonable:

AtlAxWinInit();
AtlClassName = CAxWindow2::GetWndClassName();
Host =
CreateWindowExA(ExStyle,AtlClassName,"",Style,x,y,cx,cy,Parent,Id,GetModuleHandle(NULL),CtlData);
AtlAxCreateControlLic("MSCAL.Calendar",Host,"License");

Igor Tandetnik

unread,
Oct 30, 2007, 5:19:34 PM10/30/07
to
David Liebtag <DavidL...@vermontel.net> wrote:
> Am I correct that If I want to use AtlAxWin to host a licensed
> control, I have to create the control myself?

You can do it the same way you did with unlicensed control. Just use
CAxWindow2::GetWndClassName() for the class name, and the license key
can be passed via the last parameter to CreateWindow. See the comment
inside AtlAxWindowProc2 in <atlhost.h> for the exact format of the data
this parameter should point to (the comment is slightly wrong:
nCreateSize is WORD, not int).

David Liebtag

unread,
Oct 30, 2007, 10:54:52 PM10/30/07
to
I find the comments in AtlAxWindowProc2 quite confusing. Can you direct me
to any sample code that uses AtlAxWinLicX?

Thank you.

David


Igor Tandetnik

unread,
Oct 31, 2007, 8:18:41 AM10/31/07
to
"David Liebtag" <DavidL...@vermontel.net> wrote in message
news:O72dql2G...@TK2MSFTNGP02.phx.gbl

> I find the comments in AtlAxWindowProc2 quite confusing. Can you
> direct me to any sample code that uses AtlAxWinLicX?

You do something like this:

struct CreateData {
WORD nCreateSize;
WORD nMsg;
DWORD dwLen;
DWORD cchLicKey;
};
BSTR licKey = ...; // the license key you want to provide
DWORD cchLicKey = SysStringLen(licKey);

WORD size = sizeof(CreateData) + cchLicKey;
BYTE* buf = new BYTE[size];
CreateData* data = reinterpret_cast<CreateData*>(buf);
data.nCreateSize = size;
data.nMsg = 0;
data.dwLen = 0;
data.cchLicKey = cchLicKey;
memcpy(buf + sizeof(CreateData), licKey, cchLicKey * sizeof(OLECHAR));

CreateWindow(CAxWindow2::GetWndClassName(), ..., buf);
delete[] buf;

David Liebtag

unread,
Oct 31, 2007, 10:49:58 AM10/31/07
to
Igor,

Are you sure? Is that code you copied from a working program?

When I read atlwin.h's _DialogSplitHelper::ParseInitData, it looks to me
like nMsg must be ATL_WM_OCC_LOADFROMSTREAM.

When I read atlhost.h's AtlAxWindowProc2's WM_CREATE clause that creates the
stream to pass to _DialogSplitHelper::ParseInitData, it looks to me like
nCreateSize should not include itself and so should be sizeof(WORD) smaller
than you show.

Whether or not I subtract sizeof(WORD), when I try to use a zero length
license key, ATL sends this message to the console:

Error code: 0x8000ffff - Catastrophic failure

Is that normal? Can I use a zero length license key to indicate no license?
Or, must I not pass create parameters for the no license case?

Thanks.

David Liebtag


Igor Tandetnik

unread,
Oct 31, 2007, 11:19:00 AM10/31/07
to
David Liebtag <DavidL...@vermontel.net> wrote:
> Are you sure? Is that code you copied from a working program?

No, I haven't actually tested it (yes, I'm lazy like that). I
reverse-engineered this code from _DialogSplitHelper::ParseInitData.

> When I read atlwin.h's _DialogSplitHelper::ParseInitData, it looks to
> me like nMsg must be ATL_WM_OCC_LOADFROMSTREAM.

Yes, you are right. nMsg does need to be ATL_WM_OCC_LOADFROMSTREAM,
otherwise ParseInitData would always return E_FAIL.

> When I read atlhost.h's AtlAxWindowProc2's WM_CREATE clause that
> creates the stream to pass to _DialogSplitHelper::ParseInitData, it
> looks to me like nCreateSize should not include itself and so should
> be sizeof(WORD) smaller than you show.

Yes, this does seem to be the case.

So, with these comments, change the code to

struct CreateData {
WORD nCreateSize;
WORD nMsg;
DWORD dwLen;
DWORD cchLicKey;
};
BSTR licKey = ...; // the license key you want to provide
DWORD cchLicKey = SysStringLen(licKey);

WORD size = sizeof(CreateData) + cchLicKey;
BYTE* buf = new BYTE[size];
CreateData* data = reinterpret_cast<CreateData*>(buf);

data.nCreateSize = size - sizeof(WORD);
data.nMsg = ATL_WM_OCC_LOADFROMSTREAM;

David Liebtag

unread,
Oct 31, 2007, 11:57:21 AM10/31/07
to
Igor,

That's what I had already done. Thanks for confirming I'm not misreading the
atl header files.

BTW As I said, it doesn't work if I pass a zero length license for
unlicensed controls. Apparently, the call to AtlAxCreateControlLicin
AtlAxWindowProc2 fails with a zero length license. I guess I'll have to
special case the situation and not pass creation data then.

One more final dumb question,,,

Do you know if XP or VS includes a licensed control I can test this with?

Thanks again.

David


Igor Tandetnik

unread,
Oct 31, 2007, 12:19:35 PM10/31/07
to
David Liebtag <DavidL...@vermontel.net> wrote:
> That's what I had already done. Thanks for confirming I'm not
> misreading the atl header files.
>
> BTW As I said, it doesn't work if I pass a zero length license for
> unlicensed controls. Apparently, the call to AtlAxCreateControlLicin
> AtlAxWindowProc2 fails with a zero length license. I guess I'll have
> to special case the situation and not pass creation data then.

Looking at the code, I don't see why passing a zero-length license
shouldn't work. Have you traced into AtlAxCreateControlLic and figured
out where precisely it fails? As far as I can tell, it should eventually
reach CreateNormalizedObject in althost.h, where a NULL license would
result in a plain vanilla CoCreateInstance call.

> Do you know if XP or VS includes a licensed control I can test this
> with?

I believe all Forms 2.0 controls are licensed (they have ProgIds like
Forms.* , e.g. Forms.CommandButton.1) . You likely have a machine
license for these though (installed as part of Visual Studio), so on
your dev machine they can be created without a license. You would have
to test on a clean machine.

David Liebtag

unread,
Jan 18, 2008, 8:38:33 PM1/18/08
to
Igor,

I'm finally back to working on testing the support for ActiveX licensing in
my scripting language. I've traced through the ATL code and my license
string seems to be getting processed correctly. However, it is being
rejected when it is passed to IClassFactory2's CreateInstaceLic method on
line 119 of AtlHost.h. I think I must have the format of the license string
incorrect.

I looked in the vb6controls.reg file and found the following registry data:

// FlexGrid Control 6.0 license key
HKEY_CLASSES_ROOT\Licenses\ABCDEF567ABCD-11cf-91F6-C24434543F45 =
idfsdfrwesdfsdfgdfggdsdjfhdsjfssdjmf

(I changed the data in this post to protect the innocent. :-)

Given that I know this is the correct license data, do you know the correct
format for placing the data in the BSTR I pass to ATL?

I have tried:

"ABCDEF567ABCD-11cf-91F6-C24434543F45 =
idfsdfrwesdfsdfgdfggdsdjfhdsjfssdjmf"
"ABCDEF567ABCD-11cf-91F6-C24434543F45"
"idfsdfrwesdfsdfgdfggdsdjfhdsjfssdjmf"

Igor Tandetnik

unread,
Jan 18, 2008, 9:50:26 PM1/18/08
to
"David Liebtag" <DavidL...@vermontel.net> wrote in message
news:e12KCwjW...@TK2MSFTNGP02.phx.gbl

> I'm finally back to working on testing the support for ActiveX
> licensing in my scripting language. I've traced through the ATL code
> and my license string seems to be getting processed correctly.
> However, it is being rejected when it is passed to IClassFactory2's
> CreateInstaceLic method on line 119 of AtlHost.h. I think I must
> have the format of the license string incorrect.

Are we still talking about passing a zero-length license? If so, the
code shouldn't have reached CreateInstaceLic call at all, but should
have used plain vanilla CoCreateInstance. See the check at line 114.

> I looked in the vb6controls.reg file and found the following registry
> data:
> // FlexGrid Control 6.0 license key
> HKEY_CLASSES_ROOT\Licenses\ABCDEF567ABCD-11cf-91F6-C24434543F45 =
> idfsdfrwesdfsdfgdfggdsdjfhdsjfssdjmf

This doesn't necessarily have anything to do with the license you should
pass to CreateInstaceLic. The way COM licensing works, you should obtain
IClassFactory2 interface of the object on a licensed machine, and call
IClassFactory2::RequestLicKey. You should store the returned string
somewhere - usually hard-coded in your program. On an unlicensed
machine, you pass this exact string to
IClassFactory2::CreateInstanceLic.

David Liebtag

unread,
Jan 18, 2008, 10:05:30 PM1/18/08
to
Oh. Ok. Thanks.

David


David Liebtag

unread,
Jan 19, 2008, 6:55:07 AM1/19/08
to
Hmmm. I can't seem to get the IClassFactory2 interface.

On a licensed machine:

I tried calling CoGetClassObject using the ActiveX control's CLSID. I got
REGDB_E_CLASSNOTREG.

I tried creating creating a control, calling AtlAxGetControl, and calling
QueryInterface(IID_IClassFactory2). I got
E_NOINTERFACE.

Can you help please? (Sorry if I'm being dense.)

David Liebtag


Igor Tandetnik

unread,
Jan 19, 2008, 11:19:57 AM1/19/08
to
"David Liebtag" <DavidL...@vermontel.net> wrote in message
news:%23ejpkIp...@TK2MSFTNGP02.phx.gbl

> Hmmm. I can't seem to get the IClassFactory2 interface.
>
> On a licensed machine:
>
> I tried calling CoGetClassObject using the ActiveX control's CLSID. I
> got REGDB_E_CLASSNOTREG.

Show your code. If you recall, the ATL code you stepped through managed
to use CoGetClassObject and obtain IClassFactory2 successfully. You must
be doing something wrong.

> I tried creating creating a control, calling AtlAxGetControl, and
> calling QueryInterface(IID_IClassFactory2). I got
> E_NOINTERFACE.

Of course. IClassFactory2 is not implemented on the object itself, but
on its factory.

David Liebtag

unread,
Jan 19, 2008, 12:13:31 PM1/19/08
to
Igor,

I'm not sure exactly what I had wrong, but your post prompted me sto step
through the ATL code once more and verify I was using all the correct APIs
and arguments. I now have it working.

Thanks a lot.

David


David Liebtag

unread,
Jan 21, 2008, 2:17:20 PM1/21/08
to
Hopefully one last question Igor,,,

When I pass a license key to ATL during ActiveX control, I think I need
something more in my DLGINIT structure. I fill in the first 5 members and
nothing more, Tracing through the ATL code, I see that it fails on line
1873 of atlhost.h when it tries to call IPersistStreamInit->Load to
initialize the control. Load returns E_UNEXPECTED.

Since ATL has already processed all of the stream that contains my DLGINIT
structure, Load is not finding any persisted data.

Do you know what I need to add to the end of the DLGINIT structure to get
Load to gracefully detect the end of the stream and return S_OK?

Igor Tandetnik

unread,
Jan 21, 2008, 2:52:22 PM1/21/08
to
"David Liebtag" <DavidL...@vermontel.net> wrote in message
news:uj5UBJGX...@TK2MSFTNGP05.phx.gbl

> When I pass a license key to ATL during ActiveX control, I think I
> need something more in my DLGINIT structure. I fill in the first 5
> members and nothing more, Tracing through the ATL code, I see that
> it fails on line 1873 of atlhost.h when it tries to call
> IPersistStreamInit->Load to initialize the control. Load returns
> E_UNEXPECTED.

Ah, I see the problem. When you pass this extra data to CreateWindow,
ATL machinery assumes it's creating a control previously configured and
saved by Dialog Editor. The data is expected to contain a license key
followed by whatever the control wrote with IPersistStream::Save. So the
machinery insists on calling IPersistStream::Load, even if there's no
more data in the stream (rather than InitView you would rather have it
call).

I don't see any way around this. I'm afraid you will have to do
everything separately after all: create the window, create the control,
then attach control to the window. See KB article KB218442 "How to add

ActiveX controls to an ATL composite control programmatically in Visual
C++".

David Liebtag

unread,
Jan 21, 2008, 3:17:27 PM1/21/08
to
Thanks Igor.

David


0 new messages