Passing an array of bytes from ActiveX to javascript and vice versa

I need to pass data (byte array, i.e. char *) from an ActiveX object (using Visual C ++ with ATL) to javascript code (and vice versa). I dug up the Internet for such a problem and tried many solutions, but could not. I tried the following:

  • Converting char * to BSTR and passing it to javascript (JS), but my result in JS is "", due to the nature of my data is not a string.
//in C++: STDMETHODIMP CActiveXObj::f(BSTR* msg) // msg is the return value in ATL automation function { char *buffer; // byte data is stored in buffer *msg = SysAllocStringByteLen((LPCSTR)buffer, bufferLen+1); } ////////////////////////////////////////////////////////////////////////// //in JavaScript: var myobj= new ActiveXObject("IGCE.ActiveXObj"); var result = myobj.f(); // result = "" 
  • Skip a secure array of byte data from C ++

Can someone please give me the working code in its simplest form?

Many thanks!

Christine

+4
source share
4 answers
 // In *.idl file [propget, id(0)] HRESULT ArrayProperty([out, retval] SAFEARRAY(VARIANT) *pArray); [propput, id(0)] HRESULT ArrayProperty([in] SAFEARRAY(VARIANT) Array); // Somewhere in javascript function ax2js(axArray) { return new VBArray(array).toArray(); } function js2ax(jsArray) { var dict = new ActiveXObject("Scripting.Dictionary"); for (var i = 0; i < jsArray.length; i++) { dict.add(i, jsArray[i]); } return dict.Items(); } function fooHandler() { var ax = new ActiveXObject("My.My"); var ar = ax2js(ax.ArrayProperty); ax.ArrayProperty = js2ax(ar); } 
+3
source

You probably need to use SAFEARRAY to transfer data. For this, the ATL shell CComSafeArray is called . I hope this is enough for a start, if not then I will dig out the code.

0
source

As far as I know (and in my experience), you can only use the following basic data types when talking to javascript:

  • Line
  • Int
  • Twice
  • Bool
  • IDispatch *

Nothing else works. I have never tried using SAFEARRAY, but I can offer a possible alternative.

If you get a link to the DOM window (I wonโ€™t describe it here, if you donโ€™t know how, search and / or submit a new question, and I can answer it there), you can use IDispatch to Call the Array method in window and it will return IDispatch * for an empty javascript array. Then you can call "push" in Array IDispatch * for each byte that you want to send to javascript as int, and then return the IDispatch * of the array as the return value from the method or property in question. You will get the data in javascript as an array of integers, but each element is a byte, and you can use it that way.

If you can offer another way to use binary data in javascript (forget about ActiveX control for a moment), I could tell you how to return data from the control in this way.

This is essentially the method that FireBreath (an open source framework for IE and Firefox; http://www.firebreath.org ) is used when you return a vector from the JSAPI (javascript scripted object) method to return data to javascript in array form. You can use a similar (almost identical) method for NPAPI compatible browsers.

0
source

I understand that this is a very old post, but I myself came across the same problem of transferring binary data from ActiveX to Javascript and decided to present a solution based on a taxonomic proposal.

Before that, I would like to point out that it is also possible to build SAFEARRAY from binary data and send this object back to JS. The only problem is that VBScript needs to be used to unpack this object, convert it to a data type recognized only by JScript (Microsoft Javascript dialect), which can be used to create a traditional JS array.

Without getting into the business of this solution (for checking the taxil response), here is a method that will build a Javascript array in an ActiveX control and return that array to JS.

 /** NOTE: you have to include MsHTML.h header in order to access IServiceProvider, IHTMLWindow2 and related constants. **/ IDispatch* CActiveX_TutorialCtrl::GetJSArrayObject(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); LPOLECLIENTSITE site = this->GetClientSite(); IServiceProvider* serviceProvider = nullptr; site->QueryInterface(IID_IServiceProvider, reinterpret_cast<void**>(&serviceProvider)); IHTMLWindow2* window_obj = nullptr; serviceProvider->QueryService(SID_SHTMLWindow, IID_IHTMLWindow2, reinterpret_cast<void**>(&window_obj)); DISPPARAMS disparam = { nullptr, nullptr, 0, 0 }; VARIANT ret_val; DISPID dispid; LPOLESTR method_name = L"Array"; HRESULT hr = window_obj->GetIDsOfNames(IID_NULL, &method_name, 1, LOCALE_SYSTEM_DEFAULT, &dispid); hr = window_obj->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &disparam, &ret_val, nullptr, nullptr); if (ret_val.vt != VT_DISPATCH) return nullptr; VARIANTARG push_arg; method_name = L"push"; hr = ret_val.pdispVal->GetIDsOfNames(IID_NULL, &method_name, 1, LOCALE_SYSTEM_DEFAULT, &dispid); if (hr != S_OK) return nullptr; ::VariantInit(&push_arg); ::VariantChangeType(&push_arg, &push_arg, 0, VT_I4); for (int i = -10; i <= 10; ++i) { push_arg.intVal = i; disparam.rgvarg = &push_arg; disparam.rgdispidNamedArgs = nullptr; disparam.cArgs = 1; disparam.cNamedArgs = 0; hr = ret_val.pdispVal->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &disparam, nullptr, nullptr, nullptr); if (hr != S_OK) return nullptr; } ::VariantClear(&push_arg); serviceProvider->Release(); window_obj->Release(); serviceProvider = nullptr; window_obj = nullptr; return ret_val.pdispVal; } 

Most of the code you see here is typical COM programming. First, we get a pointer to the clientโ€™s site where our control is located. Then we have a QI (request interface) for IServiceProvider, which is an IE interface that implements many supported services. One of them is IHTMLWindow2 , which is the window type of an object in Javascript. Now that we have a pointer to our window object, we can create an Array object. An array is just an IHTMLWindow2 object method, and to create a new array we must call this function.

To call a method for a COM object (and IHTMLWindow2 is just an interface implemented by some COM object), this object must implement an IDispatch interface that allows the user to call this object method using the Invoke method. The GetIDsOfNames method is used to retrieve the DISPID (send identifier) โ€‹โ€‹of the Array method, and then we finally create a new array by calling the Array method in our window_obj object. In the ret_val parameter (of type VARIANT) we get the IDispatch * pointer representing our JS array.

Obviously what to do next: use this pointer to get the DISPID of the push method, and then fill the array with the Call method of this method again and again. The sample function also shows how to create the DISPPARAMS and VARIANTARG objects needed for the IDispatch :: Invoke method.

Finally, we return the IDispatch * pointer from the method. JS recognizes this object as its own JS array, because this is actually its internal implementation.

0
source

All Articles