开发者

Hosting Silverlight in C++

I'm a bit over my head here and would like some advice on how to go about.

Basicly what I want to do is to be able to render and control silverlight inside my C++ application. I would like something as:

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
};

Easier said than done. I have found the following articles Host Silverlight Contorl in C++ and Communication between C++ Silverlight Host and Silverlight Application. My problem with these are that the provided code doesn't seem to work when compiled in VS2010 and they create an actual window instead of a windowless control. Also what happens is not very well explained and I am somewhat lacking in COM and ATL knowledge.

I've also found this which seems to have a simpler way to implement the xcpcontrolhost than the articles above.

I have found some reference information on msdn. Where ISilverlightViewer seems quite interesting for my needs. In order to allow a windowless control I believe that I probably have to implement something like IOleInPlaceSiteWindowless?.

However, I am quite a bit over my head here and I'm unsure where to even begin. I'd like to ask some advice regarding where I should get started and if you have any general advice or experience with something like this?

EDIT: Something which would also be interesting, although quite secondary, would be if such an implementation could be made platform independent?

EDIT2: I have modified the code in "TestProject" from one of the articles above. I have tried to remove redundant code and fixed it so that it runs on VS2010 (according to answer below). You can find it here.

EDIT3:

I have tried to implement a windowless XcpControlHost class. I've looked at the code in CAxHostWindow and tried to re-create it. The reason I don't use CAxHostWindow to create a windowless control is that it does not support alpha.

It seems to compile fine, however when I call DrawControl I only get back a black frame.

XcpContorlHost.h XcpControlHost.cpp

Any ideas as to what might be wrong?

EDIT4: I'm taking a step back. I use the code from "TestProject" I want to modify CreateXcpControl(HWND hWnd) to be able to take hWnd == nullptr (windowless) and use OleDraw to draw the control to memory.

Soo what I tried to do is to simply bypass the call to "AttachControl" and directly call "ActivateXcpControl". And I've replaced GetClientRect by hard-coded values.

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
}

I create the XcpControlHost inside a thread with CoInitialize:

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_)
            PostQu开发者_运维技巧itMessage(0);

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

        TranslateMessage(&msg);
        DispatchMessage(&msg); 
    }
}

And then I run the usual windows message handler loop with GetMessage, TranslateMessage and DispatchMessage.

However, still all I get is blackness. What am I doing wrong?

I seem to get E_FAIL from the following call in "ActivateXcpControl":

hr = m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, spClientSite, 0, NULL, &m_rcPos);


I have tested the code project available here: http://www.codeproject.com/KB/atl/Host_Silverlight_In_ATL.aspx under Visual Studio 2010. Here is what's needed to make it work:

  • load it under VS 2010 and convert it to VS 2010 (don't care about backupgs logs, etc...)
  • remove the registration Post-Build Event ("$(TargetPath)" /RegServer), it's only used for registration of COM components inside the projet. You can also let that event and just forget about the error if you prefer.
  • I had to do a small change in XcpControlHost.cpp.

Here is the change:

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

And it works (I'm running Windows 7 with Silverlight 4).

This is really the way to go.

One remark though: In the sample, the author does not use the official xcpctrl.idl file available from here: http://msdn.microsoft.com/en-us/library/cc296246(VS.95).aspx . Instead he redefines all interfaces and GUID, and this is not needed. You can just add the xcpctrl.idl to a Visual Studio 2010 and compile, this will trigger the MIDL compiler that will create the 3 following files: xcpctrl_h.h, xcpctrl_i.c, xcpctrl_p.c. Once they are compiled, you can add them to the project.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜