Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: COM/DCOM/ActiveX/ATL/CORBA > (TWebBrowser || TChromium || TEmbeddedWB)


Автор: BasMan 12.10.2013, 12:20
Разрабатываю ПО, на C++ Builder XE5, пробовал разные браузеры (указаны в топике) ... нигде нет возможности задать используемый клиентский сертификат, в браузерах на основе IE выскакивает штатное окно браузера с выбором сертификата, в хромиуме просто белая страница открывается. Весь инет перерыл, нигде не нашел решения, встречаются только вопросы подобные моему. Другие компоненты неподходят, нужен именно браузер. Сейчас буду вкорячивать Gecko ...

Автор: BasMan 15.10.2013, 08:30
Нашел неплохую альтернативу, Awesomium, теперь другая проблема не линкуется .lib-ка, перепробовал всякие варианты с штатным implib, coff2omf и Digital Mars-овским implib-ом, все равно, не видит функции. И незнаю, в этой теме писать, или отдельную создавать. Пока тут напишу, т.к. если продвинусь дальше, то буду описывать как работать с сертификатами.

Думаю что проблема в 

00B490 THEADR  Awe_DataPakSource_director_connect
00B4B7 COMENT  Purge: Yes, List: Yes, Class: 160 (0A0h), SubClass: 1 (01h)
    Dynamic link import (IMPDEF)
      Imported by: name
      Internal Name: Awe_DataPakSource_director_connect
      Module Name: awesomium.dll
      Imported name: _Awe_DataPakSource_director_connect@8 
00B516 MODEND

В _ перед именем функции в Imported name
Перебирал разные опции командной строки, не могу убрать "лишние" _ вообще

Автор: BasMan 15.10.2013, 15:13
Добился такого

0009E0 THEADR  Awe_DataPakSource_director_connect
000A07 COMENT  Purge: Yes, List: Yes, Class: 160 (0A0h), SubClass: 1 (01h)
    Dynamic link import (IMPDEF)
      Imported by: name
      Internal Name: Awe_DataPakSource_director_connect
      Module Name: awesomium.dll
000A41 MODEND

но все равно

[ilink32 Error] Error: Unresolved external 'Awesomium::WebStringArray::~WebStringArray()' referenced from D:\PROJECTS\IP\WIN32\DEBUG\*******
[ilink32 Error] Error: Unresolved external 'Awesomium::WebString::~WebString()' referenced from D:\PROJECTS\IP\WIN32\DEBUG\*******
[ilink32 Error] Error: Unresolved external 'Awesomium::WebConfig::WebConfig()' referenced from D:\PROJECTS\IP\WIN32\DEBUG\*********
[ilink32 Error] Error: Unresolved external 'Awesomium::WebCore::Initialize(Awesomium::WebConfig&)' referenced from D:\PROJECTS\IP\WIN32\DEBUG\*********

Автор: xvr 16.10.2013, 12:56
А Awesomium вообще под Builder? Если нет, то работать не будет, даже если вам и удасться каким то чудом ее прилинковать  smile 

Автор: BasMan 17.10.2013, 06:35
Тьфу, все правильно, так заработался, забыл что это не простые C типы. А если на VC написать библиотеку-враппер, которая экспортирует функции как C, а сама работает с Awesomium? Хотя с таким же успехом можно сразу пробовать CEF.

Автор: BasMan 21.3.2015, 18:15
Выдалось свободное время, продолжил копать в этом направлении, накопал следующее,  в Windows 7/2008 и выше, в urlmon.h присутствует интерфейс:
Код

IHttpNegotiate3 : public IHttpNegotiate2
{
    virtual HRESULT STDMETHODCALLTYPE GetSerializedClientCertContext(
        BYTE **ppbCert,
        DWORD *pcbCert) = 0;

};

Судя по описанию, в приложении должна быть реализация данного интерфейса в виде класса, где будет перегружаться функция GetSerializedClientCertContext, при вызове которой можно подсунуть блоб с сертификатом/ключом. Вызывается как раз в момент "возникнования потребности" в пользовательском сертификате (по дефолту отображается диалоговое окно IE с выбором сертификата).
Кто может  подсказать, как правильно сделать реализацию?
Вот фрагмент кода:
Код


typedef IHttpNegotiate3 *LPHTTPNEGOTIATE3;

DEFINE_GUID(IID_IHttpNegotiate3, 0x57b6c80a, 0x34c2, 0x4602, 0xbc,0x26, 0x66,0xa0,0x2f,0xc5,0x71,0x53);
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("57b6c80a-34c2-4602-bc26-66a02fc57153")
IHttpNegotiate3 : public IHttpNegotiate2
{
    virtual HRESULT STDMETHODCALLTYPE GetSerializedClientCertContext(
        BYTE **ppbCert,
        DWORD *pcbCert) = 0;

};
#ifdef __CRT_UUID_DECL
__CRT_UUID_DECL(IHttpNegotiate3, 0x57b6c80a, 0x34c2, 0x4602, 0xbc,0x26, 0x66,0xa0,0x2f,0xc5,0x71,0x53)
#endif
#else
typedef struct IHttpNegotiate3Vtbl {
    BEGIN_INTERFACE

    /*** IUnknown methods ***/
    HRESULT (STDMETHODCALLTYPE *QueryInterface)(
        IHttpNegotiate3* This,
        REFIID riid,
        void **ppvObject);

    ULONG (STDMETHODCALLTYPE *AddRef)(
        IHttpNegotiate3* This);

    ULONG (STDMETHODCALLTYPE *Release)(
        IHttpNegotiate3* This);

    /*** IHttpNegotiate methods ***/
    HRESULT (STDMETHODCALLTYPE *BeginningTransaction)(
        IHttpNegotiate3* This,
        LPCWSTR szURL,
        LPCWSTR szHeaders,
        DWORD dwReserved,
        LPWSTR *pszAdditionalHeaders);

    HRESULT (STDMETHODCALLTYPE *OnResponse)(
        IHttpNegotiate3* This,
        DWORD dwResponseCode,
        LPCWSTR szResponseHeaders,
        LPCWSTR szRequestHeaders,
        LPWSTR *pszAdditionalRequestHeaders);

    /*** IHttpNegotiate2 methods ***/
    HRESULT (STDMETHODCALLTYPE *GetRootSecurityId)(
        IHttpNegotiate3* This,
        BYTE *pbSecurityId,
        DWORD *pcbSecurityId,
        DWORD_PTR dwReserved);

    /*** IHttpNegotiate3 methods ***/
    HRESULT (STDMETHODCALLTYPE *GetSerializedClientCertContext)(
        IHttpNegotiate3* This,
        BYTE **ppbCert,
        DWORD *pcbCert);

    END_INTERFACE
} IHttpNegotiate3Vtbl;
interface IHttpNegotiate3 {
    CONST_VTBL IHttpNegotiate3Vtbl* lpVtbl;
};


Заранее спасибо.

Автор: BasMan 23.3.2015, 18:23
Нашел на другом форуме:

1. Запросите (через QueryInterface) у IWebBrowser2 интерфейс IConnectionPointContainer.

2. Метод FindConnectionPoint с идентификатором DIID_DWebBrowserEvents2 вернет
вам указатель на IConnectionPoint - это "точка", через которую можно подписаться
на нужные события.

3. Вызываете pConnectionPoint->Advise, передаете туда указатель на свой объект.
Объект этот должен быть наследником IDispatch.

4. Теперь на любые события будет вызываться метод Invoke этого объекта:
первым аргументом придет тип события, напимер для DocumentComplete
это будет DISPID_DOCUMENTCOMPLETE. Аргументы вызова, если нужно,
достаются из массива DispParams (они там в обратном порядке лежат,


Нужно запросить у XXXXX интерфейс HttpNegitiate || HttpNegitiate3 (?), метод FindConnectionPoint с идентификатором IID_IHttpNegotiate3 вернет указатель на IConnectionPoint . Нужно вызывать IConnectionPoint->Advise и передать туда указатель на свой объект наследник IDispatch.
На любые события будет вызываться метод Invoke объекта, первым аргументом будет тип события (?) ....

Автор: xvr 25.3.2015, 17:56
Цитата(BasMan @  23.3.2015,  18:23 Найти цитируемый пост)
Нашел на другом форуме:

Каким боком связывание ActiveX события с приемником этого события (а именно это описанно в вашей цитате) относится к HttpNegitiate3, который судя по описанию вообще не ActiveX объект (и не унаследован от IDispatch)
Информацию надо искать не на помойке (под названием Интернет), а у первоисточника -
https://msdn.microsoft.com/en-us/library/ms775054(v=vs.85).aspx
Там собственно сказано -
Цитата

Urlmon.dll uses the QueryInterface method on your implementation of IBindStatusCallback to obtain a pointer to your IHttpNegotiate interface.

Автор: BasMan 6.4.2015, 19:58
Ок, 
Код

class BCBindStatusCallback :public IBindStatusCallback
{
public:

    BCBindStatusCallback();
    ~BCBindStatusCallback();
 
    STDMETHODIMP QueryInterface(REFIID iid, void ** ppvObject);
    ULONG STDMETHODCALLTYPE AddRef(void);
    ULONG STDMETHODCALLTYPE Release(void);
    
    STDMETHODIMP OnStartBinding(DWORD grfBSCOption,IBinding *pib);
    STDMETHODIMP OnStopBinding(HRESULT hresult, LPCWSTR szError);
    STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown *punk);
    STDMETHODIMP OnLowResource(DWORD dwReserved);
    STDMETHODIMP OnProgress(ULONG ulProgress, ULONG ulProgressMax,
        ULONG ulStatusCode,LPCWSTR szStatusText);
    STDMETHODIMP GetBindInfo(DWORD *pgrfBINDF, BINDINFO *pbindInfo);
    STDMETHODIMP GetPriority(LONG *pnPriority);
    STDMETHODIMP OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
                                         FORMATETC *pformatetc,
                                         STGMEDIUM *pstgmed);
    STDMETHODIMP GetSerializedClientCertContext(BYTE **ppbCert, DWORD *pcbCert);
    
    BOOL SetWindow(HWND hWnd);
    BOOL GetWindow(HWND *phWnd);
    BOOL Abort(void);
    
private:
     int m_cRef;
     HWND hWndInternal;
     BOOL bAbort;
};
    BCBindStatusCallback::BCBindStatusCallback()
    {
        hWndInternal=NULL;
        bAbort=FALSE;
        m_cRef=0;
    }
     
    BCBindStatusCallback::~BCBindStatusCallback()
    {
     
    }
     
    //Èìïëåìåíòàöèÿ QueryInterface
    STDMETHODIMP BCBindStatusCallback::QueryInterface(REFIID riid, void **ppv)
    {
        HRESULT hr = E_NOINTERFACE;
        
        if (!ppv) return E_POINTER;
     
        *ppv = NULL;
        if (riid == IID_IUnknown || riid == IID_IBindStatusCallback || riid == IID_IHttpNegotiate3)
        {
            *ppv = (IBindStatusCallback *)this;
            AddRef();
            hr = S_OK;
        }
        return hr;
    }
     
    ULONG STDMETHODCALLTYPE BCBindStatusCallback::AddRef(void)
    {
        return ++m_cRef;
    }
     
    ULONG STDMETHODCALLTYPE BCBindStatusCallback::Release()
    {
        m_cRef--;
     
        if (m_cRef > 0)
            return m_cRef;
     
        //delete this;
        return 0;
    }
     
    STDMETHODIMP BCBindStatusCallback::OnStartBinding(DWORD grfBSCOption,IBinding *pib)
    {
        return E_NOTIMPL;
    }
     
    STDMETHODIMP BCBindStatusCallback::OnStopBinding(HRESULT hresult, LPCWSTR szError)
    {
        return E_NOTIMPL;
    }
     
    STDMETHODIMP BCBindStatusCallback::OnObjectAvailable(REFIID riid,IUnknown *punk)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP BCBindStatusCallback::GetPriority(LONG *pnPriority)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP BCBindStatusCallback::OnLowResource(DWORD dwReserved)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP BCBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax,
                                        ULONG ulStatusCode,
                                        LPCWSTR szStatusText)
    {

        return E_NOTIMPL;
    }

    STDMETHODIMP BCBindStatusCallback::GetSerializedClientCertContext(BYTE **ppbCert, DWORD *pcbCert)
    {
        ShowMessage("!!!");
    };


    STDMETHODIMP BCBindStatusCallback::GetBindInfo(DWORD *pgrfBINDF, BINDINFO *pbindInfo)
    {
        if (!pgrfBINDF || !pbindInfo || pgrfBINDF == NULL)
                return E_POINTER;
        if (pbindInfo->cbSize<sizeof(BINDINFO))
                return E_INVALIDARG;
     
        if (pbindInfo->dwBindVerb!=BINDVERB_POST && pbindInfo->dwBindVerb!=BINDVERB_GET)
             return E_UNEXPECTED;
     
        return E_NOTIMPL;
    }
     
    STDMETHODIMP BCBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
                                             FORMATETC *pformatetc,
                                             STGMEDIUM *pstgmed)
    {
        return E_NOTIMPL;
    }
     
    BOOL BCBindStatusCallback::SetWindow(HWND hWnd)
    {
        if (!hWnd)
        {
            hWndInternal=NULL;
            return FALSE;
        }
        hWndInternal=hWnd;
        return TRUE;
    }
     
    BOOL BCBindStatusCallback::GetWindow(HWND *phWnd)
    {
        if (!phWnd) return FALSE;
        *phWnd = hWndInternal;
        return TRUE;
    }
     
    BOOL BCBindStatusCallback::Abort(void)
    {
        bAbort=TRUE;
        return TRUE;
    }



А каким образом заставить браузер обратиться к объекту?
Я так понимаю через IServiceProvider? Тоже свою реализацию писать?

Автор: xvr 7.4.2015, 15:41
Во первых -
Код

class BCBindStatusCallback :public IBindStatusCallback, public IHttpNegotiate3 

Во вторых - методы от IHttpNegotiate2 вам тоже придется реализовать (т.к. IHttpNegotiate3 унаследован от IHttpNegotiate2)

Цитата(BasMan @  6.4.2015,  19:58 Найти цитируемый пост)
А каким образом заставить браузер обратиться к объекту?

Замечательный вопрос. Лично я не уверен, что UrlMON имеет отношение к IE  smile 

Вам скорее надо копать в сторону CryptoAPI, точнее к хранилищам сертификатов. 
Или куда то сюда - http://stackoverflow.com/questions/25771377/import-client-certificate-in-ie-with-javascript

Автор: BasMan 7.4.2015, 17:04
Я думаю имеет, т.к. в исходниках того же Chromium, FF и TEmbeddedWB есть упоминания интерфейса HttpNegotiate, вот фрагмент Chromium:
Код


-// Simple class that wraps IHttpNegotiate interface and adds "chromeframe"
-// to User-agent Http header.
-class UserAgentAddOn : public IHttpNegotiate {
- public:
-  UserAgentAddOn() {}
-  ~UserAgentAddOn() {}
-  void set_delegate(IHttpNegotiate* delegate) {
-    delegate_ = delegate;
-  }
-
-  bool has_delegate() const {
-    return delegate_ != NULL;
-  }
-
- protected:
-  // IHttpNegotiate
-  STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, DWORD reserved,
-                                  LPWSTR* additional_headers);
-  STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_headers,
-                        LPCWSTR request_headers, LPWSTR* additional_headers);
-  ScopedComPtr<IHttpNegotiate>  delegate_;
-};


и это один маленький кусочек первый попавшийся по запросу "chrome httpnegotiate interface"

Автор: xvr 8.4.2015, 12:30
Все возможно. Может быть и IE использует интерфейсы от UrlMon где то глубоко внутри себя, но как к ним достучаться снаружи - это вопрос.
Поверхостный поиск по MSDN в разделе IE результатов не дал. А на глубокий поиск у меня не хватит времени - там можно и неделю прокопаться  smile 

Цитата(BasMan @  7.4.2015,  17:04 Найти цитируемый пост)
Я думаю имеет, т.к. в исходниках того же Chromium, FF и TEmbeddedWB есть упоминания интерфейса HttpNegotiate

Это еще не значит, что и IE сделан так же  smile 
Кстати, посмотрите куда этот UserAgentAddOn передается - может какой нибудь public API интерфейс найдется.

Автор: BasMan 2.2.2016, 22:00
Может кому поможет.
Сделал так, программа при запуске очищает хранилище сертификатов (через certmgr.exe), в нужный момент (перед открытием страницы) устанавливает нужный сертификат в хранилище, страница открывается без лишних запросов, если нужно войти под другим сертификатом, снова очищаем хранилище, ставим нужный сертификат, открываем страницу.

Автор: xvr 3.2.2016, 12:11
За такой 'метод' ваши пользователи побъют вас ноутбуками (насмерть)  smile

Автор: tzirechnoy 3.2.2016, 14:47
Цитата
ваши пользователи побъют


"Нас не догонят!"

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)