从 C++/ATL 客户程序调用 Javascript 编写的组件

从 C++/ATL 客户程序调用 Javascript 编写的组件
有这个问题是因为, 我们可能要用 JavaScript 语言作为 "胶水" 粘合我们的 C++/ATL 组件, 那, 怎么在客户端使用 "胶水" 呢"? 以下就是它的简介.

首先, 用 JavaScript 语言编写组件, 以下是个例子:

<?xml version="1.0" encoding="UTF-8"?>
<?component  error="true"  debug="true"?>
<component id="XrhTest.LowerToUpper">

<registration
   description = "UpperCase and lowCase convertion"
   progid="XrhTest.LowerToUpper"
   version="1.0"
   classid="{9B88510F-9D5B-4dcd-9068-8AB0B4F7999C}" remotable="true">
</registration>

<public>

<!-- define method -->
<method name="toLower">
  <parameter name="str"/>
</method>
<method name="toUpper">
  <parameter name="str"/>
</method>

</public>

<script language="JavaScript">
<![CDATA[
function toLower(str)
{
    var result=str.toLowerCase();
    return result;
}
function toUpper(str)
{
    var result=str.toUpperCase();
    return result;
}
]]>
</script>

</component>


将这个组件保存为 lower2upper.wsc 文件.
然后, 注册这个组件, 方法是, 在这个 wsc 文件上右击鼠标, 然后选 "注册" 菜单项, 完成注册, 点击 OK 按钮完成操作. 如下图
从 C++/ATL 客户程序调用 Javascript 编写的组件_第1张图片
注册完成后, 在注册表内有以下条目
[ HKEY_CLASSES_ROOT\CLSID\{9B88510F-9D5B-4DCD-9068-8AB0B4F7999C} ]
@
= " UpperCase and lowCase convertion "
" AppID " = " {9B88510F-9D5B-4DCD-9068-8AB0B4F7999C} "

[ HKEY_CLASSES_ROOT\CLSID\{9B88510F-9D5B-4DCD-9068-8AB0B4F7999C}\InprocServer32 ]
@
= " C:\\WINDOWS\\System32\\scrobj.dll "
" ThreadingModel " = " Apartment "

[ HKEY_CLASSES_ROOT\CLSID\{9B88510F-9D5B-4DCD-9068-8AB0B4F7999C}\ProgID ]
@
= " XrhTest.LowerToUpper.1.0 "

[ HKEY_CLASSES_ROOT\CLSID\{9B88510F-9D5B-4DCD-9068-8AB0B4F7999C}\ScriptletURL ]
@
= " file:///D:/lower2upper.wsc "

[ HKEY_CLASSES_ROOT\CLSID\{9B88510F-9D5B-4DCD-9068-8AB0B4F7999C}\VersionIndependentProgID ]
@
= " XrhTest.LowerToUpper "
从以上注册表项目可以看出, 当我们要创建 wsc 组件时, COM 运行时将会加载 scrobj.dll 链接库, scrobj.dll 链接库将根据 scriptletURL 的键值 file:///D:/lower2upper.wsc 加载 wsc 脚本, 最后由 scrobj.dll 将脚本解释成一个 COM 组件实例, 将这个实例指针返回给调用者.

最后, 我们来编写 C++ 客户端, 随便创建一个 C++ 文件, 然后用 VC6 编译, 运行, 查看结果. 示例代码如下:
#include  < atlbase.h >
extern  CComModule _Module; 
#include 
< atlcom.h >

void  main()
{
    CoInitialize(NULL);

    {
        HRESULT hr 
=  E_FAIL;
        CComQIPtr
< IDispatch >  spTmp;
        hr 
=  spTmp.CoCreateInstance(L " XrhTest.LowerToUpper " );
        
if  (SUCCEEDED(hr))
        {
            CComDispatchDriver spDisp(spTmp); 
            CComVariant varParam(L
" The quick brown fox jumps over the lazy dog " ); 
            CComVariant varResult;
            hr 
=  spDisp.Invoke1(L " toUpper " & varParam,  & varResult);
            
if  (SUCCEEDED(hr))
            {
                MessageBoxW(NULL, (LPCWSTR) varResult.bstrVal, L
" MB_OK " , MB_OK); 
            }
        }
    }

    CoUninitialize(); 
}

CComModule _Module; 
如果不出意外, 运行结果将弹出一个全是大写文本的对话框. 如下图:
从 C++/ATL 客户程序调用 Javascript 编写的组件_第2张图片

以上所讲的组件注册将会在注册表内留下痕迹, 不够绿色. 如果组件不注册, 或者脚本内没有 <registration> 元素, 可以使用以下介绍的方法来使用 wsc 组件.
#include  < atlbase.h >
extern  CComModule _Module; 
#include 
< atlcom.h >

HRESULT CreateScriptComponent(LPCTSTR lpszScriptletURL, OUT IDispatch 
**  ppDispatch)
{
    HRESULT hr 
= E_FAIL;
    
do
    
{
        
if (NULL == ppDispatch) {
            
break;
        }


        CComPtr
<IBindCtx> pbc;
        CComPtr
<IMoniker> pMoniker;
        
        hr 
= CreateBindCtx(0&pbc);
        
if (FAILED(hr)) {
            
break;
        }

        
        CComBSTR strPath(L
"script:");
        strPath.Append(lpszScriptletURL);
        ULONG lEaten 
= 0;
        hr 
= MkParseDisplayName(pbc, strPath, &lEaten, &pMoniker);
        
if (FAILED(hr)) {
            
break;
        }

        
        hr 
= BindMoniker(pMoniker, 0, __uuidof(IDispatch), (void**)ppDispatch);
        
if (FAILED(hr)) {
            
break;
        }
 
    }
 while(false);

    
return hr;
}


int  _tmain( int  argc, _TCHAR *  argv[])
{
    HRESULT hr 
= E_FAIL;
    CoInitialize(NULL);
    
    
do
    
{
        CComPtr
<IDispatch> pScript;
        hr 
= CreateScriptComponent(
            _T(
"file:///d:/lower2upper.wsc"), // _T("d:\\lower2upper.wsc")
            &pScript);
        
if (FAILED(hr)) {
            
break;
        }


        CComDispatchDriver spDisp(pScript); 
        
        CComVariant varParam(L
"The quick brown fox jumps over the lazy dog"); 
        CComVariant varResult;
        HRESULT hr 
= spDisp.Invoke1(L"toUpper"&varParam, &varResult);
        
if (SUCCEEDED(hr)) {
            MessageBoxW(NULL, (LPCWSTR) varResult.bstrVal, L
"MB_OK", MB_OK); 
        }

    }

    
while (false);
    
    CoUninitialize();
    
    
return 0;
}


CComModule _Module; 


参考文献:
http://blog.csdn.net/broadview2006/archive/2009/03/19/4004361.aspx
http://www.vckbase.com/document/viewdoc/?id=1518
延伸阅读:
<< 怎样在 Windows 环境下调试 JScript 脚本>>
<< 几行代码让你的程序加入vbscipt脚本扩展功能>>
http://support.microsoft.com/kb/221992/en-us
http://support.microsoft.com/kb/223139/en-us
http://support.microsoft.com/kb/196135/en-us
http://support.microsoft.com/kb/168214/
http://support.microsoft.com/kb/183698/


PS, 一个稍微有点用的例子:
从 C++/ATL 客户程序调用 Javascript 编写的组件_第3张图片
源代码:    http://www.cppblog.com/Files/free2000fly/jsTest.zip

你可能感兴趣的:(从 C++/ATL 客户程序调用 Javascript 编写的组件)