Marshaling char * in .NetcompactFramework(Windows CE) - windows-ce

I have the following signature from c++
IDTECHREADER_EXPORTS void ReadTwoBlocks(char *pathConfig,
char *datablock1, char *datablock2, int timeout, bool &ret )
I was able to Marshal this correctly on the Full .NetFrameWork and it works as below
[DllImport("IDTechReader.dll", EntryPoint = "ReadTwoBlocks" )]
private static extern void _ReadTwoBlocks(
[In][MarshalAs(UnmanagedType.LPStr)] string pathConfig,
[Out][MarshalAs(UnmanagedType.LPStr)] StringBuilder datablock1,
[Out] [MarshalAs(UnmanagedType.LPStr)] StringBuilder datablock2,
int TimeOut,
ref bool result);
However using the same Marshaling as above doesn't work on the NetcompactFramework(Windows CE) it gives an error "NotSupported Exception"
How do we correctly Marshal the above C++ method signature so that it will work correctly on the .NET CompactFramework(windows CE)
any ideas are apperciated...thanks.

The marshaler is probably choking on the MarshalAs(UnmanagedType.LPStr). You're either going to have to change the signature to a fixed size byte[] and do the string conversion in managed code using Encoding.ASCII.GetString(), or you could use an IntPtr type and allocate the memory using Marshal.AllocHGlobal/FreeHGlobal and deal with the string conversion in your code.
I think this might work..
private const int MAX_STRING = 256;
[DllImport("IDTechReader.dll", EntryPoint = "ReadTwoBlocks")]
private static extern void _ReadTwoBlocks(
byte[] pathConfig,
[Out] byte[] datablock1,
[Out] byte[] datablock2,
int TimeOut,
ref bool result);
public void ReadTwoBlocks(string pathConfig,
StringBuilder datablock1,
StringBuilder datablock2,
int TimeOut,
ref bool result)
{
var pathConfigBuff = new byte[MAX_STRING];
var datablock1Buff = new byte[MAX_STRING];
var datablock2Buff = new byte[MAX_STRING];
// Convert unicode string to null terminated single byte charater string
Array.Copy(Encoding.ASCII.GetBytes(pathConfig), pathConfigBuff, pathConfig.Length);
// Call your native method
_ReadTwoBlocks(pathConfigBuff, datablock1Buff, datablock2Buff, TimeOut, ref result);
// If success, copy the datablocks to the StringBuffers
if (result)
{
datablock1.Append(Encoding.ASCII.GetString(datablock1Buff, 0, MAX_STRING).Replace('\0', ' ').Trim());
datablock2.Append(Encoding.ASCII.GetString(datablock2Buff, 0, MAX_STRING).Replace('\0', ' ').Trim());
}
}

It would be something like this:
[DllImport("IDTechReader.dll")]
private static extern void ReadTwoBlocks(IntPtr pathConfig,
IntPtr datablock1, IntPtr datablock2, int timeout, ref bool ret);
and when you use it like this:
string pathConfig = "..\program.ini";
IntPtr ptrPathConfig = IntPtr.Zero;
ptrPathConfig = Marshal.StringToHGlobalAnsi(pathConfig);
IntPtr ptrDatablock1 = IntPtr.Zero;
IntPtr ptrDatablock2 = IntPtr.Zero;
int timeout = 300;
bool ret = false;
ReadTwoBlocks(ptrPathConfig, ptrDatablock1, ptrDatablock2, timeout, ref ret);
string db1 = Marshal.PtrToStringAnsi(ptrDatablock1);
string db2 = Marshal.PtrToStringAnsi(ptrDatablock2);

Related

C++ to C# char[]

C# code:
class Hello{
public void helloWorld(char[] chars){
//do something
}
}
C++ code to call C#:
MyCSDLL::Hello* hello;
//init hello, some calls are ok.
char* myCharPtr;
//init with message
HRESULT result = hello->helloWorld(safeArray, (MyCSDLL::_MyRetVal) _retValPtr);
Adapting from How to create and initialize SAFEARRAY of doubles in C++ to pass to C#
void createSafeArray(SAFEARRAY** saData, char* charPtr)
{
char* iterator = charPtr;
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 10;
*saData = SafeArrayCreate(VT_R8, 1, &Bound);
char HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
do {
*pdFreq++ = *iterator;
} while (*iterator++);
}
}
How to call hello->helloWorld()? it is expecting SAFEARRAY*. The current code gives 80131538 error. How to fix it?
C++ Project is not CLR.
Let's suppose the C# code is this:
namespace ClassLibrary1
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Hello
{
public void helloWorld(char[] chars)
{
...
}
}
}
Then, you can call it with this C/C++ code, for example:
#import "C:\mycode\ClassLibrary1\bin\Debug\classlibrary1.tlb" raw_interfaces_only
using namespace ClassLibrary1;
HRESULT CallHello(wchar_t* charPtr, int count)
{
CComPtr<_Hello> p;
HRESULT hr = p.CoCreateInstance(__uuidof(Hello));
if (FAILED(hr))
return hr;
SAFEARRAY* psa = SafeArrayCreateVector(VT_UI2, 0, count);
if (!psa)
return E_OUTOFMEMORY;
LPVOID pdata;
hr = SafeArrayAccessData(psa, &pdata);
if (SUCCEEDED(hr))
{
CopyMemory(pdata, charPtr, count * 2); // count is the number of chars
SafeArrayUnaccessData(psa);
hr = p->helloWorld(psa);
}
SafeArrayDestroy(psa);
return hr;
}
.NET's char type is unicode, so the binary size is two bytes, the C equivalent is wchar_t (or unsigned short, etc...). So the safearray element type must match that, that's why I used VT_UI2 (VT_R8 that you used is Real of size 8 bytes, so it's equivalent to .NET's double type).
If you really want to use C's char, then you must do some kind of conversion to a 2-byte character.
Also, you can use the SafeArrayCreateVector function which directly allocates a 1-dimension safe array. Don't forget to call cleanup methods.

SocketCAN in dotnet core

I am writing software for the device on Linux, and which should work with the CAN interface. Ideally, I would like to work with the interface without connecting third-party libraries from c ++. Is it possible?
I solved this problem using native function. Here example to bind socket, can read and write message with native functions write( or aio_write) and read. CanPublisher in UDSim as example
const int Siocgifindex = 0x8933;
private const int PfCan = 29;
private const int SockRaw = 3;
private const int CanRaw = 1;
private const int CanMtu = 16;
[DllImport("libc", SetLastError = true)]
private static extern int socket(int domain, int type, int protocol);
[DllImport("libc", SetLastError = true)]
private static extern int ioctl(int fd, int request, ref Ifreq mtu);
[DllImport("libc", SetLastError = true)]
private static extern int bind(int fd, ref SockaddrCan addr, int addrlen);
[StructLayout(LayoutKind.Sequential)]
struct SockaddrCan
{
public ushort can_family;
public int can_ifindex;
public uint rx_id;
public uint tx_id;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct Ifreq
{
public Ifreq(string ifr_name)
{
this.ifr_name = ifr_name;
this.ifr_ifindex = 0; // ifru_ivalue
this.ifru_mtu = 0;
}
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string ifr_name;
public int ifr_ifindex;
public uint ifru_mtu;
}
var addr = new SockaddrCan();
var s = socket(PfCan, SockRaw, CanRaw);
var ifr = new Ifreq("vcan0");
var ret = ioctl(s, Siocgifindex, ref ifr);
addr.can_ifindex = ifr.ifr_ifindex;
addr.can_family = PfCan;
ret = bind(s, ref addr, Marshal.SizeOf(addr));
I have written a .NET managed wrapper library for SocketCAN called SocketCAN# (SocketCANSharp): https://github.com/derek-will/SocketCANSharp
SocketCAN# enables utilizing Raw CAN, ISO-TP, Broadcast Manager, and J1939 sockets in a .NET application on Linux.
Some sample code:
IEnumerable<CanNetworkInterface> collection = CanNetworkInterface.GetAllInterfaces(true);
var iface = collection.FirstOrDefault(i => i.Name.Equals("vcan0"));
using (var rawCanSocket = new RawCanSocket())
{
rawCanSocket.Bind(iface);
int bytesWritten = rawCanSocket.Write(
new CanFrame(0x123, new byte[] { 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }));
}
Underneath the library uses P/Invoke to call the native libc functions and marshal the various types back and fourth between the managed and unmanaged code.
You need to look at the SocketCAN library that is part of Linux.
You can also use candump and cansend to help you develop and also look at the candump.c and cansend.c source files for inspiration.
I see there is a dotnet tag, if you want to use CAN in dotnet I suggest you write a small C library to handle the CAN stuff. Then marshal that to dotnet, once you have access in dotnet you can wrap things in classes and create whatever abstractions you need.

How to detect in which Excel-workbook was clicked ?

Using Excel-2010, Visual-Studio-2013 Professional,
I am trying to find out programatically, in which Excel-Workbook a mouse-click occurrs (or keyboard-shortcut occurs would also be acceptable)? There are several ideas I persuaded, but all of them show the same issue: The Excel-AddIn used does get executed for all open Excel-Workbooks and messes up the needed information in a sense that it does give me the wrong origin of the mouse-click (or keyboard-shortcut click). It does not tell me the desired origin-window but tells me that the click occurred from a window that is not active by all means! I really don't know why the below code-snippets return arbitrary workbook-origins (but never the one I needed, which is the one window I click inside!)...
What is the best way to tell from which window a mouse-click (or keyboard-shortcut) occurrs having several Excel-Workbooks open working with the same Excel-AddIn code ???
Here is what I tried so far:
A) As seen here, a global keyboard-hook was not the solution.
B) GetActiveWindow()
const int nChars = 256;
IntPtr handle1 = GetActiveWindow();
StringBuilder Buff1 = new StringBuilder(nChars);
if (GetWindowText(handle1, Buff1, nChars) > 0) {
MessageBox.Show(Buff1.ToString());
}
C) GetForegroundWindow()
const int nChars = 256;
IntPtr handle2 = GetForegroundWindow();
StringBuilder Buff2 = new StringBuilder(nChars);
if (GetWindowText(handle2, Buff2, nChars) > 0) {
MessageBox.Show(Buff2.ToString());
}
D) ApplicationIsActivated()
public static bool ApplicationIsActivated()
{
var activatedHandle = GetForegroundWindow();
if (activatedHandle == IntPtr.Zero) {
return false; // No window is currently activated
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
MessageBox.Show(activeProcId.ToString());
MessageBox.Show(procId.ToString());
return activeProcId == procId;
}
Needed imports for the above code-snippets:
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
[DllImport("user32.dll")]
static extern IntPtr SetFocus(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr GetFocus();
Any idea appreciated!

How to get the value of a pointer to an int pointer from c++ in c#

How to get array of values from the intptr. how to get vlues pointed by int_ptr_arr into s1[].... mean to say my s1[] should contain 10,100,15
it works for me if it is char** with Marshal.PtrToStringAnsi(), but i want it for int** because i don't have anything like Marshal.ptrint().... etc..
enter code here
Native code:
extern "C" __declspec(dllexport) int** __stdcall Array_hh()
{
int x=10;
int y=100;
int z=15;
static int* myArray[3] = {&x, &y, &z};
return myArray;
}
wrapper:
[DllImport("Native_DLL.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern IntPtr Array_hh();
void some_fun
IntPtr int_ptr_arr = Wrapper.Array_hh();
int k = 0;
int[] s1 = new int[4];

jstring return in JNI program

This is JNI code.
Java code:
public class Sample1 {
public native String stringMethod(String text);
public static void main(String[] args)
{
System.loadLibrary("Sample1");
Sample1 sample = new Sample1();
String text = sample.stringMethod("world");
System.out.println("stringMethod: " + text);
}
}
Cpp Method for stringMethod function:
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
(JNIEnv *env, jobject obj, jstring string) {
const char *name = env->GetStringUTFChars(string, NULL);//Java String to C Style string
char msg[60] = "Hello ";
jstring result;
strcat(msg, name);
env->ReleaseStringUTFChars(string, name);
puts(msg);
result = env->NewStringUTF(msg); // C style string to Java String
return result;
}
When running my java code. I got the result below.
stringMethod: world
But I appended the string "world" with "Hello ". I'm also returning here the appended string. But why I'm getting only "world" not "Hello World". Really I confused with this code. What should I do to get the result with appended string?
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
(JNIEnv *env, jobject obj, jstring string)
{
const char *name = (*env)->GetStringUTFChars(env,string, NULL);
char msg[60] = "Hello ";
jstring result;
strcat(msg, name);
(*env)->ReleaseStringUTFChars(env,string, name);
puts(msg);
result = (*env)->NewStringUTF(env,msg);
return result;
}
There are several ways but the best I got by converting const char * to c++ string and then to jbyteArray, and its easy to conversion of byteArray to UTF-8 on java side.
C++ side:
const char* string = propertyValue;
std::string str = string;
jbyteArray array = env->NewByteArray(str.length());
env->SetByteArrayRegion(array,0,str.length(),(jbyte*)str.c_str());
return array;
Java/kotlin side:
String((array), Charset.defaultCharset()))

Resources