I am trying to add a crl to my cert store using Win32 api CertAddCRLContextToStore in C#. The below code is not working and failing while trying to parse the crl content to CRL_CONTEXT. Can we do this in any other way? Or am I missing something in my code?
private const int CERT_STORE_PROV_SYSTEM = 10;
private const int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);
public const int CERT_QUERY_OBJECT_FILE = 0x00000001;
public const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED = 1 << 8;
public const int CERT_QUERY_FORMAT_FLAG_BINARY = 1 << 1;
public const int CERT_STORE_ADD_REPLACE_EXISTING = 1 << 3;
[DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenStore(
int storeProvider,
int encodingType,
IntPtr hcryptProv,
int flags,
string pvPara);
[DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptQueryObject(
int dwObjectType,
[MarshalAs(UnmanagedType.LPWStr)] String pvObject,
int dwExpectedContentTypeFlags,
int dwExpectedFormatTypeFlags,
int dwFlags,
IntPtr pdwMsgAndCertEncodingType,
IntPtr pdwContentType,
IntPtr pdwFormatType,
IntPtr phCertStore,
IntPtr phMsg,
ref IntPtr ppvContext);
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CertAddCRLContextToStore(
IntPtr hCertStore,
IntPtr pCertContext,
uint dwAddDisposition,
IntPtr ppStoreContext);
IntPtr hLocalCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
IntPtr.Zero,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
"CA");
IntPtr pvContext = IntPtr.Zero;
bool queryResult = CryptQueryObject(
CERT_QUERY_OBJECT_FILE,
#"sample.crl",
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
ref pvContext
);
// FAILS HERE
if (!queryResult)
{
throw new Exception("CryptQueryObject error #" + Marshal.GetLastWin32Error());
}
bool addResult = CertAddCRLContextToStore(
hLocalCertStore, pvContext, CERT_STORE_ADD_REPLACE_EXISTING, IntPtr.Zero);
if (!addResult)
{
throw new Exception("CryptQueryObject error #" + Marshal.GetLastWin32Error());
}
The code fails with the error
-2146885623. "Cannot find the requested
object"
Related
I want to be able to copy 4 GBs of data from a drive to a file and restore it. Here's my code:
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
internal extern static IntPtr CreateFile(
String fileName,
int dwDesiredAccess,
FileShare dwShareMode,
IntPtr securityAttrs_MustBeZero,
FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile_MustBeZero);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GetVolumeInformationByHandleW(
IntPtr hDisk,
StringBuilder volumeNameBuffer,
int volumeNameSize,
ref uint volumeSerialNumber,
ref uint maximumComponentLength,
ref uint fileSystemFlags,
StringBuilder fileSystemNameBuffer,
int nFileSystemNameSize);
// Used to read in a file
[DllImport("kernel32.dll")]
public static extern bool ReadFile(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToRead,
ref uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
[DllImport("kernel32.dll")]
public static extern bool WriteFile(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
[In] ref NativeOverlapped lpOverlapped);
// Used to set the offset in file to start reading
[DllImport("kernel32.dll")]
public static extern bool SetFilePointerEx(
IntPtr hFile,
long liDistanceToMove,
ref long lpNewFilePointer,
uint dwMoveMethod);
internal const int GENERIC_READ = unchecked((int)0x80000000);
internal const int FILE_FLAG_BACKUP_SEMANTICS = unchecked((int)0x02000000);
internal const int OPEN_EXISTING = unchecked((int)3);
static void Main(string[] args)
{
IntPtr hDrive = CreateFile(
string.Format("\\\\.\\{0}:", "G"),
GENERIC_READ,
FileShare.Read | FileShare.Write,
IntPtr.Zero,
(FileMode)OPEN_EXISTING,
0,
IntPtr.Zero);
RunBackup(hDrive);
RunRestore(hDrive);
CloseHandle(hDrive);
}
private static void RunRestore(IntPtr handle)
{
// Set offset
uint chunks = 100;
uint bufferSize = 512 * chunks;
long pt = 0;
byte[] buffer = new byte[bufferSize];
SetFilePointerEx(
handle,
0,
ref pt,
0);
long oneGB = 1073741824;
var backupSize = oneGB * 4;
var loops = backupSize / bufferSize;
Console.WriteLine($"Expecting {loops:N0} loops.");
var ol = new NativeOverlapped();
uint written = 0;
using (var reader = new BinaryReader(File.OpenRead(#"D:\\fat.backup")))
{
for (int i = 0; i < loops; i++)
{
reader.Read(buffer);
WriteFile(
handle,
buffer,
bufferSize,
out written,
ref ol);
Console.Write($"\rLoop: {i:N0}");
}
reader.Close();
}
}
private static void RunBackup(IntPtr handle)
{
// Set offset
uint chunks = 100;
uint bufferSize = 512 * chunks;
long pt = 0;
byte[] buffer = new byte[bufferSize];
SetFilePointerEx(
handle,
0,
ref pt,
0);
long oneGB = 1073741824;
var backupSize = oneGB * 4;
var loops = backupSize / bufferSize;
Console.WriteLine($"Expecting {loops:N0} loops.");
uint read = 0;
using (var writer = new BinaryWriter(File.OpenWrite(#"D:\\fat.backup")))
{
for (int i = 0; i < loops; i++)
{
ReadFile(
handle,
buffer,
bufferSize,
ref read,
IntPtr.Zero);
writer.Write(buffer);
writer.Flush();
Console.Write($"\rLoop: {i:N0}");
}
writer.Close();
}
}
}
The backup function seems to be working as expected. However, in the restore part, when the program calls the WriteFile, the written variable is always 0. Am I doing something wrong?
You use the same handle for both routines, and it was opened for read access.
If you open a file for read only, and then use the same handle to write, it's pretty obvious you're going to have problems.
Solution
In order to write to the disk use the CreateFile function like this:
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
internal extern static IntPtr CreateFile(
String fileName,
FileAccess access,
FileShare dwShareMode,
IntPtr securityAttrs_MustBeZero,
FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile_MustBeZero);
IntPtr handle = CreateFile(
string.Format("\\\\.\\{0}:", driveLetter),
(FileAccess)(0x40000000),
(FileShare)0x00000001,
IntPtr.Zero,
FileMode.OpenOrCreate,
0x00000080,
IntPtr.Zero);
I made before a program where I could open a process of the notepad and while it's opened, be able to write in it from the C# program console. Now I'm trying to do the same but with the excel, I can run the process, I can open it and I can kill it. But when I try to write in it with the SendMessage() method, nothing happens, is there a way I can do this? Or am I missing something? Thanks!
Here's what I tried so far
Declarations
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
//include SendMessage
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("User32.dll")]
static extern int SetForegroundWindow(IntPtr point);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
extern static int SendMessageGetTextLength(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
const uint WM_PASTE = 0x302;
const int WM_SETTEXT = 0X000C;
const int WM_GETTEXTLENGTH = 0x000E;
const int EM_SETSEL = 0x00B1;
const int EM_REPLACESEL = 0x00C2;
static void Main(string[] args)
{
//Abre o programa
Process prcss = new Process();
prcss.StartInfo.FileName = "excel.exe";
prcss.Start();
string aux = prcss.StartInfo.FileName;
//Verifica se o processo está a correr
Process[] processlist = Process.GetProcesses();
Code to write in it with the SendMessage().
case "2":
while (true)
{
//Testar com o SendMessage
Console.WriteLine("\nTexto: \n");
string texto = Console.ReadLine();
if (aux.Length == 0)
{
return;
}
if (prcss != null)
{
IntPtr notepadTextbox = FindWindowEx(prcss.MainWindowHandle, IntPtr.Zero, "edit", null);
int length = SendMessageGetTextLength(notepadTextbox, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
if (!notepadTextbox.Equals(IntPtr.Zero))
{
//sending the message to the textbox
SendMessage(notepadTextbox, WM_SETTEXT, 0, texto);
SendMessage(notepadTextbox, EM_SETSEL, length, length);
SendMessage(notepadTextbox, EM_REPLACESEL, 1, texto + "\n");
}
}
Console.WriteLine("Sair? (S)im / (N)ão");
sair = Console.ReadLine();
if (sair == "s" || sair == "S")
{
IntPtr k = prcss.MainWindowHandle;
SetForegroundWindow(k);
prcss.Kill();
break;
}
}
I'd like to get content of a document sent to printing.
Google said an only way to do that is to use WinAPI method ReadPrinter().
I've implemented a sketch but can't get it work.
A trouble is the ReadPrinter() method always returns nothing.
Please give me a hint what is wrong.
Simplified code below:
string printerName = "Microsoft XPS Document Writer";
const uint firstJob = 0u;
const uint noJobs = 10u;
const uint level = 1u;
uint bytesNeeded;
uint returned;
uint bytesCopied;
uint structsCopied;
// Open printer
IntPtr printerHandle = OpenPrinterW(printerName.Normalize(), out printerHandle, IntPtr.Zero);
// Get byte size required for a data
EnumJobsW(printerHandle, firstJob, noJobs, level, IntPtr.Zero, 0, out bytesNeeded, out returned);
// Now we know how much memory we need to read the data (bytesNeeded value)
IntPtr pJob = Marshal.AllocHGlobal((int)bytesNeeded);
// Read the data
EnumJobsW(printerHandle, firstJob, noJobs, level, pJob, bytesNeeded, out bytesCopied, out structsCopied);
// Convert pJob to jobInfos
JOB_INFO_1W[] jobInfos = null;
// ... actual convert code missed ...
// Iterate through the jobs and try to get their content
foreach (JOB_INFO_1W jobInfo in jobInfos)
{
// Open print job
string printJobName = string.Format("{0}, Job {1}", printerName, jobInfo.JobId);
IntPtr printJobHandle;
OpenPrinterW(printJobName.Normalize(), out printJobHandle, IntPtr.Zero);
// Read print job
const int printJobBufLen = 1024;
StringBuilder printJobSb = new StringBuilder(printJobBufLen);
int printJobBytesRead = 0;
while (printJobBytesRead == 0)
{
ReadPrinter(printJobHandle, printJobSb, printJobBufLen, out printJobBytesRead);
// !!! printJobBytesRead is 0 and printJobSb is empty
}
// Close print job
ClosePrinter(printJobHandle);
}
// Close printer
ClosePrinter(printerHandle);
P/Invoke signatures:
[DllImport("winspool.drv", EntryPoint = "OpenPrinterW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinterW(
[In] string pPrinterName,
[Out] out IntPtr phPrinter,
[In] IntPtr pDefault);
[DllImport("spoolss.dll", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(
[In] IntPtr hPrinter);
[DllImport("winspool.drv", EntryPoint = "EnumJobsW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int EnumJobsW(
[In] IntPtr hPrinter,
[In] uint FirstJob,
[In] uint NoJobs,
[In] uint Level,
[Out] IntPtr pJob,
[In] uint cbBuf,
[Out] out uint pcbNeeded,
[Out] out uint pcReturned);
[DllImport("spoolss.dll", EntryPoint = "ReadPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ReadPrinter(
[In] IntPtr hPrinter,
[Out] StringBuilder data,
[In] Int32 cbBuf,
[Out] out Int32 pNoBytesRead);
Is this code inside a driver's Print Processor component? (Link updated to web archive.) If not, I don't think it will work.
So you either use a print driver component, or read from the spool file on disk. See here.
I'm calling the following function on wininet.dll in order to get online (C# pinvoke):
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int InternetDial(IntPtr hWndParent, string pszEntryName,
int dwFlags, ref int lpdwConnection,
int ReservedValue);
public static bool GetOnline()
{
int connectionID = 0;
InternetDial(IntPtr.Zero, "DefaultDialUp", INTERNET_AUTODIAL_FORCE_UNATTENDED, ref connectionID, 0);
return (connectionID != 0);
}
The problem is when error occurs in the dial up process, such as hardware failure,
Windows shows a blocking dialog that ask the user how to procceed,
And my function is stuck until the user causes the dialog to be closed:
This code should be deployed on automatic systems so this is a major issue for me...
I'm looking for a way to suppress the error dialogs on the windows API level..
Thanks in advance,
Eitan.
Iv'e managed to find a workaruond for the issue, but it's pretty nasty,
better solutions still welcome...
const int WM_CLOSE = 0x10;
const int INTERNET_AUTODIAL_FORCE_UNATTENDED = 0x2;
[DllImport("User32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(int hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int InternetDial(IntPtr hWndParent, string pszEntryName, int dwFlags, ref int lpdwConnection, int ReservedValue);
public static bool GetOnline()
{
connectionID = 0;
Form f = null;
var t = new Thread((ParameterizedThreadStart)delegate
{
f = new Form();
InternetDial(f.Handle, "DefaultDialUp", INTERNET_AUTODIAL_FORCE_UNATTENDED, ref connectionID, 0);
});
t.Start();
t.Join(23000); //wait 23 seconds before closing the window
f.Invoke((EventHandler)delegate {
PostMessage(f.Handle.ToInt32(), WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
});
t.Join();
return (connectionID != 0);
}
I am reading text from a notepad opened by my program.and this is my code
const int WM_GETTEXT = 0x000D;
const int WM_GETTEXTLENGTH = 0x000E;
[DllImport("User32.dll", EntryPoint = "SendMessage")]
extern static int SendMessageGetTextLength(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
extern static IntPtr SendMessageGetText(IntPtr hWnd, int msg, IntPtr wParam, [Out] StringBuilder lParam);
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
public static string GetText(IntPtr hwnd)
{
if (hwnd == IntPtr.Zero)
throw new ArgumentNullException("hwnd");
IntPtr handler = FindWindowEx(hwnd, new IntPtr(0), "Edit", null);
int length = SendMessageGetTextLength(handler, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
if (length > 0 && length < int.MaxValue)
{
length++;
StringBuilder sb = new StringBuilder(length);
SendMessageGetText(handler, WM_GETTEXT, (IntPtr)sb.Length, sb);
return sb.ToString();
}
return String.Empty;
}
It is getting the text but in a special encoding.
For example, if the text entered is 'hello' it gets '興梀ȿڳㇺ'.
What is the encoding of this text so I can decode it to ASCII?
Your problem is in fact that you are passing sb.Length in the WM_GETTEXT message, when in fact you should be passing sb.Capacity or even just length.
I would do it like this:
if (length > 0 && length < int.MaxValue)
{
StringBuilder sb = new StringBuilder(length+1);
SendMessageGetText(handler, WM_GETTEXT, (IntPtr)length+1, sb);
return sb.ToString();
}
I'd also point out that WM_GETTEXT will not return more than 64k characters to the length < int.MaxValue isn't what you need.
Of course, in the longer run it may be better to use the Unicode throughout so that you can support international text.
I personally would always opt for using the Unicode APIs and use the following p/invoke declarations:
[DllImport("User32.dll", EntryPoint = "SendMessage",
CharSet = CharSet.Unicode, SetLastError = true)]
extern static int SendMessageGetTextLength(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", EntryPoint = "SendMessage",
CharSet = CharSet.Unicode, SetLastError = true)]
extern static IntPtr SendMessageGetText(IntPtr hWnd, int msg, IntPtr wParam, StringBuilder lParam);
[DllImport("user32.dll", EntryPoint = "FindWindowEx",
CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
Since you're writing in managed code, you may as well use the managed code automation interfaces, which does all the interop for you. Why reinvent the wheel?
using System.Windows.Automation;
public static string GetText(IntPtr hwnd)
{
IntPtr hwndEdit = FindWindowEx(hwnd, IntPtr.Zero, "Edit", null);
return (string)AutomationElement.FromHandle(hwndEdit).
GetCurrentPropertyValue(AutomationElement.NameProperty);
}
You can even make the automation do the FindWindowEx for you:
public static string GetText(IntPtr hwnd)
{
var editElement = AutomationElement.FromHandle(hwnd).
FindFirst(TreeScope.Subtree,
new PropertyCondition(
AutomationElement.ClassNameProperty, "Edit"));
return (string)editElement.GetCurrentPropertyValue(AutomationElement.NameProperty);
}