How to use InternetQueryOption in C# interop? - c#

In my C# code I want to use InternetQueryOption which is defined in MSDN such as:
BOOL InternetQueryOption(
__in HINTERNET hInternet,
__in DWORD dwOption,
__out LPVOID lpBuffer,
__inout LPDWORD lpdwBufferLength
);
In my C# code I wrote:
[DllImport("wininet.dll", SetLastError = true)]
static extern bool InternetQueryOption(
IntPtr hInternet,
uint dwOption,
IntPtr lpBuffer,
ref int lpdwBufferLength);
My C++ code:
...
HINTERNET hRequest = HttpOpenRequest(hConnect, "POST","/BM-Login/auth-cup", NULL, NULL, accept, secureFlags, 0);
DWORD dwFlags;
DWORD dwBuffLen = sizeof(dwFlags);
InternetQueryOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
dwFlags |= SECURITY_FLAG_IGNORE_REVOCATION;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_WRONG_USAGE;
InternetSetOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS,
&dwFlags, sizeof (dwFlags) );
...
How to write the same in C#? Thanks. (Sorry for my very bad English)

I'd recommend using manged code for this instead of doing this via interop. Have a look at the WebRequest Class. Also, have a look at my answer to the stackoverflow question C# https login and download file for a working example of how this class can be used.

Related

Speed up C# native call pinvoke

mod note: I do not believe this to be a duplicate, due to me having already tried several mentioned solutions as described below.
Is there a way I can speed this up? I've already followed the Microsoft guides on this, and here's what I've done:
Added SuppressUnmanagedCodeSecurity
Placed this in a file named UnsafeNativeMethods.cs
Defined specific types for the method stub
Here is the method:
[DllImport("kernel32.dll")]
[SuppressUnmanagedCodeSecurity]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint IoControlCode,
[In] MemoryManager.MemOperation InBuffer,
int nInBufferSize,
[Out] byte[] OutBuffer,
uint nOutBufferSize,
ref int pBytesReturned,
IntPtr Overlapped
);
Here is the contents of MemOperation (the inbuffer that has to be marshal'd I'm guessing):
public struct MemOperation
{
public int Pid;
public int UserPid;
public int Size;
public int protection_mode;
public int allocation_type;
public IntPtr Addr;
public IntPtr WriteBuffer;
[MarshalAs(UnmanagedType.LPWStr)]
public string module_selection;
}
Here's is an example of usage:
public UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) {
var memOperation = new MemOperation();
byte[] buffer = new byte[48]; // 8 + 8 + 4 + 8 + 4 + 4 + 4 MEMORY_BASIC_INFORMATION
memOperation.Pid = this.Pid;
memOperation.Addr = address;
int bytes = 0;
bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), buffer, (uint)buffer.Length, ref bytes, IntPtr.Zero);
return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer);
}
In the profiler, my hotpath is the pinvoke. My application runs incredibly fast, as fast I think it can in C#. However, almost a third of all execution time is spent pinvoking due to how many memory operations the application is doing. I would like to cut this time down in any way possible, including unsafe ways.
I have seen that you can instead write a DeviceIoControl wrapper and import it from a C++ dll, however this did not lead to any changes for me, it appeared to function the exact same. Here's the source for that:
devicecontrol.cpp
#include <iostream>
#include "DeviceControl.h"
bool __cdecl DeviceIoRequestWrapper(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlappedk)
{
return DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlappedk);
}
devicecontrol.h
#pragma once
#include <Windows.h>
extern "C" {
__declspec(dllexport) bool __cdecl DeviceIoRequestWrapper(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlappedk);
}
I am on .net 6.0 and the latest version of C#.
Proposed change to out buffer:
public unsafe UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) {
var memOperation = new MemOperation();
byte* buffer = stackalloc byte[48];
memOperation.Pid = this.Pid;
memOperation.Addr = address;
int bytes = 0;
bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), (IntPtr)buffer, 48, ref bytes, IntPtr.Zero);
return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer);
}
Where GetStructure is now:
public static unsafe T GetStructure<T>(byte* bytes) where T: unmanaged {
T structure = *(T*)bytes;
return structure;
}
Here's what helped the most and I'll accept this as the answer to my own thread in a few hours.
In addition to the above steps I mentioned, I have now done the following:
Converted MemOperation to be fully blittable. The string "module_selection" was only ever used once per program start, so I have instead now added a fully blittable version of MemOperation. Thank you #Flydog57
Changed buffer to be quickly allocated (non zero'd out), and pass a PTR, rather than allocating and then marshalling a byte[] to void/char* (which is what I think likely happens when you pass it a byte[] object). Thank you #Charlieface
Running the profiler in visual studio, it appears to have eliminated the hotpath. Now the total CPU % correctly lies within kernel32.dll (the deviceiocontrol call to the device). Whether this leads to tangible performance benefits, I don't know, don't have an easy way to setup a full benchmark for this.

Using DevicIOControl with VC# [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have created two different Visual C# dll's that make use of DeviceIOControl calls and I have defined them as below:
In first dll:
[DllImport("kernel32.dll", SetLastError = true)]
static extern BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
ref Internal_COMMAND lpInBuffer,
DWORD nInBufferSize,
ref ulong lpOutBuffer,
DWORD nOutBufferSize,
ref DWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
public struct Internal_COMMAND
{
public ulong Address;
public ulong Command;
};
In second dll:
[DllImport("kernel32.dll", SetLastError = true)]
static extern BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
ref char[] lpInBuffer,
DWORD nInBufferSize,
ref char[] lpOutBuffer,
DWORD nOutBufferSize,
ref DWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
But now I have to make them as a single dll within the same class. So I tried to use the below.
[DllImport("kernel32.dll", SetLastError = true)]
static extern BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
ref char[] lpInBuffer,
DWORD nInBufferSize,
ref char[] lpOutBuffer,
DWORD nOutBufferSize,
ref DWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
as common definition and passed the variables by converting structure to character array. But the driver does not work as expected
Please guide me with the correct procedure to follow
Method overload just worked just as #Hans Passant pointed out
This means I can use both definitions in a single .cs file and method overload takes effect, allowing to use the same function with different parameters

How to get number of bytes written successfully?

I'm doing a project that convert code from C++ to C# for printer.
I replace WriteFile() in C++ with SerialPort.Write() in C#.
C#
public void Write(
byte[] buffer,
int offset,
int count
)
C++
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
In C++ i can get number of bytes written in lpNumberOfBytesWritten. How to do the same thing in C#?
In c# We can use API call like below,
[DllImport("kernel32.dll")]
static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer,
uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
[In] ref System.Threading.NativeOverlapped lpOverlapped);
For more information see http://www.pinvoke.net/default.aspx/kernel32.writefile

Call Win32 CalculatePopupWindowPosition from C#

I'm trying to call the WinAPI function CalculatePopupWindowPosition in C# using P/Invoke. From
http://msdn.microsoft.com/en-us/library/windows/desktop/dd565861(v=vs.85).aspx
I see that it's syntax is:
BOOL WINAPI CalculatePopupWindowPosition(
_In_ const POINT *anchorPoint,
_In_ const SIZE *windowSize,
_In_ UINT flags,
_In_opt_ RECT *excludeRect,
_Out_ RECT *popupWindowPosition
);
I then tried to import it using the following code in C#
[DllImport("User32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CalculatePopupWindowPosition
(
[In] ref POINT anchorPoint,
[In] ref SIZE windowSize,
[In] ref UInt32 flags,
[In,Optional] ref RECT excludeRect,
[Out] out SIZE popupWindowPosition
);
I also implemented the RECT, POINT and SIZE structures and initialized them. Finally I called the function like so.
CalculatePopupWindowPosition(ref nIconPos, ref windowSize, ref flags, ref nIconRect, out windowSize);
This doesn't seem to work though, windowSize contains nothing but zeros, which it shouldn't. Any ideas what I'm doing wrong here?
The flags parameter needs to be passed by value rather than by reference:
[DllImport("User32.dll", SetLastError = true)]
public static extern bool CalculatePopupWindowPosition
(
ref POINT anchorPoint,
ref SIZE windowSize,
uint flags,
ref RECT excludeRect,
out RECT popupWindowPosition
);
Some general advice. When an API call fails, check the return value. In this case if the function returns false then call Marshal.GetLastWin32Error to find out the error status code.

ERROR_MORE_DATA --- PVOID and C# --- Unmanaged types

How can I get the value from the following DLL? offreg.dll.
In my below code, I have successfully opened the hive, the key and now I am trying to get the value of the key and I keep running into the ERROR_MORE_DATA (234) error.
Here is the C++ .dll:
DWORD
ORAPI
ORGetValue (
__in ORHKEY Handle,
__in_opt PCWSTR lpSubKey,
__in_opt PCWSTR lpValue,
__out_opt PDWORD pdwType,
__out_bcount_opt(*pcbData) PVOID pvData,
__inout_opt PDWORD pcbData
);
Here is my C# code:
[DllImport("offreg.dll", CharSet = CharSet.Auto, EntryPoint = "ORGetValue", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern uint ORGetValue(IntPtr Handle, string lpSubKey, string lpValue, out uint pdwType, out StringBuilder pvData, out uint pcbData);
IntPtr myHive;
IntPtr myKey;
StringBuilder myValue = new StringBuilder("", 256);
uint pdwtype;
uint pcbdata;
uint ret3 = ORGetValue(myKey, "", "DefaultUserName", out pdwtype, out myValue, out pcbdata);
So the issue seems to be around PVOID pvData I can't seem to get the right type, or buffer size right. Always with the 234 error.
NOTE: When running this command pcbdata = 28... so 256 should be more than enough.
Any help would be greatly appreciated.
As shown above, I've tried string builder... string... IntPtr... etc. None of which were able to handle the out of PVData...
Thank you.
You need to initialize pcbData to the size of your buffer before passing it in. Remember C doesn't know how large of a buffer you are passing it, the pcbData value coming in tells the function how large pvData is. In your case you are passing in zero, telling OrGetValue that you that pvData is a 0 byte buffer, so it responds telling you it needs a larger buffer.
So in your PInvoke definiation pcbData should be a ref param and have a non-zero value going in:
[DllImport("offreg.dll", CharSet = CharSet.Auto, EntryPoint = "ORGetValue", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern uint ORGetValue(IntPtr Handle, string lpSubKey, string lpValue, out uint pdwType, out StringBuilder pvData, ref uint pcbData);
IntPtr myHive;
IntPtr myKey;
StringBuilder myValue = new StringBuilder("", 256);
uint pdwtype;
uint pcbdata = myValue.Capacity();
uint ret3 = ORGetValue(myKey, "", "DefaultUserName", out pdwtype, out myValue, ref pcbdata);

Categories