Bir web tarayıcısı denetimini C++ uygulamasına yerleştirdim. Bir C++ işlevi/yöntemini çağırabilmek için web tarayıcısında javascript çalışmasını istiyorum. Bir web tarayıcısı denetiminde çalışan JavaScript komut dosyasından C++ işlevi çağrısı
- bir aracı olarak gören bir ActiveX bileşeni Uygulanışı: Ben bulduk
Bunu yapmak için üç yöntemden bahseder. (Uygulama ayrıntıları burada: http://blogs.msdn.com/b/nicd/archive/2007/04/18/calling-into-your-bho-from-a-client-script.aspx)
- window.external öğesini kullanın. (Ayrıca yukarıdaki bağlantıyı tartışılan, ancak hiçbir uygulama sağlanan)
Ben üçüncü seçeneği ile gitmek istediğiniz pencere nesnesine özel bir nesne ekleme, ama nasıl herhangi bir çalışma örneklerini bulamadı bunu yapmak için. Birisi bana nasıl yapılacağını gösterir, ya da ağ üzerinde çalışan bir örneğe bağlantı verebilir.
Bulduğum örnek en yakın olan, ilk cevap Igor Tandetnik tarafından a thread in the webbrowser_ctl news group. Ama korkarım ki bundan daha fazla yardıma ihtiyacım var.
Bir IWebBrowser2 denetimi yerleştiriyorum ve MFC, ATL veya WTL kullanmıyorum.
DÜZENLEME: codeproject makalesinde bulunan daha önce bağlantılı dizisindeki Igor tarafından verilen sözde kod ve kod tarafından gidiş
"Creating JavaScript arrays and other objects from C++" Bazı kod hazırladım.
void WebForm::AddCustomObject(IDispatch *custObj, std::string name)
{
IHTMLDocument2 *doc = GetDoc();
IHTMLWindow2 *win = NULL;
doc->get_parentWindow(&win);
if (win == NULL) {
return;
}
IDispatchEx *winEx;
win->QueryInterface(&winEx);
if (winEx == NULL) {
return;
}
int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, NULL, 0);
BSTR objName = SysAllocStringLen(0, lenW);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, objName, lenW);
DISPID dispid;
HRESULT hr = winEx->GetDispID(objName, fdexNameEnsure, &dispid);
SysFreeString(objName);
if (FAILED(hr)) {
return;
}
DISPID namedArgs[] = {DISPID_PROPERTYPUT};
DISPPARAMS params;
params.rgvarg = new VARIANT[1];
params.rgvarg[0].pdispVal = custObj;
params.rgvarg[0].vt = VT_DISPATCH;
params.rgdispidNamedArgs = namedArgs;
params.cArgs = 1;
params.cNamedArgs = 1;
hr = winEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL);
if (FAILED(hr)) {
return;
}
}
Yukarıdaki kod tüm yol boyunca çalışır, bu nedenle her şey bu kadar uzak görünüyor.
Ben *custObj
olarak bu geçen DISPID_NAVIGATECOMPLETE2 DWebBrowserEvents2 olayını aldığınızda ben AddCustomObject çağırır:
class JSObject : public IDispatch {
private:
long ref;
public:
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDispatch
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
ITypeInfo **ppTInfo);
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *Params, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr);
};
Kayda Değer uygulamaları Ne yazık ki asla
HRESULT STDMETHODCALLTYPE JSObject::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if (riid == IID_IUnknown || riid == IID_IDispatch) {
*ppv = static_cast<IDispatch*>(this);
}
if (*ppv != NULL) {
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ve
HRESULT STDMETHODCALLTYPE JSObject::Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *Params, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
MessageBox(NULL, "Invoke", "JSObject", MB_OK);
return DISP_E_MEMBERNOTFOUND;
}
olabilir "Çağır" mesaj kutusu w hen javascript kodundan "JSObject" nesnesini kullanmaya çalışıyorum.
JSObject.randomFunctionName(); // This should give me the c++ "Invoke" message
// box, but it doesn't
DÜZENLEME 2:
ben şöyle GetIDsOfNames
uygulanan:
HRESULT STDMETHODCALLTYPE JSObject::GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
HRESULT hr = S_OK;
for (UINT i = 0; i < cNames; i++) {
std::map<std::wstring, DISPID>::iterator iter = idMap.find(rgszNames[i]);
if (iter != idMap.end()) {
rgDispId[i] = iter->second;
} else {
rgDispId[i] = DISPID_UNKNOWN;
hr = DISP_E_UNKNOWNNAME;
}
}
return hr;
}
ve bu * DISPID_USER_ ile benim yapıcı
JSObject::JSObject() : ref(0)
{
idMap.insert(std::make_pair(L"execute", DISPID_USER_EXECUTE));
idMap.insert(std::make_pair(L"writefile", DISPID_USER_WRITEFILE));
idMap.insert(std::make_pair(L"readfile", DISPID_USER_READFILE));
}
olan sabitler özel sınıf olarak tanımlanan üyeler
class JSObject : public IDispatch {
private:
static const DISPID DISPID_USER_EXECUTE = DISPID_VALUE + 1;
static const DISPID DISPID_USER_WRITEFILE = DISPID_VALUE + 2;
static const DISPID DISPID_USER_READFILE = DISPID_VALUE + 3;
// ...
};
DÜZENLEME 3, 4 ve 5:
taşındı 6 DÜZENLEME
a separate question için:
"bir dize dönen" düzenlemeleri dışında a separate question yapılmıştır. Bu şekilde Georg's cevabını kabul edip, orijinal soruya cevap verebiliyorum.
DÜZENLEME 7: Ben içerdiği tam kapasiteyle çalışan, kendini, örneğin uygulama için bazı istekleri aldık
. İşte burada: https://github.com/Tobbe/CppIEEmbed. Lütfen çatabilir ve geliştirebilirsiniz :)
'GetIDsOfNames()' bir şeyleri mantıklı döndürüyor mu? –
@Georg: Hayır, öyle değil. Sadece E_FAIL değerini döndürür. – Tobbe
Şu anki gibi benzer bir sorunla karşılaşıyorum ... başardığınızı düşündüğünüzde bunu başarmak için bir çalışma örneği hazırlamayı düşünür müsünüz? – titel