I used following code to provide a global variable.
namespace STR.Pref
{
public static class Pref
{
public static Lang PrimaryLang { get; set; } = Lang.Sinhala;
public static bool InsTrans { get; set; } = true;
public static HotKey Key { get; set; } = new HotKey();
}
}
So I can use following code to assign value to that global variable (any file).(without instantiating)
private static void SetValue(Pref_tempObj tempObj)
{
Pref.Pref.Key = tempObj.Key;
Pref.Pref.InsTrans = tempObj.InsTrans;
Pref.Pref.PrimaryLang = tempObj.PrimaryLang;
}
The program works perfectly,But recently I was interested in c++ so I made a decision to write that program in c++/clr with the small update. I'm bit new to c++ and I don't understand how can I accomplish this using c++.(whether using pointer or something else)
Ok, I really not recommend that but you can do following this instructions.
On a Global.h file (I mean a header will be include on every .cpp)
extern MyType MyTypeVar;
Declare on a .cpp
MyType MyTypeVar
And on every .cpp that you will include the Global.h have access to MyTypeVar.
See:
When to use extern in C++
Extern
What is the function of extern
I was given a third party library that wraps unmanaged C++ code into a C# api, one of the functions has a parameter that appears to be a struct from the native global namespace how do we create an instance of that struct in C#?
This is the c++ Struct:
struct GroupInfo
{
int cMembers; // Current # of members in the group.
char saMembers[cMaxMembers][cMaxLoginID + 1]; // Members themselves.
};
When we try to declare an instance of it in C# the compiler says global::GroupInfo is not available due to its protection level.
c++ signature
int QueryGroup(char* sGroupName,
GroupInfo& gi);
C# signature
VMIManaged.QueryGroup(sbyte*, GroupInfo*)
I have a class called group info
class GroupInfo
{
public int cMembers;
public sbyte[,] saMembers;
}
and when i try to implement that using this code i get a cannot convert error
GroupInfo gi = new GroupInfo();
unsafe
{
sbyte* grpName;
fixed (byte* p = groupNameBytes)
{
grpName = (sbyte*)p;
}
return vmi.QueryGroup(grpName, gi); // cannot convert from class GroupInfo to GroupInfo*
}
You are most likely getting the error because of the default protection level of the default constructor in C# for your GroupData class. If it is defined in a different file from the file in which you are trying to use it, defining it like this should work:
class GroupInfo
{
public GroupInfo() {}
public int cMembers;
public sbyte saMembers[cMaxMembers][cMaxLoginID + 1];
};
I have some 3rd Party iOS Static Library which has .h files containing const struct:
struct SomeStruct
{
__unsafe_unretained NSString * const FirstName;
__unsafe_unretained NSString * const SecondName;
__unsafe_unretained NSString * const ThirdName;
};
extern const struct SomeStruct someName;
I bound this static library to MonoTouch, but I did not understand how to replicate this in C# and access the string value from that structure.
In MonoTouch iOS Binding Project
public struct SomeStruct
{
public string FirstName;
public string SecondName;
public string ThirdName;
};
[Static]
public interface SomeInterface
{
[Field ("SomeStruct", "__Internal")]
IntPtr someNameStr { get; }
}
I included the dll generated by iOS binding Project in my demo application
To access the structure
public static SomeStruct Name {
get {
if (SomeInterface.someNameStr != IntPtr.Zero) {
return (SomeStruct)Marshal.PtrToStructure<SomeStruct> (SomeInterface.someNameStr);
}
return new SomeStruct ();
}
}
Here I am able to get the proper IntPtr. But I am unable to convert it into Structure and access the members in the structure.
SomeInterface.Name.FirstName;
So, could someone please help me in doing it.
Thanks in advance.
You want to use the methods in Dlfcn to get the address of the someName address. Use dlopen to open the library and dlsym to fetch the address.
Then you can marshal the result using Marshal.PtrToStructure but you must make sure that the values are IntPtr, like this:
public struct SomeStruct
{
IntPtr _FirstName;
IntPtr _SecondName;
IntPtr _ThirdName;
};
To get the strings, then you do:
public string FirstName {
get {
return (string) (new NSString (_FirstName));
}
}
I have a C# project that makes calls out to an unmanaged C++ dll. The wrapper and most of the calls are working OK, so I know that I have the basic structure of how everything ties together OK, but there is one specific call that is giving me fits. The API call requires a pointer to a structure, which contains a list of configuration data.
Here is the call:
m_status = m_XXXXBox.SetConfig(m_channelId, ref SCONFIG_LIST);
Where SCONFIG_LIST is the structure containing the data...
The issue specifically relates to SCONFIG_LIST
Here is the documentation directly from the spec for this API :
Points to the structure SCONFIG_LIST, which is defined as follows:
typedef struct
{
unsigned long NumOfParams; /* number of SCONFIG elements */
SCONFIG *ConfigPtr; /* array of SCONFIG */
} SCONFIG_LIST
where:
NumOfParms is an INPUT, which contains the number of SCONFIG elements in the array
pointed to by ConfigPtr.
ConfigPtr is a pointer to an array of SCONFIG structures.
The structure SCONFIG is defined as follows:
typedef struct
{
unsigned long Parameter; /* name of parameter */
unsigned long Value; /* value of the parameter */
} SCONFIG
Here are the 2 structures that I defined in C#:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct SConfig
{
public int Parameter;
public int Value;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct SConfig_List
{
public int NumOfParams;
// public List<SConfig> sconfig = new List<SConfig>(); // This throws compile time error
public List<SConfig> sconfig;
}
I know you can not have field initializers in structs, but I cant seem to figure out how to initialize the sconfig in the struct externally...
Here is snippet from the calling method
SConfig_List myConfig = new SConfig_List();
SConfig configData = new SConfig();
configData.Parameter = 0x04;
configData.Value = 0x10;
myConfig.NumOfParams = 1;
myConfig.sconfig.Add(configData);
This throws an error at runtime of "object reference not set to an instance of an object"
I understand this error because sconfig has not been initialized - I just cant figure out how to do that....
So my next thought was to get around this, I would just create the SCONFIG_LIST struct like this (without the list inside) - My reasoning for this is that I now do not have to initialize the object, and I could just make multiple calls to dll with a NumOfParams = 1, rather than NumOfParams > 1 and having the dll loop through the struct data.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct SConfig_List
{
public int NumOfParams;
public SConfig sconfig;
}
And here is how I called the method
configData.Parameter = 0x04;
configData.Value = 0x10;
myConfig.NumOfParams = 1;
myConfig.sconfig.Parameter = configData.Parameter;
myConfig.sconfig.Value = configData.Value;
m_status = m_XXXXBox.SetConfig(m_channelId, ref myConfig);
This got rid of the errors to this point, now on the the actual method that calls the dll
There are still several questions / issues surrounding the Marshalling, but here it is:
public XXXXErr SetConfig(int channelId, ref SConfig_List config)
{
unsafe
{
IntPtr output = IntPtr.Zero;
IntPtr input = Marshal.AllocHGlobal(Marshal.SizeOf(config));
Marshal.StructureToPtr(config, input, true);
XXXXErr returnVal = (XXXXErr)m_wrapper.Ioctl(channelId, (int)Ioctl.SET_CONFIG, input, output);
return returnVal;
}
}
This gets past all of the initial setup without error, but when I try to actually invoke the dll I get an error : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I know this is a mouthful, and I really don't even know exactly what to ask as I am sure there are multiple issues within this post, but any ideas on getting me on the right track?
I have tried so many things at this point I am at a loss, and I just need some direction. I am not looking for a "do this for me" type answer, but rather an explanation and maybe some pointers on getting this done. As with all things, I am sure there are multiple ways of accomplishing the task - maybe a way that works, but is not good form, and a longer more complicated way that may be "better practice"
Any and all suggestions / comments will be greatly appreciated. And if I excluded any relevant data that is required to help me solve this riddle let me know and I will provide what I can.
I want to thank the responses so far.
I have been trying every combination to try and resolve this myself but I have not had any luck so far. I have found quite a few ways that do NOT work, however :-)
I have tried various combinations of "unsafe" - "MarshalAs", "StructLayout" and several other things I found on the web, now I am begging for mercy.
I have successfully implemented several other calls to this unmanaged dll, but all of them use simple integer pointers etc. My problem is passing the pointer to a Struct containing an array of another struct. If you look at the very top of my original question you can see the documentation from the dll and how it wants thing structured. There is NO return value, I am merely trying to pass some configuration settings to a device through this dll.
I am going to post a framework of my entire project so that maybe I can get someone to hold my hand through this process, and hopefully help others in the future trying to solve this type of issue as well.
Here is skeleton of Wrapper (not all functions displayed)
using System;
using System.Runtime.InteropServices;
namespace My_Project
{
internal static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
internal class APIDllWrapper
{
private IntPtr m_pDll;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int APIIoctl(int channelId, int ioctlID, IntPtr input, IntPtr output);
public APIIoctl Ioctl;
//extern āCā long WINAPI APIIoctl
//(
//unsigned long ChannelID,
//unsigned long IoctlID,
//void *pInput,
//void *pOutput
//)
public bool LoadAPILibrary(string path)
{
m_pDll = NativeMethods.LoadLibrary(path);
if (m_pDll == IntPtr.Zero)
return false;
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(m_pDll, "APIIoctl");
if (pAddressOfFunctionToCall != IntPtr.Zero)
Ioctl = (APIIoctl)Marshal.GetDelegateForFunctionPointer(
pAddressOfFunctionToCall,
typeof(APIIoctl));
return true;
}
public bool FreeLibrary()
{
return NativeMethods.FreeLibrary(m_pDll);
}
}
}
And Here is the class that defines the hardware I am trying to communicate with
namespace My_Project
{
public class APIDevice
{
public string Vendor { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
}
Interface
using System.Collections.Generic;
namespace My_Project
{
public interface I_API
{
APIErr SetConfig(int channelId, ref SConfig_List config);
}
}
The actual Class containing the API Code - this is where the error is, I know that how I have the IntPtrs now is Not correct - But this displays what I am trying to do
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace My_Project
{
public class API : I_API
{
private APIDevice m_device;
private APIDllWrapper m_wrapper;
public APIErr SetConfig(int channelId, ref SConfig_List config)
{
IntPtr output = IntPtr.Zero;
IntPtr input = Marshal.AllocHGlobal(Marshal.SizeOf(config));
Marshal.StructureToPtr(config, input, true);
APIErr returnVal = (APIErr)m_wrapper.Ioctl(channelId, (int)Ioctl.SET_CONFIG, input, output);
return returnVal;
}
}
}
Here is class containing the definitions for the Structs I am using
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace My_Project
{
public enum APIErr
{
STATUS_NOERROR = 0x00,
ERR_BUFFER_EMPTY = 0x10,
ERR_BUFFER_FULL = 0x11,
ERR_BUFFER_OVERFLOW = 0x12
}
public struct SConfig
{
public int Parameter;
public int Value;
}
public struct SConfig_List
{
public int NumOfParams;
public SConfig[] sconfig;
public SConfig_List(List<SConfig> param)
{
this.NumOfParams = param.Count;
this.sconfig = new SConfig[param.Count];
param.CopyTo(this.sconfig);
}
}
}
And finally - the actual application calling the dll through the wrapper
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using My_Project;
namespace Test_API
{
public class Comm
{
private I_API m_APIBox;
APIErr m_status;
int m_channelId;
bool m_isConnected;
public Comm(I_API apiInterface)
{
m_APIBox = apiInterface;
m_isConnected = false;
m_status = APIErr.STATUS_NOERROR;
}
public bool ConfigureDevice()
{
SConfig tempConfig = new SConfig();
tempConfig.Parameter = 0x04;
tempConfig.Value = 0x10;
SConfig_List setConfig = new SConfig_List(tempConfig);
m_status = m_APIBox.SetConfig(m_channelId, ref setConfig);
if (m_status != APIErr.STATUS_NOERROR)
{
m_APIBox.Disconnect(m_channelId);
return false;
}
return true;
}
}
}
You cannot marshal List<>, it must be an array. An array is already marshaled as a pointer so you don't have to do anything special. Go easy on the Pack, no need for the unsafe keyword.
You could add a constructor to the struct to make it easy to initialize it from a List<>. Like this:
[StructLayout(LayoutKind.Sequential)]
public struct SConfig {
public int Parameter;
public int Value;
}
[StructLayout(LayoutKind.Sequential)]
public struct SConfig_List {
public int NumOfParams;
public SConfig[] sconfig;
public SConfig_List(List<SConfig> param) {
this.NumOfParams = param.Count;
this.sconfig = new SConfig[param.Count];
param.CopyTo(this.sconfig);
}
}
To initialize list you just have to add line:
myConfig.sconfig = new List<SConfig>()
before you start adding elements into it.
I started another thread because I was asking the wrong question due to my inexperience
The working solution is here
Marshal array of struct and IntPtr
Thanks for the help
-Lee
I am creating an interpreter from IL (A compiled C#\VB code) to C. I tried to create extern property when I interpret it I'll set my own code.
For an example:
struct String {
public extern override ValueType Clone( ); //Works but with some warnings.
public char this[ int index ] {
extern get;
//'System.String.this[int].get' must declare a body because it is not marked abstract, extern, or partial
//The modifier 'extern' is not valid for this item
extern set; //Didn't work either.
}
}
How I can make getters and setters without body? (BTW I can't mark it as abstract too without getting errors.)
I know this question isn't useful. But very to me.
I think you want to suggest your interpretator to use alternative implemetation (instead of IL use your custom code). Most CLR friendly way would be to create attribute that your interpreter will read and correspondingly use some of your own code, sort of reverse PInvoke.
struct MyString {
[WhenRunningInInterpretator(implementationFunction="function42")]
public char this[ int index ] {
get {...} set {....}; }
}