Scriptable plugin: Error calling method on NPObject - c++

I am getting a JavaScript error: Error calling method on NPObject when calling a method in my NPAPI plugin in Chrome & Firefox on XP. Running the same code on Windows 7 with the same browsers was successful.
I have built a Scriptable plugin using the NPAPI, so far I can debug into the Invoke method of my scriptable object. But I don't believe I have any control after it's finished.
Does anyone have any ideas? Is this an issue only in Windows XP?
bool MY_ScriptableObject::Invoke(NPObject* npobj,
NPIdentifier name,
const NPVariant* args,
uint32_t argCount,
NPVariant* result)
{
bool rc = true;
char* wptr = NULL;
rc = false;
wptr = NULL;
if (name == NPN_GetStringIdentifier("getVersion"))
{
wptr = (NPUTF8*)NPN_MemAlloc(strlen("version:1.0.1") + 1); //Should be freed by browser
if (wptr != NULL)
{
rc = true;
memset(wptr,
0x00,
strlen("version:1.0.1")+1);
memcpy(wptr,
"version:1.0.1",
strlen("version:1.0.1"));
STRINGZ_TO_NPVARIANT(wptr,
*result);
}
}
return (rc);
}
Here is the HTML function that I am executing:
function Version()
{
var plugin = document.getElementById("plugin");
if (plugin == undefined)
{
alert("plugin failed");
return;
}
var text = plugin.getVersion(); //Error happens at this line
alert(text);
}

The (sarcasm)awesome(/sarcasm) thing about NPAPI in current versions of the browsers is that if anything goes wrong with the call you automatically get that error message, even if the plugin has otherwise tried to set an exception with NPN_SetException.
My first guess would be that you compiled your code targeting a later version of windows than windows XP; I'm not sure if that would produce this issue or not. I have never seen the issue you're describing, and I've got plugins running on xp, vista, and 7 with no trouble. You might also try playing with a FireBreath plugin and see if the issue occurs there or not.
I would recommend that you attach with a debugger and set some breakpoints. Start in NPN_GetValue and make sure that it's instantiating your NPObject, then set breakpoints in your NPObject's HasMethod and Invoke methods and see what is hit. Likely something in there will show you what is actually happening, or at least tell you what code is or isn't getting hit.

Related

Reparenting wm and BadWindow errors

I'm writing a reparenting window manager in XCB and C++:http://ix.io/3yNo
At the moment it works pretty well, but occasionally when I close a window, all the windows of that application close because the process exits with a BadWindow. For example if I have a couple xfce4-terminal windows open, all managed by one process,and I close one, occasionally the application will close and I will get a BadWindow (invalid window parameter) error (in the app, not my wm). The very interesting thing is that this is not reproducible but kind of rare, probably a race condition between reporting the error and closing the window due to X11's asynchoronous nature.I have no clue where to begin debugging this, any tips?I kind of suspect it might be something in the Unmap O
Your link contains almost 500 lines of code. I am not going to try to fully understand that. Instead, I'll just randomly guess.
auto window_manager::handle_unmap_notify(xcb_unmap_notify_event_t *ev) -> void {
if (unmap_ignore > 0) {
unmap_ignore--;
return;
}
client *cl = nullptr;
size_t idx = 0;
for (client &c : clients) {
if (c.window == ev->window) {
cl = &c;
break;
}
idx++;
}
if (not cl)
return;
xcb_destroy_window(conn, cl->frame);
clients.erase(clients.begin() + idx);
}
You are destroying windows that are not yours. When the owner of the window accesses it the next time, it will get a BadWindow error.
Instead, you should check a window's WM_PROTOCOLS property and check for WM_DELETE_WINDOW. If that is present, you are supposed to send a WM_DELETE_WINDOW message to the window. See ICCCM § 4.2.8.1: https://tronche.com/gui/x/icccm/sec-4.html#s-4.2.8.1

Cannot set Scanner Capability because L_TwainStartCapsNeg returns error -84

I'm trying to use the Leadtools API version 21 for automatically scanning some documents and here is a sudo code of what I have done (it runs in a secondary thread and the unlock has been done in the main thread):
void CheckRetCode(int rc)
{
if (SUCCESS != rc)
{
L_TCHAR errMsg[1024];
memset(errMsg, 0, sizeof(errMsg));
L_GetFriendlyErrorMessage(rc, errMsg, 1024, L_FALSE);
throw TLeadException(errMsg, rc);
}
}
void OnThreadExecute(void)
{
HTWAINSESSION hSession = nullptr;
APPLICATIONDATA appData;
L_INT nRet;
L_TCHAR pszTwnSourceName[1024];
LTWAINSOURCE sInfo;
memset(&appData, 0, sizeof(APPLICATIONDATA));
appData.uStructSize = sizeof(APPLICATIONDATA);
appData.hWnd = hWnd;// hWnd is valid handle of my main window
appData.uLanguage = TWLG_ENGLISH_USA;
appData.uCountry = TWCY_USA;
wcscpy(appData.szManufacturerName, L"MyCompanyName");
wcscpy(appData.szAppProductFamily, L"MyProductName");
wcscpy(appData.szAppName, appData.szAppProductFamily);
wcscpy(appData.szVersionInfo, L"Version 0.1.0.1");
nRet = L_TwainInitSession2(&hSession, &appData, LTWAIN_INIT_MULTI_THREADED);
CheckRetCode(nRet);// the exception gets catched elsewhere but no error reported here
memset(pszTwnSourceName, 0, sizeof(pszTwnSourceName));
wcscpy(pszTwnSourceName, L"EPSON Artisan837/PX830"); // the name of the scanner is verifyed
sInfo.uStructSize = sizeof(LTWAINSOURCE);
sInfo.pszTwainSourceName = pszTwnSourceName;
CheckRetCode(L_TwainSelectSource(hSession, &sInfo)); // No error reported here
CheckRetCode(L_TwainStartCapsNeg(hSession)); // in here I get the return value -84 which is reported as "TWAIN DS or DSM reported error, app shouldn't (no need for your app to report the error)."
// the rest of the code but we cannot get there since above code reports error
}
Can anyone tell me what I'm doing wrong? Is there a step that I'm missing here?
EditThe function L_TwainSelectSource() make no effort to make sure the supplied source is valid and does not even return an error. As result, if you set the selected source to a garbage name, it will act as if it accepted it. From that point on if you try to Get/Set anything or try to acquire an image, every function returns -84.
Thank you
Sam
To test your code, I put the main window’s handle in a global variable:
globalhWnd = hWnd;
And modified your function to use that handle like this:
void OnThreadExecute(void *)
{
...
appData.hWnd = globalhWnd; // hWnd is valid handle of my main window
...
}
Then created a thread for it from the main program like this:
globalhWnd = hWnd;
_beginthread(OnThreadExecute, 0, 0);
I tried this with 5 different Twain sources: 2 virtual and 3 physical scanners (one of them an old Epson). All 5 drivers returned SUCCESS when calling L_TwainStartCapsNeg() from within the thread.
Two possibilities come to mind:
The problem might be caused by something else in your code other than the thread function.
Or the problem could be specific to your Twain driver.
To rule out the first possibility, I suggest creating a small test project that only creates a similar thread and does nothing else and trying it with different scanners. If it causes the same problem with all scanners, send that test project (not your full application) to support#leadtools.com and our support engineers with test it for you.
If the problem only happens with a specific Twain driver, try contacting the scanner’s vendor to see if they have an updated driver.

How to make Chrome Dev Tools show the JavaScript source

I slightly modified the hello-world.cc sample, importing some code from d8. Then, using websocketpp and asio, I added a WebSocket Server to the program.
Also, I used V8 inspector from an embedder standpoint to add a simple implementation for the inspector protocol back-end.
Now, when I start my program and then use Chrome to navigate to chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9002, I receive the following messages from the CDT:
{"id":1,"method":"Profiler.enable"}
for witch the response is:
{"id":1,"result":{}}
then
{"id":2,"method":"Runtime.enable"}
for this one a notification and a response are sent:
{"method":"Runtime.executionContextCreated",
"params":{"context":{"id":1,"origin":"","name":"MyApplication"}}}
{"id":2,"result":{}}
then:
{"id":3,"method":"Debugger.enable"}
again, a notification and a response sent back to the front-end:
{"method":"Debugger.scriptParsed",
"params":{
"scriptId":"4","url":"func_add.js","startLine":0,
"startColumn":0,"endLine":0,"endColumn":35,
"executionContextId":1,"hash":"365568ee6245be1376631dbf20e7de9d42c9adf1",
"isLiveEdit":false,"sourceMapURL":"","hasSourceURL":false,
"isModule":false,"length":35
}
}
{"id":3,"result":{"debuggerId":"(DC239109305DBEF825A955524584A826)"}}
For the moment, I will not add to the question the other messages received from the front-end, and the responses sent.
The last exchange is:
{"id":7,"method":"Runtime.runIfWaitingForDebugger"}
{"id":7,"result":{}}
My problem: in CDT, the Sources tab is empty (and therefore, I can't try to put a breakpoint).
My code to inject JS in V8:
const char * pszScript = "function add( a, b) { return a+b; }";
v8::Local<v8::String> source =
v8::String::NewFromUtf8(isolate, pszScript, v8::NewStringType::kNormal).ToLocalChecked();
v8::Local<v8::String> name =
v8::String::NewFromUtf8(isolate, "func_add.js", v8::NewStringType::kNormal).ToLocalChecked();
ExecuteString( isolate, source, name );
My ExecuteString function:
bool ExecuteString(v8::Isolate* isolate, v8::Local<v8::String> source,
v8::Local<v8::Value> name) {
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Context::Scope context_scope(context);
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
v8::MaybeLocal<v8::Value> maybe_result;
bool success = true;
v8::ScriptOrigin origin(name);
v8::ScriptCompiler::Source script_source(source, origin);
v8::MaybeLocal<v8::Script> maybe_script;
maybe_script = v8::ScriptCompiler::Compile(context, &script_source);
v8::Local<v8::Script> script;
if (!maybe_script.ToLocal(&script)) {
// Print errors that happened during compilation.
ReportException(isolate, &try_catch);
return false;
}
maybe_result = script->Run(context);
v8::Local<v8::Value> result;
if (!maybe_result.ToLocal(&result)) {
// Print errors that happened during execution.
ReportException(isolate, &try_catch);
return false;
}
if (!result->IsUndefined()) {
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(isolate, result);
fwrite(*str, sizeof(**str), str.length(), stdout);
printf("\n");
} else {
printf("undefined\n");
}
return success;
}
I think I am doing something wrong, as I should be able to see some func_add.js source in CDT with the content function add( a, b) { return a+b; }
W/o checking the source code at all, I remember having some bad times at this exact use case.
try adding to your source parameter a protocol.
CDT needs any protocol file, http, https to create the sources tree.
It will also use this uri to request for maps, or any other source code related thing.
v8::Local<v8::String> name =
v8::String::NewFromUtf8(isolate, "file://func_add.js", v8::NewStringType::kNormal).ToLocalChecked();
ExecuteString( isolate, source, name );
It also happens from time to time, that depending on your v8 implementation, official chrome is not able to show source code, debug, etc.
Try using chrome canary if this is the case.
The protocol implementation is as I described in your referenced post.
Hope this helps.
In your code, I don't see where you discover your Context to the Inspector object, but something like this must happen somewhere in your code:
inspector_->contextCreated(
v8_inspector::V8ContextInfo(context, 1, v8_inspector::StringView(
reinterpret_cast<const uint8_t *>("ABCD"), 4)));
I do this right after creating the Context and setting its global object.
CDT will query script contents with a message of the form:
{"id":8,"method":"Debugger.getScriptSource","params":{"scriptId":"7"}}
While the implementation is very simple, there are many reasons why your code simply will not show up.
Hope that helps.

How come GetDefaultCommConfig fails on windows 10

I use the following code to verify that a serial port name is valid on the computer:
typedef std::pair<StrAsc const, bool> port_pair_type;
typedef std::list<port_pair_type> port_pairs_type;
port_pairs_type pairs;
StrBin config_buffer;
config_buffer.fill(0,sizeof(COMMCONFIG));
while(!pairs.empty())
{
port_pair_type pair(pairs.front());
pairs.pop_front();
if(!pair.second)
{
// we need to get the default configuration for the port. This may
// require some fudging on the buffer size. That is why two calls
// are being made.
uint4 config_size = config_buffer.length();
StrUni temp(pair.first);
COMMCONFIG *config(reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable()));
config->dwSize = sizeof(COMMCONFIG);
rcd = GetDefaultCommConfigW(
temp.c_str(), config, &config_size);
if(!rcd && config_buffer.length() < config_size)
{
config_buffer.fill(0, config_size);
config = reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable());
config->dwSize = sizeof(COMMCONFIG);
rcd = GetDefaultCommConfigW(
temp.c_str(),
reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable()),
&config_size);
}
// if the call succeeded, we can go ahead and look at the
// configuration structure.
if(rcd)
{
COMMCONFIG const *config = reinterpret_cast<COMMCONFIG const *>(
config_buffer.getContents());
if(config->dwProviderSubType == PST_RS232)
port_names.push_back(pair.first);
}
else
{
OsException error("GetDefaultCommConfig Failed");
trace("\"%s\"", error.what());
}
}
else
port_names.push_back(pair.first);
}
On windows 10, when trying to confirm a serial port that uses usbser.sys, the call to GetDefaultCommConfig() is failing and the error code returned by GetLastError() is 87 (invalid parameter). As I am aware, the usbser.sys driver has been rewritten on windows 10 and I suspect that this is a problem with that driver. Does anyone else have an idea of what might be going wrong?
This had been a bug in usbser.sys and was fixed with the Windows 10 Update KB3124262 from 27.01.2016.
The Microsoft employee explained:
The COM port name in the HKLM\HARDWARE\DEVICEMAP\SERIALCOMM registry is not NULL terminated.
Related discussion on MSDN
Because of Windows 10's update policies this issue should not appear in the future anymore.
When you call GetDefaultCommConfigW the second time you probably need to config->dwSize to the new size the structure. Eg:
config->dwSize = config_size;

Abnormal Execution after wglCreateContext in MFC based Application

We have a 32-bit Visual C++/MFC based (Multi-Document Interface-MDI) application which is compiled using Visual Studio 2005.
We are running the application on Windows Server 2008 R2 (64-bit) having ATI Graphics card (ATIES1000 version 8.240.50.5000 to be exact).
We are using OpenGL in certain parts of our software.
The problem is that the software is randomly crashing after executing the code related to initialization of an OpenGL based window. After including heavy tracing in the code, we found out that the program execution becomes abnormal after executing wglCreateContext() function; it skips the rest of the code for the current function for initializing of OpenGL based Window and instead starts executing the default View (drawing) function of the application (eg. ApplicationView::OnDraw).
After executing a few lines of code for the default view, the program generates an exception when trying to access a main document member variable. Our unhandled exception filter is able to catch the exception and generate an execution dump, but the execution dump does not provide much useful information either, other than specifying that the exception code is c0000090.
The problem is quite random and is only reported to appear on this Windows server environment only.
Any help or hints in solving this situation?
EDIT :
in other words, the program structure looks like this, with the execution randomly skipping the lines after wglCreateContext() function, executing a few lines of ApplicationView::onDraw and then causing an exception:
void 3DView::InitializeOpenGL()
{
....
Init3DWindow( m_b3DEnabled, m_pDC->GetSafeHdc());
m_Font->init();
....
}
bool 3DView::Init3DWindow( bool b3DEnabled, HDC pHDC)
{
...
static PIXELFORMATDESCRIPTOR pd = {
sizeof (PIXELFORMATDESCRIPTOR), // Specifies the size
1, // Specifies the version of this data structure
...
};
int iPixelFormat = ChoosePixelFormat(pHDC, &pd);
if(iPixelFormat == 0)
{
...
}
bSuccess = SetPixelFormat(pHDC, iPixelFormat, &pd);
m_hRC = wglCreateContext(pHDC);
//Execution becomes abnormal afterwards and control exits from 3DView::Init3DWindow
if(m_hRC==NULL)
{
...
}
bSuccess = wglMakeCurrent(pHDC, m_hRC);
....
return true;
}
void ApplicationView::OnDraw(CDC* pDC)
{
...
CApplicationDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
...
double currentValue = pDoc->m_CurrentValue;
//EXCEPTION raised at the above line
double nextValue = pDoc->nextValue;
}