Подтвердить что ты не робот

Хостинг Silverlight в С++

Я немного над головой, и мне хотелось бы посоветовать, как это сделать.

В основном то, что я хочу сделать, - это возможность отображать и контролировать 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
};

Легче сказать, чем сделать. Я нашел следующие статьи Host Silverlight Contorl в С++ и Связь между С++ Silverlight Приложение Host и Silverlight. Моя проблема заключается в том, что предоставленный код, похоже, не работает при компиляции в VS2010, и они создают фактическое окно вместо управления без окон. То, что происходит, не очень хорошо объяснено, и мне не хватает знаний COM и ATL.

Я также нашел этот, который, кажется, имеет более простой способ реализации xcpcontrolhost, чем статьи выше.

Я нашел некоторую справочную информацию о msdn. Где ISilverlightViewer кажется довольно интересным для моих нужд. Чтобы разрешить управление без окон, я считаю, что мне, вероятно, придется реализовать что-то вроде IOleInPlaceSiteWindowless.

Тем не менее, я совсем немного над головой, и я не знаю, с чего начать. Я хотел бы задать несколько советов относительно того, где я должен начать, и если у вас есть какие-либо общие советы или опыт с чем-то вроде этого?

EDIT: Что-то, что также было бы интересно, хотя и довольно второстепенное, было бы, если бы такая реализация могла быть независимой от платформы?

EDIT2: я изменил код в "TestProject" из одной из приведенных выше статей. Я попытался удалить избыточный код и исправил его так, чтобы он работал на VS2010 (в соответствии с ответом ниже). Вы можете найти здесь здесь.

EDIT3:

Я попытался реализовать класс xcpControlHost без окон. Я просмотрел код в CAxHostWindow и попытался его воссоздать. Причина, по которой я не использую CAxHostWindow для создания элемента управления без окон, заключается в том, что он не поддерживает альфа.

Кажется, компилируется отлично, однако, когда я вызываю DrawControl, я возвращаю только черный кадр.

XcpContorlHost.h XcpControlHost.cpp

Любые идеи относительно того, что может быть неправильным?

EDIT4: Я делаю шаг назад. Я использую код из "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
}

Я создаю XcpControlHost внутри потока с 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_)
            PostQuitMessage(0);

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

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

И затем я запускаю обычный цикл обработчика сообщений Windows с помощью GetMessage, TranslateMessage и DispatchMessage.

Однако все же я получаю черноту. Что я делаю неправильно?

Кажется, я получил E_FAIL из следующего вызова в "ActivateXcpControl":

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

Ответ 1

Я тестировал проект кода, доступный здесь: http://www.codeproject.com/KB/atl/Host_Silverlight_In_ATL.aspx в Visual Studio 2010. Вот что нужно для его работы:

  • загрузите его под VS 2010 и преобразуйте его в VS 2010 (не заботятся о журналах backupgs и т.д.)
  • удалить регистрационное событие Post-Build ( "$ (TargetPath)" /RegServer ), оно используется только для регистрации COM-компонентов внутри проекта. Вы также можете оставить это событие и просто забыть об ошибке, если хотите.
  • Мне пришлось сделать небольшое изменение в XcpControlHost.cpp.

Вот это изменение:

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

И он работает (я запускаю Windows 7 с Silverlight 4).

Это действительно путь.

Одно замечание: В примере автор не использует официальный xcpctrl.idl файл, доступный здесь: http://msdn.microsoft.com/en-us/library/cc296246(VS.95).aspx. Вместо этого он переопределяет все интерфейсы и GUID, и это не нужно. Вы можете просто добавить xcpctrl.idl в Visual Studio 2010 и скомпилировать, это вызовет компилятор MIDL, который создаст 3 следующих файла: xcpctrl_h.h, xcpctrl_i.c, xcpctrl_p.c. После их компиляции вы можете добавить их в проект.