I am currently working on a third party dll, and randomly when the delegate OnReceive is invoked I get the following error:
CallbackOnCollectedDelegate was detected
I read that GC.Collect() can solve the problem using static but also not as, I have hours and trying every way CallbackOnCollectedDelegate get the error, please help...
namespace Interfaz
{
class TMPDlg:
{
public CTMIF m_objTMPInterface;
public uint m_dwLocalIP;
public ushort m_nPort;
public byte m_nSubNet;
public uint m_nRadioID;
public uint m_nIndex;
public uint m_dwMobileID;
public int nLength;
public string mensaje_destino;
public string mensaje_recibido;
public TMPDlg()
{
m_objTMPInterface = null;
}
unsafe public void OnReceive(ushort wOpcode, System.IntPtr pbPayload, uint dwSize, uint dwLocalIP)
{
TMReceive(wOpcode, (byte*)pbPayload, dwSize, dwLocalIP);
}
unsafe public void TMReceive(ushort wOpcode, byte * pbPayload, uint dwSize, uint dwLocalIP)
{
// Some Work....
}
public void Send_PrivateMsg(string textBoxMensaje, string labelID)
{
m_nRadioID = uint.Parse(labelID);
mensaje_destino = textBoxMensaje;
nLength = textBoxMensaje.Length;
m_objTMPInterface.SendPrivateMsg(m_nRadioID, mensaje_destino, nLength, 0);
}
public void conect_master(ushort port, string ip)
{
m_objTMPInterface = new CTMIF();
m_dwLocalIP = (uint)IPAddressToNumber(ip);
ADKCALLBACK myOnReceive = new ADKCALLBACK(OnReceive);
m_objTMPInterface.SetCallBackFn(myOnReceive);
//m_objTMPInterface.SetCallBackFn(OnReceive);
m_objTMPInterface.OpenSocket(m_dwLocalIP, port, m_dwMobileID, 10)<
}
Presumably this part is the problem?
ADKCALLBACK myOnReceive = new ADKCALLBACK(OnReceive);
m_objTMPInterface.SetCallBackFn(myOnReceive);
If you have an instance variable of type ADKCALLBACK, then so long as your instance isn't garbage collected before (or while) the callback function is executing, you should be okay. What controls your instance's lifetime?
class TMPDlg
{
// Instance variable to protect from garbage collection
private readonly ADKCALLBACK receiveCallback;
public TMPDlg()
{
receiveCallback = myOnReceive;
}
...
public void ConnectMaster(ushort port, string ip)
{
...
m_objTMPInterface.SetCallBackFn(receiveCallback);
...
}
}
(As an aside, your naming could be improved significantly, and you should avoid having public fields.)
Related
Context
The context appears to be irrelevant to my question, but anyway let me explain it a bit:
I am using SWIG to generate code that glues C++ and C# together. I have a struct in C++ like this:
struct Student {
char* name;
double score1;
double score2;
double score3;
double score4;
};
and I generate the glue code with: swig -c++ -csharp -O mylib.i so that I can work with it in C#.
Question
The C# code is generated as follows:
public class Student : global::System.IDisposable {
private global::System.Runtime.InteropServices.HandleRef swigCPtr;
protected bool swigCMemOwn;
internal Student (global::System.IntPtr cPtr, bool cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Student obj) {
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
}
~Student () {
//...
What confuses me is its constructor,
swigCMemOwn = cMemoryOwn;
swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
This two lines take 100+ ns to execute. I examined the internals of HandleRef, it is rather straightforward (if I am not mistaken):
public readonly struct HandleRef
{
// ! Do not add or rearrange fields as the EE depends on this layout.
//------------------------------------------------------------------
private readonly object? _wrapper;
private readonly IntPtr _handle;
//------------------------------------------------------------------
public HandleRef(object? wrapper, IntPtr handle)
{
_wrapper = wrapper;
_handle = handle;
}
public object? Wrapper => _wrapper;
public IntPtr Handle => _handle;
public static explicit operator IntPtr(HandleRef value) => value._handle;
public static IntPtr ToIntPtr(HandleRef value) => value._handle;
}
How come this simple value assignment takes so long? My expectation is that it should take no more than a few ns.
Im building an Add-In for Outlook where I copy all exchange users from the global address list to the local contacts.
The problem is I want transfer the picture of the exchange user too, but exchUser.GetPicture() returns a stdole.stdPicture and I have not yet found a working solution to download or convert it into an image/jpg/...
Here the code to get the exchange User from the global address list:
private void EnumerateGAL()
{
Outlook.AddressList gal = Application.Session.GetGlobalAddressList();
if (gal != null)
{
for (int i = 1; i <= gal.AddressEntries.Count - 1; i++)
{
Outlook.AddressEntry addrEntry = gal.AddressEntries[i];
Outlook.ExchangeUser exchUser = addrEntry.GetExchangeUser();
if (addrEntry.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry
&& exchUser.CompanyName == "")
{
CreateContact(exchUser);
//exchUser.GetPicture() returns stdole.stdPicture
}
}
}
return;
}
The closest solution I found, was a conversion of stdole.IPictureDisp which returns a bitmap but IPuctureDisp and stdPicture isn´t the same as I read somewhere.
public static System.Drawing.Image ConvertPicture(stdole.IPictureDisp image)
{
int type = image.Type;
if (type == 1)
{
IntPtr hPal = (IntPtr)image.hPal;
return Image.FromHbitmap((IntPtr)image.Handle, hPal);
}
return null;
}
In the end I need to download the picture because I can only upload a picture to a contact with a path.
So, is there a way to download a stdPicture or convert it to be able to download it?
There are four main ways to get the job done.
The "traditional" approach is to use the GetIPictureDispFromPicture and GetPictureFromIPicture methods in the System.Windows.Forms.AxHost class. These are both protected members of the class, so you can't use them externally. For this reason, it is common to subclass the AxHost class and expose public methods that internally call the base class protected methods. This approach allows you to convert in both directions:
internal class AxHostConverter : AxHost
{
private AxHostConverter() : base("") { }
static public stdole.IPictureDisp ImageToPictureDisp(Image image)
{
return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
}
static public Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return GetPictureFromIPicture(pictureDisp);
}
}
Your second option is to use OleLoadPicture or OleCreatePictureIndirect. There's an old support article on the topic here. OleLoadPicture creates a new picture object and initializes it from the contents of a stream.
internal class OleCreateConverter
{
[DllImport("oleaut32.dll", EntryPoint = "OleCreatePictureIndirect",
CharSet = CharSet.Ansi, ExactSpelling = true, PreserveSig = true)]
private static extern int OleCreatePictureIndirect(
[In] PictDescBitmap pictdesc, ref Guid iid, bool fOwn,
[MarshalAs(UnmanagedType.Interface)] out object ppVoid);
const short _PictureTypeBitmap = 1;
[StructLayout(LayoutKind.Sequential)]
internal class PictDescBitmap
{
internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PictDescBitmap));
internal int pictureType = _PictureTypeBitmap;
internal IntPtr hBitmap = IntPtr.Zero;
internal IntPtr hPalette = IntPtr.Zero;
internal int unused = 0;
internal PictDescBitmap(Bitmap bitmap)
{
this.hBitmap = bitmap.GetHbitmap();
}
}
public static stdole.IPictureDisp ImageToPictureDisp(Image image)
{
if (image == null || !(image is Bitmap))
{
return null;
}
PictDescBitmap pictDescBitmap = new PictDescBitmap((Bitmap)image);
object ppVoid = null;
Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;
OleCreatePictureIndirect(pictDescBitmap, ref iPictureDispGuid, true, out ppVoid);
stdole.IPictureDisp picture = (stdole.IPictureDisp)ppVoid;
return picture;
}
public static Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
Image image = null;
if (pictureDisp != null && pictureDisp.Type == _PictureTypeBitmap)
{
IntPtr paletteHandle = new IntPtr(pictureDisp.hPal);
IntPtr bitmapHandle = new IntPtr(pictureDisp.Handle);
image = Image.FromHbitmap(bitmapHandle, paletteHandle);
}
return image;
}
}
Your third option is to use the VB6 compatibility library, documented here. To use this, you'll need to add a reference to Microsoft.VisualBasic.Compatibility.dll, which is listed on the .NET tab of the Add References dialog (it resides in the GAC). Then, you can use the ImageToIPictureDisp and IPictureDispToImage methods in the Support class. This is obviously by far the simplest approach, although it does pull in the VB6 compatibility DLL. Internally, the VB6 compatibility code looks a lot like the second option above – using OleCreatePictureIndirect.
using Microsoft.VisualBasic.Compatibility.VB6;
internal class VB6CompatibilityConverter
{
public static stdole.IPictureDisp ImageToPictureDisp(Image image)
{
return (stdole.IPictureDisp)Support.ImageToIPictureDisp(image);
}
public static Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return Support.IPictureDispToImage(pictureDisp);
}
}
Finally, you can implement IPictureDisp and IPicture yourself. This is fine if you just want to convert from an Image to an IPictureDisp, but doesn't help you converting in the other direction. The implementation below relies on the Image actually being a derived Bitmap type, because we call Bitmap.GetHbitmap internally. If you want to keep the support to the generic Image type, you'll have to do a lot more work to p/invoke to a bunch of undocumented GDI methods instead
internal class PictureDispConverter
{
public static stdole.IPictureDisp BitmapToPictureDisp(Bitmap bitmap)
{
return new PictureDispImpl(bitmap);
}
public static Image PictureDispToBitmap(stdole.IPictureDisp pictureDisp)
{
// TODO
return null;
}
}
internal class PictureDispImpl : stdole.IPictureDisp, stdole.IPicture
{
#region Init
[DllImport("gdi32.dll")]
static extern void DeleteObject(IntPtr handle);
private Bitmap _image;
private IntPtr _handle;
public PictureDispImpl(Bitmap image)
{
_image = image;
}
~PictureDispImpl()
{
if (_handle != IntPtr.Zero)
{
DeleteObject(_handle);
}
}
#endregion
#region IPictureDisp Members
public int Width
{
get { return _image.Width; }
}
public int Height
{
get { return _image.Height; }
}
public short Type
{
get { return 1; }
}
public int Handle
{
get
{
if (_handle == IntPtr.Zero)
{
_handle = _image.GetHbitmap();
}
return _handle.ToInt32();
}
}
public int hPal
{
get { return 0; }
set { }
}
public void Render(
int hdc, int x, int y, int cx, int cy, int xSrc, int ySrc, int cxSrc, int cySrc, IntPtr prcWBounds)
{
Graphics graphics = Graphics.FromHdc(new IntPtr(hdc));
graphics.DrawImage(
_image, new Rectangle(x, y, cx, cy), xSrc, ySrc, cxSrc, cySrc, GraphicsUnit.Pixel);
}
#endregion
#region IPicture Members
public int Attributes
{
get { return 0; }
}
public int CurDC
{
get { return 0; }
}
public bool KeepOriginalFormat
{
get { return false; }
set { }
}
public void PictureChanged()
{
}
public void SaveAsFile(IntPtr pstm, bool fSaveMemCopy, out int pcbSize)
{
pcbSize = 0;
}
public void SelectPicture(int hdcIn, out int phdcOut, out int phbmpOut)
{
phdcOut = 0;
phbmpOut = 0;
}
public void SetHdc(int hdc)
{
}
#endregion
}
I'been developing a library on C# for the last days, and now, I need to build that library into a dll, and use that dll from Qt.
The library includes three classes I need to access, and my original idea was to simply build the dll, use dumpcpp to get the headers and use them from Qt along with activeqt, which I have used before.
The problem is that I cannot manage to get the headers from dumpcpp, it fails, returning:
dumpcpp: loading '.\Wrapper.dll' as a type library failed
dumpcpp: error processing type library '.\Wrapper.dll'
The Visual Studio project I'm using is a Class library (.Net Standard), and I'm using building it for x86 architecture. I've seen this link and tried using
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
with the three classes I need in order to get a COM dll which I suppose must be usable by dumpcpp, but it fails with the same error I mentioned before. Almost every documentation I have found is about using C++ dlls on C#, and there's nothing about using dumpcpp with C# dlls.
Do somebody has any ideas on how to get this dll working with dumpcpp, so that I can use it with Qt? I'd be really grateful.
Thanks a lot!
Edit: In case it helps, here it's the basic structure (without the complex funcionality) of the unique main .cs file the dll includes:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Wrapper
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Device
{
public string host;
public string username;
public string password;
public uint port;
private bool _serverConnected;
public uint serverGroupId { get; private set; }
public uint serverId { get; private set; }
private object[] _cameraIds;
public Device(string host, string username, string password, uint port)
{
this.host = host;
this.username = username;
this.password = password;
this.port = port;
this._serverConnected = false;
Debug.WriteLine("Device Initialized");
}
public bool isConnected() => _serverConnected;
public void onServerConnected(uint serverGroupId, uint serverId)
{
Debug.WriteLine("ServerConnectedEventHandler"); // TODO: Remove, just for testing
_serverConnected = true;
}
public void onServerGroupDisconnected(uint serverGroupId)
{
Debug.WriteLine("ServerGroupDisconnectedEventHandler"); // TODO: Remove, just for testing
_serverConnected = false;
}
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
class Player
{
private Device _device;
private static readonly int NUM_FRAMES = 10;
private Frame[] _lastFrames = new Frame[NUM_FRAMES];
private int _toReadFrame, _toReceivedFrame;
public Player(Device device)
{
this._device = device;
_toReadFrame = 0;
_toReceivedFrame = 0;
}
public Frame Image()
{
Frame tmp = _lastFrames[_toReadFrame];
_toReadFrame = (++_toReadFrame) % NUM_FRAMES;
return tmp;
}
void FrameAvailableEventHandler(int width, int height, byte[] data)
{
_lastFrames[_toReceivedFrame] = new Frame(width, height, data);
_toReceivedFrame = (++_toReceivedFrame) % NUM_FRAMES;
}
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
class Frame
{
public int width { get; private set; }
public int height { get; private set; }
public byte[] data { get; private set; }
public Frame(int width, int height, byte[] data)
{
this.data = data;
this.width = width;
this.height = height;
}
}
}
Attempting to learn and use a bit more about class serialization to XML.
I can do basic serialisation.
In the following case I have a nested class structure and would like to get it output in its implemented hierarchy to a file in XML standard. The same for deserializing if it there are any caveats.
I had a good search but couldn't understand how to do it.
I know some bits below are not 100% safe but I'm more worried about the serialization functionality. The serializer class extends the Serialize() to any of my classes.
Your help is much appreciated.
public class SysConfigs
{
public SysConfigs() { }
public struct DeadVolumes
{
public struct Valve
{
public uint V1; //valve 1 dead volume in uL
public uint V2; //valve 2 deal volume
public uint V3;
public uint V4;
public uint V5p0;
public uint V5p1;
public uint V5p2;
public uint V5p3;
public uint V5p4;
public uint V5p5;
public uint v5p6;
public uint V5p7;
public uint V5p8;
public uint V5p9;
public uint V5p10;
public uint V5p11;
public uint V5p12;
public uint V5p13;
public uint V5p14;
public uint V6;
}
public struct Mixer
{
public uint M1p1;
public uint M1p2;
public uint M1p3;
public uint M2p1;
public uint M2p2;
public uint M2p3;
}
}
}
public static class Serializer
{
public static void Serialize(this Object obj, string filePath)
{
// Creates an instance of the XmlSerializer class;
// specifies the type of object to be deserialized.
XmlSerializer _xml_serializer = new XmlSerializer(obj.GetType());
XmlWriter _xml_textwriter = XmlWriter.Create(filePath);
try
{
_xml_serializer.Serialize(_xml_textwriter, obj);
}
catch (Exception ex)
{
throw ex;
}
_xml_textwriter.Close();
// If the XML document has been altered with unknown
// nodes or attributes, handles them with the
// UnknownNode and UnknownAttribute events.
_xml_serializer.UnknownNode += new XmlNodeEventHandler(serializer_UnknownNode);
_xml_serializer.UnknownAttribute += new XmlAttributeEventHandler(serializer_UnknownAttribute);
}
// this is where I am testing the my serialization implementation from
private void button1_Click(object sender, EventArgs e)
{
SysConfigs stuff = new SysConfigs();
stuff.Serialize("myfile.xml");
}
The example above produces an XML without contents - that is understood.
<?xml version="1.0" encoding="utf-8"?><SysConfigs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
I would like to understand what is required, given the example above, to achieve the following XML program output:
<SysConfigs>
<DeadVolumes>
<Valve>
<V1>123</V1>
<V2>123</V2>
<V3>123</V3>
..etc..
</Valve>
<Mixer>
<M1p1>1</M1p1>
<M1p2>1</M1p2>
<M1p3>1</M1p3>
..etc..
</Mixer>
</DeadVolumes>
</SysConfigs>
The problem is that your SysConfigs class has no members. So there's nothing to serialize. There's also no need to make the structs nested, or to use structs in the first place. So instead just create a series of classes:
public class Valve
{
public uint V1;
// ...
public uint V6;
}
public class Mixer
{
public uint M1p1;
// ...
public uint M1p3;
}
Then create the container class containing the proper members:
public class DeadVolume
{
public Valve Valve { get;set; }
public Mixer Mixer { get;set; }
}
Then add a property to the SysConfigs class:
public class SysConfigs
{
public DeadVolume DeadVolumes { get; set; }
}
Now you can instantiate and populate a SysConfigs instance and serialize it:
var config = new SysConfigs
{
DeadVolumes = new DeadVolume
{
Valve = new Valve
{
V1 = 42,
// ...
},
Mixer = new Mixer
{
M1p1 = 43,
// ..
}
}
};
I have been working with an interface which read measurement data from a sensor and use a library written in C++ to analyse that data.
The function is just about the following:
Set measurement parameters on the C++ library
Get data from the sensor (1200 measurements alltogether)
Write data to C++ library
Process all 1200 measurements in C++ library
Read results from C++ library
Calling this C++ library from C#-code is previously dealt with this question: Calling unmanaged C++ library (dll) from C# creates an access violation error (0xc0000005).
Now it seems, that the C++ library either
doesn't get data correctly
is not able to hold data
is not able to properly return results to my C#-code.
Bad thing is, that I'm not able to debug this C++ library.
What is wrong with my code?
1) Setting the measurement parameters
namespace PdWaveApi
{
[StructLayout(LayoutKind.Sequential)]
public struct PDDataInfo
{
public int nPings;
public int nDataRate;
public int nSamples;
public float fFrequency;
public float fBeamAngle;
public int nInstrument;
public int nCoordSystem;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public short[] hBeamToXYZ;
public short hWaveT1;
// Constructor
public static PDDataInfo Create()
{
PDDataInfo DataStruct = new PDDataInfo();
DataStruct.hBeamToXYZ = new short[9];
return DataStruct;
}
}
}
public class PdWaveBaseLWrapper
{
[DllImport("PdWaveBase.dll", EntryPoint = "PDSetInstrumentConfig")]
public static extern int PDSetInstrumentConfig(ref PDDataInfo pDataInfo);
}
public void SetInstrumentConfiguration()
{
PdWaveApi.PDDataInfo InstrumentConfiguration = new PdWaveApi.PDDataInfo();
.................
Initializing the InstrumentConfiguration structure
...............
PdWaveBaseLWrapper.PDSetInstrumentConfig(ref InstrumentConfiguration);
}
3) Reading data from sensor and writing data to C++ library
namespace PdWaveApi
{
[StructLayout(LayoutKind.Sequential)]
public struct PDWaveSample
{
[MarshalAs(UnmanagedType.I1)]
public bool Valid;
public float fPressure;
public float fDistance;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PD_MAX_WAVEBEAMS)]
public float[] fVel;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PD_MAX_WAVEBEAMS)]
public ushort[] nAmp;
// Constructor
public static PDWaveSample Create()
{
PDWaveSample DataStruct = new PDWaveSample();
DataStruct.fVel = new float[Constants.PD_MAX_WAVEBEAMS];
DataStruct.nAmp = new ushort[Constants.PD_MAX_WAVEBEAMS];
return DataStruct;
}
}
}
public class PdWaveBaseLWrapper
{
[DllImport("PdWaveBase.dll", EntryPoint = "PDSetWaveSample")]
public static extern int PDSetWaveSample(ref PDWaveSample pWaveSample);
}
namespace SensorInterface
{
public partial class frmSensorInterface : Form
{
public PdWaveApi.PDWaveSample WaveSampleData = PdWaveApi.PDWaveSample.Create();
private void OnNewData(object sender, OnNewDataEvent e)
{
ReadWaveSample(ref WaveSampleData);
SetWaveSample(ref WaveSampleData);
}
public void ReadWaveSample(ref PdWaveApi.PDWaveSample WaveSampleData)
{
DateTime MeasurementTimeStamp;
float[] dVel = new float[4];
float dTemperature = new float();
float dPitch = new float();
float dRoll = new float();
float dHeading = new float();
float dPressure = new float();
short[] sAmp = new short[4];
// Read some of the latest data from the control
GetVelocity(ref dVel[0], ref dVel[1], ref dVel[2], ref dVel[3]);
GetAmplitude(ref sAmp[0], ref sAmp[1], ref sAmp[2], ref sAmp[2]);
..............
// Set other data to the structure
}
public void SetWaveSample(ref PdWaveApi.PDWaveSample WaveSampleData)
{
PdWaveBaseLWrapper.PDSetWaveSample(ref WaveSampleData);
}
}
}
4) Process all 1200 measurements in C++ library
[StructLayout(LayoutKind.Sequential)]
public struct PDWaveBurst
{
[MarshalAs(UnmanagedType.ByValArray , SizeConst = Constants.PD_MAX_WAVEMEAS_AST)]
public float[] fST;
public float fWinFloor;
public float fWinCeil;
[MarshalAs(UnmanagedType.I1)]
public bool bUseWindow;
[MarshalAs(UnmanagedType.I1)]
public bool bSTOk;
[MarshalAs(UnmanagedType.I1)]
public bool bGetRawAST;
[MarshalAs(UnmanagedType.I1)]
public bool bValidBurst;
public static PDWaveBurst Create()
{
PDWaveBurst DataStruct = new PDWaveBurst();
DataStruct.fST = new float[Constants.PD_MAX_WAVEMEAS_AST];
return DataStruct;
}
}
[DllImport("PdWaveBase.dll", EntryPoint = "PDPreProcess")]
public static extern int PDPreProcess(int nSample, ref PDWaveBurst pWaveBurst);
[DllImport("PdWaveBase.dll", EntryPoint = "PDProcessReturnInt")]
public static extern int PDProcessReturnInt();
public void PreprocessBurstData(int nSamples)
{
PdWaveApi.PDWaveBurst WaveBurstData = PdWaveApi.PDWaveBurst.Create();
WaveBurstData.fST = new float[4096];
WaveBurstData.fWinFloor = (float)1.25;
WaveBurstData.fWinCeil = 2;
WaveBurstData.bUseWindow = false;
WaveBurstData.bSTOk = false;
WaveBurstData.bGetRawAST = false;
WaveBurstData.bValidBurst = false;
PdWaveBaseLWrapper.PDPreProcess(nSamples, ref WaveBurstData);
}
public void ProcessData()
{
int ProcessError = PdWaveBaseLWrapper.PDProcessReturnInt();
}
5) Read results from C++ library
[StructLayout(LayoutKind.Sequential)]
public struct PDWavePar {
public float fTm02;
public float fTp;
public float fDirTp;
public float fSprTp;
public float fMainDir;
public float fUI;
public float fHm0;
public float fH3;
public float fT3;
public float fH10;
public float fT10;
public float fHmax;
public float fTmax;
public float fTz;
public float fMeanPres;
public int nNumNoDet;
public int nNumBadDet;
public int nErrCode;
public int nSpectrum;
public float fMeanAST;
}
[DllImport("PdWaveBase.dll", EntryPoint = "PDGetWavePar")]
public static extern int PDGetWavePar(ref PDWavePar pwWavePar);
public void GetOutput()
{
PdWaveApi.PDWavePar WaveParameters = new PdWaveApi.PDWavePar();
PdWaveBaseLWrapper.PDGetWavePar(ref WaveParameters);
}
So, as conclusion:
What should I change in my code
- to pass data correctly to unmanaged dll
- to have dll hold and process the data in its' internal structures
- to read results correctly from unmanaged code to my C# program?
(Sorry about the length of my question.)
The final solution to my problem was to change the alignment to 1 byte, like this:
C# struct definitions:
From:
[StructLayout(LayoutKind.Sequential)]
to
[StructLayout(LayoutKind.Sequential, Pack=1)]
This has been discussed at least here:
Calling C++ metro dll from c# metro app and returning filled structures