Newbie to C#. I have written a WDF driver and DLL that work. I am creating an application in C# to access the hardware through the DLL. There is a specific function that is causing an ExecutionEngineException soon after it is first called. Here is the function definition from the DLL:
DECLDIR int ReadDatagram(int channel, unsigned long *msgID, unsigned int *msgType, int *msgLen, unsigned int *data);
In my C# application code, I import this function with the following lines:
[DllImport("pcmcanDLL.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern int ReadDatagram(int channel, ref uint msgID, ref uint msgType, ref int msgLen, uint[] data);
When I start the application and open a channel, this function is periodically called by a timer. After a short indefinite time, I get the following exception message. If I comment out he call of this function, the application never has an issue.
Mesage: An unhandled exception of type 'System.ExecutionEngineException' occurred in mscorlib.dll
My application code is here. I believe I am handling the pointer arguments correctly because occasionally this will work a few times and the data is good in those ceases. Appreciate any insights.
private void rcvTimer_Tick(object sender, EventArgs e)
{
int channel = 1;
String dsplyString = "Packet Received\n";
uint msgID = 0, msgType = 0;
int msgLen = 0;
uint[] data = new uint[8];
ErrorTypes dllReturn = ErrorTypes.RCV_BUFFER_EMPTY;
do
{
dllReturn = (ErrorTypes)NativeMethods.ReadDatagram(channel, ref msgID, ref msgType, ref msgLen, data);
if (dllReturn != ErrorTypes.SUCCESS && dllReturn != ErrorTypes.RCV_BUFFER_EMPTY)
{
MessageBox.Show("Error receiving packet.", "Receipt Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
else if (dllReturn == ErrorTypes.SUCCESS)
{
dsplyString = String.Format("{0} {1} {2} {3}\n", channel, msgID, msgType, msgLen);
}
} while (dllReturn != ErrorTypes.RCV_BUFFER_EMPTY);
}
Try following
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
}
}
public enum ErrorTypes : int
{
RCV_BUFFER_EMPTY = 0,
SUCCESS = 1
}
public class Test
{
[DllImport("pcmcanDLL.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern int ReadDatagram(int channel, ref uint msgID, IntPtr msgType, ref int msgLen, IntPtr dataPtr);
private void rcvTimer_Tick(object sender, EventArgs e)
{
int channel = 1;
String dsplyString = "Packet Received\n";
uint msgID = 0;
uint msgType = 0;
int msgLen = 0;
uint[] data = new uint[8];
ErrorTypes dllReturn = ErrorTypes.RCV_BUFFER_EMPTY;
IntPtr dataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(data));
IntPtr msgTypePtr = Marshal.AllocHGlobal(Marshal.SizeOf(msgType));
do
{
Marshal.StructureToPtr(msgType, msgTypePtr, true);
Marshal.StructureToPtr(data, dataPtr, true);
dllReturn = (ErrorTypes)ReadDatagram(channel, ref msgID, msgTypePtr, ref msgLen, dataPtr);
if (dllReturn != ErrorTypes.SUCCESS && dllReturn != ErrorTypes.RCV_BUFFER_EMPTY)
{
MessageBox.Show("Error receiving packet.", "Receipt Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
else if (dllReturn == ErrorTypes.SUCCESS)
{
dsplyString = String.Format("{0} {1} {2} {3}\n", channel, msgID, msgType, msgLen);
}
} while (dllReturn != ErrorTypes.RCV_BUFFER_EMPTY);
Marshal.FreeHGlobal(dataPtr);
Marshal.FreeHGlobal(msgTypePtr);
}
}
}
Related
We suddenly have problems with the smart card api on some windows installations.
There seem to be a memory leak while calling the SCardEstablishContext function.
The problem can be reproduced in a console application with the code sample available at
http://www.pinvoke.net/default.aspx/winscard.scardestablishcontext
class Program
{
#region Win32
// WinSCard APIs to be imported.
[DllImport("WinScard.dll")]
static extern int SCardEstablishContext(uint dwScope,
IntPtr notUsed1,
IntPtr notUsed2,
out IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardReleaseContext(IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardConnect(IntPtr hContext,
string cReaderName,
uint dwShareMode,
uint dwPrefProtocol,
ref IntPtr phCard,
ref IntPtr ActiveProtocol);
[DllImport("WinScard.dll")]
static extern int SCardDisconnect(IntPtr hCard, int Disposition);
[DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
static extern int SCardListReaders(
IntPtr hContext,
byte[] mszGroups,
byte[] mszReaders,
ref UInt32 pcchReaders);
#endregion
static void Main(string[] args)
{
while (true)
{
SmartCardInserted();
System.Threading.Thread.Sleep(10);
}
}
internal static bool SmartCardInserted()
{
bool cardInserted = false;
IntPtr hContext = IntPtr.Zero;
try
{
List<string> readersList = new List<string>();
int ret = 0;
uint pcchReaders = 0;
int nullindex = -1;
char nullchar = (char)0;
// Establish context.
ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);
// First call with 3rd parameter set to null gets readers buffer length.
ret = SCardListReaders(hContext, null, null, ref pcchReaders);
byte[] mszReaders = new byte[pcchReaders];
// Fill readers buffer with second call.
ret = SCardListReaders(hContext, null, mszReaders, ref pcchReaders);
// Populate List with readers.
ASCIIEncoding ascii = new ASCIIEncoding();
string currbuff = ascii.GetString(mszReaders);
int len = (int)pcchReaders;
if (len > 0)
{
while (currbuff[0] != nullchar)
{
nullindex = currbuff.IndexOf(nullchar); // Get null end character.
string reader = currbuff.Substring(0, nullindex);
readersList.Add(reader);
len = len - (reader.Length + 1);
currbuff = currbuff.Substring(nullindex + 1, len);
}
}
// We have list of readers, check for cards.
IntPtr phCard = IntPtr.Zero;
IntPtr ActiveProtocol = IntPtr.Zero;
int result = 0;
foreach (string readerName in readersList)
{
try
{
result = SCardConnect(hContext, readerName, 2, 3, ref phCard, ref ActiveProtocol);
if (result == 0)
{
cardInserted = true;
break;
}
}
finally
{
SCardDisconnect(phCard, 0);
}
}
}
finally
{
SCardReleaseContext(hContext);
}
return cardInserted;
}
}
To test, we call the method SmartCardInserted() in an infinite loop with a small delay => the memory grows constantly and new hadles are allocated.
We see this problem on systems runing Windows 10 or Windows Server 2012, but not on Windows Server 2008.
Any ideas are greatly appreciated!
The problem seems to have been released with v1709 of Windows 10. The shortest amount of code to reproduce the bug is
while(true) {
ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);
SCardReleaseContext(hContext);
}
It leaks ~264 bytes of memory each time a context is established and released.
If you maintain hContext outside of the loop and only create a context if it's IntPtr.Zero you should be able to avoid the leak. Then when you call SCardListReaders, check to see if you get SCARD_E_INVALID_HANDLE back and invalidate your hContext.
class Program
{
#region Win32
// WinSCard APIs to be imported.
[DllImport("WinScard.dll")]
static extern int SCardEstablishContext(uint dwScope,
IntPtr notUsed1,
IntPtr notUsed2,
out IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardReleaseContext(IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardConnect(IntPtr hContext,
string cReaderName,
uint dwShareMode,
uint dwPrefProtocol,
ref IntPtr phCard,
ref IntPtr ActiveProtocol);
[DllImport("WinScard.dll")]
static extern int SCardDisconnect(IntPtr hCard, int Disposition);
[DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
static extern int SCardListReaders(
IntPtr hContext,
byte[] mszGroups,
byte[] mszReaders,
ref UInt32 pcchReaders);
#endregion
static void Main(string[] args)
{
IntPtr hContext = IntPtr.Zero;
while (true)
{
SmartCardInserted(hContext);
System.Threading.Thread.Sleep(10);
}
SCardReleaseContext(hContext);
}
internal static bool SmartCardInserted(IntPtr hContext)
{
bool cardInserted = false;
try
{
List<string> readersList = new List<string>();
int ret = 0;
uint pcchReaders = 0;
int nullindex = -1;
char nullchar = (char)0;
// Establish context.
if(hContext == IntPtr.Zero)
ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);
// First call with 3rd parameter set to null gets readers buffer length.
ret = SCardListReaders(hContext, null, null, ref pcchReaders);
if(ret == 0x80100003) // SCARD_E_INVALID_HANDLE = 0x80100003, // The supplied handle was invalid
{
try
{
SCardReleaseContext(hContext);
}
catch {}
finally
{
hContext = IntPtr.Zero;
}
return false;
}
byte[] mszReaders = new byte[pcchReaders];
// Fill readers buffer with second call.
ret = SCardListReaders(hContext, null, mszReaders, ref pcchReaders);
// Populate List with readers.
ASCIIEncoding ascii = new ASCIIEncoding();
string currbuff = ascii.GetString(mszReaders);
int len = (int)pcchReaders;
if (len > 0)
{
while (currbuff[0] != nullchar)
{
nullindex = currbuff.IndexOf(nullchar); // Get null end character.
string reader = currbuff.Substring(0, nullindex);
readersList.Add(reader);
len = len - (reader.Length + 1);
currbuff = currbuff.Substring(nullindex + 1, len);
}
}
// We have list of readers, check for cards.
IntPtr phCard = IntPtr.Zero;
IntPtr ActiveProtocol = IntPtr.Zero;
int result = 0;
foreach (string readerName in readersList)
{
try
{
result = SCardConnect(hContext, readerName, 2, 3, ref phCard, ref ActiveProtocol);
if (result == 0)
{
cardInserted = true;
break;
}
}
finally
{
SCardDisconnect(phCard, 0);
}
}
}
return cardInserted;
}
}
It's a workaround until the Winscard.dll API is fixed.
My current code works on elements outside of an iframe. How should I approach fetching elements within an iframe using getElementById? My end goal is to write text within the the <body id="tinymce"><p>...</p></body> tags. I am not using a webBrowser control - this is for an external instance of iexplore
HTML Sample
Code Sample
foreach (InternetExplorer ie in new ShellWindowsClass())
{
if (ie.LocationURL.ToString().IndexOf("intranet_site_url") != -1)
{
IWebBrowserApp wb = (IWebBrowserApp)ie;
while (wb.Busy) { Thread.Sleep(100); }
HTMLDocument document = ((HTMLDocument)wb.Document);
// FETCH BY ID
IHTMLElement element;
HTMLInputElementClass hitem;
element = document.getElementById("tinymce");
hitem = (HTMLInputElementClass)element;
hitem.value = first_name;
// FETCH BY ID in IFRAME
IHTMLFramesCollection2 hframes = document.frames;
for (int i = 0; i < hframes.length; i++)
{
object ref_index = i;
IHTMLWindow2 currentFrame = (IHTMLWindow2)hframes.item(ref ref_index);
if (currentFrame != null)
{
MessageBox.Show(currentFrame.name);
// what to do from here?
}
else
MessageBox.Show("Null");
}
}
}
- update idea
Chance of adapting my idea below?
if (currentFrame != null)
{
MessageBox.Show(currentFrame.name);
HTMLDocument document_sub = ((HTMLDocument)currentFrame.document);
IHTMLElement element_sub;
HTMLInputElementClass hitem_sub;
element_sub = (document_sub.getElementById("tinymce"));
hitem_sub = (HTMLInputElementClass)element_sub;
try
{
hitem_sub.value = first_name;
// the above will produce...
// InvalidCastException: Unable to cast COM object of type 'mshtml.HTMLBodyCLass' to class type 'mshtml.HTMLInputElementClass'
}
catch { }
}
This answer was inspired by some research I recently did on using eval to inject script into an out-of-proc instance of Internet Explorer.
The idea is to bypass MSHTML DOM interop interfaces and use dynamic JavaScript to obtain a DOM object of interest. There are some implications:
execScript method is deprecated in upcoming IE11.
Unmanaged IDispatchEx::InvokeEx has to be used to access dynamic JavaScript objects inside HTML window object out-of-proc (in case of in-proc WebBrowser control, standard Type.Invoke, HtmlDocument.InvokeScript or dynamic invocation work just fine with this technique).
To address the question itself, it should be quite easy to get the desired body element, using the approach illustrated below:
var tinymceBody = DispExInvoker.Invoke(ie.Document.parentWindow, "eval", "document.getElementById('decrpt_ifr').contentWindow.document.getElementById('tinymce')");
Here's a sample which executes alert(document.URL) in the context of a child frame of jsfiddle.net, by automating an out-of-proc instance of InternetExplorer.Application:
private async void Form1_Load(object sender, EventArgs ev)
{
SHDocVw.InternetExplorer ie = new SHDocVw.InternetExplorer();
ie.Visible = true;
var documentCompleteTcs = new TaskCompletionSource<bool>();
ie.DocumentComplete += delegate
{
if (documentCompleteTcs.Task.IsCompleted)
return;
documentCompleteTcs.SetResult(true);
};
ie.Navigate("http://jsfiddle.net/");
await documentCompleteTcs.Task;
// inject __execScript code into the top window
var execScriptCode = "(window.__execScript = function(exp) { return eval(exp); }, window.self)";
var window = DispExInvoker.Invoke(ie.Document.parentWindow, "eval", execScriptCode);
// inject __execScript into a child iframe
var iframe = DispExInvoker.Invoke(window, "__execScript",
String.Format("document.all.tags('iframe')[0].contentWindow.eval('{0}')", execScriptCode));
// invoke 'alert(document.URL)' in the context of the child frame
DispExInvoker.Invoke(iframe, "__execScript", "alert(document.URL)");
}
/// <summary>
/// Managed wrapper for calling IDispatchEx::Invoke
/// https://stackoverflow.com/a/18349546/1768303
/// </summary>
public class DispExInvoker
{
// check is the object supports IsDispatchEx
public static bool IsDispatchEx(object target)
{
return target is IDispatchEx;
}
// invoke a method on the target IDispatchEx object
public static object Invoke(object target, string method, params object[] args)
{
var dispEx = target as IDispatchEx;
if (dispEx == null)
throw new InvalidComObjectException();
var dp = new System.Runtime.InteropServices.ComTypes.DISPPARAMS();
try
{
// repack arguments
if (args.Length > 0)
{
// should be using stackalloc for DISPPARAMS arguments, but don't want enforce "/unsafe"
int size = SIZE_OF_VARIANT * args.Length;
dp.rgvarg = Marshal.AllocCoTaskMem(size);
ZeroMemory(dp.rgvarg, size); // zero'ing is equal to VariantInit
dp.cArgs = args.Length;
for (var i = 0; i < dp.cArgs; i++)
Marshal.GetNativeVariantForObject(args[i], dp.rgvarg + SIZE_OF_VARIANT * (args.Length - i - 1));
}
int dispid;
dispEx.GetDispID(method, fdexNameCaseSensitive, out dispid);
var ei = new System.Runtime.InteropServices.ComTypes.EXCEPINFO();
var result = Type.Missing;
dispEx.InvokeEx(dispid, 0, DISPATCH_METHOD, ref dp, ref result, ref ei, null);
return result;
}
finally
{
if (dp.rgvarg != IntPtr.Zero)
{
for (var i = 0; i < dp.cArgs; i++)
VariantClear(dp.rgvarg + SIZE_OF_VARIANT * i);
Marshal.FreeCoTaskMem(dp.rgvarg);
}
}
}
// interop declarations
[DllImport("oleaut32.dll", PreserveSig = false)]
static extern void VariantClear(IntPtr pvarg);
[DllImport("Kernel32.dll", EntryPoint = "RtlZeroMemory", SetLastError = false)]
static extern void ZeroMemory(IntPtr dest, int size);
const uint fdexNameCaseSensitive = 0x00000001;
const ushort DISPATCH_METHOD = 1;
const int SIZE_OF_VARIANT = 16;
// IDispatchEx interface
[ComImport()]
[Guid("A6EF9860-C720-11D0-9337-00A0C90DCAA9")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IDispatchEx
{
// IDispatch
int GetTypeInfoCount();
[return: MarshalAs(UnmanagedType.Interface)]
System.Runtime.InteropServices.ComTypes.ITypeInfo GetTypeInfo([In, MarshalAs(UnmanagedType.U4)] int iTInfo, [In, MarshalAs(UnmanagedType.U4)] int lcid);
void GetIDsOfNames([In] ref Guid riid, [In, MarshalAs(UnmanagedType.LPArray)] string[] rgszNames, [In, MarshalAs(UnmanagedType.U4)] int cNames, [In, MarshalAs(UnmanagedType.U4)] int lcid, [Out, MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
void Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr);
// IDispatchEx
void GetDispID([MarshalAs(UnmanagedType.BStr)] string bstrName, uint grfdex, [Out] out int pid);
void InvokeEx(int id, uint lcid, ushort wFlags,
[In] ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pdp,
[In, Out] ref object pvarRes,
[In, Out] ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pei,
System.IServiceProvider pspCaller);
void DeleteMemberByName([MarshalAs(UnmanagedType.BStr)] string bstrName, uint grfdex);
void DeleteMemberByDispID(int id);
void GetMemberProperties(int id, uint grfdexFetch, [Out] out uint pgrfdex);
void GetMemberName(int id, [Out, MarshalAs(UnmanagedType.BStr)] out string pbstrName);
[PreserveSig]
[return: MarshalAs(UnmanagedType.I4)]
int GetNextDispID(uint grfdex, int id, [In, Out] ref int pid);
void GetNameSpaceParent([Out, MarshalAs(UnmanagedType.IUnknown)] out object ppunk);
}
}
Try this:
Windows.Forms.HtmlWindow frame = WebBrowser1.Document.GetElementById("decrpt_ifr").Document.Window.Frames["decrpt_ifr"];
HtmlElement body = frame.Document.GetElementById("tinymce");
body.InnerHtml = "Hello, World!";
That gets the frame and treats it as a different document (because it is) and then it tries to get the element from its id. Good luck.
Edit: This should do the trick taking advantage of the dynamic datatype, and InternetExplorer interface:
private void Form1_Load(object sender, EventArgs e)
{
foreach (InternetExplorer ie in new ShellWindows())
{
if (ie.LocationURL.ToString().IndexOf("tinymce") != -1)
{
IWebBrowserApp wb = (IWebBrowserApp)ie;
wb.Document.Frames.Item[0].document.body.InnerHtml = "<p>Hello, World at </p> " + DateTime.Now.ToString();
}
}
}
Explore the sandbox attribute.
http://www.w3schools.com/tags/att_iframe_sandbox.asp
Also another way would be to get url of that iframe and load that into your browser.
For me accepted solution is giving "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" error.
this is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, int lpBaseAddress, out string buffer, int size, out int lpNumberOfBytesRead);
public List<int> Search(string ProcessName, int _Length, int Value)
{
Process[] P = Process.GetProcessesByName(ProcessName);
List<int> tmp = new List<int>();
if (P.Length < 0) return tmp;
try
{
if (P[0].HasExited)
return tmp;
}
catch { return tmp; }
byte[] buff = new byte[4];
int Address = P[0].MainModule.BaseAddress.ToInt32();
for (int i = 0; i < _Length; i++)
{
ReadProcessMemory(P[0].Handle, Address + i, buff, 4, 0);
if (BitConverter.ToInt32(buff, 0) == Value)
{
tmp.Add(Address + i);
}
}
return tmp;
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
listBox1.DataSource = Search("plugin-container", 0x100, 15035990);
}
}
}
the problem:
ReadProcessMemory(P[0].Handle, Address + i, buff, 4, 0);
That line is wrong
He marks it with a red line
Does anyone have any idea why he does not recognize this line?
Sorry about my bad English
Your P/Invoke definitions are not quite right. While lpBuffer is annotated as an __out parameter, this does not translate to the .Net P/Invoke meaning of out. If you notice it is an LPVOID, which if this was truly a .Net out it should be LPVOID* (pointer to a pointer).
Instead:
[DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]
public static extern bool ReadProcessMemory(
IntPtr hProcess, // <-- Pointers should be IntPtr
IntPtr lpBaseAddress,
byte[] buffer, // <-- Using byte[], also IntPtr could be used
uint size, // <-- SIZE_T is unsigned
out uint lpNumberOfBytesRead);
Used like so:
uint bytesRead;
byte[] buffer = new byte[4];
IntPtr baseAddress = P[0].MainModule.BaseAddress;
for (int i = 0; i < _Length; i++)
{
IntPtr nextAddress = IntPtr.Add(baseAddress, i);
if (ReadProcessMemory(
P[0].Handle,
nextAddress,
buffer,
(uint)buffer.Length,
out bytesRead))
{
if (bytesRead == buffer.Length
&& BitConverter.ToInt32(buffer, 0) == Value)
{
tmp.Add(nextAddress);
}
else if (bytesRead != buffer.Length)
{
throw new InvalidOperationException(String.Format(
#"Read {0} bytes (expecting {1}) at {2:X}",
bytesRead,
buffer.Length,
nextAddress.ToInt64()));
}
}
else
{
throw new InvalidOperationException(String.Format(
#"Could not read {0} bytes at {1:X}",
buffer.Length,
nextAddress.ToInt64()));
}
}
return tmp;
I have been heavily contemplating adding the Embedded MYSQL Server Library into my application. My software is a layer between a Game Server and a Web Management Panel that provides extra functionality. Many of our customers have been requesting MySQL databases for their servers (since this is what their plugins are developed to use), and being able to run one within my software rather than manually set them up would be fantastic.
Is there a .NET wrapper for this library I am missing?
The software being ran by my application will need to be able to connect to it, but the software is obviously being ran locally. Will this work?
i'm not aware of any .NET wrapper for this library although i remember there was a talk about introducing support for this library in the .NET Connector from version 5. I can't find any information about that right now though.
There is some sample code out there on the web which you can extend your code upon. I quess the most complete would be http://forums.mysql.com/read.php?38,67281,67917 ->
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Configuration;
class EntryPoint
{
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_init(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_fetch_lengths(IntPtr result);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_store_result(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_fetch_row(IntPtr result);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_real_connect(IntPtr mysql, string host, string user, string passwd, string db, uint port, string unix_socket, uint client_flag);
[DllImport("libmySQL.dll")]
static extern uint mysql_field_count(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern string mysql_error(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern int mysql_real_query(IntPtr mysql, string query, uint length);
static Array MarshalArray(Type structureType, IntPtr arrayPtr, int length)
{
if (structureType == null)
throw new ArgumentNullException("structureType");
if (!structureType.IsValueType)
throw new ArgumentException("Only struct types are supported.", "structureType");
if (length < 0)
throw new ArgumentOutOfRangeException("length", length, "length must be equal to or greater than zero.");
if (arrayPtr == IntPtr.Zero)
return null;
int size = System.Runtime.InteropServices.Marshal.SizeOf(structureType);
Array array = Array.CreateInstance(structureType, length);
for (int i = 0; i < length; i++)
{
IntPtr offset = new IntPtr((long)arrayPtr + (size * i));
object value = System.Runtime.InteropServices.Marshal.PtrToStructure(offset, structureType);
array.SetValue(value, i);
}
return array;
}
static void mysql_real_query(IntPtr mysql, string query)
{
int result = (query != null) ? mysql_real_query(mysql, query, (uint)query.Length) : mysql_real_query(mysql, null, 0);
if (result == 0)
return;
throw new ApplicationException(mysql_error(mysql));
}
static int Main(string[] args)
{
IntPtr ptr = mysql_init(IntPtr.Zero);
Debug.Assert(ptr != IntPtr.Zero);
IntPtr mysql = mysql_real_connect(ptr, ConfigurationSettings.AppSettings["server"], ConfigurationSettings.AppSettings["username"], ConfigurationSettings.AppSettings["password"], ConfigurationSettings.AppSettings["database"], 0, null, 0);
Debug.Assert(ptr != IntPtr.Zero, mysql_error(ptr));
string query = "SELECT * FROM proxy_servers";
Console.WriteLine("Executing query: {0}", query);
mysql_real_query(mysql, query);
IntPtr result = mysql_store_result(mysql);
Debug.Assert(result != IntPtr.Zero, mysql_error(mysql));
uint fieldCount = mysql_field_count(mysql);
Console.WriteLine("field count: {0}", fieldCount);
for (IntPtr ptrRow = mysql_fetch_row(result); ptrRow != IntPtr.Zero; ptrRow = mysql_fetch_row(result))
{
IntPtr[] mysqlRow = (IntPtr[])MarshalArray(typeof(IntPtr), ptrRow, (int)fieldCount);
IntPtr ptrLengths = mysql_fetch_lengths(result);
uint[] lengths = (uint[])MarshalArray(typeof(uint), ptrLengths, (int)fieldCount);
for (int i = 0; i < (int)fieldCount; i++)
{
string str = Marshal.PtrToStringAnsi(mysqlRow[i], (int)lengths[i]);
Console.Write("{0}, ", str);
}
Console.WriteLine();
}
return 0;
}
}
Here's some C# source code which implements an unmanaged DLL (advapi32).
public void AddPrivileges(string account, string privilege)
{
IntPtr pSid = GetSIDInformation(account);
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
int error = Win32Sec.LsaNtStatusToWinError((int)ret);
throw new Win32Exception(error);
}
The variable values at runtime are as follows:
privilege: "SeServiceLogonRight"
account: "named"
ret: 3221225485 (STATUS_INVALID_PARAMETER)
error: 87
When caught, the message within the Win32Exception is: "The parameter is incorrect"
The code is running on Windows Web Server 2008. I can verify that the account does exist, and this code works fine on another server... I'm not sure if this could have been caused by Windows 2008 SP2. I'm thinking that I've forgotten to install something, but I can't think what...
The code is from: http://weblogs.asp.net/avnerk/archive/2007/05/10/granting-user-rights-in-c.aspx
Following the provided link through to the code at http://www.hightechtalks.com/csharp/lsa-functions-276626.html
IntPtr GetSIDInformation(string account)
{
LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
LSA_TRANSLATED_SID2 lts;
IntPtr tsids = IntPtr.Zero;
IntPtr tdom = IntPtr.Zero;
names[0] = InitLsaString(account);
lts.Sid = IntPtr.Zero;
Console.WriteLine("String account: {0}", names[0].Length);
int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
if (ret != 0)
{
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
}
lts = (LSA_TRANSLATED_SID2) Marshal.PtrToStructure(tsids,
typeof(LSA_TRANSLATED_SID2));
Win32Sec.LsaFreeMemory(tsids);
Win32Sec.LsaFreeMemory(tdom);
return lts.Sid;
}
lts (an LSA_TRANSLATED_SID2 struct) contains a pointer that points at memory that is freed by the call to Win32Sec.LsaFreeMemory. Using the pointer after the memory is freed is bad practice and will have unpredictable results -- it might even "work".
Tweaking the code at the link by using the SecurityIdentifier class (.Net 2 and above) along a little cleanup of unneeded code avoids the memory problem.
using System;
namespace Willys.LsaSecurity
{
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using LSA_HANDLE = IntPtr;
[StructLayout(LayoutKind.Sequential)]
struct LSA_OBJECT_ATTRIBUTES
{
internal int Length;
internal IntPtr RootDirectory;
internal IntPtr ObjectName;
internal int Attributes;
internal IntPtr SecurityDescriptor;
internal IntPtr SecurityQualityOfService;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct LSA_UNICODE_STRING
{
internal ushort Length;
internal ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)]
internal string Buffer;
}
sealed class Win32Sec
{
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaOpenPolicy(
LSA_UNICODE_STRING[] SystemName,
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
int AccessMask,
out IntPtr PolicyHandle
);
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaAddAccountRights(
LSA_HANDLE PolicyHandle,
IntPtr pSID,
LSA_UNICODE_STRING[] UserRights,
int CountOfRights
);
[DllImport("advapi32")]
internal static extern int LsaNtStatusToWinError(int NTSTATUS);
[DllImport("advapi32")]
internal static extern int LsaClose(IntPtr PolicyHandle);
}
sealed class Sid : IDisposable
{
public IntPtr pSid = IntPtr.Zero;
public SecurityIdentifier sid = null;
public Sid(string account)
{
sid = (SecurityIdentifier) (new NTAccount(account)).Translate(typeof(SecurityIdentifier));
Byte[] buffer = new Byte[sid.BinaryLength];
sid.GetBinaryForm(buffer, 0);
pSid = Marshal.AllocHGlobal(sid.BinaryLength);
Marshal.Copy(buffer, 0, pSid, sid.BinaryLength);
}
public void Dispose()
{
if (pSid != IntPtr.Zero)
{
Marshal.FreeHGlobal(pSid);
pSid = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~Sid()
{
Dispose();
}
}
public sealed class LsaWrapper : IDisposable
{
enum Access : int
{
POLICY_READ = 0x20006,
POLICY_ALL_ACCESS = 0x00F0FFF,
POLICY_EXECUTE = 0X20801,
POLICY_WRITE = 0X207F8
}
const uint STATUS_ACCESS_DENIED = 0xc0000022;
const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
const uint STATUS_NO_MEMORY = 0xc0000017;
IntPtr lsaHandle;
public LsaWrapper()
: this(null)
{ }
// // local system if systemName is null
public LsaWrapper(string systemName)
{
LSA_OBJECT_ATTRIBUTES lsaAttr;
lsaAttr.RootDirectory = IntPtr.Zero;
lsaAttr.ObjectName = IntPtr.Zero;
lsaAttr.Attributes = 0;
lsaAttr.SecurityDescriptor = IntPtr.Zero;
lsaAttr.SecurityQualityOfService = IntPtr.Zero;
lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
lsaHandle = IntPtr.Zero;
LSA_UNICODE_STRING[] system = null;
if (systemName != null)
{
system = new LSA_UNICODE_STRING[1];
system[0] = InitLsaString(systemName);
}
uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
(int) Access.POLICY_ALL_ACCESS, out lsaHandle);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int) ret));
}
public void AddPrivileges(string account, string privilege)
{
uint ret = 0;
using (Sid sid = new Sid(account))
{
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
ret = Win32Sec.LsaAddAccountRights(lsaHandle, sid.pSid, privileges, 1);
}
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int) ret));
}
public void Dispose()
{
if (lsaHandle != IntPtr.Zero)
{
Win32Sec.LsaClose(lsaHandle);
lsaHandle = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~LsaWrapper()
{
Dispose();
}
// helper functions
static LSA_UNICODE_STRING InitLsaString(string s)
{
// Unicode strings max. 32KB
if (s.Length > 0x7ffe)
throw new ArgumentException("String too long");
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
lus.Buffer = s;
lus.Length = (ushort) (s.Length * sizeof(char));
lus.MaximumLength = (ushort) (lus.Length + sizeof(char));
return lus;
}
}
}
I couldn't get this to work, so instead I used the source code from the CodeProject project, LSA Functions - Privileges and Impersonation which works nicely.
lts.Sid is freed before returning in GetSIDInformation.
Moving the codes of GetSIDInformation out. It worked fine for .Net 4.5.
public void AddPrivileges(string account, string privilege)
{
LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
LSA_TRANSLATED_SID2 lts;
IntPtr tsids = IntPtr.Zero;
IntPtr tdom = IntPtr.Zero;
names[0] = InitLsaString(account);
lts.Sid = IntPtr.Zero;
Console.WriteLine("String account: {0}", names[0].Length);
int ret1 = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
if (ret1 != 0)
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret1));
lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids, typeof(LSA_TRANSLATED_SID2));
IntPtr pSid = lts.Sid;
//IntPtr pSid = GetSIDInformation(account);
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
Win32Sec.LsaFreeMemory(tsids);
Win32Sec.LsaFreeMemory(tdom);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
}
I came across the same error when calling LsaAddAccountRights and I found out I was using sizeof(char) instead of sizeof(wchar) when initializing LSA_UNICODE_STRING.
I checked the code at http://www.codeproject.com/KB/cs/lsadotnet.aspx and found similar issue:
static LSA_UNICODE_STRING InitLsaString(string s)
{
// Unicode strings max. 32KB
if (s.Length > 0x7ffe)
throw new ArgumentException("String too long");
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
lus.Buffer = s;
lus.Length = (ushort)(s.Length * sizeof(char));
lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
return lus;
}
Should be something like:
lus.Length = (ushort)(s.Length * UnicodeEncoding.CharSize);
lus.MaximumLength = (ushort)(lus.Length + UnicodeEncoding.CharSize);
I was able to get this working on one box but then on another box it failed with the error you received:
System.ComponentModel.Win32Exception: The parameter is incorrect
I discovered that the root cause of this issue for me had to do with architecture of the process that was running the code. I was running a msbuild 32-bit process which worked fine, but when I used the 64-bit msbuild.exe to run this it failed with this error.
I hope that helps!
Regards,
Brandon
I found this problem is related to .NET 4.0. Downgrade your project to .NET 3.5 and it will work.