Scripting ActiveX control in WSH
The worse part is that it took me significant amount of time to find the answer from google group. I picked wrong words at the beginning which unfortunately generated lots of noise.
The lesson: think harder about the search string instead wasting time on irrelevant results ("catastrophic failure activex wsh" is the best for this issue). And it's better if I go directly to the related news groups/maillists (microsoft.public.scripting.wsh in this case).
Here I just quote the answer from Kyle Alons:
"First, a little background: ActiveX controls are normally persisted to/from some type of permanent storage, and they do this by implementing one or more IPersist* interfaces. Containers are supposed to call one of the IPersist methods to initialize or load the control upon creation.
COleControl, which all MFC controls derive from, enforces that this initialization has taken place before allowing any calls to be made to the control (COleDispatchImpl::Invoke, line 1209 of OLEDISP1.CPP calls IsInvokeAllowed, which checks a protected m_bInitialized member variable for TRUE; this variable is set in the IPersist* implementations in CTLPSTM.CPP).
Since WSH never calls the IPersist* methods, the above test fails, and the result is the 'catastrophic failure' error message. The test control container (and VB6, which I also tested), are smart enough to detect when a control class has been instantiated and call an IPersist*->InitNew method to initialize the control.
One workaround is to add the statement m_bInitialized = TRUE; in your control's constructor. This may be an acceptable workaround in this case, because the control isn't truly being hosted and its state isn't being loaded from anywhere. This seems like an oversight by the WSH team, since most other environments don't require the workaround; on the outside chance that the MS developers are actually reading this, maybe they can address it.