C
Charles Calvert
All,
I think that I've been staring at this for too long. I need a sanity
check.
Problem: To get values from an unmanaged DLL written in C++, I set
m_data.TunerID = 1 and pass it to the imported function GetData().
When the function call returns, TunerID is zero. It shouldn't be
modified by the DLL and should still be 1.
Note that I don't have access to all of the souce for the DLL, only
the header that specifies the interface, so it may be that the DLL is
doing something incorrectly. The author says it is not.
Please take a look at the following code and let me know if I've done
something stupid.
Using VS 2008. The C++ is being built for Unicode, not ANSI.
Everything is built for 32-bit Windows.
C++ code from DLL (Win32 unmanaged code):
-----------------------------------------
enum TunerMode
{
DVB_S,
DVB_S2
};
enum Modulation
{
QPSK,
EightPSK
};
enum FEC
{
FEC_1_2,
FEC_3_5,
FEC_2_3,
FEC_3_4,
FEC_4_5,
FEC_5_6,
FEC_6_7,
FEC_7_8,
FEC_8_9,
FEC_9_10
};
#define MAXDATAPIDS 7
#define MAX_ERROR_LEN 255
typedef struct
{
int TunerID;
bool TunerLock;
DWORD TunerFrequency;
DWORD SymbolRate;
TunerMode TunerMode;
Modulation Modulation;
FEC ForwardErrorCode;
int CommandPID;
int DataPID[MAXDATAPIDS];
int SignalQuality;
int SignalLevel;
float SignalToNoiseRatio;
long BitErrorRate;
long TotalIPPackets;
long TotalDVBPackets;
TCHAR szError[MAX_ERROR_LEN + 1];
} TunerData;
// Uses .def file to avoid C++ decoration
__declspec( dllexport ) DWORD GetData(TunerData &data);
C# code:
--------
public enum FECRates
{
FEC_1_2,
FEC_3_5,
FEC_2_3,
FEC_3_4,
FEC_4_5,
FEC_5_6,
FEC_6_7,
FEC_7_8,
FEC_8_9,
FEC_9_10
}
public enum ModulationTypes
{
QPSK,
EightPSK
}
public enum TunerModes
{
DVB_S,
DVB_S2
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct TunerData
{
public int TunerID;
public bool TunerLock;
public uint TunerFrequency;
public uint SymbolRate;
public TunerModes TunerMode;
public ModulationTypes Modulation;
public FECRates ForwardErrorCode;
public int CommandPID;
//public IntPtr DataPID;
// NOTE: we cannot use a constant to define the length here,
// and C# doesn't support macros like C++, so we must be careful
// to ensure that this constant matches MAXDATAPIDS as defined
// in the C++ header.
[MarshalAs(UnmanagedType.ByValArray, SizeConst=7)]
public int[] DataPID;
public int SignalQuality;
public int SignalLevel;
public float SignalToNoiseRatio;
// The next three are declared as "long" in C++, but
// that's a 32-bit long, so we'll declare them as int here.
public int BitErrorRate;
public int TotalIPPackets;
public int TotalDVBPackets;
[MarshalAs(UnmanagedType.LPTStr)]
public string szError;
}
[DllImport("DLL.dll", CharSet = CharSet.Unicode, CallingConvention =
CallingConvention.Cdecl)]
private static extern uint GetData(ref TunerData data);
I think that I've been staring at this for too long. I need a sanity
check.
Problem: To get values from an unmanaged DLL written in C++, I set
m_data.TunerID = 1 and pass it to the imported function GetData().
When the function call returns, TunerID is zero. It shouldn't be
modified by the DLL and should still be 1.
Note that I don't have access to all of the souce for the DLL, only
the header that specifies the interface, so it may be that the DLL is
doing something incorrectly. The author says it is not.
Please take a look at the following code and let me know if I've done
something stupid.
Using VS 2008. The C++ is being built for Unicode, not ANSI.
Everything is built for 32-bit Windows.
C++ code from DLL (Win32 unmanaged code):
-----------------------------------------
enum TunerMode
{
DVB_S,
DVB_S2
};
enum Modulation
{
QPSK,
EightPSK
};
enum FEC
{
FEC_1_2,
FEC_3_5,
FEC_2_3,
FEC_3_4,
FEC_4_5,
FEC_5_6,
FEC_6_7,
FEC_7_8,
FEC_8_9,
FEC_9_10
};
#define MAXDATAPIDS 7
#define MAX_ERROR_LEN 255
typedef struct
{
int TunerID;
bool TunerLock;
DWORD TunerFrequency;
DWORD SymbolRate;
TunerMode TunerMode;
Modulation Modulation;
FEC ForwardErrorCode;
int CommandPID;
int DataPID[MAXDATAPIDS];
int SignalQuality;
int SignalLevel;
float SignalToNoiseRatio;
long BitErrorRate;
long TotalIPPackets;
long TotalDVBPackets;
TCHAR szError[MAX_ERROR_LEN + 1];
} TunerData;
// Uses .def file to avoid C++ decoration
__declspec( dllexport ) DWORD GetData(TunerData &data);
C# code:
--------
public enum FECRates
{
FEC_1_2,
FEC_3_5,
FEC_2_3,
FEC_3_4,
FEC_4_5,
FEC_5_6,
FEC_6_7,
FEC_7_8,
FEC_8_9,
FEC_9_10
}
public enum ModulationTypes
{
QPSK,
EightPSK
}
public enum TunerModes
{
DVB_S,
DVB_S2
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct TunerData
{
public int TunerID;
public bool TunerLock;
public uint TunerFrequency;
public uint SymbolRate;
public TunerModes TunerMode;
public ModulationTypes Modulation;
public FECRates ForwardErrorCode;
public int CommandPID;
//public IntPtr DataPID;
// NOTE: we cannot use a constant to define the length here,
// and C# doesn't support macros like C++, so we must be careful
// to ensure that this constant matches MAXDATAPIDS as defined
// in the C++ header.
[MarshalAs(UnmanagedType.ByValArray, SizeConst=7)]
public int[] DataPID;
public int SignalQuality;
public int SignalLevel;
public float SignalToNoiseRatio;
// The next three are declared as "long" in C++, but
// that's a 32-bit long, so we'll declare them as int here.
public int BitErrorRate;
public int TotalIPPackets;
public int TotalDVBPackets;
[MarshalAs(UnmanagedType.LPTStr)]
public string szError;
}
[DllImport("DLL.dll", CharSet = CharSet.Unicode, CallingConvention =
CallingConvention.Cdecl)]
private static extern uint GetData(ref TunerData data);