Pass pointer to a pointer in Go DLL Syscall - c#

If I have the following C# DllImport which is importing a non-C# DLL and I want to port it over to Go, how would I go about doing that?
[DllImport("my.dll", EntryPoint = "Greet", CallingConvention = CallingConvention.Cdecl)]
public static extern int Greet(IntPtr name, ref IntPtr greetings);
I've run into problems figuring out how to pass a pointer to a pointer which is needed for the greetings parameter (I assume since the type is ref IntPtr, I'm not that familiar at all with C#). The dll function will populate the memory pointed to by the pointer that I provide which I'll use in subsequent syscalls. Here's what I've got so far,
package main
import (
"fmt"
"syscall"
"unsafe"
)
var (
MyDll = syscall.MustLoadDLL("my.dll")
greet = MyDll.MustFindProc("Greet")
)
func Greet(name string) error {
nameP, err := syscall.UTF16PtrFromString(name)
if err != nil {
return err
}
// I need to provide a pointer to a pointer for greetings. How can I allocate some memory here
// then pass a pointer to its pointer? I tried this: create a handle with a zero-value, then
// take a pointer to it, then pass a pointer to the pointer as the second parameter to Call but
// the pointer becomes nil after the Call.
handle := syscall.Handle(0)
handleP := &handle
r1, _, _ := greet.Call(uintptr(unsafe.Pointer(nameP)), uintptr(unsafe.Pointer(&handleP)))
if r1 == 0 {
return fmt.Errorf("there was an error")
}
return nil
}
I'm open to any and all suggestions including links and resources that might help me get a better grasp on this syscall and unsafe stuff. Thanks!

Firstly, it would help if you could show how the C# Greet method is used. A method in isolation its quite hard to understand especially when the parameter is the equivalent of void ** which means anything can go in.
TL;DR
ref IntPtr is probably just a **struct{} where you don't have to allocate any struct. The library will simply manage the memory for you. You just need to give it a pointer to "*MyStruct" so that it can change you "*MyStruct" to actually point to the internal resource.
REF
The C# ref keyword is quite well explained in the docs. Basically it allows a pass by reference for any type.
The following declaration in C#
void Increment(ref value) { ... }
int counter = 10;
Increment(ref counter);
// counter is now 11
Increment(counter); // won't compile must be passed with 'ref'
Increment(null); // won't compile
is equivalent to C++
void Increment(int& value) { ... }
int counter;
Increment(counter);
// counter is now 11
Increment(null); // won't compile
A reference which should not be null.
IntPtr
IntPtr is usually used to represent pointers and allows for interop between native and CLR (C#) programs.
If a C program has the following signature
void Increment(int* value);
a C# program could call it in one of a few ways
[DllImport("example.dll")]
static unsafe extern void Increment(int* value); // this way allows null to be passed in
unsafe {
int counter = 10;
Increment(&10);
}
,
[DllImport("example.dll")]
static extern void Increment(ref int value);
int counter = 10;
Increment(ref counter);
If a C program has the following signature
void AllocateStruct(struct MyStruct** ppStruct);
void IncrementStruct(struct MyStruct* pStruct);
then
[DllImport("example.dll")]
static extern void AllocateStruct(ref IntPtr ppStruct);
// static unsafe extern void AllocateStruct(MyStruct** ppStruct)
[DllImport("example.dll")]
static extern void IncrementStruct(IntPtr pStruct);
// static unsafe extern void IncrementStruct(MyStruct* pStruct);
IntPtr pMyStruct;
AllocateStruct(ref pMyStruct);
IncrementStruct(pMyStruct);
// Free My Struct
// If you need to get inside the struct then
// MyStruct myStruct = Marshal.StructureToPtr<MyStruct>(pMyStruct)
// Often you don't (need to) or (should not) manipulate the struct directly so keeping it as IntPtr is perfectly acceptable.
From the example above you can see MyStruct is more of a token/reference than anything else. ref IntPtr allows you to pass a reference to the location which you will use to store your token/reference after the library allocates it on your behalf. Then all the other methods will usually just use the reference IntPtr to perform subsequent manipulations on it. Basically Object Orientated Programming without classes.
"Real" Life Example with ref IntPtr
It is a bit quick and dirty and error handling leave a lot to be desired.
It shows the C, C# and Go versions which call the same GetSecurityInfo
and LookupAccountSid Win32 library functions.
The only real use case I can find for ref IntPtr is type**/void** so that the library can allocate the memory for you or give you a pointer to memory it has already allocated.
C
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include "accctrl.h"
#include "aclapi.h"
#pragma comment(lib, "advapi32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
// --- get the executing program's file path and handle -----
LPTSTR executablePath = argv[0];
_tprintf(TEXT("Opening File %s\n"), executablePath);
HANDLE hFile = CreateFile(
executablePath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) return EXIT_FAILURE;
// -------------------------------------------------
// --------- Get the owner SID of the file ---------
PSID pSidOwner = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
DWORD dwRtnCode = GetSecurityInfo(
hFile,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
&pSidOwner,
NULL,
NULL,
NULL,
&pSD);
if (dwRtnCode != ERROR_SUCCESS) return EXIT_FAILURE;
// -------------------------------------------------
// -------
TCHAR AcctName[MAX_PATH];
DWORD dwAcctName = MAX_PATH;
TCHAR DomainName[MAX_PATH];
DWORD dwDomainName = MAX_PATH;
SID_NAME_USE eUse = SidTypeUnknown;
BOOL bRtnBool = LookupAccountSid(
NULL, // local computer
pSidOwner,
&AcctName,
&dwAcctName,
DomainName,
&dwDomainName,
&eUse);
if (bRtnBool == FALSE) return EXIT_FAILURE;
_tprintf(TEXT("Account Owner = %s\n"), AcctName);
_tprintf(TEXT("Account Owner's Domain = %s\n"), DomainName);
return 0;
}
C#
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
public class Example
{
[DllImport("advapi32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern uint GetSecurityInfo(
IntPtr handle,
uint ObjectType,
uint SecurityInfo,
ref IntPtr ppsidOwner, // <-- HERE
IntPtr ppsidGroup, // bit hacky (in safe C# you must "pass a reference" in C you can pass a pointer to a pointer or null)
IntPtr ppDacl,
IntPtr ppSacl,
ref IntPtr ppSecurityDescriptor // <-- HERE
);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool LookupAccountSid(
string lpSystemName,
IntPtr Sid,
StringBuilder lpName,
ref uint cchName,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out uint peUse);
const uint ERROR_SUCCESS = 0;
const uint OWNER_SECURITY_INFORMATION = 0x00000001;
const uint SE_FILE_OBJECT = 1;
public static void Main()
{
// get the executing program's file path and handle
string executablePath = Environment.GetCommandLineArgs().GetValue(0).ToString();
IntPtr hFile = File.Open(executablePath, FileMode.Open, FileAccess.Read, FileShare.Read)
.SafeFileHandle.DangerousGetHandle();
IntPtr pSidOwner = IntPtr.Zero; // some internal struct you shouldn't allocate or modify (acts like a token)
IntPtr pSD = IntPtr.Zero; // some internal struct you shouldn't allocate or modify (acts like a token)
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
uint dwRtnCode = GetSecurityInfo(
hFile,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
ref pSidOwner, // <-- HERE
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
ref pSD // <-- HERE
);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if (dwRtnCode != ERROR_SUCCESS) throw new InvalidOperationException("GetSecurityInfo Failed");
StringBuilder name = new StringBuilder(50);
uint cchName = (uint)name.Capacity;
StringBuilder domainName = new StringBuilder(50);
uint cchDomainName = (uint)domainName.Capacity;
uint sidUse;
LookupAccountSid(
null,
pSidOwner,
name,
ref cchName,
domainName,
ref cchDomainName,
out sidUse);
Console.WriteLine("Account Owner = {0}", name);
Console.WriteLine("Account Owner's Domain = {0}", domainName);
// PLEASE FREE pSD once done
}
}
Go
my second Go program I have ever written so there are probably some blaring mistakes (other than the lack of error checking)
package main
import (
"fmt"
"syscall"
"unsafe"
"os"
)
var (
advapi32, _ = syscall.LoadLibrary("advapi32.dll")
kernel32, _ = syscall.LoadLibrary("kernel32.dll")
createFileW, _ = syscall.GetProcAddress(kernel32, "CreateFileW")
getSecurityInfo, _ = syscall.GetProcAddress(advapi32, "GetSecurityInfo")
lookupAccountSidW, _ = syscall.GetProcAddress(advapi32, "LookupAccountSidW")
)
type SE_OBJECT_TYPE uint32
const (SE_FILE_OBJECT = 1)
type SECURITY_INFORMATION uint32
const (OWNER_SECURITY_INFORMATION = 0x00000001)
const (
GENERIC_READ = 0x80000000
FILE_SHARE_READ = 0x00000001
OPEN_EXISTING = 0x00000003
FILE_ATTRIBUTE_NORMAL = 0x00000080
)
type Handle uintptr
func CreateFile(
name string,
access uint32,
mode uint32,
sa *uint, // *SecurityAttributes,
createmode uint32,
attrs uint32,
templatefile *uint,
) (handle Handle, err error) {
utf16name, _ := syscall.UTF16PtrFromString(name)
r0, _, _ := syscall.Syscall9(
uintptr(createFileW), 7,
uintptr(unsafe.Pointer(utf16name)),
uintptr(access),
uintptr(mode),
uintptr(unsafe.Pointer(sa)),
uintptr(createmode),
uintptr(attrs),
uintptr(unsafe.Pointer(templatefile)),
0, 0)
handle = Handle(r0)
return
}
func GetSecurityInfo(
handle Handle,
objectType SE_OBJECT_TYPE,
securityInformation SECURITY_INFORMATION,
owner **struct{},
group **struct{},
dacl **struct{},
sacl **struct{},
sd **struct{}, //**SECURITY_DESCRIPTOR,
) (ret error) {
r0, _, _ := syscall.Syscall9(
uintptr(getSecurityInfo), 8,
uintptr(handle),
uintptr(objectType),
uintptr(securityInformation),
uintptr(unsafe.Pointer(owner)),
uintptr(unsafe.Pointer(group)),
uintptr(unsafe.Pointer(dacl)),
uintptr(unsafe.Pointer(sacl)),
uintptr(unsafe.Pointer(sd)),
0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func LookupAccountSid(
systemName *uint16,
sid *struct{}, // *SID,
name *uint16,
nameLen *uint32,
refdDomainName *uint16,
refdDomainNameLen *uint32,
use *uint32,
) (err error) {
r, _, e := syscall.Syscall9(
uintptr(lookupAccountSidW), 7,
uintptr(unsafe.Pointer(systemName)),
uintptr(unsafe.Pointer(sid)),
uintptr(unsafe.Pointer(name)),
uintptr(unsafe.Pointer(nameLen)),
uintptr(unsafe.Pointer(refdDomainName)),
uintptr(unsafe.Pointer(refdDomainNameLen)),
uintptr(unsafe.Pointer(use)),
0, 0)
if r == 0 {
err = e
}
return
}
func main() {
defer syscall.FreeLibrary(advapi32)
defer syscall.FreeLibrary(kernel32)
// get the executing program's file path and handle
var hFile, _ = CreateFile(os.Args[0], GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nil);
// defer LocalFree(Handle(unsafe.Pointer(pSD))) // PLEASE FREE pSD once done
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
var pSD *struct{} //*SECURITY_DESCRIPTOR
var pSidOwner *struct{}
GetSecurityInfo(hFile, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pSidOwner, nil, nil, nil, &pSD)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nameLen := uint32(50)
name := make([]uint16, nameLen)
domainLen := uint32(50)
domainName := make([]uint16, domainLen)
var sidUse uint32
LookupAccountSid(nil, pSidOwner, &name[0], &nameLen, &domainName[0], &domainLen, &sidUse)
var n = syscall.UTF16ToString(name)
var dn = syscall.UTF16ToString(domainName)
fmt.Printf("Account Owner = %s\n", n)
fmt.Printf("Account Owner's Domain = %s\n", dn)
}

Related

QueryDisplayConfig() does not initialize pathArray and modeArray correctly

I'm trying to set-up an easy 1-click change of the mode of my screens (extended <--> disconnected)
but my screens are assigned no ID by the QueryDisplayConfig method.
(I'm using the User32 PInvoke lib from https://github.com/AArnott/pinvoke, in addition to what you can find in the code below)
I tried:
stepping through the code with breakpoints, making sure EVERY value is the default value.
elevating VS to run with administrator privileges.
making extra sure that the flags and errors are functioning correctly.
[DllImport("User32.dll")]
public static extern int GetDisplayConfigBufferSizes(uint flags, ref uint numPathArrayElements, ref uint numModeInfoArrayElements);
[DllImport("User32.dll")]
public static extern int QueryDisplayConfig(
uint flags,
ref uint numPathArrayElements, DISPLAYCONFIG_PATH_INFO[] pathArray,
ref uint numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO[] modeInfoArray,
DISPLAYCONFIG_TOPOLOGY_ID[] currentTopologyId
);
const int QDC_ALL_PATHS = 1;
const int QDC_ONLY_ACTIVE_PATHS = 2;
const int QDC_DATABASE_CURRENT = 4;
public static void CheckDisplays() {
uint numPathArrayElements = 0;
uint numModeInfoArrayElements = 0;
uint filter = QDC_ONLY_ACTIVE_PATHS;
int bufferError = GetDisplayConfigBufferSizes(filter, ref numPathArrayElements, ref numModeInfoArrayElements);
DISPLAYCONFIG_PATH_INFO[] pathArray = new DISPLAYCONFIG_PATH_INFO[numPathArrayElements];
DISPLAYCONFIG_MODE_INFO[] modeArray = new DISPLAYCONFIG_MODE_INFO[numModeInfoArrayElements];
int queryError = QueryDisplayConfig(filter, ref numPathArrayElements, pathArray, ref numModeInfoArrayElements, modeArray, null);
Console.WriteLine();
Console.WriteLine("Elements: " + numPathArrayElements); // Prints the correct amount of connected screens.
Console.WriteLine("BUFFER ERROR: " + bufferError); // Prints 0 -- as in Success.
Console.WriteLine("PATH ERROR: " + queryError); // Prints 0 -- as in Success.
for (int i = 0; i < pathArray.Length; i++) {
if (pathArray[i].sourceInfo.id != 0) { Console.WriteLine($"Path{i} has been initialized correctly!!"); }
// Every object in the array has default values and IDs of 0.
// Nothing prints here.
}
}
Each screen should be assigned an ID and a proper mode.
Instead, everything has the default value and I seem to be stuck.
Your declaration for QueryDisplayConfig is wrong : arrays must be [Out]
This works for me :
(I have only 1 monitor but the values received in arrays are the same as in C++ (I translated structures from SDK headers))
(IntPtr.Zero for currentTopologyId with QDC_ONLY_ACTIVE_PATHS)
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int QueryDisplayConfig(uint flags, ref uint numPathArrayElements, [Out] DISPLAYCONFIG_PATH_INFO[] pathArray,
ref uint modeInfoArrayElements, [Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId);

Cast LPVOID to struct

I want to read the arguments I have send through CreateRemoteThread to my injected DLL inside another process.
I can call the function without problem, I just don't know how to cast LPVOID to a struct.
This is a example:
#pragma pack(push,1)
struct tagRemoteThreadParams
{
int Param1;
int Param2;
} RemoteThreadParams, *PRemoteThreadParams;
#pragma pack(pop)
DWORD WINAPI testfunction(LPVOID param)
{
// cast LPVOID to tagRemoteThreadParams (param)
WriteToLog("YES YOU CALLED THE FUNCTION WITH PARAM: ");
return 0;
}
This is my struct and how I have allocated the mem inside the process:
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct RemoteThreadParams
{
[MarshalAs(UnmanagedType.I4)]
public int Param1;
[MarshalAs(UnmanagedType.I4)]
public int Param2;
}
public uint CallFunction(int _arg1)
{
RemoteThreadParams arguments = new RemoteThreadParams();
arguments.Param1 = 1;
arguments.Param2 = 2;
//pointer to the function im trying to call
IntPtr _functionPtr = IntPtr.Add(this.modulePtr, 69772);
// Allocate some native heap memory in your process big enough to store the
// parameter data
IntPtr iptrtoparams = Marshal.AllocHGlobal(Marshal.SizeOf(arguments));
// Copies the data in your structure into the native heap memory just allocated
Marshal.StructureToPtr(arguments, iptrtoparams, false);
//allocate som mem in remote process
IntPtr lpAddress = VirtualAllocEx(this.processHandle, IntPtr.Zero, (IntPtr)Marshal.SizeOf(arguments), AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ExecuteReadWrite);
if (lpAddress == IntPtr.Zero)
{
return 0;
}
if (WriteProcessMemory(this.processHandle, lpAddress, iptrtoparams, (uint)Marshal.SizeOf(arguments), 0) == 0)
{
return 0;
}
//Free up memory
Marshal.FreeHGlobal(iptrtoparams);
uint threadID = 0;
IntPtr hThread = CreateRemoteThread(this.processHandle, IntPtr.Zero, 0, _functionPtr, lpAddress, 0, out threadID);
if (hThread == IntPtr.Zero)
{
//throw new ApplicationException(Marshal.GetLastWin32Error().ToString());
throw new Win32Exception();
}
WaitForSingleObject(hThread, 0xFFFFFFFF);
// wait for thread to exit
// get the thread exit code
uint exitCode = 0;
GetExitCodeThread(hThread, out exitCode);
// close thread handle
CloseHandle(hThread);
return exitCode;
}
If I understand your code correctly, you inject UT8 encoded string into the other's process memory (I'm kind of surprised that it works).
Assuming it does work, in your C++ code you need to convert the UTF8 encoded byte array pointed by param to some kind of string that C++ understands.
One way to do it is to use MultiByteToWideChar
Another way is to use STL. I found a question about it here.
And the answer to the cast problem was:
struct tagRemoteThreadParams *tData = (struct tagRemoteThreadParams *)param;
Thank you for the help guys

Show digital signature / certificate dialogs

I have PKCS #7 SignedData from an Authenticode-signed PE file. I want to show it in a dialog like this:
This is a standard Windows dialog, like you will see if you click Details on the Digital Signatures tab of a PE file.
Any idea how to do this?
I would prefer a C# solution, but the standard C API would also work (I could make a C++/CLI interface.)
Well it took a lot of research, and a bit of reverse-engineering, but I eventually got it to work.
The magic function is CryptUIDlgViewSignerInfo().
The CryptUIDlgViewSignerInfo function displays a dialog box that contains the signer information for a signed message.
Unfortunately it, along with the definition for its only argument, CRYPTUI_VIEWSIGNERINFO_STRUCT aren't in any header files. So first you need to declare:
CryptUI.h
#ifdef __cplusplus
extern "C" {
#endif
typedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT {
DWORD dwSize;
HWND hwndParent;
DWORD dwFlags;
LPCTSTR szTitle;
CMSG_SIGNER_INFO *pSignerInfo;
HCRYPTMSG hMsg;
LPCSTR pszOID;
DWORD_PTR dwReserved;
DWORD cStores;
HCERTSTORE *rghStores;
DWORD cPropSheetPages;
LPCPROPSHEETPAGE rgPropSheetPages;
} CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT;
#ifdef UNICODE
#define CryptUIDlgViewSignerInfo CryptUIDlgViewSignerInfoW
#else
#define CryptUIDlgViewSignerInfo CryptUIDlgViewSignerInfoA
#endif
BOOL WINAPI CryptUIDlgViewSignerInfo(
_In_ CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi
);
#ifdef __cplusplus
} // extern "C"
#endif
Now, this is a C++ CLI function, but it should easily work in plain C if you tweak the beginning. Of course, you'll want to do some better error checking as well, but this was just a proof-of-concept:
// Link against these libraries
#pragma comment (lib, "Crypt32")
#pragma comment (lib, "Cryptui")
void CertHelper::DoStuff(array<Byte>^ data) {
// http://stackoverflow.com/questions/17689154
pin_ptr<Byte> pData = &data[0];
CERT_BLOB blob;
blob.cbData = data->Length;
blob.pbData = pData;
BOOL res;
DWORD MsgAndCertEncodingType;
DWORD ContentType;
DWORD FormatType;
HCERTSTORE hCertStore;
HCRYPTMSG hMsg;
res = CryptQueryObject(
CERT_QUERY_OBJECT_BLOB, // dwObjectType [in]
&blob, // pvObject [in]
CERT_QUERY_CONTENT_FLAG_ALL, // dwExpectedContentTypeFlags [in]
CERT_QUERY_FORMAT_FLAG_BINARY, // dwExpectedFormatTypeFlags [in]
0, // dwFlags [in]
&MsgAndCertEncodingType, // pdwMsgAndCertEncodingType [out]
&ContentType, // pdwContentType [out]
&FormatType, // pdwFormatType [out]
&hCertStore, // phCertStore [out]
&hMsg, // phMsg [out]
NULL // ppvContext [out]
);
// Get the SignerInfo - call once to get size
DWORD cb;
res = CryptMsgGetParam(
hMsg, // hCryptMsg [in]
CMSG_SIGNER_INFO_PARAM, // dwParamType [in]
0, // dwIndex [in]
NULL, // pvData [out]
&cb // pcbData [in, out]
);
CMSG_SIGNER_INFO* signerinfo = (CMSG_SIGNER_INFO*)LocalAlloc(LPTR, cb);
res = CryptMsgGetParam(
hMsg, // hCryptMsg [in]
CMSG_SIGNER_INFO_PARAM, // dwParamType [in]
0, // dwIndex [in]
signerinfo, // pvData [out]
&cb // pcbData [in, out]
);
// Initialize the View Signer Info structure
CRYPTUI_VIEWSIGNERINFO_STRUCT vsi;
memset(&vsi, 0, sizeof(vsi));
vsi.dwSize = sizeof(vsi);
vsi.hwndParent = NULL; // TODO
vsi.dwFlags = 0; // SHDocvw.dll passes 0x14
vsi.szTitle = NULL;
vsi.pSignerInfo = signerinfo;
vsi.hMsg = hMsg;
vsi.pszOID = "1.3.6.1.5.5.7.3.3"; // XCN_OID_PKIX_KP_CODE_SIGNING
// Show the dialog already!
res = CryptUIDlgViewSignerInfo(&vsi);
// Free resources
LocalFree(signerinfo);
if (hCertStore) CertCloseStore(hCertStore, 0);
if (hMsg) CryptMsgClose(hMsg);
}
For reference sake, this was RE'd from ViewCertProperties() in shdocvw.dll.
Most of the work leading up to the CryptUIDlgViewSignerInfo call seems to be already done internally by the .NET class System.Security.Cryptography.Pkcs.SignedCms.
The two pieces required to populate the CRYPTUI_VIEWSIGNERINFO_STRUCT are already there, as private fields of SignedCms:
hMsg is SignedCms.m_safeCryptMsgHandle
pSignerInfo is SignerInfo.m_pbCmsgSignerInfo
It would be incredible if we could just call a hypothetical SignedCms.ShowSignerInfoDialog() function, or somehow have access to these members without reflection.
The following hack does however work!
class Program
{
static void Main(string[] args) {
var data = ...;
var cms = new SignedCms();
cms.Decode(data);
var pbCmsgSignerInfo = typeof(SignerInfo).GetField("m_pbCmsgSignerInfo", BindingFlags.NonPublic | BindingFlags.Instance);
var si = (SafeHandle)pbCmsgSignerInfo.GetValue(cms.SignerInfos[0]);
var safeCryptMessageHandle = typeof(SignedCms).GetField("m_safeCryptMsgHandle", BindingFlags.NonPublic | BindingFlags.Instance);
var hMsg = (SafeHandle)safeCryptMessageHandle.GetValue(cms);
var vsi = new CRYPTUI_VIEWSIGNERINFO_STRUCT {
dwSize = (uint)Marshal.SizeOf(typeof(CRYPTUI_VIEWSIGNERINFO_STRUCT)),
pSignerInfo = si,
hMsg = hMsg,
};
CryptUIDlgViewSignerInfo(ref vsi);
}
[DllImport("Cryptui.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CryptUIDlgViewSignerInfo(ref CRYPTUI_VIEWSIGNERINFO_STRUCT pcvsi);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct CRYPTUI_VIEWSIGNERINFO_STRUCT
{
public UInt32 dwSize;
public IntPtr hwndParent;
public UInt32 dwFlags;
public string szTitle;
public SafeHandle pSignerInfo;
public SafeHandle hMsg;
[MarshalAs(UnmanagedType.LPStr)]
public string pszOID;
public IntPtr dwReserved;
public UInt32 cStores;
public IntPtr rghStores;
public UInt32 cPropSheetPages;
public IntPtr rgPropSheetPages;
}

C#: AccessViolationException when trying to call an imported C++ function

I have been reading many threads about this but I can't fix it.
I'm trying to import this function (originally written in C++)
__declspec( dllexport ) int __stdcall GeekFunction(void *indices,
unsigned int *vertexRemap,
unsigned int numIndices,
unsigned int numVertices,
int indexFormat,
void *allocator);
To my C# project:
[DllImport("sce_psp2vertexcache.dll",
CallingConvention = CallingConvention.StdCall,
EntryPoint = "GeekFunction")]
unsafe private static extern int GeekFunction(
[In, Out] IntPtr indices,
[Out] IntPtr vertexRemap,
[In] UInt32 numIndices,
[In] UInt32 numVertices,
[In] int indexFormat,
[In] void* allocator);
I am calling the function this way:
UInt32[] vertexRemap = new UInt32[locs.data.Length * 6];
GCHandle handleVertexRemap = GCHandle.Alloc(vertexRemap, GCHandleType.Pinned);
GCHandle handleIndexdata = GCHandle.Alloc(indexdata, GCHandleType.Pinned);
if (GeekFunction(
GCHandle.ToIntPtr(handleIndexdata),
GCHandle.ToIntPtr(handleVertexRemap),
Convert.ToUInt32(indexdata.Length),
Convert.ToUInt32(locs.data.Length), 1, null) != 0)
StatusOutput.FatalError("Geekfunction Failed");
handleIndexdata.Free();
Am I missing something?
Finally, I have found out what was happening.
I was calling several times to GeekFunction with the same handle:
if (GeekFunction(
GCHandle.ToIntPtr(handleIndexdata),
GCHandle.ToIntPtr(handleVertexRemap),
Convert.ToUInt32(indexdata.Length),
Convert.ToUInt32(locs.data.Length), 1, null) != 0)
StatusOutput.FatalError("Geekfunction Failed");
...
if (GeekFunction(
GCHandle.ToIntPtr(handleIndexdata),
GCHandle.ToIntPtr(handleVertexRemap),
Convert.ToUInt32(indexdata.Length),
Convert.ToUInt32(locs.data.Length), 1, null) != 0)
StatusOutput.FatalError("Geekfunction Failed");
If I rebuild the handle between the calls I don't get the AccessViolationException:
try
{
if (GeekFunction(
handleBoneIndices.AddrOfPinnedObject(),
handleVertexRemap.AddrOfPinnedObject(),
Convert.ToUInt32(boneindices.data.Length),
Convert.ToUInt32(sizeof(VertexData.Index4)), null) != 0)
StatusOutput.FatalError("GeekFunctionFailed: boneIndices");
}
finally
{
handleBoneIndices.Free();
handleVertexRemap.Free();
}
**handleVertexRemap = GCHandle.Alloc(vertexRemap, GCHandleType.Pinned);**
try
{
if (scePsp2VertexCacheApplyVertexRemapping(
handleBoneIndices.AddrOfPinnedObject(),
handleVertexRemap.AddrOfPinnedObject(),
Convert.ToUInt32(boneindices.data.Length),
Convert.ToUInt32(sizeof(VertexData.Index4)), null) != 0)
StatusOutput.FatalError("scePsp2VertexCacheApplyVertexRemapping Failed: boneIndices");
}
finally
{
handleBoneIndices.Free();
handleVertexRemap.Free();
}
thank you for your help. The tests with the simpler function helped a lot.

C# to C++ process with WM_COPYDATA passing struct with strings

From a c# program I want to use WM_COPYDATA with SendMessage to communicate with a legacy c++/cli MFC application.
I want to pass a managed struct containing string objects.
I can find the handle to the c++ application for use with SendMessage fine.
The bit I don't know about is how the struct and it's strings can be marshalled and read at the other end. Especially as it contains non-blittables.
Do people think this is feasible?
I'll continue to work on it, but would apprecite someone who's done this sort of thing telling me if it just isn't going to work.
Here is some demo code if it was a c++/cli program and it's not difficult to get it working.
However, I'd like this to be in a .Net class library so it can easily be re-used.
//Quick demonstation code only, not correctly styled
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
struct MessageInfo
{
int nVersion;
char szTest[ 10 ];
};
MessageInfo sMessageInfo;
sMessageInfo.nVersion = 100;
strcpy( sMessageInfo.szTest, "TEST");
COPYDATASTRUCT CDS;
CDS.dwData = 1; //just for test
CDS.cbData = sizeof( sMessageInfo );
CDS.lpData = &sMessageInfo;
//find running processes and send them a message
//can't just search for "MYAPP.exe" as will be called "MYAPP.exe *32" on a 64bit machine
array<System::Diagnostics::Process^>^allProcesses = System::Diagnostics::Process::GetProcesses();
for each (System::Diagnostics::Process^ targetProcess in allProcesses)
{
if (targetProcess->ProcessName->StartsWith("MYAPP", System::StringComparison::OrdinalIgnoreCase))
{
HWND handle = static_cast<HWND>(targetProcess->MainWindowHandle.ToPointer());
BOOL bReturnValue = SendMessage( handle, WM_COPYDATA, (WPARAM)0, (LPARAM)&CDS ) == TRUE;
}
}
return 0;
}
I have it working.
A simple approach is to serialize the struct to a single string and transfer a string.
The swhistlesoft blog was helpful http://www.swhistlesoft.com/blog/2011/11/19/1636-wm_copydata-with-net-and-c
This may be enough to provide the simple messaging.
The struct can be re-constructed at the other end if necessary.
If a struct with any number of strings is to be marshalled as-is then it must be a fixed size, that's the main thing I wasn't getting.
The
MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9)
basically sets the size to match the c++ size which in our case is a TCHAR szTest[ 9 ];
In order to transfer a .Net struct via WM_COPYDATA from c# to c++(/cli) I had to do as follows:
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern bool SetForegroundWindow(IntPtr hWnd);
public static uint WM_COPYDATA = 74;
//from swhistlesoft
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(param));
System.Runtime.InteropServices.Marshal.StructureToPtr(param, retval, false);
return (retval);
}
//from swhistlesoft
public static void IntPtrFree(IntPtr preAllocated)
{
if (IntPtr.Zero == preAllocated) throw (new Exception("Go Home"));
System.Runtime.InteropServices.Marshal.FreeHGlobal(preAllocated);
preAllocated = IntPtr.Zero;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public uint dwData;
public int cbData;
public IntPtr lpData;
}
/// <summary>
/// Dot net version of AppInfo structure. Any changes to the structure needs reflecting here.
/// struct must be a fixed size for marshalling to work, hence the SizeConst entries
/// </summary>
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
struct AppInfoDotNet
{
public int nVersion;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 9)]
public string test;
};
To send a string:
COPYDATASTRUCT cd = new COPYDATASTRUCT();
cd.dwData = 2;
cd.cbData = parameters.Length + 1;
cd.lpData = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(parameters);
IntPtr cdBuffer = IntPtrAlloc(cd);
messageReceived = ((int)SendMessage(targetProcess.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, cdBuffer)) != 0;
To receive string in C++:
else if(pCDS->dwData == 2)
{
//copydata message
CString csMessage = (LPCTSTR)pCDS->lpData;
OutputDebugString("Copydata message received: " + csMessage);
}
To send struct:
AppInfoDotNet appInfo = new AppInfoDotNet();
appInfo.test = "a test";
COPYDATASTRUCT cds3;
cds3.dwData = 1;
cds3.cbData = System.Runtime.InteropServices.Marshal.SizeOf(appInfo);
IntPtr structPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(appInfo));
System.Runtime.InteropServices.Marshal.StructureToPtr(appInfo, structPtr, false);
cds3.lpData = structPtr;
IntPtr iPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(System.Runtime.InteropServices.Marshal.SizeOf(cds3));
System.Runtime.InteropServices.Marshal.StructureToPtr(cds3, iPtr, false);
messageReceived = ((int)SendMessage(targetProcess.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, iPtr)) != 0;
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(iPtr);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(structPtr);
To receive struct in C++:
LRESULT CMainFrame::OnCopyData( WPARAM wParam, LPARAM lParam )
{
LRESULT lResult = FALSE;
COPYDATASTRUCT *pCDS = (COPYDATASTRUCT*)lParam;
//Matching message type for struct
if(pCDS->dwData == 1)
{
AppInfo *pAppInfo = (AppInfo*)pCDS->lpData
lResult = true;
}
Please note this is demo code and needs work in terms of styling, exception handling etc, etc...
From the documentation:
The data being passed must not contain pointers or other references to objects not accessible to the application receiving the data.
So you need to pack your string into COPYDATASTRUCT.lpData. If you have a max length for each string then you can embed it in a fixed length structure
typedef struct tagMYDATA
{
char s1[80];
char s2[120];
} MYDATA;
If you have only one variable length string you can put the string at the end and use a header followed by string data
typedef struct tagMYDATA
{
int value1;
float value2;
int stringLen;
} MYDATAHEADER;
MyCDS.cbData = sizeof(MYDATAHEADER)+(int)stringData.size();
MyCDS.lpData = new BYTE[MyCDS.cbData];
memcpy(MyCDS.lpData,&dataHeader,sizeof*(MYDATAHEADER);
StringCbCopyA (
((BYTE*)MyCDS.lpData)+sizeof*(MYDATAHEADER)
,stringData.size()
,stringData.c_str());
If you have multiple variable length strings you can still use a header and allocate more spaces for every strings plus a double null terminator, or serialize everything into one XML string.

Categories

Resources