Related
I am trying to take some old code written by my predecessor in C and migrate it to C#. I have tried using the P/invoke way but running into issues with sprint_s. Any recommendation on how to fix this or maybe write it using C#'s SerialPort class?
[StructLayout(LayoutKind.Sequential)]
internal struct Dcb
{
internal uint DCBLength;
internal uint BaudRate;
private BitVector32 Flags;
private ushort wReserved; // not currently used
internal ushort XonLim; // transmit XON threshold
internal ushort XoffLim; // transmit XOFF threshold
internal byte ByteSize;
internal Parity Parity;
internal StopBits StopBits;
internal sbyte XonChar; // Tx and Rx XON character
internal sbyte XoffChar; // Tx and Rx XOFF character
internal sbyte ErrorChar; // error replacement character
internal sbyte EofChar; // end of input character
internal sbyte EvtChar; // received event character
private ushort wReserved1; // reserved; do not use
private static readonly int fBinary;
private static readonly int fParity;
private static readonly int fOutxCtsFlow;
private static readonly int fOutxDsrFlow;
private static readonly BitVector32.Section fDtrControl;
private static readonly int fDsrSensitivity;
private static readonly int fTXContinueOnXoff;
private static readonly int fOutX;
private static readonly int fInX;
private static readonly int fErrorChar;
private static readonly int fNull;
private static readonly BitVector32.Section fRtsControl;
private static readonly int fAbortOnError;
static Dcb()
{
// Create Boolean Mask
int previousMask;
fBinary = BitVector32.CreateMask();
fParity = BitVector32.CreateMask(fBinary);
fOutxCtsFlow = BitVector32.CreateMask(fParity);
fOutxDsrFlow = BitVector32.CreateMask(fOutxCtsFlow);
previousMask = BitVector32.CreateMask(fOutxDsrFlow);
previousMask = BitVector32.CreateMask(previousMask);
fDsrSensitivity = BitVector32.CreateMask(previousMask);
fTXContinueOnXoff = BitVector32.CreateMask(fDsrSensitivity);
fOutX = BitVector32.CreateMask(fTXContinueOnXoff);
fInX = BitVector32.CreateMask(fOutX);
fErrorChar = BitVector32.CreateMask(fInX);
fNull = BitVector32.CreateMask(fErrorChar);
previousMask = BitVector32.CreateMask(fNull);
previousMask = BitVector32.CreateMask(previousMask);
fAbortOnError = BitVector32.CreateMask(previousMask);
// Create section Mask
BitVector32.Section previousSection;
previousSection = BitVector32.CreateSection(1);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
fDtrControl = BitVector32.CreateSection(2, previousSection);
previousSection = BitVector32.CreateSection(1, fDtrControl);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
fRtsControl = BitVector32.CreateSection(3, previousSection);
previousSection = BitVector32.CreateSection(1, fRtsControl);
}
public bool Binary
{
get { return Flags[fBinary]; }
set { Flags[fBinary] = value; }
}
public bool CheckParity
{
get { return Flags[fParity]; }
set { Flags[fParity] = value; }
}
public bool OutxCtsFlow
{
get { return Flags[fOutxCtsFlow]; }
set { Flags[fOutxCtsFlow] = value; }
}
public bool OutxDsrFlow
{
get { return Flags[fOutxDsrFlow]; }
set { Flags[fOutxDsrFlow] = value; }
}
public DtrControl DtrControl
{
get { return (DtrControl)Flags[fDtrControl]; }
set { Flags[fDtrControl] = (int)value; }
}
public bool DsrSensitivity
{
get { return Flags[fDsrSensitivity]; }
set { Flags[fDsrSensitivity] = value; }
}
public bool TxContinueOnXoff
{
get { return Flags[fTXContinueOnXoff]; }
set { Flags[fTXContinueOnXoff] = value; }
}
public bool OutX
{
get { return Flags[fOutX]; }
set { Flags[fOutX] = value; }
}
public bool InX
{
get { return Flags[fInX]; }
set { Flags[fInX] = value; }
}
public bool ReplaceErrorChar
{
get { return Flags[fErrorChar]; }
set { Flags[fErrorChar] = value; }
}
public bool Null
{
get { return Flags[fNull]; }
set { Flags[fNull] = value; }
}
public RtsControl RtsControl
{
get { return (RtsControl)Flags[fRtsControl]; }
set { Flags[fRtsControl] = (int)value; }
}
public bool AbortOnError
{
get { return Flags[fAbortOnError]; }
set { Flags[fAbortOnError] = value; }
}
}
public enum DtrControl : int
{
/// <summary>
/// Disables the DTR line when the device is opened and leaves it disabled.
/// </summary>
Disable = 0,
/// <summary>
/// Enables the DTR line when the device is opened and leaves it on.
/// </summary>
Enable = 1,
/// <summary>
/// Enables DTR handshaking. If handshaking is enabled, it is an error for the application to adjust the line by
/// using the EscapeCommFunction function.
/// </summary>
Handshake = 2
}
public enum RtsControl : int
{
/// <summary>
/// Disables the RTS line when the device is opened and leaves it disabled.
/// </summary>
Disable = 0,
/// <summary>
/// Enables the RTS line when the device is opened and leaves it on.
/// </summary>
Enable = 1,
/// <summary>
/// Enables RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer
/// is less than one-half full and lowers the RTS line when the buffer is more than
/// three-quarters full. If handshaking is enabled, it is an error for the application to
/// adjust the line by using the EscapeCommFunction function.
/// </summary>
Handshake = 2,
/// <summary>
/// Specifies that the RTS line will be high if bytes are available for transmission. After
/// all buffered bytes have been sent, the RTS line will be low.
/// </summary>
Toggle = 3
}
public enum Parity : byte
{
None = 0,
Odd = 1,
Even = 2,
Mark = 3,
Space = 4,
}
public enum StopBits : byte
{
One = 0,
OnePointFive = 1,
Two = 2
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadFile(IntPtr handle,
byte[] buffer, uint toRead, ref uint read, IntPtr lpOverLapped);
[DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemSet(IntPtr dest, int c, int byteCount);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetCommTimeouts(IntPtr hFile, [In] ref COMMTIMEOUTS
lpCommTimeouts);
struct COMMTIMEOUTS
{
public UInt32 ReadIntervalTimeout;
public UInt32 ReadTotalTimeoutMultiplier;
public UInt32 ReadTotalTimeoutConstant;
public UInt32 WriteTotalTimeoutMultiplier;
public UInt32 WriteTotalTimeoutConstant;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
[MarshalAs(UnmanagedType.LPTStr)] string filename,
[MarshalAs(UnmanagedType.U4)] FileAccess access,
[MarshalAs(UnmanagedType.U4)] FileShare share,
IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
IntPtr templateFile);
struct FILE
{
IntPtr _ptr;
int _cnt;
IntPtr _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
IntPtr _tmpfname;
};
[DllImport("kernel32.dll")]
static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer,
uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
IntPtr lpOverLapped);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FlushFileBuffers(IntPtr handle);
public bool InitSerialComms()
{
FILE file = new FILE();
COMMTIMEOUTS timeouts;
Dcb dcb = new Dcb();
long len;
char[] name = new char[10];
char[] settings = new char[40];
string str;
// Form the initialization file name
sprintf_s(str, 800, "%s\\SerialComms.ini", path);
// Open the initialization file
fopen_s(&file, str, "r");
// Check for errors
if (file)
{
Console.WriteLine("Error: cannot open file %s\n");
return false;
}
// Scan the serial port name
fgets(name, 10, file);
len = strlen(name);
name[len - 1] = 0;
// Scan the serial port settings
fgets(settings, 40, file);
len = settings.Length;
settings[len - 1] = 0;
// Scan the timeout settings
fgets(str, 40, file); len = strlen(str); string[len - 1] = 0;
sscanf_s(str, "%d,%d,%d,%d,%d",
&timeouts.ReadIntervalTimeout,
&timeouts.ReadTotalTimeoutConstant,
&timeouts.ReadTotalTimeoutMultiplier,
&timeouts.WriteTotalTimeoutConstant,
&timeouts.WriteTotalTimeoutMultiplier);
// Close the initialization file
fclose(file);
// Open the serial port
port = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
// Check for errors
if (port == INVALID_HANDLE_VALUE)
{
// Report the error and return
fprintf(stderr, "Error: cannot open serial port %s\n", name);
fflush(stderr);
return false;
}
// Build the serial port device control block
MemSet(dcb., 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!BuildCommDCB(settings, &dcb))
{
// Report the error and return
fprintf(stderr, "Error: cannot create device control block for %s\n", name);
CloseHandle(port);
fflush(stderr);
return false;
}
// Configure the serial port
if (!SetCommState(port, &dcb))
{
// Report the error and return
fprintf(stderr, "Error: cannot configure serial port %s\n", name);
CloseHandle(port);
fflush(stderr);
return false;
}
// Set the timeouts for the serial port
if (!SetCommTimeouts(port, &timeouts))
{
// Report the error and return
fprintf(stderr, "Error: cannot set timeouts for %s\n", name);
CloseHandle(port);
fflush(stderr);
return false;
}
// Success
return true;
}
bool ReceiveReply(IntPtr port, ref byte[] reply, ref byte num)
{
uint num_read = 0;
uint num_to_read = 255;
ushort crc = 0XFFFF;
byte i, j;
// Clear the reply buffer
//reply = new byte[255];
num = 0;
// Read the data
if (!ReadFile(port, reply, num_to_read, ref num_read, IntPtr.Zero)) return false;
// Check number of bytes that were read
if (num_read < 2) return false;
// Check number of bytes that were read
if (num_read > 255) return false;
// Form the CRC
for (i = 0; i < num_read - 2; i++)
{
crc ^= reply[i];
for (j = 0; j < 8; j++)
{
ushort flag = (ushort) (crc & 0X0001);
crc >>= 1;
//TODO: risky flag check
if (flag == 0) crc ^= 0XA001;
}
}
// Check the CRC
if (reply[i++] != (crc & 0X00FF)) return false;
if (reply[i++] != (crc & 0XFF00) >> 8) return false;
num = (byte)(num_read - 2);
// Success
return true;
}
public static bool SendRequest(IntPtr port, ref byte[] request, ref byte num)
{
ushort crc = 0XFFFF;
byte i, j;
// Check number of bytes
if (num > 253) return false;
// Set number of bytes to write
uint num_to_write = num;
// Form the CRC
for (i = 0; i < num_to_write; i++)
{
crc ^= request[i];
for (j = 0; j < 8; j++)
{
ushort flag = (ushort) (crc & 0X0001);
crc >>= 1; if (flag == 0) crc = (ushort) (crc ^ 0XA001);
}
}
// Set the CRC bytes in the request
request[num_to_write++] = (byte) (crc & 0X00FF);
request[num_to_write++] = (byte) ((crc & 0XFF00) >> 8);
// Send the request
if (!WriteFile(port, request, num_to_write, out uint _, IntPtr.Zero)) return false;
string text = request.ToString().Substring(0, (int) num_to_write).Replace("\r\n", " ");
// Flush the serial line
if (!FlushFileBuffers(port)) return false;
// Success
return true;
}
You don't need sprintf-family functions in higher level languages like C# since they normally allow string concatenation and assignment with the simple = and += operators.
Just write idiomatic C# code for it:
str = path + "\\SerialComms.ini";
Commenter #itsme86 points out that for the task of building a path, you should instead use Path.Combine:
Path.Combine(path, "SerialComms.ini");
c# proxy authentication using wininet;
I should ensure that the proxy works only within the winforms appplication( webbrowser control), not systemwide.
This is the proxy class I use;
public static class WinInetInterop
{
public static string applicationName;
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr InternetOpen(
string lpszAgent, int dwAccessType, string lpszProxyName,
string lpszProxyBypass, int dwFlags);
[DllImport("wininet.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InternetCloseHandle(IntPtr hInternet);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct INTERNET_PER_CONN_OPTION_LIST
{
public int Size;
// The connection to be set. NULL means LAN.
public System.IntPtr Connection;
public int OptionCount;
public int OptionError;
// List of INTERNET_PER_CONN_OPTIONs.
public System.IntPtr pOptions;
}
private enum INTERNET_OPTION
{
// Sets or retrieves an INTERNET_PER_CONN_OPTION_LIST structure that specifies
// a list of options for a particular connection.
INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
// Notify the system that the registry settings have been changed so that
// it verifies the settings on the next call to InternetConnect.
INTERNET_OPTION_SETTINGS_CHANGED = 39,
// Causes the proxy data to be reread from the registry for a handle.
INTERNET_OPTION_REFRESH = 37
}
private enum INTERNET_PER_CONN_OptionEnum
{
INTERNET_PER_CONN_FLAGS = 1,
INTERNET_PER_CONN_PROXY_SERVER = 2,
INTERNET_PER_CONN_PROXY_BYPASS = 3,
INTERNET_PER_CONN_AUTOCONFIG_URL = 4,
INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5,
INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL = 6,
INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = 7,
INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME = 8,
INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL = 9,
INTERNET_PER_CONN_FLAGS_UI = 10
}
private const int INTERNET_OPEN_TYPE_DIRECT = 1; // direct to net
private const int INTERNET_OPEN_TYPE_PRECONFIG = 0; // read registry
/// <summary>
/// Constants used in INTERNET_PER_CONN_OPTON struct.
/// </summary>
private enum INTERNET_OPTION_PER_CONN_FLAGS
{
PROXY_TYPE_DIRECT = 0x00000001, // direct to net
PROXY_TYPE_PROXY = 0x00000002, // via named proxy
PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
}
/// <summary>
/// Used in INTERNET_PER_CONN_OPTION.
/// When create a instance of OptionUnion, only one filed will be used.
/// The StructLayout and FieldOffset attributes could help to decrease the struct size.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct INTERNET_PER_CONN_OPTION_OptionUnion
{
// A value in INTERNET_OPTION_PER_CONN_FLAGS.
[FieldOffset(0)]
public int dwValue;
[FieldOffset(0)]
public System.IntPtr pszValue;
[FieldOffset(0)]
public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
}
[StructLayout(LayoutKind.Sequential)]
private struct INTERNET_PER_CONN_OPTION
{
// A value in INTERNET_PER_CONN_OptionEnum.
public int dwOption;
public INTERNET_PER_CONN_OPTION_OptionUnion Value;
}
/// <summary>
/// Sets an Internet option.
/// </summary>
[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool InternetSetOption(
IntPtr hInternet,
INTERNET_OPTION dwOption,
IntPtr lpBuffer,
int lpdwBufferLength);
/// <summary>
/// Queries an Internet option on the specified handle. The Handle will be always 0.
/// </summary>
[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true,
EntryPoint = "InternetQueryOption")]
private extern static bool InternetQueryOptionList(
IntPtr Handle,
INTERNET_OPTION OptionFlag,
ref INTERNET_PER_CONN_OPTION_LIST OptionList,
ref int size);
/// <summary>
/// Set the proxy server for LAN connection.
/// </summary>
public static bool SetConnectionProxy(string proxyServer)
{
IntPtr hInternet = InternetOpen(applicationName, INTERNET_OPEN_TYPE_DIRECT, null, null, 0);
//// Create 3 options.
//INTERNET_PER_CONN_OPTION[] Options = new INTERNET_PER_CONN_OPTION[3];
// Create 2 options.
INTERNET_PER_CONN_OPTION[] Options = new INTERNET_PER_CONN_OPTION[2];
// Set PROXY flags.
Options[0] = new INTERNET_PER_CONN_OPTION();
Options[0].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS;
Options[0].Value.dwValue = (int)INTERNET_OPTION_PER_CONN_FLAGS.PROXY_TYPE_PROXY;
// Set proxy name.
Options[1] = new INTERNET_PER_CONN_OPTION();
Options[1].dwOption =
(int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER;
Options[1].Value.pszValue = Marshal.StringToHGlobalAnsi(proxyServer);
//// Set proxy bypass.
//Options[2] = new INTERNET_PER_CONN_OPTION();
//Options[2].dwOption =
// (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS;
//Options[2].Value.pszValue = Marshal.StringToHGlobalAnsi(“local”);
//// Allocate a block of memory of the options.
//System.IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(Options[0])
// + Marshal.SizeOf(Options[1]) + Marshal.SizeOf(Options[2]));
// Allocate a block of memory of the options.
System.IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(Options[0])
+ Marshal.SizeOf(Options[1]));
System.IntPtr current = buffer;
// Marshal data from a managed object to an unmanaged block of memory.
for (int i = 0; i < Options.Length; i++)
{
Marshal.StructureToPtr(Options[i], current, false);
// current = (System.IntPtr)((int)current + Marshal.SizeOf(Options[i]));
current = (System.IntPtr)((Environment.Is64BitProcess ? current.ToInt64() : current.ToInt32()) + Marshal.SizeOf(Options[i]));
}
// Initialize a INTERNET_PER_CONN_OPTION_LIST instance.
INTERNET_PER_CONN_OPTION_LIST option_list = new INTERNET_PER_CONN_OPTION_LIST();
// Point to the allocated memory.
option_list.pOptions = buffer;
// Return the unmanaged size of an object in bytes.
option_list.Size = Marshal.SizeOf(option_list);
// IntPtr.Zero means LAN connection.
option_list.Connection = IntPtr.Zero;
option_list.OptionCount = Options.Length;
option_list.OptionError = 0;
int size = Marshal.SizeOf(option_list);
// Allocate memory for the INTERNET_PER_CONN_OPTION_LIST instance.
IntPtr intptrStruct = Marshal.AllocCoTaskMem(size);
// Marshal data from a managed object to an unmanaged block of memory.
Marshal.StructureToPtr(option_list, intptrStruct, true);
// Set internet settings.
bool bReturn = InternetSetOption(hInternet,
INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION, intptrStruct, size);
// Free the allocated memory.
Marshal.FreeCoTaskMem(buffer);
Marshal.FreeCoTaskMem(intptrStruct);
InternetCloseHandle(hInternet);
// Throw an exception if this operation failed.
if (!bReturn)
{
throw new ApplicationException("Set Internet Option Failed!");
}
return bReturn;
}
/// <summary>
/// Backup the current options for LAN connection.
/// Make sure free the memory after restoration.
/// </summary>
private static INTERNET_PER_CONN_OPTION_LIST GetSystemProxy()
{
// Query following options.
INTERNET_PER_CONN_OPTION[] Options = new INTERNET_PER_CONN_OPTION[3];
Options[0] = new INTERNET_PER_CONN_OPTION();
Options[0].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS;
Options[1] = new INTERNET_PER_CONN_OPTION();
Options[1].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER;
Options[2] = new INTERNET_PER_CONN_OPTION();
Options[2].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS;
// Allocate a block of memory of the options.
System.IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(Options[0])
+ Marshal.SizeOf(Options[1]) + Marshal.SizeOf(Options[2]));
System.IntPtr current = (System.IntPtr)buffer;
// Marshal data from a managed object to an unmanaged block of memory.
for (int i = 0; i < Options.Length; i++)
{
Marshal.StructureToPtr(Options[i], current, false);
current = (System.IntPtr)((int)current + Marshal.SizeOf(Options[i]));
}
// Initialize a INTERNET_PER_CONN_OPTION_LIST instance.
INTERNET_PER_CONN_OPTION_LIST Request = new INTERNET_PER_CONN_OPTION_LIST();
// Point to the allocated memory.
Request.pOptions = buffer;
Request.Size = Marshal.SizeOf(Request);
// IntPtr.Zero means LAN connection.
Request.Connection = IntPtr.Zero;
Request.OptionCount = Options.Length;
Request.OptionError = 0;
int size = Marshal.SizeOf(Request);
// Query internet options.
bool result = InternetQueryOptionList(IntPtr.Zero,
INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
ref Request, ref size);
if (!result)
{
throw new ApplicationException("Set Internet Option Failed!");
}
return Request;
}
/// <summary>
/// Restore the options for LAN connection.
/// </summary>
/// <param name=”request”></param>
/// <returns></returns>
public static bool RestoreSystemProxy()
{
IntPtr hInternet = InternetOpen(applicationName, INTERNET_OPEN_TYPE_DIRECT, null, null, 0);
INTERNET_PER_CONN_OPTION_LIST request = GetSystemProxy();
int size = Marshal.SizeOf(request);
// Allocate memory.
IntPtr intptrStruct = Marshal.AllocCoTaskMem(size);
// Convert structure to IntPtr
Marshal.StructureToPtr(request, intptrStruct, true);
// Set internet options.
bool bReturn = InternetSetOption(hInternet,
INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
intptrStruct, size);
// Free the allocated memory.
Marshal.FreeCoTaskMem(request.pOptions);
Marshal.FreeCoTaskMem(intptrStruct);
if (!bReturn)
{
throw new ApplicationException("Set Internet Option Failed!");
}
// Notify the system that the registry settings have been changed and cause
// the proxy data to be reread from the registry for a handle.
InternetSetOption(hInternet, INTERNET_OPTION.INTERNET_OPTION_SETTINGS_CHANGED,
IntPtr.Zero, 0);
InternetSetOption(hInternet, INTERNET_OPTION.INTERNET_OPTION_REFRESH,
IntPtr.Zero, 0);
InternetCloseHandle(hInternet);
return bReturn;
}
}
And I use the class this way and it works fine;
WinInetInterop.RestoreSystemProxy();
WinInetInterop.SetConnectionProxy(123.456.789.99:80);
Since good proxy services always require authentication, I had to use proxy authetication like this;
123.456.789.99:80:username:password
and WinInetInterop.SetConnectionProxy(123.456.789.99:80:username:password) doesn't work.
I googled web but couldn't find solution other than this;
"You could always use straight WinINet functions to do proxy auth once you get the 407 response from the proxy. Here is an article on that (no I do not have a .NET sample but you could write one I am sure): http://msdn.microsoft.com/en-us/library/windows/desktop/aa384220(v=vs.85).aspx"
Since I am a newbie and thus couldn't write codes for this.
I tried for a few days but could not solve it. Please help me.
For proxy authentication, the WebBroser ActiveX control calls the host ole client site's IServiceProvider.QueryService method to look up its SID_IAuthenticate service.
For WinForms, the client site is the WebBrowser.WebBrowserSite class. You can derive from it to add your own IServiceProvider and IAuthenticate implementation then Override the WebBrowser.CreateWebBrowserSiteBase method to use your extended ole client site instead of the default one.
Info:
.Net 4.5
Tested on:
Win7 64 bit
Win10 64 bit (Virtual Box)
I am trying to get a list of handles of an external process and return their names as string so I can close a specific one afterwards. Therefore i wrote this function using the Win32API which will check if the handle is the handle i want to close: `
const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
const uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004;
public static string getObjectTypeName(Win32API.SYSTEM_HANDLE_INFORMATION shHandle, Process process)
{
IntPtr m_ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id);
IntPtr ipHandle = IntPtr.Zero;
var objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
IntPtr ipBasic = IntPtr.Zero;
var objObjectType = new Win32API.OBJECT_TYPE_INFORMATION();
IntPtr ipObjectType = IntPtr.Zero;
IntPtr ipObjectName = IntPtr.Zero;
string strObjectTypeName = "";
int nLength = 0;
int nReturn = 0;
IntPtr ipTemp = IntPtr.Zero;
if (!Win32API.DuplicateHandle(m_ipProcessHwnd, shHandle.Handle,
Win32API.GetCurrentProcess(), out ipHandle,
0, false, Win32API.DUPLICATE_SAME_ACCESS))
return null;
ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectBasicInformation,
ipBasic, Marshal.SizeOf(objBasic), ref nLength);
objBasic = (Win32API.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
Marshal.FreeHGlobal(ipBasic);
ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
nLength = objBasic.TypeInformationLength;
while ((uint)(nReturn = Win32API.NtQueryObject(
ipHandle, (int)Win32API.ObjectInformationClass.ObjectTypeInformation, ipObjectType,
nLength, ref nLength)) ==
Win32API.STATUS_INFO_LENGTH_MISMATCH)
{
Marshal.FreeHGlobal(ipObjectType);
ipObjectType = Marshal.AllocHGlobal(nLength);
}
objObjectType = (Win32API.OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType());
if (Is64Bits())
{
ipTemp = new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32);
}
else
{
ipTemp = objObjectType.Name.Buffer;
}
strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
Marshal.FreeHGlobal(ipObjectType);
Win32API.CloseHandle(ipHandle);
return strObjectTypeName;
}`
The problem however is that this code works in Win7 64bit, not in Win10! --> In Win 10 strObjectTypeName = Marshal.PtrToStringUni(); throws a AcessViolationException (Last few lines in the code)
System.AccessViolationException Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Am I missing something here about how unmanaged memory has to be accessed in win10?
I have just come across the same issue. I haven't tried Win7, but when you run the code on Win10(x64) as 32bit (e.g. set the "Prefer 32-bit flag" of your application) it should work.
When the exception happens, drag&drop the variable "ipTemp" to the "memory window" of Visual Studio, if it displays only question marks or an error message you don't have a valid pointer.
As far as I figured out, there are (more) padding bytes in the 64bit versions of the structs that are used by this API:
OBJECT_TYPE_INFORMATION contains a UNICODE_STRING and UNICODE_STRING has 4 padding bytes before the Buffer-field in 64bit Mode.
My workaraound was this:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UNICODE_STRING
{
private IntPtr _dummy; // the two ushorts seem to be padded with 4 bytes in 64bit mode only
/// <summary>
/// The length, in bytes, of the string stored in Buffer. If the string is null-terminated, Length does not include the trailing null character.
/// </summary>
public ushort Length
{
get { return (ushort)Marshal.ReadInt16(this, 0); }
}
/// <summary>
/// The length, in bytes, of Buffer.
/// </summary>
public ushort MaximumLength
{
get { return (ushort)Marshal.ReadInt16(this, 2); }
}
public IntPtr Buffer;
}
During my research I found so many questions regarding this topic and basically two kinds of sample code
that have been copied all over the Internet that I am considering to create an open-source library named WinKernelObjectsDotNet.
Update: The library is now available here. It supports finding the process that is locking a file or a serial-port (COM) with a single line of code.
I suggest to change UNICODE_STRING structure in a such way.
public struct UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)] public string Buffer;
}
So getObjectTypeName method will be something like this and will work for both 32/64:
public static string getObjectTypeName(SYSTEM_HANDLE_INFORMATION shHandle, Process process) {
IntPtr ipProcessHwnd = OpenProcess(ProcessAccessFlags.All, false, process.Id);
if (!DuplicateHandle(ipProcessHwnd, shHandle.Handle, GetCurrentProcess(), out IntPtr ipHandle, 0, false, DUPLICATE_SAME_ACCESS)) {
return null;
}
OBJECT_BASIC_INFORMATION objBasicInformation = new OBJECT_BASIC_INFORMATION();
IntPtr ipBasicInformation = Marshal.AllocHGlobal(Marshal.SizeOf(objBasicInformation));
int iBasicInformationLength = 0;
NtQueryObject(ipHandle, (int) ObjectInformationClass.ObjectBasicInformation, ipBasicInformation, Marshal.SizeOf(objBasicInformation), ref iBasicInformationLength);
objBasicInformation = (OBJECT_BASIC_INFORMATION) Marshal.PtrToStructure(ipBasicInformation, typeof(OBJECT_BASIC_INFORMATION));
Marshal.FreeHGlobal(ipBasicInformation);
int iObjectTypeInformationLength = objBasicInformation.TypeInformationLength;
IntPtr ipObjectTypeInformation = Marshal.AllocHGlobal(iObjectTypeInformationLength);
while (Win32API.STATUS_INFO_LENGTH_MISMATCH == (uint) (NtQueryObject(ipHandle, (int) ObjectInformationClass.ObjectTypeInformation, ipObjectTypeInformation, iObjectTypeInformationLength, ref iObjectTypeInformationLength))) {
Marshal.FreeHGlobal(ipObjectTypeInformation);
ipObjectTypeInformation = Marshal.AllocHGlobal(iObjectTypeInformationLength);
}
CloseHandle(ipHandle);
OBJECT_TYPE_INFORMATION objObjectType = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectTypeInformation, typeof(OBJECT_TYPE_INFORMATION));
Marshal.FreeHGlobal(ipObjectTypeInformation);
return objObjectType.Name.Buffer;
}
I need to access Windows MFT(Master File Table) using C# in my .net application.
I have googled about this and couldn't find any good results. I have been searching for the information from the past 2 days but have been unable to find any information on the same.
I am not looking for exact code to do the same, I am just looking for some information which can get me started.
The only thing I have been able to figure out is that I have to use P/Invoke.
I want to know the functions I would be using to have access to MFT.
If you are able to provide some code sample then that would be great.
First, you have to have and assert sufficient privileges to access the MFT - this is a pain all by itself. Then, you have to get a handle to a file/folder on the volume - for the calls in the last step...which is to call a Windows API (called DeviceIOControl) in a loop and read the entries from the returned API call - and this is it's own special headache.
Conceptually - this looks like:
static void Main( string[ ] args )
{
if ( Privileges.HasBackupAndRestorePrivileges )
{
using ( var volume = GetVolumeHandle( "C:\\" ) )
{
ReadMft( volume );
}
}
}
If you take each of these in turn, asserting sufficient privileges is the most obscure part. There's a Windows API to change the privileges of the running token - and you use that to add the necessary privileges. Here's an excerpt from a class that I use to assert those privileges. You could assert a bunch more privileges - but this should be sufficient for reading the MFT.
Your application will need to run under an account that can actually obtain the requisite privileges - an admin account is good. Also, a backup operator will work.
public static class Privileges
{
private static int asserted = 0;
private static bool hasBackupPrivileges = false;
public static bool HasBackupAndRestorePrivileges
{
get { return AssertPriveleges( ); }
}
/// <remarks>
/// First time this method is called, it attempts to set backup privileges for the current process.
/// Subsequently, it returns the results of that first call.
/// </remarks>
private static bool AssertPriveleges( )
{
bool success = false;
var wasAsserted = Interlocked.CompareExchange( ref asserted, 1, 0 );
if ( wasAsserted == 0 ) // first time here? come on in!
{
success =
AssertPrivelege( NativeMethods.SE_BACKUP_NAME ) &&
AssertPrivelege( NativeMethods.SE_RESTORE_NAME );
hasBackupPrivileges = success;
}
return hasBackupPrivileges;
}
private static bool AssertPrivelege( string privelege )
{
IntPtr token;
var tokenPrivileges = new NativeMethods.TOKEN_PRIVILEGES( );
tokenPrivileges.Privileges = new NativeMethods.LUID_AND_ATTRIBUTES[ 1 ];
var success =
NativeMethods.OpenProcessToken( NativeMethods.GetCurrentProcess( ), NativeMethods.TOKEN_ADJUST_PRIVILEGES, out token )
&&
NativeMethods.LookupPrivilegeValue( null, privelege, out tokenPrivileges.Privileges[ 0 ].Luid );
try
{
if ( success )
{
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[ 0 ].Attributes = NativeMethods.SE_PRIVILEGE_ENABLED;
success =
NativeMethods.AdjustTokenPrivileges( token, false, ref tokenPrivileges, Marshal.SizeOf( tokenPrivileges ), IntPtr.Zero, IntPtr.Zero )
&&
( Marshal.GetLastWin32Error( ) == 0 );
}
if ( !success )
{
Console.WriteLine( "Could not assert privilege: " + privelege );
}
}
finally
{
NativeMethods.CloseHandle( token );
}
return success;
}
}
Once you're past that hurdle, the rest is - well...still a festival of obscurity. You have to get a handle to a file or folder - with backup semantics. You can more-than-likely just open a FileStream on any old file on the volume you're after and the FileStream will have a handle you can use for subsequent calls. This isn't precisely what my application did - but my app had to do things this answer doesn't have to do.
internal static SafeFileHandle GetVolumeHandle( string pathToVolume, NativeMethods.EFileAccess access = NativeMethods.EFileAccess.AccessSystemSecurity | NativeMethods.EFileAccess.GenericRead | NativeMethods.EFileAccess.ReadControl )
{
var attributes = ( uint ) NativeMethods.EFileAttributes.BackupSemantics;
var handle = NativeMethods.CreateFile( pathToVolume, access, 7U, IntPtr.Zero, ( uint ) NativeMethods.ECreationDisposition.OpenExisting, attributes, IntPtr.Zero );
if ( handle.IsInvalid )
{
throw new IOException( "Bad path" );
}
return handle;
}
For ReadMft - There is a rather complex windows API function - DeviceIOControl - that takes buffers with an epic variety of inputs and returns buffers containing a mind-bending variety of outputs. It's a kind of catch-all API for querying information about various devices - and the volume containing the MFT is a device.
To read the MFT, you call DeviceIOControl with a device IO control code of FSCTL_ENUM_USN_DATA - which returns one USN record for each record in the MFT. There are lots of records per each invocation - and after each invocation, you parameterize the next call in the loop with the first bit of info returned by the previous call.
BTW - I renamed the windows API calls in my code to make them look more .Net-like. I'm not sure I'd do that in the future.
Special note here: You're getting one record for each file - regardless of how many hard links there are - you have to do additional calls to enumerate the hard links.
The file system hierarchy is encoded in the FileReferenceNumber and ParentFileReferenceNumber of the structures you get back from the call. You'd nominally save off these usn records to a list, sorted by FileReferenceNumber and make a secondary index for the ParentFileReferenceNumber - or something like that. For the purpose of illustration, this code just dumps the MFT entries.
This example uses unsafe code - and fixes the location of the buffers containing the input and output. There are different ways to approach this - but this is nice and zippy. If you use this, you have to allow unsafe code in your project settings.
public unsafe static bool ReadMft( SafeHandle volume )
{
var outputBufferSize = 1024 * 1024;
var input = new NativeMethods.MFTEnumDataV0( );
var usnRecord = new NativeMethods.UsnRecordV2( );
var outputBuffer = new byte[ outputBufferSize ];
var okay = true;
var doneReading = false;
try
{
fixed ( byte* pOutput = outputBuffer )
{
input.StartFileReferenceNumber = 0;
input.LowUsn = 0;
input.HighUsn = long.MaxValue;
using ( var stream = new MemoryStream( outputBuffer, true ) )
{
while ( !doneReading )
{
var bytesRead = 0U;
okay = NativeMethods.DeviceIoControl
(
volume.DangerousGetHandle( ),
NativeMethods.DeviceIOControlCode.FsctlEnumUsnData,
( byte* ) &input.StartFileReferenceNumber,
( uint ) Marshal.SizeOf( input ),
pOutput,
( uint ) outputBufferSize,
out bytesRead,
IntPtr.Zero
);
if ( !okay )
{
var error = Marshal.GetLastWin32Error( );
okay = error == NativeMethods.ERROR_HANDLE_EOF;
if ( !okay )
{
Console.WriteLine( "Crap! Windows error " + error.ToString( ) );
break;
}
else
{
doneReading = true;
}
}
input.StartFileReferenceNumber = stream.ReadULong( );
while ( stream.Position < bytesRead )
{
usnRecord.Read( stream );
//-->>>>>>>>>>>>>>>>>
//--> just an example of reading out the record...
Console.WriteLine( "FRN:" + usnRecord.FileReferenceNumber.ToString( ) );
Console.WriteLine( "Parent FRN:" + usnRecord.ParentFileReferenceNumber.ToString( ) );
Console.WriteLine( "File name:" + usnRecord.FileName );
Console.WriteLine( "Attributes: " + ( NativeMethods.EFileAttributes ) usnRecord.FileAttributes );
Console.WriteLine( "Timestamp:" + usnRecord.TimeStamp );
//-->>>>>>>>>>>>>>>>>>>
}
stream.Seek( 0, SeekOrigin.Begin );
}
}
}
}
catch ( Exception ex )
{
Console.Write( ex );
okay = false;
}
return okay;
}
I do something probably kind of cheesy to save myself a lot of work - I add pseudo-serialization methods to windows API structures - so that they can read themselves out of streams. For example, the usnRecord used to read the buffer in the foregoing code is a windows API structure - but with a serialization interface implemented:
[StructLayout( LayoutKind.Sequential )]
internal struct UsnRecordV2: IBinarySerialize
{
public uint RecordLength;
public ushort MajorVersion;
public ushort MinorVersion;
public ulong FileReferenceNumber;
public ulong ParentFileReferenceNumber;
public long Usn;
public long TimeStamp;
public UsnReason Reason;
public uint SourceInfo;
public uint SecurityId;
public uint FileAttributes;
public ushort FileNameLength;
public ushort FileNameOffset;
public string FileName;
/// <remarks>
/// Note how the read advances to the FileNameOffset and reads only FileNameLength bytes.
/// </remarks>
public void Read( Stream stream )
{
var startOfRecord = stream.Position;
RecordLength = stream.ReadUInt( );
MajorVersion = stream.ReadUShort( );
MinorVersion = stream.ReadUShort( );
FileReferenceNumber = stream.ReadULong( );
ParentFileReferenceNumber = stream.ReadULong( );
Usn = stream.ReadLong( );
TimeStamp = stream.ReadLong( );
Reason = ( UsnReason ) stream.ReadUInt( );
SourceInfo = stream.ReadUInt( );
SecurityId = stream.ReadUInt( );
FileAttributes = stream.ReadUInt( );
FileNameLength = stream.ReadUShort( );
FileNameOffset = stream.ReadUShort( );
stream.Position = startOfRecord + FileNameOffset;
FileName = Encoding.Unicode.GetString( stream.ReadBytes( FileNameLength ) );
stream.Position = startOfRecord + RecordLength;
}
/// <summary>We never write instances of this structure</summary>
void IBinarySerialize.Write( Stream stream )
{
throw new NotImplementedException( );
}
}
...where IBinarySerialze is:
public interface IBinarySerialize
{
/// <summary>Reads an object's data from a <see cref="Stream"/></summary>
void Read( Stream stream );
/// <summary>Writes an objects serializable content to a <see cref="Stream"/></summary>
void Write( Stream stream );
}
There are stream extension methods used in this structure. Basically, they're lifted from BinaryReader. Why? Because in .Net 3.5 - where I had to write this originally - the BCL BinaryReader would close the stream you wrapped it around - and I had lots of places where that was just intolerable.
internal static class StreamingExtensions
{
public static ushort ReadUShort( this Stream stream )
{
return BitConverter.ToUInt16( ReadBytes( stream, 2 ), 0 );
}
public static uint ReadUInt( this Stream stream )
{
return BitConverter.ToUInt32( ReadBytes( stream, 4 ), 0 );
}
public static long ReadLong( this Stream stream )
{
return BitConverter.ToInt64( ReadBytes( stream, 8 ), 0 );
}
public static ulong ReadULong( this Stream stream )
{
return BitConverter.ToUInt64( ReadBytes( stream, 8 ), 0 );
}
public static byte[ ] ReadBytes( this Stream stream, int length, bool throwIfIncomplete = false )
{
var bytes = new byte[ length ];
var bytesRead = 0;
var offset = 0;
if ( length > 0 )
{
while ( offset < length )
{
bytesRead = stream.Read( bytes, offset, length - offset );
if ( bytesRead == 0 )
{
if ( throwIfIncomplete ) throw new InvalidOperationException( "incomplete" );
break;
}
offset += bytesRead;
}
}
return bytes;
}
}
And for completeness, here are the native methods, enums, constants, and noise. Most are from from PInvoke.net, but again...the names of many of these things were .Net-ified. Apologies to the purists.
internal class NativeMethods
{
internal const int ERROR_HANDLE_EOF = 38;
//--> Privilege constants....
internal const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
internal const string SE_BACKUP_NAME = "SeBackupPrivilege";
internal const string SE_RESTORE_NAME = "SeRestorePrivilege";
internal const string SE_SECURITY_NAME = "SeSecurityPrivilege";
internal const string SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege";
internal const string SE_CREATE_SYMBOLIC_LINK_NAME = "SeCreateSymbolicLinkPrivilege";
internal const string SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege";
internal const string SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege";
internal const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege";
internal const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege";
internal const string SE_TCB_NAME = "SeTcbPrivilege";
internal const string SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege";
internal const string SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege";
//--> For starting a process in session 1 from session 0...
internal const int TOKEN_DUPLICATE = 0x0002;
internal const uint MAXIMUM_ALLOWED = 0x2000000;
internal const int CREATE_NEW_CONSOLE = 0x00000010;
internal const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
internal const int TOKEN_QUERY = 0x00000008;
[DllImport( "advapi32.dll", SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool OpenProcessToken( IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle );
[DllImport( "kernel32.dll" )]
internal static extern IntPtr GetCurrentProcess( );
[DllImport( "advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool LookupPrivilegeValue( string lpSystemName, string lpName, out LUID lpLuid );
[DllImport( "advapi32.dll", SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool AdjustTokenPrivileges( IntPtr TokenHandle, [MarshalAs( UnmanagedType.Bool )]bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, Int32 BufferLength, IntPtr PreviousState, IntPtr ReturnLength );
[DllImport( "kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static unsafe extern bool DeviceIoControl( IntPtr hDevice, DeviceIOControlCode controlCode, byte* lpInBuffer, uint nInBufferSize, byte* lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped );
[DllImport( "kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode )]
internal static extern SafeFileHandle CreateFile( string lpFileName, EFileAccess dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile );
[DllImport( "kernel32.dll", SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
internal static extern bool CloseHandle( IntPtr hObject );
[Flags]
internal enum EMethod: uint
{
Buffered = 0,
InDirect = 1,
OutDirect = 2,
Neither = 3
}
[Flags]
internal enum EFileAccess: uint
{
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
Delete = 0x10000,
ReadControl = 0x20000,
WriteDAC = 0x40000,
WriteOwner = 0x80000,
Synchronize = 0x100000,
StandardRightsRequired = 0xF0000,
StandardRightsRead = ReadControl,
StandardRightsWrite = ReadControl,
StandardRightsExecute = ReadControl,
StandardRightsAll = 0x1F0000,
SpecificRightsAll = 0xFFFF,
AccessSystemSecurity = 0x1000000,
MaximumAllowed = 0x2000000
}
[Flags]
internal enum EFileDevice: uint
{
Beep = 0x00000001,
CDRom = 0x00000002,
CDRomFileSytem = 0x00000003,
Controller = 0x00000004,
Datalink = 0x00000005,
Dfs = 0x00000006,
Disk = 0x00000007,
DiskFileSystem = 0x00000008,
FileSystem = 0x00000009,
InPortPort = 0x0000000a,
Keyboard = 0x0000000b,
Mailslot = 0x0000000c,
MidiIn = 0x0000000d,
MidiOut = 0x0000000e,
Mouse = 0x0000000f,
MultiUncProvider = 0x00000010,
NamedPipe = 0x00000011,
Network = 0x00000012,
NetworkBrowser = 0x00000013,
NetworkFileSystem = 0x00000014,
Null = 0x00000015,
ParallelPort = 0x00000016,
PhysicalNetcard = 0x00000017,
Printer = 0x00000018,
Scanner = 0x00000019,
SerialMousePort = 0x0000001a,
SerialPort = 0x0000001b,
Screen = 0x0000001c,
Sound = 0x0000001d,
Streams = 0x0000001e,
Tape = 0x0000001f,
TapeFileSystem = 0x00000020,
Transport = 0x00000021,
Unknown = 0x00000022,
Video = 0x00000023,
VirtualDisk = 0x00000024,
WaveIn = 0x00000025,
WaveOut = 0x00000026,
Port8042 = 0x00000027,
NetworkRedirector = 0x00000028,
Battery = 0x00000029,
BusExtender = 0x0000002a,
Modem = 0x0000002b,
Vdm = 0x0000002c,
MassStorage = 0x0000002d,
Smb = 0x0000002e,
Ks = 0x0000002f,
Changer = 0x00000030,
Smartcard = 0x00000031,
Acpi = 0x00000032,
Dvd = 0x00000033,
FullscreenVideo = 0x00000034,
DfsFileSystem = 0x00000035,
DfsVolume = 0x00000036,
Serenum = 0x00000037,
Termsrv = 0x00000038,
Ksec = 0x00000039,
// From Windows Driver Kit 7
Fips = 0x0000003A,
Infiniband = 0x0000003B,
Vmbus = 0x0000003E,
CryptProvider = 0x0000003F,
Wpd = 0x00000040,
Bluetooth = 0x00000041,
MtComposite = 0x00000042,
MtTransport = 0x00000043,
Biometric = 0x00000044,
Pmi = 0x00000045
}
internal enum EFileIOCtlAccess: uint
{
Any = 0,
Special = Any,
Read = 1,
Write = 2
}
internal enum DeviceIOControlCode: uint
{
FsctlEnumUsnData = ( EFileDevice.FileSystem << 16 ) | ( 44 << 2 ) | EMethod.Neither | ( EFileIOCtlAccess.Any << 14 ),
FsctlReadUsnJournal = ( EFileDevice.FileSystem << 16 ) | ( 46 << 2 ) | EMethod.Neither | ( EFileIOCtlAccess.Any << 14 ),
FsctlReadFileUsnData = ( EFileDevice.FileSystem << 16 ) | ( 58 << 2 ) | EMethod.Neither | ( EFileIOCtlAccess.Any << 14 ),
FsctlQueryUsnJournal = ( EFileDevice.FileSystem << 16 ) | ( 61 << 2 ) | EMethod.Buffered | ( EFileIOCtlAccess.Any << 14 ),
FsctlCreateUsnJournal = ( EFileDevice.FileSystem << 16 ) | ( 57 << 2 ) | EMethod.Neither | ( EFileIOCtlAccess.Any << 14 )
}
/// <summary>Control structure used to interrogate MFT data using DeviceIOControl from the user volume</summary>
[StructLayout( LayoutKind.Sequential )]
internal struct MFTEnumDataV0
{
public ulong StartFileReferenceNumber;
public long LowUsn;
public long HighUsn;
}
/// <summary>A structure resurned form USN queries</summary>
/// <remarks>
/// FileName is synthetic...composed during a read of the structure and is not technically
/// part of the Win32 API's definition...although the actual FileName is contained
/// "somewhere" in the structure's trailing bytes, according to FileNameLength and FileNameOffset.
///
/// Alignment boundaries are enforced, and so, the RecordLength
/// may be somewhat larger than the accumulated lengths of the members plus the FileNameLength.
/// </remarks>
[StructLayout( LayoutKind.Sequential )]
internal struct UsnRecordV2: IBinarySerialize
{
public uint RecordLength;
public ushort MajorVersion;
public ushort MinorVersion;
public ulong FileReferenceNumber;
public ulong ParentFileReferenceNumber;
public long Usn;
public long TimeStamp;
public UsnReason Reason;
public uint SourceInfo;
public uint SecurityId;
public uint FileAttributes;
public ushort FileNameLength;
public ushort FileNameOffset;
public string FileName;
/// <remarks>Note how the read advances to the FileNameOffset and reads only FileNameLength bytes</remarks>
public void Read( Stream stream )
{
var startOfRecord = stream.Position;
RecordLength = stream.ReadUInt( );
MajorVersion = stream.ReadUShort( );
MinorVersion = stream.ReadUShort( );
FileReferenceNumber = stream.ReadULong( );
ParentFileReferenceNumber = stream.ReadULong( );
Usn = stream.ReadLong( );
TimeStamp = stream.ReadLong( );
Reason = ( UsnReason ) stream.ReadUInt( );
SourceInfo = stream.ReadUInt( );
SecurityId = stream.ReadUInt( );
FileAttributes = stream.ReadUInt( );
FileNameLength = stream.ReadUShort( );
FileNameOffset = stream.ReadUShort( );
stream.Position = startOfRecord + FileNameOffset;
FileName = Encoding.Unicode.GetString( stream.ReadBytes( FileNameLength ) );
stream.Position = startOfRecord + RecordLength;
}
void IBinarySerialize.Write( Stream stream )
{
throw new NotImplementedException( );
}
}
/// <summary>Structure returned from USN query that describes the state of the journal</summary>
[StructLayout( LayoutKind.Sequential )]
internal struct UsnJournalDataV1: IBinarySerialize
{
public ulong UsnJournalId;
public long FirstUsn;
public long NextUsn;
public long LowestValidUsn;
public long MaxUsn;
public ulong MaximumSize;
public ulong AllocationDelta;
public ushort MinSupportedMajorVersion;
public ushort MaxSupportedMajorVersion;
public void Read( Stream stream )
{
UsnJournalId = stream.ReadULong( );
FirstUsn = stream.ReadLong( );
NextUsn = stream.ReadLong( );
LowestValidUsn = stream.ReadLong( );
MaxUsn = stream.ReadLong( );
MaximumSize = stream.ReadULong( );
AllocationDelta = stream.ReadULong( );
MinSupportedMajorVersion = stream.ReadUShort( );
MaxSupportedMajorVersion = stream.ReadUShort( );
}
void IBinarySerialize.Write( Stream stream )
{
throw new NotImplementedException( );
}
}
[StructLayout( LayoutKind.Sequential )]
internal struct LUID
{
public UInt32 LowPart;
public Int32 HighPart;
}
[StructLayout( LayoutKind.Sequential )]
internal struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public UInt32 Attributes;
}
internal struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 1 )] // !! think we only need one
public LUID_AND_ATTRIBUTES[ ] Privileges;
}
[Flags]
internal enum EFileAttributes: uint
{
/// <summary/>
None = 0,
//--> these are consistent w/ .Net FileAttributes...
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
//--> additional CreateFile call attributes...
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}
/// <summary>Reasons the file changed (from USN journal)</summary>
[Flags]
public enum UsnReason: uint
{
BASIC_INFO_CHANGE = 0x00008000,
CLOSE = 0x80000000,
COMPRESSION_CHANGE = 0x00020000,
DATA_EXTEND = 0x00000002,
DATA_OVERWRITE = 0x00000001,
DATA_TRUNCATION = 0x00000004,
EA_CHANGE = 0x00000400,
ENCRYPTION_CHANGE = 0x00040000,
FILE_CREATE = 0x00000100,
FILE_DELETE = 0x00000200,
HARD_LINK_CHANGE = 0x00010000,
INDEXABLE_CHANGE = 0x00004000,
NAMED_DATA_EXTEND = 0x00000020,
NAMED_DATA_OVERWRITE = 0x00000010,
NAMED_DATA_TRUNCATION = 0x00000040,
OBJECT_ID_CHANGE = 0x00080000,
RENAME_NEW_NAME = 0x00002000,
RENAME_OLD_NAME = 0x00001000,
REPARSE_POINT_CHANGE = 0x00100000,
SECURITY_CHANGE = 0x00000800,
STREAM_CHANGE = 0x00200000,
None = 0x00000000
}
internal enum ECreationDisposition: uint
{
New = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
}
}
You can use this https://sourceforge.net/projects/ntfsreader/ open source library that is written in C# by Danny Couture.
I tested it and its performance is good. It can parse an NTFS drive with more than 100000 entry(file and folder) in less than 2 seconds.
Using the https://sourceforge.net/projects/ntfsreader/ library by Danny Couture is quite straightforward:
There are two main activities in which I am interested.
The first is reading the information for a given drive
The second part is processing the information retrieved (Search for a given file/folder, etc, rename all files, find files with length greater than 260, etc).
All information is returned as nodes and these can be files or folders or some other strange NTFS stuff such as extensions, etc, which I currently do not need.
You can test for which types of nodes you are interested in by testing node.Attributes - for example:
if((node.Attributes & Attributes.Directory) != 0 ) { /*...*/ }
On a 10 TB hard-drive (not particularly fast!) with 5 million files and 70k folders retrieving the nodes takes around 60 seconds using minimal retrieval mode - see later
Searching the collection of Inode(s) - in my case searching for all folders with archive in the name - took less than 500ms.
Because of the huge difference in times for these two activities, I find it best to retrieve all nodes (60 seconds) once and then perform repeated searches (~500ms) on the node collection.
The node retrieval only needs to be re-run if folders or files have changed.
You have to add a reference to ntfsreader and an example of its use is shown in the following pseudocode:
using System.IO.Filesystem.Ntfs;
public IEnumerable<INode> nodes;
public void DoStuff
{
// Obviously you can also use whatever you like to store this collection; array, dictionary, datatable, etc.
public List<string> foundObjects = new List<string>();
// string drive is "c" or "d" or whatever. Note that there is no "c:\" or "c:".
// Just "c" or "d" for the string drive argument.
// Read the NTFS MFT
RefreshNodes("f");
// If, for example, you are looking for a folder with a given name then
string strPattern="archive";
foreach (INode node in nodes)
{
if ((node.Attributes & Attributes.Directory) != 0 && node.Name.Contains(strPattern))
{
foundObjects.Add(node.FullName.Replace(#"\\", #"\"));
}
}
}
public void RefreshNodes(string drive)
{
DriveInfo driveToAnalyze = new DriveInfo(drive);
NtfsReader ntfsReader = new NtfsReader(driveToAnalyze, RetrieveMode.Minimal);
nodes = ntfsReader.GetNodes(driveToAnalyze.Name);
}
The time taken to retrieve the nodes depends on the RetrieveMode you use. RetrieveMode.Minimal brings back most of the information I need and it is quicker.
Hope this helps and happy NTFSing!
I'm trying to change the icon of external executable programmatically. I've googled and found much information about this problem using C++. Basically, I need to use BeginUpdateResource, UpdateResource and EndUpdateResource. The problem is - I don't know what to pass to UpdateResource in C#.
Here's the code I have so far:
class IconChanger
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage,
IntPtr lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
public enum ICResult
{
Success,
FailBegin,
FailUpdate,
FailEnd
}
public ICResult ChangeIcon(string exeFilePath, byte[] iconData)
{
// Load executable
IntPtr handleExe = BeginUpdateResource(exeFilePath, false);
if (handleExe == null)
return ICResult.FailBegin;
// Get language identifier
CultureInfo currentCulture = CultureInfo.CurrentCulture;
int pid = ((ushort)currentCulture.LCID) & 0x3ff;
int sid = ((ushort)currentCulture.LCID) >> 10;
ushort languageID = (ushort)((((ushort)pid) << 10) | ((ushort)sid));
// Get pointer to data
GCHandle iconHandle = GCHandle.Alloc(iconData, GCHandleType.Pinned);
// Replace the icon
if (UpdateResource(handleExe, "#3", "#1", languageID, iconHandle.AddrOfPinnedObject(), (uint)iconData.Length))
{
if (EndUpdateResource(handleExe, false))
return ICResult.Success;
else
return ICResult.FailEnd;
}
else
return ICResult.FailUpdate;
}
}
Regarding lpType - in C++, you pass RT_ICON (or RT_GROUP_ICON). What value should I pass in C#?
The same question goes for lpName parameter.
I'm not sure about language identifier (I found this on Internet) since I cannot test it.
I'm also not sure whether I'm providing appropriate icon data. Currently, iconData contains the bytes from .ico file.
Can anybody point me to right direction?
Thank you very much.
Just some pointers, this is quite hard to get right. Pass an RT_ICON by lying about the lpType argument. Change it from string to IntPtr and pass (IntPtr)3.
The lpData argument is quite tricky. You need to pass the data the way it is compiled by the resource compiler (rc.exe). I have no idea if it mangles the raw data of the .ico file. The only reasonable thing to try is to read the data from the .ico file with FileStream into a byte[], you already seem to be doing this. I think the function was really designed to copy a resource from one binary image to another. Odds of your approach working are not zero.
You are also ignoring another potential problem, the resource ID of the icon of the program isn't necessarily 1. It often is not, 100 tends to be a popular choice, but anything goes. EnumResourceNames would be required to make it reliable. The rule is that the lowest numbered ID sets the icon for the file. I'm not actually sure if that really means that the resource compiler puts the lowest number first, something that the API probably doesn't do.
A very small failure mode is that UpdateResource can only updated numbered resource items, not named ones. Using names instead of numbers is not uncommon but the vast majority of images use numbers for icons.
And of course, the odds that this will work without a UAC manifest are zero. You are hacking files that you don't normally have write access to.
I managed to get this working in pure C# using ResourceHacker and this posting as an example. Just use a regular .ico as input. In ResourceHacker (http://www.angusj.com/resourcehacker/) you will see the icon identifier (in my case 1) and the language identifier (in my case 1043):
I used this code:
internal class IconChanger
{
#region IconReader
public class Icons : List<Icon>
{
public byte[] ToGroupData(int startindex = 1)
{
using (var ms = new MemoryStream())
using (var writer = new BinaryWriter(ms))
{
var i = 0;
writer.Write((ushort)0); //reserved, must be 0
writer.Write((ushort)1); // type is 1 for icons
writer.Write((ushort)this.Count); // number of icons in structure(1)
foreach (var icon in this)
{
writer.Write(icon.Width);
writer.Write(icon.Height);
writer.Write(icon.Colors);
writer.Write((byte)0); // reserved, must be 0
writer.Write(icon.ColorPlanes);
writer.Write(icon.BitsPerPixel);
writer.Write(icon.Size);
writer.Write((ushort)(startindex + i));
i++;
}
ms.Position = 0;
return ms.ToArray();
}
}
}
public class Icon
{
public byte Width { get; set; }
public byte Height { get; set; }
public byte Colors { get; set; }
public uint Size { get; set; }
public uint Offset { get; set; }
public ushort ColorPlanes { get; set; }
public ushort BitsPerPixel { get; set; }
public byte[] Data { get; set; }
}
public class IconReader
{
public Icons Icons = new Icons();
public IconReader(Stream input)
{
using (BinaryReader reader = new BinaryReader(input))
{
reader.ReadUInt16(); // ignore. Should be 0
var type = reader.ReadUInt16();
if (type != 1)
{
throw new Exception("Invalid type. The stream is not an icon file");
}
var num_of_images = reader.ReadUInt16();
for (var i = 0; i < num_of_images; i++)
{
var width = reader.ReadByte();
var height = reader.ReadByte();
var colors = reader.ReadByte();
reader.ReadByte(); // ignore. Should be 0
var color_planes = reader.ReadUInt16(); // should be 0 or 1
var bits_per_pixel = reader.ReadUInt16();
var size = reader.ReadUInt32();
var offset = reader.ReadUInt32();
this.Icons.Add(new Icon()
{
Colors = colors,
Height = height,
Width = width,
Offset = offset,
Size = size,
ColorPlanes = color_planes,
BitsPerPixel = bits_per_pixel
});
}
// now get the Data
foreach (var icon in Icons)
{
if (reader.BaseStream.Position < icon.Offset)
{
var dummy_bytes_to_read = (int)(icon.Offset - reader.BaseStream.Position);
reader.ReadBytes(dummy_bytes_to_read);
}
var data = reader.ReadBytes((int)icon.Size);
icon.Data = data;
}
}
}
}
#endregion
[DllImport("kernel32.dll", SetLastError = true)]
static extern int UpdateResource(IntPtr hUpdate, uint lpType, ushort lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName, [MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
public enum ICResult
{
Success,
FailBegin,
FailUpdate,
FailEnd
}
const uint RT_ICON = 3;
const uint RT_GROUP_ICON = 14;
public ICResult ChangeIcon(string exeFilePath, string iconFilePath)
{
using (FileStream fs = new FileStream(iconFilePath, FileMode.Open, FileAccess.Read))
{
var reader = new IconReader(fs);
var iconChanger = new IconChanger();
return iconChanger.ChangeIcon(exeFilePath, reader.Icons);
}
}
public ICResult ChangeIcon(string exeFilePath, Icons icons)
{
// Load executable
IntPtr handleExe = BeginUpdateResource(exeFilePath, false);
if (handleExe == null) return ICResult.FailBegin;
ushort startindex = 1;
ushort index = startindex;
ICResult result = ICResult.Success;
var ret = 1;
foreach (var icon in icons)
{
// Replace the icon
// todo :Improve the return value handling of UpdateResource
ret = UpdateResource(handleExe, RT_ICON, index, 0, icon.Data, icon.Size);
index++;
}
var groupdata = icons.ToGroupData();
// todo :Improve the return value handling of UpdateResource
ret = UpdateResource(handleExe, RT_GROUP_ICON, startindex, 0, groupdata, (uint)groupdata.Length);
if (ret == 1)
{
if (EndUpdateResource(handleExe, false))
result = ICResult.Success;
else
result = ICResult.FailEnd;
}
else
result = ICResult.FailUpdate;
return result;
}
}
This is the solution that worked for me. I was not able to write it in .NET, but have managed to write C++ DLL which I am referencing in my C# application.
C++ DLL
The contents of C++ solution I am building the DLL from:
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <windows.h>
extern "C"
{
#pragma pack(push, 2)
typedef struct {
WORD Reserved1; // reserved, must be 0
WORD ResourceType; // type is 1 for icons
WORD ImageCount; // number of icons in structure (1)
BYTE Width; // icon width (32)
BYTE Height; // icon height (32)
BYTE Colors; // colors (0 means more than 8 bits per pixel)
BYTE Reserved2; // reserved, must be 0
WORD Planes; // color planes
WORD BitsPerPixel; // bit depth
DWORD ImageSize; // size of structure
WORD ResourceID; // resource ID
} GROUPICON;
#pragma pack(pop)
__declspec(dllexport) void __stdcall ChangeIcon(char *executableFile, char *iconFile, INT16 imageCount)
{
int len = strlen(executableFile) + 1;
wchar_t *executableFileEx = new wchar_t[len];
memset(executableFileEx, 0, len);
::MultiByteToWideChar(CP_ACP, NULL, executableFile, -1, executableFileEx, len);
len = strlen("MAINICON") + 1;
wchar_t *mainIconEx = new wchar_t[len];
memset(mainIconEx, 0, len);
::MultiByteToWideChar(CP_ACP, NULL, "MAINICON", -1, mainIconEx, len);
HANDLE hWhere = BeginUpdateResource(executableFileEx, FALSE);
char *buffer; // Buffer to store raw icon data
long buffersize; // Length of buffer
int hFile; // File handle
hFile = open(iconFile, O_RDONLY | O_BINARY);
if (hFile == -1)
return; // If file doesn't exist, can't be opened etc.
// Calculate buffer length and load file into buffer
buffersize = filelength(hFile);
buffer = (char *)malloc(buffersize);
read(hFile, buffer, buffersize);
close(hFile);
// Calculate header size
int headerSize = 6 + imageCount * 16;
UpdateResource(
hWhere, // Handle to executable
RT_ICON, // Resource type - icon
MAKEINTRESOURCE(1), // Make the id 1
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), // Default language
buffer + headerSize, // Skip the header bytes
buffersize - headerSize // Length of buffer
);
GROUPICON grData;
grData.Reserved1 = 0; // reserved, must be 0
grData.ResourceType = 1; // type is 1 for icons
grData.ImageCount = 1; // number of icons in structure (1)
grData.Width = 32; // icon width (32)
grData.Height = 32; // icon height (32)
grData.Colors = 0; // colors (256)
grData.Reserved2 = 0; // reserved, must be 0
grData.Planes = 2; // color planes
grData.BitsPerPixel = 32; // bit depth
grData.ImageSize = buffersize - 22; // size of image
grData.ResourceID = 1; // resource ID is 1
UpdateResource(
hWhere,
RT_GROUP_ICON,
// RT_GROUP_ICON resources contain information
// about stored icons
mainIconEx,
// MAINICON contains information about the
// application's displayed icon
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
&grData,
// Pointer to this structure
sizeof(GROUPICON)
);
delete buffer; // free memory
// Perform the update, don't discard changes
EndUpdateResource(hWhere, FALSE);
}
}
C# code
This is C# code which I'm using to import ChangeIcon function from previously written DLL:
[DllImport("IconChanger.dll")]
static extern void ChangeIcon(String executableFile, String iconFile, short imageCount);
/// <summary>
/// Changes the executable's icon
/// </summary>
/// <param name="exeFilePath">Path to executable file</param>
/// <param name="iconFilePath">Path to icon file</param>
static public void ChangeIcon(string exeFilePath, string iconFilePath)
{
short imageCount = 0;
using (StreamReader sReader = new StreamReader(iconFilePath))
{
using (BinaryReader bReader = new BinaryReader(sReader.BaseStream))
{
// Retrieve icon count inside icon file
bReader.ReadInt16();
bReader.ReadInt16();
imageCount = bReader.ReadInt16();
}
}
// Change the executable's icon
ChangeIcon(exeFilePath, iconFilePath, imageCount);
}
Hope at least somebody will find this useful.
C# declaration for UpdateResource:
/// <summary>
/// Adds, deletes, or replaces a resource in a portable executable (PE) file. There are some restrictions on resource updates in files that contain Resource Configuration (RC Config) data: language-neutral (LN) files and language-specific resource (.mui) files.
/// </summary>
/// <param name="hUpdate">A module handle returned by the BeginUpdateResource function, referencing the file to be updated. </param>
/// <param name="lpType">The resource type to be updated. Alternatively, rather than a pointer, this parameter can be MAKEINTRESOURCE(ID), where ID is an integer value representing a predefined resource type. If the first character of the string is a pound sign (#), then the remaining characters represent a decimal number that specifies the integer identifier of the resource type. For example, the string "#258" represents the identifier 258. For a list of predefined resource types, see Resource Types. </param>
/// <param name="lpName">The name of the resource to be updated. Alternatively, rather than a pointer, this parameter can be MAKEINTRESOURCE(ID), where ID is a resource ID. When creating a new resource do not use a string that begins with a '#' character for this parameter.</param>
/// <param name="wLanguage">The language identifier of the resource to be updated. For a list of the primary language identifiers and sublanguage identifiers that make up a language identifier, see the MAKELANGID macro. </param>
/// <param name="lpData">The resource data to be inserted into the file indicated by hUpdate. If the resource is one of the predefined types, the data must be valid and properly aligned. Note that this is the raw binary data to be stored in the file indicated by hUpdate, not the data provided by LoadIcon, LoadString, or other resource-specific load functions. All data containing strings or text must be in Unicode format. lpData must not point to ANSI data. If lpData is NULL and cbData is 0, the specified resource is deleted from the file indicated by hUpdate. Prior to Windows 7: If lpData is NULL and cbData is nonzero, the specified resource is NOT deleted and an exception is thrown.</param>
/// <param name="cbData">The size, in bytes, of the resource data at lpData. </param>
/// <returns>Returns TRUE if successful or FALSE otherwise. To get extended error information, call GetLastError.</returns>
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)]
public static extern Int32 UpdateResourceW(void* hUpdate, char* lpType, char* lpName, UInt16 wLanguage, [CanBeNull] void* lpData, UInt32 cbData);
For a string resource type or name, you just pass the string.
For system-predefined types like RT_ICON and int IDs like IDI_APPLICATION, you pass that integer value reinterpret-casting it to a pointer, like (char*)3 for RT_ICON.