So I try to communicate c# code in unity and objective c code in Xcode.
Here is my code:
text.h
extern "C" {
int textTotexture(int hello,int world);
}
text.mm
int textTotexture(int hello,int world){
NSString *myString =[[NSString alloc] init];
NSSize size = [myString sizeWithAttributes:0];
NSImage* newImage = [[NSImage alloc] initWithSize: size];
[newImage lockFocus];
/* if you have a second image you're going to overlay on top of the first, do the same except use NSCompositeSourceOver as the operation */
//NSRect myRect = NSMakeRect(0,0,size.width,size.height);
//[myString drawInRect:myRect withAttributes:0];
[newImage unlockFocus];
//NSData *imageData = [newImage TIFFRepresentation];
//NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
//NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor];
//imageData = [imageRep representationUsingType:NSPNGFileType properties:imageProps];
//int len = [imageData length];
//memcpy(data, [imageData bytes], len);
return hello+world;
}
calling function:
[DllImport("CubePlugin")]
public static extern int textTotexture(int s, int w);
Debug.Log(textTotexture(1,2));
The basic communication is fine as debug log returns 3. but as soon as I add functional code in, the unity just crashes. I suspect some of the native code just doesn't run to the end.
I just found out the issue occurs when I add lock focus and lose focus back in. What shall I do to avoid doing this but achieve my goal?
its not obvious how your are handling your class "text" but you can try this: (I am writing without editor so there might be typos)
#implementation text
//....
-(int)textToTexture:(int)A andValue:(int)B
{
int result = 0;
// do stuff
return result
}
#end
static text* myObject = nil;
extern "C"{
int textToTexture(int a, int b)
{
if(myObject == nil)
myObject = [[text alloc] init];
return [myObject textToTexture:a andValue:b];
}
}
inside your C# file
[DllImport ("__Internal")]
public static extern int textTotexture(int a, int b);
then call the function
Related
I have a function in a C++ DLL that takes one input. I'm trying to have that input be used as an output to the C# call.
Here is my C++ function:
MYAPI int testStuff3(unsigned char* str)
{
printf("%s\n", str);
str = (unsigned char*)malloc(9);
str[0] = 'G';
str[1] = 'o';
str[2] = 'o';
str[3] = 'd';
str[4] = 'b';
str[5] = 'y';
str[6] = 'e';
str[7] = '!';
str[8] = '\0';
return 1;
}
Here is the C# code:
public class Program
{
[DllImport("NativeLib.dll")]
private static extern int testStuff3([In, Out] IntPtr str);
static void Main(string[] args)
{
IntPtr junk3 = IntPtr.Zero;
int ret = testStuff3(junk3);
Byte[] stuff3 = new byte[9];
Marshal.Copy(junk3, stuff3, 0, 9);
}
}
When the Marshal.Copy is called, it gives an error saying that the source (junk3) can not be null.
Will this not work, sending a null pointer to C++ DLL from C# and having the DLL allocate the memory and store something inside and return it to the caller? I want to keep it an IntPtr and not a StringBuilder because the data won't necessarily be a string in the final code. Just an unsigned char array in C++ and I want the IntPtr to point to it.
I've tried different variations of [In, Out], [Out], out and ref for the IntPtr passing.
Never ever allow memory allocations to cross a DLL boundary. That way lies madness, and/or Sparta.
(For the pedantic: you can allocate memory and then pass a pointer across, as long as you either pass ownership back to free it, or guarantee that the same allocator is used as part of a contract. But it's still something to avoid when possible.)
Typically to use a string output parameter you should pass a StringBuilder as the argument, setting its capacity to the maximum expected length. Then in the native code you simply fill this existing buffer.
See the "Fixed length string buffers" section here for an example.
Thanks for the help!
Here's what I ended up with.
C++ function:
MYAPI int testStuff4(wchar_t* str)
{
unsigned char* stuff = (unsigned char*)malloc(10);
stuff[0] = 'G';
stuff[1] = 'o';
stuff[2] = 'o';
stuff[3] = 'd';
stuff[4] = 'b';
stuff[5] = 'y';
stuff[6] = 'e';
stuff[7] = '!';
stuff[8] = '\0';
mbstowcs(str, (const char*)stuff, 1024);
free(stuff);
return 1;
}
C# function:
public class Program
{
[DllImport("NativeLib.dll")]
private static extern int testStuff4(IntPtr str);
static void Main(string[] args)
{
IntPtr junk4 = Marshal.AllocHGlobal(1024);
int ret = testStuff4(junk4);
string junkString = Marshal.PtrToStringUni(junk4);
Console.WriteLine(junkString);
Marshal.FreeHGlobal(junk4);
}
}
Your C++ function doesn’t modify the passed string. It allocates a new one with malloc, stores it in a local variable forgetting the passed value, then returns leaking the memory.
If for some reason you want to do manual marshalling, you probably want something like this (assuming this is for Windows):
MYAPI BOOL __stdcall testStuff3( char** pp )
{
if( nullptr == pp )
return FALSE; // null pointer
if( nullptr != *pp )
{ // Print & release an old string
printf( "%s\n", *pp );
CoTaskMemFree( *pp );
*pp = nullptr;
}
// Allocate a new one
const char* const str = CoTaskMemAlloc( 9 );
if( nullptr == str ) return FALSE;
strncpy( str, "Goodbye!", 9 );
*pp = str;
return TRUE;
}
C#:
public class Program
{
[DllImport( "NativeLib.dll" )]
private static extern bool testStuff3( [In, Out] ref IntPtr str );
static void Main( string[] args )
{
IntPtr ptr = IntPtr.Zero;
if( testStuff3( ref ptr ) )
{
Console.WriteLine( Marshal.PtrToStringAnsi( ptr ) );
Marshal.FreeCoTaskMem( ptr );
}
}
}
However, this is not something I recommend doing unless you have very good reasons. In most cases automatic marshalling is better. For C# -> C++ way it’s trivially simple, const char* or const wchar_t* in C++, string (with correct attributes) in C#. For C++ -> C# you can allocate a StringBuilder in C#, pass char* or wchar_t* to C++, and buffer length in another argument.
I have written an application which calls methods from a dll written in C++. It is a WinForms application, which has a WCF service self-hosted in it. One of the WCF methods is
called in 2-3 seconds periodically. The problem does not occur when only the WCF part is executed. The problem does no appear when only the SDK functions are called. However if
I start the WCF client which calls my method periodically, and the same time I execute some SDK functions, after 10 seconds a FatalExecutionEngineError (System.ExecutionEngineException).
exception is raised and the application crashes. I really don't know what could be the problem, or how to solve it. I suspect it is somehow related with the SDK, but I'm not sure, just a
feeling. Reading the related answers here in SO, maybe the method-imports are wrong? Here is what I got so far:
WCF class:
[ServiceContract]
public partial interface IWCFSample
{
[OperationContract]
string GetData(string param);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public partial class WCFSample : IWCFSample
{
#region Delegates
public delegate string OnGetDataDelegate(object sender, string getDataParam);
#endregion Delegates
#region Events
public event OnGetDataDelegate OnGetData;
#endregion Events
public string GetData(string serializedGetDataParam)
{
string res = string.Empty;
try
{
if (OnGetData != null)
{
res = OnGetData(this, (serializedGetDataParam));
}
}
catch
{
throw;
}
return res;
}
}
Initiated like this:
private ServiceHost _serviceHost;
private WCFSample _samplewcf;
private void Form1_Load(object sender, EventArgs e)
{
_samplewcf = new WCFSample();
_samplewcf.OnGetData += samplewcfOnGetData;
_serviceHost = new ServiceHost(_samplewcf);
_serviceHost.Open();
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += (o, args) =>
{
WCFSampleClient client = new WCFSampleClient();
while (true)
{
if (bw.CancellationPending)
{
return;
}
client.GetData(DateTime.Now.ToString());
Thread.Sleep(200);
}
};
bw.RunWorkerAsync();
}
private string samplewcfOnGetData(object sender, string getDataParam)
{
richTextBox1.Text += "GetData Called - " + getDataParam + "\n";
richTextBox1.SelectionStart = richTextBox1.Text.Length;
richTextBox1.ScrollToCaret();
return getDataParam;
}
The C++ related parts are pretty long, but here are the imports I use.
int OpenDevice (char* strUSBName, int iPortNum )
Imported as:
[DllImport("TP9000.dll")]
public static extern int OpenDevice(string USBNam, int portnum);
int CheckFeeder (int* nCheck)
Imported as:
[DllImport("TP9000.dll")]
public static extern int CheckFeeder(ref int pStatus);
int DP_GetSensorStatus (BYTE *pRailStatus, BYTE *pFeedRollerStatus, BYTE *pTraySensorState)
Imported as:
[DllImport("TP9000.dll")]
public static extern int DP_GetSensorStatus(ref byte pRailStatus, ref byte pFeedRollerStatus, byte[] pTraySensorState);
int PathSenser(int *pStatus)
Imported as:
[DllImport("TP9000.dll")]
public static extern int PathSenser(ref int p1);
int CheckRibbonEx( int *nRibbon, int *nTagRibbon)
Imported as:
[DllImport("TP9000.dll")]
public static extern int CheckRibbonEx(ref int nRibbon, ref int nTagRibbon);
int N_EndOfPrint(int nPanel, int *pPanelCount, int *pJobNo)
Imported as:
[DllImport("TP9000.dll")]
public static extern int N_EndOfPrint(int p1, ref int p2, ref int p3);
int N_PrintJobStatus (int *pJobStatus )
Imported as:
[DllImport("TP9000.dll")]
public static extern int N_PrintJobStatus(int[] p1);
UPDATE:
It seems that the last import is wrong:
int N_PrintJobStatus (int *pJobStatus )
Imported as:
[DllImport("TP9000.dll")]
public static extern int N_PrintJobStatus(int[] p1);
If I don't call this function in my code, it does not hang. But how should I marshal it. The documentation says:
It checks the status of the printing.
int N_PrintJobStatus (int *pJobStatus )
Parameter pJobStatus[out]:
JobStatus[0] = Priter Status : idle(0x00), in printing(0x01), Error-Printing Stop(0xFF)
JobStatus[1] = No Standby Job (on Error, No pausing Job)
JobStatus[2] = the number of standby job (including the currently operating job)
JobStatus[3] = the number of copies of the currently operating job(total number of printing copies)
JobStatus[4] = the number of copies of the remaining jobs (Remaining Count)
JobStatus[5] = if the re-printig checking window displays or not. 1: AUTO Option display, 2:Manual option display, 0: No Checking Window
JobStatus[6] = it checks the error processing and status message level (1~4) then show 0t at retprinting checking window(Auto Option)
Open the printer and then check the ribbon.
Card is ejecting
Ribbon is being synchronized
If you want to re-print, please press “OK” button.( make “OK” button activated)
Return value 0: Success. -1: Failure. (Get_Status)
Okay, without the rest of the code it was impossible to solve this. The wrong code was the following:
int[] nJobSt = { 0, 0, 0, 0, 0, 0 }; //notice that the array length is 6
LastErrorCode = TP9000Dll.N_PrintJobStatus(nJobSt);
From the SDK documentation we should assume the function needs an array length of 7
So the correct code is:
int[] nJobSt = { 0, 0, 0, 0, 0, 0, 0 }; //notice that the array length is 7
LastErrorCode = TP9000Dll.N_PrintJobStatus(nJobSt);
The conclusion: Read every documentation 3 times, never trust the sample applications which are coming with the SDK.
I have a DLL which exports a function that returns a float*, that I would like to use it in my C# code. I am not sure how to Marshal my float* so that I can safely use it in C#.
So, in my C++ DLL, I have declared:
static float* GetSamples(int identifier, int dataSize);
In my C# script, I have:
[DllImport ("__Internal")]
public static extern float[] GetSamples (int identifier, int dataSize);
The C++ GetSamples(int,int) allocates memory and return a pointer t the float array. How do I declare the C# GetSamples to Marshal my float array, and how do I access the data (either by iteration or Marshal.Copy)?
Also, can I delete the float* from C# or do I have to call another C++ function to delete the allocated memory?
EDIT:
So this is what I have tried up to now.
First, on the C# side:
Declaration:
[DllImport ("__Internal")]
public static extern int GetSamples ([In, Out]IntPtr buffer,int length, [Out] out IntPtr written);
Trying to call it:
IntPtr dataPointer = new IntPtr();
IntPtr outPtr;
GetSamples(dataPointer, data.Length, out outPtr);
for (var i = 0; i < data.Length; i++){
copiedData[i] = Marshal.ReadByte(dataPointer, i);
}
Then in my C++ lib:
int AudioReader::RetrieveSamples(float * sampleBuffer, size_t dataLength, size_t * /* out */ written)
{
float* mydata = new float[dataLength];
//This is where I copy the actual data into mydata
memcpy(sampleBuffer, mydata, dataLength*sizeof(float));
delete data;
return dataLength;
}
I don't really know what outPtr is for... And I know I have some additional copying steps that I can removes, I just want to get it working for now.
So this is a bit of a complicated answer...
.NET doesn't know how to handle C++ memory allocation, so regardless returning a float * is dangerous at best for this. Furthermore the .NET memory model is based on COM so it is CoTaskMemAlloc based, not that it really helps you here. So here is what I would suggest:
int AudioReader::RetrieveSamples(
float * sampleBuffer,
int dataLength,
int * /* out */ written)
{
// assuming mydata is already defined
if(sampleBuffer == NULL || dataLength == 0)
{
*written = sizeof(mydata);
return -1;
}
ZeroMemory(sampleBuffer, dataLength);
int toCopy = min(dataLength, sizeof(myData));
//This is where I copy the actual data into mydata
memcpy(sampleBuffer, mydata, toCopy);
*written = toCopy;
return 0;
}
[DLLImport("__internal")]
private static extern int GetSamples(
[In, Out]IntPtr buffer,
[In] int length,
[Out] out int written);
float[] RetrieveFloats()
{
int bytesToAllocate = 0;
GetSamples(IntPtr.Zero, 0, out bytesToAllocate);
if(bytesToAllocate == 0)
return null;
int floatCount = bytesToAllocate/ sizeof(float);
float[] toReturn = new float[floatCount];
IntPtr allocatedMemory = Marshal.AllocHGlobal(bytesToAllocate);
int written = 0;
if(GetSamples(allocatedMemory, bytesToAllocate, out written) != -1)
{
floatCount = written/sizeof(float);
Marshal.Copy(allocatedMemory, toReturn, 0, floatCount);
}
Marshal.FreeHGlobal(allocatedMemory);
return toReturn;
}
Passing a bufferLength of zero would return the space required for the buffer, which can then be allocated and passed in.
You will need to allocate the memory for the buffer in C#, you cannot allocate it in C++
I am trying to create a Win32 DLL exposes some functions which are called in C# as follows
__declspec(dllexport) int GetData(unsigned char* *data, int* size)
{
try
{
int tlen = 3;
unsigned char* tchr = new unsigned char[5];
tchr[0] = 'a';
tchr[1] = 'b';
tchr[2] = 'c';
*size = tlen;
*data = tchr;
return 1;
}
catch (char *p)
{
return 0;
}
}
And on C# side
[DllImport("MyDll.dll")]
static extern int GetData(ref byte[] data, ref int size);
static void Main()
{
try
{
int hr = 0;
byte[] gData = null;
int gSize = 0;
hr = GetData(ref gData, ref gSize);
Console.WriteLine(gSize);
for (int i = 0; i < gSize; i++)
Console.WriteLine((char)gData[i]);
}
catch (Exception p)
{
Console.WriteLine(p.ToString());
}
}
When I run C# code, AccessViolationException happens on GetData function which is a sign of exception in C++ code however, following C++ code snippet works fine without any error.
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char* data = NULL;
int size = NULL;
GetData(&data, &size);
printf("%d", size);
for (int i = 0; i < size; i++)
printf("%c,", data[i]);
return 0;
}
If you compare C# main function and C++ _tmain, they are almost analoguous so where I may make a mistake?
You are returning an array allocated by a call to C++ new and hoping that the marshaler will turn it into a C# byte[]. That won't happen.
You'll need to pass a pointer by reference and then marshal it by hand. Your p/invoke should look like this:
[DllImport("MyDll.dll")]
static extern int GetData(out IntPtr data, out int size);
When the function returns data will point to the array and you can read the contents using the Marshal class. I guess you would copy it to a new byte array.
var arr = new byte[size];
Marshal.Copy(data, arr, 0, size);
Some other points:
The calling conventions do not match. The native side is cdecl and the managed is stdcall.
You'll need to export a deallocator to delete the memory returned by the native function. Consider a re-design where the caller allocates the buffer.
I have a C++ project in which I have to return some variables from C++ to C#.
These char variables are in the main program:
char test1[MAX_Q_LEN], test2[MAX_Q_LEN], test3[MAX_Q_LEN];
After I finish doing something with these variables in my C program, I have to return the values of these variables in a C# program.
ReturnChar.h
extern "C" RETURNCHAR_API TCHAR* __cdecl testString();
ReturnChar.cpp
extern "C" RETURNCHAR_API TCHAR* testString()
{
return ;
}
TestImport C#
static class TestImport
{
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr testString();
}
public partial class MainWindow : Window
{
public MainWindow()
{
try
{
InitializeComponent();
textBox1.Text = ReturnSomething()
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private static string ReturnSomething()
{
IntPtr t = TestImport.testString();
String result = Marshal.PtrToStringAuto(t);
}
I tried with the above approach but I am not able to find out how to return the above char values. Also, this should not be an independent function because the values shoud be fetched only after executing the main which will give the right values in these variables.
Any suggestions?
I will suggest a solution which would require you to change function signature to this:
extern "C" int __cdecl testString(char *output, int outputSize);
That is, pass an allocated buffer as the first argument to the function which will hold the output, and pass the size of the buffer as the second argument.
Note that I mention the return type of the function as int. It is because you could return the output actual size from the function, and the caller can interpret this value to confirm that outputSize value was large enough to hold the output string. For example, you could implement testString() as:
int testString(char *output, int outputSize)
{
std::string const & s = getString();
if ( s.size() <= outputSize )
{
std::strncpy(output, s.c_str(), s.size());
return s.size(); //return the actual size of output
}
else //means s.size() > outputSize, i.e outputSize is smaller than required!
{
std::strncpy(output, s.c_str(), outputSize);
return s.size(); //return what is required (the actual size of output)!
}
}
Then in C# code, do this:
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int testString(out StringBuilder output, int outputSize);
And call it as:
private static string ReturnSomething()
{
int bufferSize = 100;
StringBuilder buffer= new StringBuilder(bufferSize);
int outputSize = TestImport.testString(buffer, bufferSize);
if ( outputSize < bufferSize ) //output bufferSize was sufficient
{
return buffer.ToString();
}
else //output bufferSize was insufficient
{
//retry!
bufferSize = outputSize;
buffer = new StringBuilder(bufferSize); //reallocate!
outputSize = TestImport.testString(buffer, bufferSize);
if ( outputSize <= bufferSize )
return buffer.ToString();
else
{
throw new Exception("PANIC");
}
}
}
I'm not quite big c++ spec, but maybe to use bstrs in c++
_bstr_t text("saasas");
return text.Detach();
and for c# parameter
[MarshalAs(UnmanagedType.BStr)]
or to pass StringBuilder to your c++ func with some preallocated capacity