Tôi đã nhúng điều khiển trình duyệt web trong ứng dụng C++ của mình. Tôi muốn javascript chạy trong điều khiển trình duyệt web để có thể gọi một hàm/phương thức C++.Gọi hàm C++ từ tập lệnh JavaScript chạy trong điều khiển trình duyệt web
Tôi đã tìm thấy đề cập đến trong ba cách để làm điều này:
- Thực hiện một thành phần ActiveX hoạt động như một người đàn ông trung. (Chi tiết triển khai tại đây: http://blogs.msdn.com/b/nicd/archive/2007/04/18/calling-into-your-bho-from-a-client-script.aspx)
- Sử dụng window.external. (Ngoài ra thảo luận trong diễn đàn, nhưng không thực hiện được cung cấp)
- Thêm một đối tượng tùy chỉnh để các đối tượng cửa sổ
Tôi muốn đi với các tùy chọn thứ ba, nhưng tôi đã không tìm thấy bất kỳ ví dụ làm việc trên như thế nào Để làm việc đó. Có thể ai đó vui lòng chỉ cho tôi cách thực hiện hoặc liên kết với ví dụ hoạt động trên mạng ở đâu đó.
Gần nhất với ví dụ mà tôi đã tìm thấy là câu trả lời đầu tiên của Igor Tandetnik trong a thread in the webbrowser_ctl news group. Nhưng tôi e rằng tôi cần được giúp đỡ nhiều hơn thế.
Tôi đang nhúng điều khiển IWebBrowser2 và tôi không sử dụng MFC, ATL hoặc WTL.
EDIT:
Going by the pseudo-code do Igor trong thread tôi liên kết trước đó, và mã tìm thấy trong bài viết CodeProject "Creating JavaScript arrays and other objects from C++" Tôi đã tạo ra một số 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;
}
}
Đoạn mã trên chạy toàn bộ, vì vậy mọi thứ sẽ ổn hoàn toàn.
tôi gọi AddCustomObject khi tôi nhận được sự kiện DISPID_NAVIGATECOMPLETE2 DWebBrowserEvents2 đi này như *custObj
:
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);
};
hiện thực đáng chú ý có thể là
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;
}
và
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;
}
Đáng tiếc là tôi không bao giờ có được Hộp thông báo "Gọi" Tôi cố gắng sử dụng đối tượng "JSObject" từ mã javascript.
JSObject.randomFunctionName(); // This should give me the c++ "Invoke" message
// box, but it doesn't
EDIT 2:
tôi thực hiện GetIDsOfNames
như vậy:
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;
}
và đây là nhà xây dựng
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));
}
tôi với DISPID_USER_ * hằng số định nghĩa là lớp tin thành viên
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;
// ...
};
EDIT 3, 4 và 5:
Chuyển đến a separate question
EDIT 6:
Made a separate question ra khỏi "trả về một chuỗi" chỉnh sửa. Bằng cách đó tôi có thể chấp nhận trả lời Georg's vì câu trả lời cho câu hỏi gốc.
EDIT 7:
Tôi đã nhận được một vài yêu cầu cho một, tự hoàn toàn làm việc kín, ví dụ thực hiện. Đây là: https://github.com/Tobbe/CppIEEmbed. Vui lòng ngã ba và cải thiện nếu bạn có thể :)
'GetIDsOfNames()' có trả về một điều gì đó hợp lý không? –
@Georg: Không, không. Nó chỉ trả về E_FAIL. – Tobbe
Tôi hiện đang chạy trong một vấn đề tương tự như bạn ... xem xét rằng bạn đã quản lý để thực hiện điều này bạn sẽ xem xét việc làm một ví dụ làm việc có sẵn để tải về một nơi nào đó? – titel