I am trying to marshal libnl's nla_parse call into C#.
iw's nla_parse extern signature is:
extern int nla_parse(struct nlattr **, int, struct nlattr *, int, struct nla_policy *);
I believe my problem is in correctly marshaling the tb nlattr double pointer (**).
The relevant C# extern signatures are (am omitting the DllImport clause for brevity - the calls work and return results)
public static extern IntPtr nlmsg_data(IntPtr nlh);
public static extern IntPtr nlmsg_hdr(IntPtr n);
public static extern int nla_parse(IntPtr tb, int maxtype, IntPtr head, int len, IntPtr policy);
My C# marshal call looks like
[StructLayout(LayoutKind.Sequential)]
public struct nlattr
{
public ushort nla_len;
public ushort nla_type;
}
var NL80211_ATTR_MAX = 305;
var nlAttrStructSize = Marshal.SizeOf<nlattr>();
var nlAttrStructArrayPtr = Marshal.AllocHGlobal(nlAttrStructSize * (NL80211_ATTR_MAX + 1));
var nlMsgHeaderPtr = NetlinkDemo.nlmsg_hdr(msg);
var gnlMsgHeaderPtr = NetlinkDemo.nlmsg_data(nlMsgHeaderPtr);
var gnlMsgAttrDataHeaderPtr = NetlinkDemo.genlmsg_attrdata(gnlMsgHeaderPtr, 0);
var returnCode = NetlinkDemo.nla_parse(nlAttrStructArrayPtr, NL80211_ATTR_MAX, gnlMsgAttrDataHeaderPtr, gnlMsgAttrLength, IntPtr.Zero);
I keep getting malloc(): memory corruption. Are my marshal mappings correct, and my problem is either my msg input pointer or any of the fields in any of the subsequent pointers that work as input to nla_parse ? Or this is not the way to marshal a struct double pointer ?
Related
I am attempting to PInvoke into the CCKeyDerivationPBKDF here.
The method signature looks like this:
int
CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
const uint8_t *salt, size_t saltLen,
CCPseudoRandomAlgorithm prf, uint rounds,
uint8_t *derivedKey, size_t derivedKeyLen)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
Currently I am attempting this:
[DllImport(ObjCRuntime.Constants.libSystemLibrary, EntryPoint = "CCKeyDerivationPBKDF")]
public extern static void CCKeyCerivationPBKDF(int algorithm, string password, int passwordLen,
string salt, int saltLen, int prf, int rounds, out byte[] derivedKey, int derivedKeyLength);
and am getting the error:
malloc: *** error for object 0xb9374fc61e8f9d1e: pointer being freed was not allocated
This is my first attempt to PInvoke something. I'm fairly certain that my signature is probably way off. What does it need to be?
You are getting the pointer being freed was not allocated error due to the out flag on the derivedKey parameter, just pass it as an IntPtr (byte[]) and Mono will marshall it correctly:
CCKeyCerivationPBKDF signature:
[DllImport(ObjCRuntime.Constants.libSystemLibrary, EntryPoint = "CCKeyDerivationPBKDF")]
public extern static int CCKeyCerivationPBKDF(
int algorithm,
string password,
nint passwordLen,
string salt,
nint saltLen,
UInt32 prf,
int rounds,
byte[] derivedKey,
int derivedKeyLength);
Example:
var passwordEntry = "StackOverflow";
var saltEntry = "SaltyMcSalty";
var keyBytes = new byte[32 + 1];
Array.Clear(keyBytes, 0, keyBytes.Length);
var result = CCKeyCerivationPBKDF(2, passwordEntry, passwordEntry.Length, saltEntry, saltEntry.Length, 3, 1, keyBytes, keyBytes.Length);
Use "native" objects / reduced marshaling:
(Had to due it this way to get passed on a military/aerospace certification/review)
[DllImport(ObjCRuntime.Constants.libSystemLibrary, EntryPoint = "CCKeyDerivationPBKDF")]
public extern static int CCKeyCerivationPBKDF(
int algorithm,
IntPtr password,
nuint passwordLen,
IntPtr salt,
nuint saltLen,
UInt32 prf,
nuint rounds,
IntPtr derivedKey,
nuint derivedKeyLength);
Example (w/ Base64):
var passwordEntry = "StackOverflow";
var passwordBytes = System.Text.Encoding.UTF8.GetBytes(passwordEntry);
var passwordBase64 = Convert.ToBase64String(passwordBytes);
var passwordNSStringBase64 = new NSString(passwordBase64);
var passwordNSData = new NSData(passwordNSStringBase64, NSDataBase64DecodingOptions.None);
var saltEntry = "SaltyMcSalty";
var saltBytes = System.Text.Encoding.UTF8.GetBytes(saltEntry);
var saltBase64 = Convert.ToBase64String(saltBytes);
var saltNSStringBase64 = new NSString(saltBase64);
var saltNSData = new NSData(saltNSStringBase64, NSDataBase64DecodingOptions.None);
var keyBytes = new NSMutableData();
keyBytes.Length = 33;
var result = CCKeyCerivationPBKDF(2, passwordNSData.Bytes, passwordNSData.Length, saltNSData.Bytes, saltNSData.Length, 3, 1, keyBytes.MutableBytes, keyBytes.Length - 1);
My target is to write a c++/cli wrap arount ffmpeg library, using by importing ffmpeg functions from dll-modules.
Later I will use this interface in c#.
This is my challenge, don't ask me why))
So i've implemented Wrap class, which is listed below:
namespace FFMpegWrapLib
{
public class Wrap
{
private:
public:
//wstring libavcodecDllName = "avcodec-56.dll";
//wstring libavformatDllName = "avformat-56.dll";
//wstring libswscaleDllName = "swscale-3.dll";
//wstring libavutilDllName = "avutil-54.dll";
HMODULE libavcodecDLL;
HMODULE libavformatDLL;
HMODULE libswsscaleDLL;
HMODULE libavutilDLL;
AVFormatContext **pFormatCtx = nullptr;
AVCodecContext *pCodecCtxOrig = nullptr;
AVCodecContext *pCodecCtx = nullptr;
AVCodec **pCodec = nullptr;
AVFrame **pFrame = nullptr;
AVFrame **pFrameRGB = nullptr;
AVPacket *packet = nullptr;
int *frameFinished;
int numBytes;
uint8_t *buffer = nullptr;
struct SwsContext *sws_ctx = nullptr;
void Init();
void AVRegisterAll();
void Release();
bool SaveFrame(const char *pFileName, AVFrame * frame, int w, int h);
bool GetStreamInfo();
int FindVideoStream();
bool OpenInput(const char* file);
AVCodec* FindDecoder();
AVCodecContext* AllocContext3();
bool CopyContext();
bool OpenCodec2();
AVFrame* AllocFrame();
int PictureGetSize();
void* Alloc(size_t size);
int PictureFill(AVPicture *, const uint8_t *, enum AVPixelFormat, int, int);
SwsContext* GetSwsContext(int, int, enum AVPixelFormat, int, int, enum AVPixelFormat, int, SwsFilter *, SwsFilter *, const double *);
int ReadFrame(AVFormatContext *s, AVPacket *pkt);
int DecodeVideo2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt);
int SwsScale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]);
void PacketFree(AVPacket *pkt);
void BufferFree(void *ptr);
void FrameFree(AVFrame **frame);
int CodecClose(AVCodecContext *);
void CloseInput(AVFormatContext **);
bool SeekFrame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
Wrap();
~Wrap();
bool GetVideoFrame(char* str_in_file, char* str_out_img, uint64_t time);
};
public ref class managedWrap
{
public:
managedWrap(){}
~managedWrap(){ delete unmanagedWrap; }
bool GetVideoFrameToFile(char* str_in_file, char* str_out_img, uint64_t time)
{
return unmanagedWrap->GetVideoFrame(str_in_file, str_out_img, time);
}
static Wrap* unmanagedWrap = new Wrap();
};
}
So the imports to libavcodec and etc. are succesful.
The problem is in AccessViolationException during calling dll func, for example, in OpenInput (i.e. av_open_input in native ffmpeg library)
The OpenInput func code is below:
bool FFMpegWrapLib::Wrap::OpenInput(const char* file)
{
typedef int avformat_open_input(AVFormatContext **, const char *, AVInputFormat *, AVDictionary **);
avformat_open_input* pavformat_open_input = (avformat_open_input *)GetProcAddress(libavformatDLL, "avformat_open_input");
if (pavformat_open_input == nullptr)
{
throw exception("Unable to find avformat_open_input function address in libavformat module");
return false;
}
//pin_ptr<AVFormatContext *> pinFormatContext = &(new interior_ptr<AVFormatContext *>(pCodecCtx));
pFormatCtx = new AVFormatContext*;
//*pFormatCtx = new AVFormatContext;
int ret = pavformat_open_input(pFormatCtx, file, NULL, NULL); // here it fails
return ret == 0;
}
So the problem, i think, is that class-fields of Wrap class are in secure memory. And ffmpeg works with native memory, initialising pFormatCtx variable by it's address.
Can I avoid this, or it is impossible?
Got the same problem, you need to initialise AVFormatContext object.
Good Example:
AVFormatContext *pFormatCtx = avformat_alloc_context();
Bad example:
AVFormatContext *pFormatCtx = NULL;
I need to call a C++ library from a C# program, I have a method whose signature looks like:
int __stdcall meythodName(const char *c, struct TheirStruct[] s1, struct TheirStruct[] s2)
all parameters are output parameters.
I'm trying to call this method like this:
[DllImport("theirlib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int meythodName(ref string c, ref TheirStruct[] s1, ref TheirStruct[] s2);
With TheirStruct being like:
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 13)]
public class TheirStruct
{
public int i;
public int j;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string s;
}
TheirStruct (PACKED and 13 byte in size) is described in dll manual as:
#define LEN 5
#define SIZE 50
struct TheirStruct
{
char c[LEN];
int i;
int j;
};
When I try to call this method my application simply terminates without giving me an error code, can you give me some explanations about this issue?
Found!!!
I just needed to change "class" to "struct" in TheirStruct declaration, remove di "ref" keyword in method invocation and set the [In]/[Out] accordingly.
Quite simple, hope this can be of any help!!
I have the following c++ function which I cannot alter (3rd-Party):
[c++]
int __stdcall TEST(wchar_t **xml, int &result_size)
{
// xml is instantiated here!
}
[c#]
class native
{
[DllImport("somedll.dll")]
public static extern int TEST(StringBuilder a, ref int size);
{
}
}
Example:
StringBuilder b = new StringBuilder();
int size = 0;
native.Test(b,ref size)
The stringbuilder object only contains first character . If I resize the object:
b.Length = size; The data is incorrect except first character.
Is this the correct way to pass wchar_t** from c++ to c#?
Regards,
John
The function would be p/invoked like this:
[DllImport(#"mylib.dll")]
static extern int TEST(out IntPtr xml);
I removed the size paramter since it is not needed since you can use a null-terminated string.
Call the function like this:
IntPtr xmlptr;
int retval = TEST(out xmlptr);
string xml = Marshal.PtrToStringUni(xmlptr);
// deallocate xmlptr somehow
The tricky bit is to deallocate the memory allocated on the native side. Either use a shared allocator, e.g. the COM allocator. Or export a deallocator from the native code.
Personally I'd re-design the interface to use COM BSTR. I'd have the C++ return a BSTR and on the managed side use [MarshalAs(UnmanagedType.BStr)]. Then the framework handles all the deallocation and marshalling for you.
On the Media Foundation SDK there is the GetPhysicalMonitorsFromHMONITOR function
that I am trying to implement using C# but with no luck ...
In the returned PHYSICAL_MONITOR[], the function returns the string description of the monitor but for some mysterious reasons, the hPhysicalMonitor handle remains at 0.
I have generated the signatures with P/Invoke Interop Assistant with minor modifications.
Does the PHYSICAL_MONITOR structure or anything else needs further tuning ?
Thank you.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WindowsFormsApplication1;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public enum MC_DISPLAY_TECHNOLOGY_TYPE
{
MC_SHADOW_MASK_CATHODE_RAY_TUBE,
MC_APERTURE_GRILL_CATHODE_RAY_TUBE,
MC_THIN_FILM_TRANSISTOR,
MC_LIQUID_CRYSTAL_ON_SILICON,
MC_PLASMA,
MC_ORGANIC_LIGHT_EMITTING_DIODE,
MC_ELECTROLUMINESCENT,
MC_MICROELECTROMECHANICAL,
MC_FIELD_EMISSION_DEVICE,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PHYSICAL_MONITOR
{
public IntPtr hPhysicalMonitor;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szPhysicalMonitorDescription;
}
#region Imports
[DllImport("user32.dll", EntryPoint = "MonitorFromWindow")]
public static extern IntPtr MonitorFromWindow(
[In] IntPtr hwnd, uint dwFlags);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorTechnologyType")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorTechnologyType(
IntPtr hMonitor, ref MC_DISPLAY_TECHNOLOGY_TYPE pdtyDisplayTechnologyType);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorCapabilities")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorCapabilities(
IntPtr hMonitor, ref uint pdwMonitorCapabilities, ref uint pdwSupportedColorTemperatures);
[DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DestroyPhysicalMonitors(
uint dwPhysicalMonitorArraySize, ref PHYSICAL_MONITOR[] pPhysicalMonitorArray);
[DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);
[DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray);
#endregion
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e)
{
// Get monitor handle.
uint dwFlags = 0u;
IntPtr ptr = MonitorFromWindow(Handle, dwFlags);
// Get number of physical monitors.
uint pdwNumberOfPhysicalMonitors = 0u;
bool b1 = GetNumberOfPhysicalMonitorsFromHMONITOR(ptr, ref pdwNumberOfPhysicalMonitors);
if (b1)
{
// Get physical monitors.
uint dwPhysicalMonitorArraySize = 0u;
dwPhysicalMonitorArraySize = pdwNumberOfPhysicalMonitors;
PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];
//NOTE : Handles remain null !
bool b2 = GetPhysicalMonitorsFromHMONITOR(ptr, dwPhysicalMonitorArraySize, pPhysicalMonitorArray);
if (pPhysicalMonitorArray[0].hPhysicalMonitor
== IntPtr.Zero)
{
throw new Exception("ERROR !");
}
// Monitor has capabilities to do that ?
if (b2)
{
uint pdwMonitorCapabilities = 0u;
uint pdwSupportedColorTemperatures = 0u;
bool b3 = GetMonitorCapabilities(
ptr, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);
// If yes, get technology type.
if (b3)
{
MC_DISPLAY_TECHNOLOGY_TYPE type = MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;
bool b4 = GetMonitorTechnologyType(ptr, ref type);
if (b4)
{
// Do work.
}
else
{
throw new Exception("Couldn't get monitor technology type.");
}
}
else
{
throw new Exception("Couldn't get monitor capabilities.");
}
}
else
{
throw new Exception("The monitor doesn't have the required capabilities.");
}
bool b5 = DestroyPhysicalMonitors(dwPhysicalMonitorArraySize, ref pPhysicalMonitorArray);
if (!b5)
{
throw new Exception("Couldn't destroy physical monitors.");
}
}
else
{
throw new Exception("Couldn't get number of physical monitors.");
}
}
}
}
Your statement:
The function returns the string description of the monitor but for some mysterious reasons, the hMonitor handle remains at 0.
is correct. If you look at the docs here, you'll see that hMonitor is clearly an [in] parameter and will not be changed.
Update following comment:
Sorry, didn't realize you meant the physical handle being returned in the structure. All the information I can find on that particular problem seems to indicate that your monitor probably isn't fully DDC/CI compatible (e.g., here).
All your structure definitions look fine to me, based on the docs on MSDN for that particular call. And indeed, it is populating the description for you.
What is the value for the number of physical monitors being returned from GetNumberOfPhysicalMonitorsFromHMONITOR (pdwNumberOfPhysicalMonitors)?
Also, what is the size of your PHYSICAL_MONITOR structure and are you running in 32 or 64 bits?
It is alright that the hPhysicalMonitor value is 0. However, in the question's code sample all calls after the GetPhysicalMonitorsFromHMONITOR should use the hPhysicalMonitor reference instead of the ptr reference. The updated Form_Load method should be the following:
private void Form1_Load(object sender, EventArgs e)
{
// Get monitor handle.
uint dwFlags = 0u;
IntPtr ptr = MonitorFromWindow(Handle, dwFlags);
// Get number of physical monitors.
uint pdwNumberOfPhysicalMonitors = 0u;
bool b1 = GetNumberOfPhysicalMonitorsFromHMONITOR(ptr, ref pdwNumberOfPhysicalMonitors);
if (b1)
{
// Get physical monitors.
uint dwPhysicalMonitorArraySize = 0u;
dwPhysicalMonitorArraySize = pdwNumberOfPhysicalMonitors;
PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];
//NOTE : Handles remain null !
bool b2 = GetPhysicalMonitorsFromHMONITOR(ptr, dwPhysicalMonitorArraySize, pPhysicalMonitorArray);
// Monitor has capabilities to do that ?
if (b2)
{
uint pdwMonitorCapabilities = 0u;
uint pdwSupportedColorTemperatures = 0u;
bool b3 = GetMonitorCapabilities(pPhysicalMonitorArray[0].hPhysicalMonitor, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);
// If yes, get technology type.
if (b3)
{
MC_DISPLAY_TECHNOLOGY_TYPE type = MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;
bool b4 = GetMonitorTechnologyType(pPhysicalMonitorArray[0].hPhysicalMonitor, ref type);
if (b4)
{
// Do work.
}
else
{
throw new Exception("Couldn't get monitor technology type.");
}
}
else
{
throw new Exception("Couldn't get monitor capabilities.");
}
}
else
{
throw new Exception("The monitor doesn't have the required capabilities.");
}
bool b5 = DestroyPhysicalMonitors(dwPhysicalMonitorArraySize, ref pPhysicalMonitorArray);
if (!b5)
{
throw new Exception("Couldn't destroy physical monitors.");
}
}
else
{
throw new Exception("Couldn't get number of physical monitors.");
}
}
The monitor supports this function because with software like softMCCS and WinI2C/DDC,
the properties are returned correctly.
The return pdwNumberOfPhysicalMonitors value is 1 which is correct.
As you can see, its size is pdwNumberOfPhysicalMonitors :
PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];
And I am running Vista 32.
It is somewhat strange because half of it works, that's now about 4 days I am over it but still no progress ...
Thank you.