在C++中托管Silverlight

ron*_*nag 17 c++ com silverlight atl

我在这里有点头脑,想要了解如何去做.

基本上我想要做的是能够在我的C++应用程序中呈现和控制silverlight.我想要的东西是:

class silverlight_host
{    
public: 
     // Prio 1
     silverlight_host(const std::string& filename); // Load a xap file       
     void draw(void* dest); // Draw with alpha to dest
     std::pair<size_t, size_t> get_size(); // Need to know required size of dest

     // Prio 2
     bool is_dirty() const; // Check for dirty rect since last call to draw
     void send_param(const std::string& param); // Send data to silverlight control or call functions. Alternative name maybe, call_function
     void set_size(size_t width, size_t height); // Set the size of drawing.  

     // Prio 3
     // Some more nice to have functions, although not as important as those above
     double get_desired_frame_rate(); // The desired frame rate which is specified in xap
     std::pair<size_t, size_t> get_desired_size(); // The desired size which is specified in xap
     void tick(); // Tick a synchronous timeline, disable internal asynchronous timer
     void set_param_callback(const std::function<void(const std::string&)>& callback); // Let the xap file call the application
};
Run Code Online (Sandbox Code Playgroud)

说起来容易做起来难.我在C++中找到了以下文章Host Silverlight Contorl以及C++ Silverlight Host和Silverlight Application之间的通信.我的问题是,在VS2010中编译时提供的代码似乎不起作用,并且它们创建了一个实际窗口而不是无窗口控件.发生的事情也没有得到很好的解释,我有点缺乏COM和ATL的知识.

我也发现似乎比上面的文章更简单的方法来实现xcpcontrolhost.

我在msdn上找到了一些参考信息.凡ISilverlightViewer似乎满足我的需求挺有意思的.为了实现无窗口控制,我相信我可能必须实现类似IOleInPlaceSiteWindowless的东西?

但是,我在这里有点过头了,我不确定从哪里开始.我想问一些关于我应该在哪里开始的建议,以及你是否有任何一般性的建议或经验与这样的事情?

编辑:如果这样的实现可以与平台无关,那么也会很有趣的东西,虽然非常次要的吗?

EDIT2:我已经从上面的一篇文章修改了"TestProject"中的代码.我试图删除冗余代码并修复它以便它在VS2010上运行(根据下面的答案).你可以在这里找到它.

EDIT3:

我试图实现一个无窗口的XcpControlHost类.我查看了CAxHostWindow中的代码并尝试重新创建它.我不使用CAxHostWindow创建无窗口控件的原因是它不支持alpha.

它似乎编译得很好,但是当我调用DrawControl时,我只回到黑框.

XcpContorlHost.h XcpControlHost.cpp

关于什么可能是错的任何想法?

编辑4:我退后一步.我使用"TestProject"中的代码我想修改CreateXcpControl(HWND hWnd)以便能够获取hWnd == nullptr(无窗口)并使用OleDraw将控件绘制到内存中.

所以我试图做的只是绕过调用"AttachControl"并直接调用"ActivateXcpControl".我用硬编码的值替换了GetClientRect.

STDMETHODIMP XcpControlHost::AttachControl(IUnknown* pUnKnown, HWND hWnd)
{
    assert(hWnd == nullptr); 
    ReleaseAll();
    // Removed all hWnd related code
    return ActivateXcpControl(pUnKnown);
}

HRESULT XcpControlHost::ActivateXcpControl(IUnknown* pUnKnown) 
{
     // Lots of code
     // GetClientRect(&m_rcPos); // Remove this
     m_rcPos.top = 0;
     m_rcPos.left = 0;
     m_rcPos.right = 720;
     m_rcPos.bottom = 576;
     // Lots of code
}
Run Code Online (Sandbox Code Playgroud)

我使用CoInitialize在一个线程中创建XcpControlHost:

void run()
{
    struct co_init
    {
        co_init(){CoInitialize(nullptr);}
        ~co_init(){CoUninitialize();}
    } co;

    if(FAILED(CComObject<XcpControlHost>::CreateInstance(&host_)))
        throw std::exception("Failed to create XcpControlHost");

    if(FAILED(host_->CreateXcpControl()))
        throw std::exception("Failed to create XcpControl");

    while(GetMessage(&msg, 0, 0, 0))
    {  
        if(!is_running_)
            PostQuitMessage(0);

        if(msg.message == WM_USER + 1) // Sent from app
            OleDraw(host_->m_pUnKnown, DVASPECT_CONTENT, targetDC, 0);

        TranslateMessage(&msg);
        DispatchMessage(&msg); 
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我使用GetMessage,TranslateMessage和DispatchMessage运行通常的Windows消息处理程序循环.

然而,我仍然得到的只是黑度.我究竟做错了什么?

我似乎从"ActivateXcpControl"中的以下调用获得了E_FAIL:

hr = m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, spClientSite, 0, NULL, &m_rcPos);
Run Code Online (Sandbox Code Playgroud)

Sim*_*ier 8

我已经测试了这里可用的代码项目:Visual Studio 2010下的http://www.codeproject.com/KB/atl/Host_Silverlight_In_ATL.aspx.以下是使其工作所需的内容:

  • 在VS 2010下加载它并将其转换为VS 2010(不关心backupgs日志等...)
  • 删除注册后构建事件("$(TargetPath)"/ RegServer),它仅用于注册项目内的COM组件.如果您愿意,也可以让该事件忘记错误.
  • 我不得不在XcpControlHost.cpp中进行一些小改动.

这是改变:

HRESULT CXcpControlHost::CreateXcpControl(HWND hWnd) 
{
    AtlAxWinInit();
    CoInitialize(NULL); // add this line to initialize COM
    ... 
}
Run Code Online (Sandbox Code Playgroud)

它的工作原理(我使用Silverlight 4运行Windows 7).

这真的是要走的路.

但需要注意的一点是:在示例中,作者没有使用此处提供的官方xcpctrl.idl文件:http://msdn.microsoft.com/en-us/library/cc296246(VS.95).aspx.相反,他重新定义了所有接口和GUID,这是不需要的.您只需将xcpctrl.idl添加到Visual Studio 2010并进行编译,这将触发将创建以下3个文件的MIDL编译器:xcpctrl_h.h,xcpctrl_i.c,xcpctrl_p.c.编译完成后,您可以将它们添加到项目中.