I have a code like-
void CSomeClass::Remove()
{
BSTR tempStr = NULL;
while(!m_list.IsEmpty()) //m_list is a CSomeClass member of type CList<BSTR, BSTR>
{
tempStr = m_list.RemoveHead(); //application crash here!!
if(NULL==tempStr)
continue;
}
SysFreeString(tempStr);
}
And I am not sure why the application got crash.
Is it possible to initialize a BSTR to another BSTR using assignment operator?
Can anyone help me in finding out why the application is crashing?
Yes. BSTR can be assigned to another BSTR variable. BSTR is actually the starting address of the actual data.
The problem here is with the RemoveHead() function and not the assignment.
Please see the complete stack trace or just attach a debugger to your program to debug the issue further.
Put the SysFreeString inside the loop
void CSomeClass::Remove()
{
BSTR tempStr = NULL;
while(!m_list.IsEmpty()) //m_list is a CSomeClass member of type CList<BSTR, BSTR>
{
tempStr = m_list.RemoveHead(); //application crash here!!
if(NULL==tempStr)
continue;
SysFreeString(tempStr);
}
}
Related
Hi there I have a c native library that is returning me json as char*. What I would like to do in c# is to use this pointer and write it straight to the
this.ControllerContext.HttpContext.Response.BodyWriter;
I'm able to create ReadOnlySpan from the ptr but as far as I can tell PipeWriter only accepts ReadOnlyMemory<byte> which does not have a constructor from IntPtr. Is there a way to create ReadOnlyMemory<byte> from IntPtr or some other way to writer my string from native library withou copying it one extra time?
This answer provides a solution that does not need to copy the entire buffer:
Marshalling pointer to array P/Invoke
TL;DR: Take UnmanagedMemoryManager from Pipelines.Sockets.Unofficial by Marc Gravell.
int* ptr = ...
int len = ...
var memory = new UnmanagedMemoryManager<int>(ptr, len).Memory;
Unfortunately, you still need to allocate the MemoryManager (it must be a class, not a struct).
Thank you for your answers but none of them was without extra copy. I was finally figure it out so in case somebody struggle with it, here is the solution.
So the only way I as able to achieve this is like.
await Response.StartAsync(HttpContext.RequestAborted);
var dest = Response.BodyWriter.GetMemory((int)jsonLen).Pin();
unsafe { memcpy(dest.Pointer), srcPtr, srcLen); }
Response.BodyWriter.Advance(srcLen);
await Response.BodyWriter.FlushAsync(HttpContext.RequestAborted);
Maybe use something like this?
public class Utility
{
public System.ReadOnlyMemory<T> ConvertToReadOnlyMemory(System.ReadOnlySpan<T> input) {
var tmp = new System.Memory<T>();
input.CopyTo(tmp.Span);
return (System.ReadOnlyMemory<T>)tmp;
}
}
However, I think this will involve completely copying the stream into heap storage, which is probably not what you want...
I glad if this could speed up and match to what you wants.
namespace Helper
{
using System;
using System.Runtime.InteropServices;
public static class CStringMapper
{
// convert unmanaged c string to managed c# string
public string toCSharpString(char* unmanaged_c_string)
{
return Marshal.PtrToStringAnsi((IntPtr)unmanaged_c_string);
}
// Free unmanaged c pointer
public void free(char* unmanaged_c_string)
{
Marshal.FreeHGlobal((IntPtr)unmanaged_c_string);
}
}
}
Usage:
using Helper;
/* generate your unmanaged c string here */
try
{
// eg. char* OO7c = cLibFunc();
string cSharpString = CStringMapper.toCSharpString(OO7c);
}
finally
{
// Make sure to freeing the pointer
CStringMapper.free(OO7c);
}
I have a string object which is passed between managed (C++/cli) and unmanaged (C++) environments.
const WCHAR *unique() const { return L"Hellow World" ; }
String^ csCol = gcnew String(unique());
String^ csColOut = csCol;
Now I want to do append "__a" to csCol which I do as:
csCol = csCol + "__a"
However it seems to be giving an error: "The pointer passed in as a String must not be in the bottom 64K of the process's address space". Can someone please help me understand as to where am I going wrong.
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.
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.
I've run into this problem before, but never in a situation like this. I'm completely confused. As the question states, I'm getting the runtime error "Object reference not set to an instance of an object." Using the debugger tools, I think I've pinpointed the problem to this line:
dataFileLocation = path;
The entire function is here:
void DATReader::SetPath(String^ path)
{
if(!File::Exists(path))
{
MessageBox::Show( "DATReader (missing dat file: \n"+path+"\n )", "Error", MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
return;
}
dataFileLocation = path;
}
dataFileLocation is declared here, but nothing is assigned to it:
ref class DATReader
{
private:
System::String^ dataFileLocation;
// ...
}
Now I know the reason I'm getting the error is because dataFileLocation is assigned to nothing. But I'm having problems assigning it. When I add = 0; to it, it won't build because its a ref class. When I try to assigned it to = 0; in the constructor, it yells at me for trying to convert it from a System::String^ to an int. If I assign it to a = gcnew String(""); it builds, but throws the same runtime exception.
I don't get it, am I reading the debugger wrong, and this isn't the source of the problem at all? I've just started to use managed code recently, so I'm confused :\
You may want to check and make sure your DATReader object isn't null as well It may be throwing the exception at your DATReader.SetPath() call.
This is a nicety in C# that's missing in C++/CLI. C# generates code that ensures this can never be null. Easily seen in the debugger by setting a breakpoint on the method and inspecting "this". Here's an example program that reproduces the exception:
#include "stdafx.h"
using namespace System;
ref class Example {
String^ dataFileLocation;
public:
void SetPath(String^ path) {
dataFileLocation = path; // Set breakpoint here and inspect "this"
}
};
int main(array<System::String ^> ^args)
{
Example^ obj /* = gcnew Example */;
obj->SetPath("foo");
return 0;
}
Remove the /* */ comments to fix. Fix your code by looking at the call stack to find the method that forgot to instantiate the object.
Managed C++ uses nullptr for null references. So you can check:
if (path == nullptr) { ... }
or use:
if (!String::IsNullOrEmpty(path))