I am newbie of C++/CLI.
I already know that the pin_ptr's functionality is making GC not to learn to specified object.
now let me show you msdn's example.
https://msdn.microsoft.com/en-us//library/1dz8byfh.aspx
// pin_ptr_1.cpp
// compile with: /clr
using namespace System;
#define SIZE 10
#pragma unmanaged
// native function that initializes an array
void native_function(int* p) {
for(int i = 0 ; i < 10 ; i++)
p[i] = i;
}
#pragma managed
public ref class A {
private:
array<int>^ arr; // CLR integer array
public:
A() {
arr = gcnew array<int>(SIZE);
}
void load() {
pin_ptr<int> p = &arr[0]; // pin pointer to first element in arr
int* np = p; // pointer to the first element in arr
native_function(np); // pass pointer to native function
}
int sum() {
int total = 0;
for (int i = 0 ; i < SIZE ; i++)
total += arr[i];
return total;
}
};
int main() {
A^ a = gcnew A;
a->load(); // initialize managed array using the native function
Console::WriteLine(a->sum());
}
hear is the question.
Isn't it okay, the passed object(arr) not pinned ?
because the unmanaged code(native_function) is sync operation and finished before the C++/CLI code (load)
is there any chance the gc destory arr, even though the main logic is running?
(I think A is main's stack variable and arr is A's member variable, so while running main, it should visible)
if so, how can we guarantee that the A is there before invoking load?
(only while not running in native-code?)
int main() {
A^ a = gcnew A;
// I Think A or arr can be destroyed in here, if it is able to be destroyed in native_function.
a->load();
...
}
Thanks, in advance.
The problem that is solved by pinning a pointer is not a normal concurrency issue. It might be true that no other thread will preempt the execution of your native function. However, you have to count in the garbage collector, which might kick in whenever the .NET runtime sees fit. For instance, the system might run low on memory, so the runtime decides to collect disposed objects. This might happen while your native function executes, and the garbage collector might relocate the array it is using, so the pointer you passed in isn't valid anymore.
The golden rule of thumb is to pin ALL array pointers and ALL string pointers before passing them to a native function. ALWAYS. Don't think about it, just do it as a rule. Your code might work fine for a long time without pinning, but one day bad luck will strike you just when it's most annoying.
Given:
{
CComSafeArray<VARIANT> sa;
CComVariant ccv(L"test");
sa.Add(ccv, TRUE);
}
I was hoping the dtor of CComSafeArray would call ::VariantClear on each contained member and the documentation seems to indicate that:
In certain cases, it may be preferable to clear a variant in code without calling VariantClear.
For example, you can change the type of a VT_I4 variant to another type without calling this
function. Safearrays of BSTR will have SysFreeString called on each element not VariantClear.
However, you must call VariantClear if a VT_type is received but cannot be handled. Safearrays
of variant will also have VariantClear called on each member.
(source: http://msdn.microsoft.com/en-us/library/windows/desktop/ms221165(v=vs.85).aspx)
But I see no such thing happening in the code in atlsafe.h.
Am I just looking in the wrong place or is this just supposed to happen as a side-effect of ::SafeArrayDestroy() -- which is the only thing happening via the CComSafeArray dtor.
Ultimately VariantClear will get called on the contents of the CComSafeArray object, albeit after progressing through multiple layers. CComSafeArray::~CComSafeArray() calls CComSafeArray::Destroy() which is ultimately a wrapper of SafeArrayDestroy():
HRESULT Destroy()
{
HRESULT hRes = S_OK;
if (m_psa != NULL)
{
hRes = Unlock();
if (SUCCEEDED(hRes))
{
hRes = SafeArrayDestroy(m_psa);
if (SUCCEEDED(hRes))
m_psa = NULL;
}
}
return hRes;
}
SafeArrayDestroy() is documented as calling VariantClear on its contents if it contains VARIANTs:
Safe arrays of variant will have the VariantClear function called on
each member and safe arrays of BSTR will have the SysFreeString
function called on each element.
I have made a COM object with multiple dual interfaces. It worked in an earlier version of compiler, but not in the current version.
My question: Does the COM spec say this should work (and therefore I should report a compiler bug), or is not meant to work? This page suggests that perhaps it is not meant to work.
The RIDL file:
[
uuid(0A6CC6CE-623E-4455-8B9B-65178FB7585A),
version(1.0),
helpstring("Library to illustrate failure of Dispatch interface")
]
library DaxFail
{
importlib("stdole2.tlb");
interface IFoo;
coclass DaxFailClass;
interface IBar;
[
uuid(2CD15FFC-0C09-4A29-BD57-99BBC53AE01F),
helpstring("Dispatch interface for DaxFailClass Object"),
dual,
oleautomation
]
interface IFoo: IDispatch
{
[id(0x000000C9)]
HRESULT _stdcall foo_method(void);
};
[
uuid(AECB5DF3-EDE3-441A-93E6-220CB271AD43),
dual,
oleautomation
]
interface IBar: IDispatch
{
[id(0x000000C9)]
HRESULT _stdcall bar_method(void);
};
[
uuid(9DCD1024-6E1A-435E-82F9-FD4FE863D710),
helpstring("DaxFailClass Object")
]
coclass DaxFailClass
{
[default] interface IFoo;
interface IBar;
};
};
The code to access it (this is pseudocode, I have extra statements in "real" code to display the HRESULTs):
const GUID CLSID_DaxFailClass = {0x9DCD1024, 0x6E1A, 0x435E,{ 0x82, 0xF9, 0xFD,0x4F, 0xE8, 0x63,0xD7, 0x10} };
const GUID IID_IFoo = {0x2CD15FFC, 0x0C09, 0x4A29,{ 0xBD, 0x57, 0x99,0xBB, 0xC5, 0x3A,0xE0, 0x1F} };
const GUID IID_IBar = {0xAECB5DF3, 0xEDE3, 0x441A,{ 0x93, 0xE6, 0x22,0x0C, 0xB2, 0x71,0xAD, 0x43} };
int _tmain()
{
IDispatch *intf, *ibar;
HRESULT hr;
DISPID disp_id;
wchar_t *name;
CoInitialize(NULL);
hr = CoCreateInstance(CLSID_DaxFailClass, 0, CLSCTX_ALL, IID_IDispatch, (void **)&intf);
// This returns 0 , and doing Invoke with disp_id executes foo_method
name = L"foo_method";
intf->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &disp_id );
// returns 0
hr = intf->QueryInterface(IID_IBar, (void **)&ibar);
// this returns 0x80020006
name = L"bar_method";
hr = ibar->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &disp_id );
// This returns 0 , and doing Invoke with disp_id executes foo_method
name = L"foo_method";
hr = ibar->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &disp_id );
CoUninitialize();
getchar();
}
So, the trouble is that ibar behaves exactly like intf. ibar can have foo_method called on it, but does not seem to know what bar_method is.
I was expecting the second GetIDsOfNames call to give 0 and then Invoke to be able to call bar_method, and the third GetIDsOfNames should give 0x80020006.
Extra info about compilers (although, to be clear, my question is whether the COM spec says it should work or not): Works in BDS 2006 and does not work in C++Builder XE5. I trawled through the code in XE5 which implements COM, and the ojbect factory fills an ITypeInfo * using GetTypeInfoOfGUID(CLSID_....) when the object is first created, but then the implementation of QueryInterface just uses the same ITypeInfo for all results, it does not call GetTypeInfoOfGUID again with the new IID. That ITypeInfo is passed to DispGetIDsOfNames in the implementation of IDispatch::GetIDsOfNames.
The specs don't have to say something to that.
You have to different interfaces on one class. This is allowed.
Both derive from IDispatch. This is allowed too.
Both have to do their own implementation and this implementation should do its job.
If something is wrong with your dual interface "usally" the IDL compiler will tell it to you.
Here with your code: I can say nothing without seeing the class implementation for the interfaces.
And yes: It works and you find a sample for ATL here at CodeProject
It is exactly what you are doing and far more.
When I return a direct ByteBuffer to JNI, how long until it can get reclaimed by the JVM/GC?
Suppose I have a function like this:
void* func()
{
[ ... ]
jobject result = env->CallStaticObjectMethod(testClass, doSomethingMethod);
void* pointerToMemory = env->GetDirectBufferAddress(result);
return pointerToMemory;
}
The JVM can't possibly know how long I'm going to use that pointerToMemory, right? What if I want to hold on to that address and the corresponding memory for a while?
Suppose I want to circumvent this issue and return a byte[] from Java to JNI like this:
ByteBuffer buf;
byte[] b = new byte[1000];
buf = ByteBuffer.wrap(b);
buf.order(ByteOrder.BIG_ENDIAN);
return buf.array();
AND THEN do the same as above, I store a pointer to that byte[] and want to hold on to it for a while. How / when / why is the JVM going to come after that backing byte[] from Java?
void* function()
{
jbyteArray byteArr = (jbytearray)env->CallStaticObjectMethod(testClass, doSomethingMethod);
jbyte *b= env->GetByteArrayElements(byteArr, 0);
return b;
}
The short answer is: If the function implements a native method, the pointer will be invalid as soon as you return.
To avoid this, you should get a global reference for all objects that you intend to keep valid after returning. See the documentation on local and global references for more information.
To understand better how JNI manages references from native code, see the documentation on PushLocalFrame/PopLocalFrame.
Is it possible to increase the RCW reference count on an unknown interface?
(i.e. not the reference count on the underlying COM object)
I have some old COM server code
int Method1(object comobject) {
try {
// do something with comobject
return 0;
}
finally {
Marshal.ReleaseComObject(comobject);
}
}
This code works fine but now I need to call it from another method.
int Method2(object comobject) {
int result = Method1(comobject);
// Do something with combject
}
The type of comobject will vary (that is why it is object)
There is a way, the RCW count counts how many times the object has been marshaled you can increase this number by performing an additional marshal.
public static T AddRcwRef<T>(T t)
{
IntPtr ptr = Marshal.GetIUnknownForObject(t);
try {
return (T)Marshal.GetObjectForIUnknown(ptr);
}
finally {
Marshal.Release(ptr); // done with the IntPtr
}
}
I'm not sure I would recommend using this method, it's probably better to try and get rid of your ReleaseComObject calls.
For further reading, see this blog post on the subject I wrote.
There's the Marshal.AddRef() method, wrong reference count change though. I'm pretty sure incrementing the RCW count directly is not possible. Dig yourself out of the deep hole you're in and fix the old code.