Implementing IServiceProvider and IInternetSecurityManager for WebBrowser control - com

I am trying to implement the IInternetSecurityManager on a WebBrowser control in order to override some IE security restrictions.
I have extended the WebBrowser control (call it MyWebBrowser) and have subclassed the WebBrowserSite class (call it ExtendedWebBrowserSite), and I've overridden the CreateWebBrowserSiteBase method on MyWebBrowser to return an instance of ExtendedWebBrowserSite.
class MyWebBrowser : System.Windows.Forms.WebBrowser
{
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
return new ExtendedWebBrowserSite(this);
}
}
My ExtendedWebBrowserSite class implements IServiceProvider and IInternetSecurityManager interfaces:
class ExtendedWebBrowserSite : WebBrowserSite, IServiceProvider, IInternetSecurityManager
{
// constructors omitted...
// IServiceProvider implementation
public int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject)
{
if (guidService == SID_IInternetSecurityManager && riid == SID_IInternetSecurityManager)
{
ppvObject = this;
return HRESULTS.S_OK; // = 0x0
}
ppvObject = IntPtr.Zero;
return HRESULTS.E_NOINTERFACE; // 0x80004002
}
// IInternetSecurityManager implementation ommitted...
}
COM Interface Definitions
[ComImport, GuidAttribute("6D5140C1-7436-11CE-8034-00AA006009FA")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
int QueryService(ref Guid guidService, ref Guid riid [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}
[ComImport, Guid("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInternetSecurityManager
{
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int SetSecuritySite([In] IntPtr pSite);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int GetSecuritySite([Out] IntPtr pSite);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int MapUrlToZone([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out UInt32 pdwZone, UInt32 dwFlags);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int GetSecurityId([MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSecurityId, ref UInt32 pcbSecurityId, uint dwReserved);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int ProcessUrlAction([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, UInt32 dwAction, out byte pPolicy, UInt32 cbPolicy, byte pContext, UInt32 cbContext, UInt32 dwFlags, UInt32 dwReserved);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int QueryCustomPolicy([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, ref Guid guidKey, ref byte ppPolicy, ref UInt32 pcbPolicy, ref byte pContext, UInt32 cbContext, UInt32 dwReserved);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int SetZoneMapping(UInt32 dwZone, [In,MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, UInt32 dwFlags);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int GetZoneMappings(UInt32 dwZone, out IEnumString ppenumString, UInt32 dwFlags);
}
Results
The QueryService method is called when the WebBrowser is initialized. However, right after the QueryService method finishes and returns HRESULTS.E_NOINTERFACE, an AccessViolationException is thrown:
AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Windows.Forms.UnsafeNativeMethods.IOleObject.SetClientSite(IOleClientSite pClientSite)
at System.Windows.Forms.WebBrowserBase.TransitionFromLoadedToRunning()
at System.Windows.Forms.WebBrowserBase.TransitionUpTo(AXState state)
at System.Windows.Forms.WebBrowser.get_AxIWebBrowser2()
at System.Windows.Forms.WebBrowser.set_ScriptErrorsSuppressed(Boolean value)
Note: None of the IInternetSecurityManager methods get called, because QueryService never gets the chance to assign an implementation of it. So I omitted the IInernetSecurityManager methods for brevity.
Anyone have any ideas as to why this could be happening?

Related

Trying to send a keystroke using SENDMESSAGE rather than SENDKEYS (VB.Net) [duplicate]

I'm trying to use SendMessage to Notepad, so that I can insert written text without making Notepad the active window.
I have done something like this in the past using SendText, but that required giving Notepad focus.
Now, first I'm retrieving the Windows handle:
Process[] processes = Process.GetProcessesByName("notepad");
Console.WriteLine(processes[0].MainWindowHandle.ToString());
I've confirmed it's the right handle for Notepad, the same shown within Windows Task Manager.
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);
From here, I haven't been able to get SendMessage to work in all my experimentation. Am I going in the wrong direction?
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
private void button1_Click(object sender, EventArgs e)
{
Process [] notepads=Process.GetProcessesByName("notepad");
if(notepads.Length==0)return;
if (notepads[0] != null)
{
IntPtr child= FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000C, 0, textBox1.Text);
}
}
WM_SETTEXT=0x000c
You first have to find the child window where the text is entered. You can do this by finding the child window with the window class "Edit".
Once you have that window handle, use WM_GETTEXT to get the text which is already entered, then modify that text (e.g., add your own), then use WM_SETTEXT to send the modified text back.
using System.Diagnostics;
using System.Runtime.InteropServices;
static class Notepad
{
#region Imports
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
//this is a constant indicating the window that we want to send a text message
const int WM_SETTEXT = 0X000C;
#endregion
public static void SendText(string text)
{
Process notepad = Process.Start(#"notepad.exe");
System.Threading.Thread.Sleep(50);
IntPtr notepadTextbox = FindWindowEx(notepad.MainWindowHandle, IntPtr.Zero, "Edit", null);
SendMessage(notepadTextbox, WM_SETTEXT, 0, text);
}
}

IIS Hosted WCF Service permission to use interop

Is it possible to execute the following code, in any way through an IIS hosted wcf service? Any way I can give the appropriate permissions to the appPool? This code simply changes global printer settings:
public class PrinterSettings
{
#region "Private Variables"
private IntPtr hPrinter = new System.IntPtr();
private PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
private PRINTER_INFO_2 pinfo = new PRINTER_INFO_2();
private DEVMODE dm;
private IntPtr ptrDM;
private IntPtr ptrPrinterInfo;
private int sizeOfDevMode = 0;
private int lastError;
private int nBytesNeeded;
private long nRet;
private int intError;
private System.Int32 nJunk;
private IntPtr yDevModeData;
#endregion
#region "Win API Def"
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg,
IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
private static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel,
IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
/*[DllImport("winspool.Drv", EntryPoint="OpenPrinterA",
SetLastError=true, CharSet=CharSet.Ansi,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out IntPtr hPrinter, ref PRINTER_DEFAULTS pd)
[ DllImport( "winspool.drv",CharSet=CharSet.Unicode,ExactSpelling=false,
CallingConvention=CallingConvention.StdCall )]
public static extern long OpenPrinter(string pPrinterName,
ref IntPtr phPrinter, int pDefault);*/
/*[DllImport("winspool.Drv", EntryPoint="OpenPrinterA",
SetLastError=true, CharSet=CharSet.Ansi,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
*/
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA",
SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool
OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr
pPrinter, int Command);
/*[DllImport("winspool.drv", CharSet=CharSet.Ansi, SetLastError=true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr
pPrinter, int Command);*/
// Wrapper for Win32 message formatter.
/*[DllImport("kernel32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage( int dwFlags,
ref IntPtr pMessageSource,
int dwMessageID,
int dwLanguageID,
ref string lpBuffer,
int nSize,
IntPtr* pArguments);*/
#endregion
#region "Data structure"
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
/*[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct PRINTER_DEFAULTS
{
public int pDataType;
public IntPtr pDevMode;
public ACCESS_MASK DesiredAccess;
}*/
[StructLayout(LayoutKind.Sequential)]
private struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPStr)]
public string pServerName;
[MarshalAs(UnmanagedType.LPStr)]
public string pPrinterName;
[MarshalAs(UnmanagedType.LPStr)]
public string pShareName;
[MarshalAs(UnmanagedType.LPStr)]
public string pPortName;
[MarshalAs(UnmanagedType.LPStr)]
public string pDriverName;
[MarshalAs(UnmanagedType.LPStr)]
public string pComment;
[MarshalAs(UnmanagedType.LPStr)]
public string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPStr)]
public string pSepFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pPrintProcessor;
[MarshalAs(UnmanagedType.LPStr)]
public string pDatatype;
[MarshalAs(UnmanagedType.LPStr)]
public string pParameters;
public IntPtr pSecurityDescriptor;
public Int32 Attributes;
public Int32 Priority;
public Int32 DefaultPriority;
public Int32 StartTime;
public Int32 UntilTime;
public Int32 Status;
public Int32 cJobs;
public Int32 AveragePPM;
}
private const short CCDEVICENAME = 32;
private const short CCFORMNAME = 32;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
#endregion
#region "Constants"
private const int DM_DUPLEX = 0x1000;
private const int DM_IN_BUFFER = 8;
private const int DM_OUT_BUFFER = 2;
private const int PRINTER_ACCESS_ADMINISTER = 0x4;
private const int PRINTER_ACCESS_USE = 0x8;
private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
private const int PRINTER_ALL_ACCESS =
(STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER
| PRINTER_ACCESS_USE);
#endregion
#region "Function to change printer settings"
public bool ChangePrinterSetting(string PrinterName, PrinterData PS)
{
if (((int)PS.Duplex < 1) || ((int)PS.Duplex > 3))
{
throw new ArgumentOutOfRangeException("nDuplexSetting",
"nDuplexSetting is incorrect.");
}
else
{
dm = this.GetPrinterSettings(PrinterName);
dm.dmDefaultSource = (short)PS.source;
dm.dmOrientation = (short)PS.Orientation;
dm.dmPaperSize = (short)PS.Size;
dm.dmDuplex = (short)PS.Duplex;
Marshal.StructureToPtr(dm, yDevModeData, true);
pinfo.pDevMode = yDevModeData;
pinfo.pSecurityDescriptor = IntPtr.Zero;
/*update driver dependent part of the DEVMODE
1 = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, yDevModeData
, ref pinfo.pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));*/
try
{
Marshal.StructureToPtr(pinfo, ptrPrinterInfo, false);
}
catch
{
}
lastError = Marshal.GetLastWin32Error();
nRet = Convert.ToInt16(SetPrinter(hPrinter, 2, ptrPrinterInfo, 0));
if (nRet == 0)
{
//Unable to set shared printer settings.
lastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(lastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (hPrinter != IntPtr.Zero)
ClosePrinter(hPrinter);
return Convert.ToBoolean(nRet);
}
}
private DEVMODE GetPrinterSettings(string PrinterName)
{
PrinterData PData = new PrinterData();
DEVMODE dm;
const int PRINTER_ACCESS_ADMINISTER = 0x4;
const int PRINTER_ACCESS_USE = 0x8;
const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
nRet = Convert.ToInt32(OpenPrinter(PrinterName,
out hPrinter, ref PrinterValues));
if (nRet == 0)
{
lastError = Marshal.GetLastWin32Error();
throw new Win32Exception(Marshal.GetLastWin32Error());
}
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out nBytesNeeded);
if (nBytesNeeded <= 0)
{
throw new System.Exception("Unable to allocate memory");
}
else
{
// Allocate enough space for PRINTER_INFO_2...
{// ptrPrinterIn fo =
Marshal.AllocCoTaskMem(nBytesNeeded);
};
ptrPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded);
// The second GetPrinter fills in all the current settings, so all you
// need to do is modify what you're interested in...
nRet = Convert.ToInt32(GetPrinter(hPrinter, 2,
ptrPrinterInfo, nBytesNeeded, out nJunk));
if (nRet == 0)
{
lastError = Marshal.GetLastWin32Error();
throw new Win32Exception(Marshal.GetLastWin32Error());
}
pinfo = (PRINTER_INFO_2)Marshal.PtrToStructure(ptrPrinterInfo,
typeof(PRINTER_INFO_2));
IntPtr Temp = new IntPtr();
if (pinfo.pDevMode == IntPtr.Zero)
{
// If GetPrinter didn't fill in the DEVMODE, try to get it by calling
// DocumentProperties...
IntPtr ptrZero = IntPtr.Zero;
//get the size of the devmode structure
sizeOfDevMode = DocumentProperties(IntPtr.Zero, hPrinter,
PrinterName, ptrZero, ref ptrZero, 0);
ptrDM = Marshal.AllocCoTaskMem(sizeOfDevMode);
int i;
i = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrDM,
ref ptrZero, DM_OUT_BUFFER);
if ((i < 0) || (ptrDM == IntPtr.Zero))
{
//Cannot get the DEVMODE structure.
throw new System.Exception("Cannot get DEVMODE data");
}
pinfo.pDevMode = ptrDM;
}
intError = DocumentProperties(IntPtr.Zero, hPrinter,
PrinterName, IntPtr.Zero, ref Temp, 0);
//IntPtr yDevModeData = Marshal.AllocCoTaskMem(i1);
yDevModeData = Marshal.AllocHGlobal(intError);
intError = DocumentProperties(IntPtr.Zero, hPrinter,
PrinterName, yDevModeData, ref Temp, 2);
dm = (DEVMODE)Marshal.PtrToStructure(yDevModeData, typeof(DEVMODE));
//nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, yDevModeData
// , ref yDevModeData, (DM_IN_BUFFER | DM_OUT_BUFFER));
if ((nRet == 0) || (hPrinter == IntPtr.Zero))
{
lastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(lastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return dm;
}
#endregion
}
}
However, I cannot get this code to execute in the IIS hosted wcf service. I've tried creating an external program and then use Process.start to execute a console app that runs the code shown above - but still won't execute.

Java crashes when calling dll function using JNA

I'm using JNA to run a dll function:
Here is all the code corresponding to that manner:
The Native Declarations:
//how the method declared
H264_Login (char *sIP, unsigned short wPort, char *sUserName, char *sPassword, LP_DEVICEINFO lpDeviceInfo, int *error, ,SocketStyle socketTyle=TCPSOCKET); // where LP_DEVICEINFO is a struct
//how the struct declared
typedef struct _H264_DVR_DEVICEINFO
{
SDK_SYSTEM_TIME tmBuildTime; // the "SDK_SYSTEM_TIME" is another struct
char sSerialNumber[64];
int byChanNum;
unsigned int uiDeviceRunTime;
SDK_DeviceType deviceTye; // the "SDK_DeviceType" is a enum
}H264_DVR_DEVICEINFO,*LP_DEVICEINFO;
// this is how "SDK_SYSTEM_TIME" is defined
typedef struct SDK_SYSTEM_TIME{
int year;
int month;
int day;
}SDK_SYSTEM_TIME;
// this is how "SDK_DeviceType" is defined
enum SDK_DeviceType
{
SDK_DEVICE_TYPE_DVR,
SDK_DEVICE_TYPE_MVR,
SDK_DEVICE_TYPE_NR
};
// this is how "SocketStyle" is defined
enum SocketStyle
{
TCPSOCKET=0,
UDPSOCKET,
SOCKETNR
};
The following is their corresponding Java mappings:
public class Test implements StdCallLibrary {
public interface simpleDLL extends StdCallLibrary {
long H264_Login(String sIP, short wPort, String sUserName, String sPassword,
Structure DeviceDate, int error, int TCPSOCKET);
}
static
{
System.loadLibrary("NetSdk");
}
// the struct implementation
public static class DeviceDate extends Structure{
public SDK_SYSTEM_TIME tmBuildTime;
public String sSerialNumber;
public IntByReference byChanNum;
public IntByReference uiDeviceRunTime;
public IntByReference deviceTpye;
#Override
protected List<Object> getFieldOrder() {
List<Object> list = new ArrayList<>();
list.add("tmBuildTime");
list.add("sSerialNumber");
list.add("byChanNum");
list.add("uiDeviceRunTime");
list.add("deviceTpye");
return list;
}
}
public static class SDK_SYSTEM_TIME extends Structure{
public IntByReference year;
public IntByReference month;
public IntByReference day;
#Override
protected List<Object> getFieldOrder() {
List<Object> list = new ArrayList<>();
list.add("year");
list.add("month");
list.add("day");
return list;
}
}
// and then how I called it through the main function
public static void main(String args[]) throws FileNotFoundException{
simpleDLL INSTANCE = (simpleDLL) Native.loadLibrary( ("NetSdk"), simpleDLL.class);
DeviceDate dev = new DeviceDate() // where DeviceDate is a static class inherits com.sun.jna.Structure
int err = (int) INSTANCE.H264_GetLastError();
long result = INSTANCE.H264_Login("255.255.255.255", (short) 33333, "admin", "admin", dev, err, 0);
}
}
upon running the app, the Java crashes:
and this is the full problem signature:
Problem signature:
Problem Event Name: APPCRASH
Application Name: javaw.exe
Application Version: 7.0.600.19
Application Timestamp: 536a95c6
Fault Module Name: jna3976113557901128571.dll
Fault Module Version: 4.0.0.215
Fault Module Timestamp: 52d3949a
Exception Code: c0000005
Exception Offset: 0000e3a2 OS
Version: 6.1.7601.2.1.0.256.1
Locale ID: 1033
Additional Information 1: 7bc2
Additional Information 2: 7bc24d73a5063367529b81d28aecc01c
Additional Information 3: 5bea
Additional Information 4: 5beaa1c0441c3adb156a170a61c93d19
Read our privacy statement online:
http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0409
If the online privacy statement is not available, please read our
privacy statement offline: C:\Windows\system32\en-US\erofflps.txt
Your mappings have a number of errors. Your structures should look like the following (IntByReference represents places where you would pass the address of an int, and you can't substitute String for a primitive native char array). Please refer to the JNA mapping documentation to ensure you understand how native types map to Java types:
public static class LP_DEVICE_INFO extends Structure{
public SDK_SYSTEM_TIME tmBuildTime;
public byte[] sSerialNumber = new byte[64];
public int byChanNum;
public int uiDeviceRunTime;
public int deviceType; // Assuming the size of the enum is int
#Override
protected List<Object> getFieldOrder() {
List<Object> list = new ArrayList<>();
list.add("tmBuildTime");
list.add("sSerialNumber");
list.add("byChanNum");
list.add("uiDeviceRunTime");
list.add("deviceTpye");
return list;
}
}
public static class SDK_SYSTEM_TIME extends Structure{
public int year;
public int month;
public int day;
#Override
protected List<Object> getFieldOrder() {
List<Object> list = new ArrayList<>();
list.add("year");
list.add("month");
list.add("day");
return list;
}
}

Options for HIDAPI on OS X

I have been working with HIDAPI with C and trying to get Mono to communicate with the HIDAPI using interop. I have done a lot of searching and have not been able to find anyone who has gotten HIDAPI to work with Mono on OS X.
Does anyone know if I can redirect the output from a HID device using HIDAPI to a local virtual serial port and then have Mono just read from the serial port?
Another option, would anyone know if I could use something like Arduino leonardo or Circuits#Home USB Host Shield?
At least until I can sort out PInvoke on Mono.
Thanks
I found and adapted this code from elsewhere, though I can't for the life of me find the source. If someone knows, please let me know so I can properly attribute it and link to it. It's been working well for me on both Windows and OS X. You do have to build hidapi for each platform, obviously.
using System;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace HidApiCommunicationLayer
{
internal class HidApiInteropCommLayer
{
#region Interop
#if WINDOWS
private const string HIDAPI_DLL = "hidapi.dll";
#else
private const string HIDAPI_DLL = "hidapi.dylib";
#endif
protected IntPtr _device;
private Object _locker = new object();
public bool IsOpen()
{
return _device != IntPtr.Zero;
}
public void Open(ushort vid, ushort hid, string serial)
{
if (_device != IntPtr.Zero) throw new Exception("a device is already opened; close it first.");
IntPtr ret = hid_open(vid, hid, serial);
_device = ret;
//if (_device != IntPtr.Zero)
// hid_set_nonblocking(_device, true);
}
public int Read(byte[] buffer, int length)
{
lock (_locker)
{
AssertValidDev();
int ret = hid_read_timeout(_device, buffer, (uint)length, 1);
if (ret < 0)
throw new Exception("Failed to Read.");
return ret;
}
}
public void Close()
{
AssertValidDev();
hid_close(_device);
_device = IntPtr.Zero;
}
public int ExitHidAPI()
{
return hid_exit();
}
public String GetProductString()
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_product_string(_device, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive product string");
return EncodeBuffer(buf);
}
public String GetManufacturerString()
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_manufacturer_string(_device, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive manufacturer string");
return EncodeBuffer(buf);
}
public int GetFeatureReport(byte[] buffer, int length)
{
AssertValidDev();
int ret = hid_get_feature_report(_device, buffer, (uint)length);
if (ret < 0)
throw new Exception("failed to get feature report");
return ret;
}
public int SendFeatureReport(byte[] buffer)
{
int ret = hid_send_feature_report(_device, buffer, (uint)buffer.Length);
//if (ret < 0)
// throw new Exception ("failed to send feature report");
return ret;
}
public int Write(byte[] buffer)
{
lock (_locker)
{
AssertValidDev();
int ret = hid_write(_device, buffer, HID_MAX_PACKET_SIZE + 1);
//if (ret < 0)
// Custom logging
return ret;
}
}
public String Error()
{
AssertValidDev();
IntPtr ret = hid_error(_device);
return Marshal.PtrToStringAuto(ret);
}
public string GetIndexedString(int index)
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_indexed_string(_device, index, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive indexed string");
return EncodeBuffer(buf);
}
public string GetSerialNumberString()
{
AssertValidDev();
byte[] buf = new byte[1000];
int ret = HidApiInteropCommLayer.hid_get_serial_number_string(_device, buf, (uint)(buf.Length / 4) - 1);
if (ret < 0)
throw new Exception("failed to receive serial number string");
return EncodeBuffer(buf);
}
private string EncodeBuffer(byte[] buffer)
{
return Encoding.Unicode.GetString(buffer).Trim('\0');
}
private void AssertValidDev()
{
if (_device == IntPtr.Zero) throw new Exception("No device opened");
}
#region DllImports
[DllImport(HIDAPI_DLL)]
private static extern int hid_read(IntPtr device, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_read_timeout(IntPtr device, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length, int timeout);
[DllImport(HIDAPI_DLL)]
private static extern IntPtr hid_open(ushort vid, ushort pid, [MarshalAs(UnmanagedType.LPWStr)] string serial);
[DllImport(HIDAPI_DLL)]
private static extern void hid_close(IntPtr device);
[DllImport(HIDAPI_DLL)]
private static extern int hid_init();
[DllImport(HIDAPI_DLL)]
private static extern int hid_exit();
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_product_string(IntPtr device, [Out] byte[] _string, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_manufacturer_string(IntPtr device, [Out] byte[] _string, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_feature_report(IntPtr device, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_serial_number_string(IntPtr device, [Out] byte[] serial, uint maxlen);
[DllImport(HIDAPI_DLL)]
private static extern int hid_get_indexed_string(IntPtr device, int string_index, [Out] byte[] _string, uint maxlen);
[DllImport(HIDAPI_DLL)]
private static extern IntPtr hid_error(IntPtr device);
[DllImport(HIDAPI_DLL)]
private static extern int hid_send_feature_report(IntPtr device, [In, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern int hid_set_nonblocking(IntPtr device, [In, MarshalAs(UnmanagedType.SysInt)] bool nonblock);
[DllImport(HIDAPI_DLL)]
private static extern int hid_write(IntPtr device, [In, MarshalAs(UnmanagedType.LPArray)] byte[] data, uint length);
[DllImport(HIDAPI_DLL)]
private static extern IntPtr hid_open_path([In, MarshalAs(UnmanagedType.LPStr)] string path);
#endregion DllImports
#endregion Interop
#region Constructors
public static HidApiInteropCommLayer GetDevice(ushort vid, ushort pid)
{
try
{
HidApiInteropCommLayer layer = new HidApiInteropCommLayer();
layer.Open(vid, pid, null);
return layer._device == IntPtr.Zero ? null : layer;
}
catch (System.BadImageFormatException fx)
{
//Custom logging
return null;
}
catch (Exception ex)
{
//Custom logging
return null;
}
}
#endregion Constructors
private const int HID_MAX_PACKET_SIZE = 1024;
#region ICommunicationLayer
public void Init()
{
try
{
if (IsOpen())
{
ContinueReadProcessing = true;
ReadThread = new Thread(new ThreadStart(ReadLoop));
ReadThread.Name = "HidApiReadThread";
ReadThread.Start();
}
else
{
Disconnect();
}
}
catch (Exception ex)
{
//Custom logging
throw;
}
}
public bool SendData(byte[] data)
{
try
{
MemoryStream stream = new MemoryStream(HID_MAX_PACKET_SIZE + 1);
stream.WriteByte(0);
stream.Write(data, 0, HID_MAX_PACKET_SIZE);
int ret = Write(stream.ToArray());
if (ret >= 0)
return true;
else
{
return false;
}
}
catch (Exception ex)
{
//Custom logging
return false;
}
}
public event EventHandler<DataEventArgs> DataReceived;
public event EventHandler Disconnected;
public void Start()
{
ContinueReadProcessing = true;
}
public void Stop()
{
Disconnect();
}
#endregion ICommunicationLayer
private Thread ReadThread = null;
protected volatile bool ContinueReadProcessing = true;
private void ReadLoop()
{
var culture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
while (ContinueReadProcessing)
{
try
{
byte[] report = new byte[HID_MAX_PACKET_SIZE];
var result = Read(report, HID_MAX_PACKET_SIZE);
if (result > 0)
{
DataReceived(this, new DataEventArgs(report));
}
else if (result < 0)
{
Disconnect();
}
}
catch (Exception ex)
{
Disconnect();
}
Thread.Sleep(1);
}
}
private void Disconnect()
{
ContinueReadProcessing = false;
Disconnected(this, EventArgs.Empty);
}
#region IDisposable Members
public void Dispose()
{
ContinueReadProcessing = false;
ReadThread.Join(500);
if (ReadThread.IsAlive)
{
ReadThread.Abort();
}
if (IsOpen())
Close();
int res = ExitHidAPI();
}
#endregion IDisposable Members
}
internal class Utf32Marshaler : ICustomMarshaler
{
private static Utf32Marshaler instance = new Utf32Marshaler();
public static ICustomMarshaler GetInstance(string s)
{
return instance;
}
public void CleanUpManagedData(object o)
{
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
//UnixMarshal.FreeHeap(pNativeData);
}
public int GetNativeDataSize()
{
return IntPtr.Size;
}
public IntPtr MarshalManagedToNative(object obj)
{
string s = obj as string;
if (s == null)
return IntPtr.Zero;
return Marshal.StringToHGlobalAuto(s);
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return Marshal.PtrToStringAuto(pNativeData);
}
}
public class DataEventArgs : EventArgs
{
public DataEventArgs(byte[] data)
{
Data = data;
}
public byte[] Data { get; private set; }
}
}
Arduino Leonardo can't act as a USB Host.
In principle though, yes, you could make a device act as a CDC Serial Port on the device side, and have it act as Host USB to a HID device.
Alternatively, you could skip the HIDAPI step entirely and use HidSharp. :) It'll P/Invoke directly into the MacOS X native APIs.
Hope this helps
James

Return string from c++ function pointer invoked from c#

I need to call a c++ callback function from c# that returns a String. When I try with the code below the application crashes hard (with a message saying that it may be due to a corruption of the heap).
Here's the c++ code:
static String^ CppFunctionThatReturnsString()
{
return gcnew String("From C++");
}
void main()
{
CSharp::CSharpFunction(IntPtr(CppFunctionThatReturnsString));
}
And here's the c# code:
public class CSharp
{
private delegate string CppFuncDelegate();
public static void CSharpFunction(IntPtr cppFunc)
{
var func = (CppFuncDelegate)Marshal.GetDelegateForFunctionPointer(cppFunc, typeof(CppFuncDelegate));
func(); // Crash
}
}
Do I have to do some kind of marshaling magic with the string before returning it?
Why are you using function pointers in the first place? Just pass an instance of the delegate to the C# code:
C++:
static String^ CppFunctionThatReturnsString()
{
return gcnew String("From C++");
}
void main()
{
CSharp::CSharpFunction(new CSharp::CppFuncDelegate(CppFuncThatReturnsString));
}
C#:
public class CSharp
{
private delegate string CppFuncDelegate();
public static void CSharpFunction(CppFuncDelegate d)
{
d();
}
}
I think you may need to put CppFuncThatReturnsString inside a class.
I found the answer on this ten year old page.
c++:
static const char* __stdcall CppFunctionThatReturnsString()
{
return "From C++";
}
void main()
{
CSharp::CSharpFunction(IntPtr(CppFunctionThatReturnsString));
}
c#:
public class CSharp
{
private delegate IntPtr CppFuncDelegate();
public static void CSharpFunction(IntPtr cppFunc)
{
var func = (CppFuncDelegate)Marshal.GetDelegateForFunctionPointer(cppFunc, typeof(CppFuncDelegate));
Marshal.PtrToStringAnsi(func());
}
}
That is, pass it as an IntPtr and marshal it into a string on the C# side.