I am seeing this warning in my JNI code:
JNI WARNING: 0x44be7258 is not a valid JNI reference
I am assigning a LocalReference returned by FindClass method in JNI to my class member variable within the constructor:
Header:
...
jclass m_class;
Cpp:
m_class = env->FindClass( classSignature );
Does FindClass return a LocalReference and storing it in my class member variable is invalid?
From the Liang book, chapter 5.1.1 "Local References"
Most JNI functions create local references ... A local reference is valid only within the dynamic context of the native method that creates it, and only within that one invocation of the native method. All local references created during the execution of a native method will be freed once the native method returns.
Followed by an illegal code example which uses exactly your method FindClass. In other words, yes, FindClass returns a local reference. In the following chapter is an example of creating a global reference which is usable in the way you wanted. Don't forget to DeleteGlobalRef when you don't need it anymore. Otherwise JVM cannot GC it and your program will leak.
Related
I'm trying to write a DLL to access the C++-only method Windows.Devices.Bluetooth.BluetoothLEDevice.Close() from a C# app. I seem to be able to access the class, but Visual Studio will not build if I try to use that one method. It is shown in the member list that comes up as you type, and there is no Intellisense error, just the build error.
using namespace Windows::Devices::Bluetooth;
__declspec(dllexport) void CloseBleDeviceUnmanaged(BluetoothLEDevice^device)
{
if (device->ConnectionStatus == BluetoothConnectionStatus::Connected) //no complaints for a property
{
device->GetDeviceSelector(); //no complaints for a method either
device->Close(); //Error C2039 | 'Close': is not a member of 'Windows::Devices::Bluetooth::BluetoothLEDevice'
}
return;
}
How do I get this to at least build?
(edit: removed extraneous syntax problem as per Nico Zhu - MSFT's answer)
You don't need to do any of this to call Close from C# -- just put it in a using(...) block and it will dispose (close) the object for you automatically. If the lifetime of the objection doesn't lend itself well to a using block, you can simply call IDisposabe.Dispose() on it directly.
For the compiler error, this is documented in MSDN since you should never call Close from C++/CX:
Close methods aren't callable through Visual C++ component extensions (C++/CX) on Windows Runtime class instances where the class implemented IClosable. Instead, Visual C++ component extensions (C++/CX) code for runtime classes should call the destructor or set the last reference to null.
The parameter of CloseBleDeviceUnmanaged method is Value Type in your case. When you pass a parameter to the method. The parameter will generate a copy. And the original parameter has not been changed. Please pass the
reference type parameter like the follow.
void DevicesTool::CloseBleDeviceUnmanaged(Windows::Devices::Bluetooth::BluetoothLEDevice^device)
{
if (device->ConnectionStatus == BluetoothConnectionStatus::Connected)
{
device->GetDeviceSelector();
device->Close();
}
}
As for the Close method, I have reproduced the issue in my side(target platform version 16299), and I have report this to related team. Please pay attention to the thread update.
I'd like to use a single duktape/C constructor function as dispatcher for these kind of calls. When the dispatcher function is called I need to know for which class this happend to call the appropriate C++ construction function.
I guess the this binding won't help since it represents the (not yet fully initialized) JS object we are creating here.
Another option would be the current function, but from the docs I can't see how to get the class name from that. What else could I use?
Could you elaborate what you mean by "class name"? Do you mean the .name property of the Ecmascript function object which is used as a the 'new' target?
If so, you can use duk_is_constructor_call() to see if the current call is a constructor call, then use duk_push_current_function() to get access to the Ecmascript constructor function object, and then read its properties using the usual property API calls. For example, if by "class name" you mean .name of the function object, you'd just read its "name" property using duk_get_prop_string().
In Win CE 6.0, class TankObject is defined in a static library, C++ compiler is VS2008; target is ARM4 (/QRarch4).
An instance of class TankObject is constructed by a call of the form
*TankObject myTankObject = new TankObject(parm1, parm2 ...);
Last attribute declared in TankObject definition is an object pointer, and when an assignment is made to same, memory corruption of another dynamically allocated object occurs.
Step into constructor reveals that operator new is called with a size of 0x500. sizeof(TankObject) reveals two different values, depending on the context:
In instantiating context (the application), sizeof(TankObject) and sizeof(*myTankObject) is 0x500.
In context of the object itself (the constructor, or object methods), sizeof(TankObject) and sizeof(*this) is 0x508. The address of last declared attribute is 0x500, relative to object.
The call to new requests and receives 0x500 bytes. The object itself expects and uses 0x508 bytes, which can cause assignments to last attribute to step on other dynamically allocated objects.
Work around is to declare another unused attribute at the end of the object definition, to pad the request to new.
Both contexts include the same .h file, to debug I changed include statement to an explicit path name. I also went through compiler switches, made them identical. So I am puzzled, if any one can shed light, I'm glad, I would like to know a proper solution.
this is the source of the issue. My answer there was deleted with the hint to start a new question. So, here we go:
I want to pass the managed reference of this to unmanaged code. And then call the managed callback out of the unmanaged callback.
public ref class CReader
with a private field
private:
[...]
void *m_pTag;
[...]
In the constructor of the managed class I initialize the m_pTag like this:
m_pTag = new gcroot<CReader ^>(this);
Later, I pass this void *m_pTag to the unmanaged code. If the unmanaged callback is called, I'm casting the void *m_pTag back to managed reference and call the managed callback
(*(gcroot<CReader ^>*)pTag)->MANAGEDCALLBACKFUNCTION
and there is an exception thrown, if the DLL is used under another AppDomain. The Debugger stops in gcroot.h on line
// don't return T& here because & to gc pointer not yet implemented
// (T should be a pointer anyway).
T operator->() const {
// gcroot is typesafe, so use static_cast
return static_cast<T>(__VOIDPTR_TO_GCHANDLE(_handle).Target);
}
with Cannot pass a GCHandle across AppDomains.
My question is, what should I do?
Sincerly,
Sebastian
==================== EDIT ====================
I am now able to reproduce the problem. I've took some screenshots, to show the issue.
1st screenshot: constructor
snd screenshot: callback
The problem is, that the value-member of the struct gcroot in the callback is empty.
Thank you.
Sebastian
==================== EDIT ====================
Push.
The gcroot<> C++ class is a wrapper that uses the GCHandle class. The constructor calls GCHandle.ToIntPtr() to turn the handle into an opaque pointer, one that you can safely store as a member of an unmanaged struct or C++ class.
The cast then, later, converts that raw pointer back to the handle with the GCHandle.FromIntPtr() method. The GCHandle.Target property gives you the managed object reference back.
GCHandle.FromIntPtr() can indeed fail, the generic exception message is "Cannot pass a GCHandle across AppDomains". This message only fingers the common reason that this fails, it assumes that GCHandle is used in safe code and simply used incorrectly.
The message does not cover the most common reason that this fails in unsafe code. Code that invariably dies with undiagnosable exceptions due to heap corruption. In other words, the gcroot<> member of the C++ class or struct getting overwritten with an arbitrary value. Which of course dooms GCHandle.FromIntPtr(), the CLR can no longer find the handle back from a junk pointer value.
You diagnose this bug the way you diagnose any heap corruption problem. You first make sure that you get a good repro so you can trip the exception reliably. And you set a data breakpoint on the gcroot member. The debugger automatically breaks when the member is written inappropriately, the call stack gives you good idea why this happened.
In the MSDN documentation for the AppDomain.CreateInstanceAndUnwrap method, it states as a note
If you make an early-bound call to a method M of an object of type T1 that was returned by CreateInstanceAndUnwrap, and that method makes an early-bound call to a method of an object of type T2 in an assembly C other than the current assembly or the assembly containing T1, assembly C is loaded into the current application domain. This loading occurs even if the early-bound call to T1.M() was made in the body of a DynamicMethod, or in other dynamically generated code. If the current domain is the default domain, assembly C cannot be unloaded until the process ends. If the current domain later attempts to load assembly C, the load might fail.
(http://msdn.microsoft.com/en-us/library/3c4f1xde.aspx)
Does anyone have a technical explanation for the above note? Why is this the case? Is Assembly dependency lookup done when a method is first called on the object?
Assembly dependency is call when you're creating instance of the object.
Let's analyze hypothetical scenario. We have 2 DLLs: Lib1 and Lib2. (Lib1 uses methods from Lib2).
In our application main method looks as below:
Worker localWorker = new Worker();
localWorker.PrintDomain();
AppDomain ad = AppDomain.CreateDomain("New domain");
Worker remoteWorker = (Worker)ad.CreateInstanceAndUnwrap("Lib1","Lib1.Worker");
remoteWorker.PrintDomain();
Assembly dependency is checking in line:
Worker remoteWorker = (Worker)ad.CreateInstanceAndUnwrap("Lib1","Lib1.Worker");
For example if the Lib2.dll doesn't exist we'll get an exception.