Well, I am intended to apply Marshalling between managed and unmanaged codes. That is, to retrieve the result from a c++ code to c# code. I am not intended to know the definitions of managed or unmanaged here, rather am willing to find out the proper way of doing so.
Section: Unmanaged code
File: unmanaged_operation.cpp
#pragma managed(push, off)
typedef struct _IOperation
{
double stOutput;
double* dblPtrValue;
BSTR* parseValue;
BSTR* evenValue;
BSTR* oddValue;
BSTR* stripValue;
BSTR* contextValue;
BSTR* rangeValue;
} IOperation, *LPIOperation;
#pragma managed(pop)
#if (_MANAGED == 1) || (_M_CEE == 1)
#include <vcclr.h>
using namespace System;
using namespace System::Runtime::InteropServices;
#endif
// In unmanaged_operation.h file
extern __declspec(dllexport) LPIOperation operation;
// In unmanaged_operation.cpp file
__declspec(dllexport) LPIFactory factory = new IFactory();
extern "C" __declspec(dllexport) void __stdcall Parse(/* in */ BSTR* input)
{
BSTR* value = Do_Something_With_BSTR_Input_Value(input);
String^ _output = gcnew String(*value);
IntPtr ptr = Marshal::StringToBSTR(_output);
operation->parseValue = (BSTR*)ptr.ToPointer();
Marshal::FreeBSTR(ptr);
}
extern "C" __declspec(dllexport) void __stdcall Strip(/* in */ BSTR* input)
{
BSTR* value = Do_Something_With_BSTR_Input_Value(input);
String^ _output = gcnew String(*value);
IntPtr ptr = Marshal::StringToBSTR(_output);
operation->stripValue = (BSTR*)ptr.ToPointer();
Marshal::FreeBSTR(ptr);
}
extern "C" __declspec(dllexport) void __stdcall Range(/* in */ BSTR* input)
{
BSTR* value = Do_Something_With_BSTR_Input_Value(input);
String^ _output = gcnew String(*value);
IntPtr ptr = Marshal::StringToBSTR(_output);
operation->rangeValue = (BSTR*)ptr.ToPointer();
Marshal::FreeBSTR(ptr);
}
extern "C" __declspec(dllexport) void __stdcall Operate(/* in */ double input)
{
double output = Do_Something_With_Double_Input_Value(input);
operation->stOutput = output;
}
extern "C" __declspec(dllexport) LPIOperation GetOperation()
{
return operation;
}
Section: Managed code
File: managed_operation.cs
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct IOperation
{
/* MarshalAs(UnmanagedType.R8)] */
public double stOutput;
public double[] dblPtrValue;
/* MarshalAs(UnmanagedType.BStr)] */
public string parseValue;
};
Class Program
{
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Parse([In] String input);
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Strip([In] String input);
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Range([In] String input);
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void Operate([In] Double input);
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetOperation();
[STAThread]
public static void Main(string[] args)
{
try
{
IOperation operation = new IOperation();
Parse("The parse value.");
Strip("The strip value.");
Range("The range value.");
Operate((double)2.45);
IntPtr ptr = GetOperation();
// The following line throws the exception
operation = (IOperation)(Marshal.PtrToStructure(ptr, typeof(IOperation)));
// The above line throws the exception
Console.WriteLine("{0}", operation.parseValue);
Console.WriteLine("{0}", operation.stOutput);
}
catch (Exception e)
{
throw e;
// Exception of type 'System.ExecutionEngineException' was thrown.
}
}
}
Let's say that the Do_Something_With_BSTR_Input_Value method in unmanaged_operation.cpp be:
BSTR* __stdcall Do_Something_With_BSTR_Input_Value(/* in */ BSTR* input)
{
return input;
}
only for testing purpose, rather the original cited. And I wanted to print the same value to Console, that I passed as a parameter in Parse, Strip or Range method in managed_operation.cs
I used the following code for testing purpose in unmanaged_operation.cpp:
extern "C" __declspec(dllexport) void GetOperationPtr(LPIOperation output)
{
operation->stOutput = (double)2;
operation->parseValue = (BSTR*)"The BSTR string";
*output = *operation;
// OR output = operation;
}
And used the following code in managed_operation.cs
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void GetOperationPtr([Out] [MarshalAs(UnmanagedType.Struct] out IntPtr ptr);
[STAThread]
public static void Main(string[] args)
{
try
{
IOperation operation = new IOperation();
Parse("The parse value.");
Strip("The strip value.");
Range("The range value.");
Operate((double)7.45);
IntPtr ptr;
GetOperationPtr(ptr);
// The following line throws the exception
operation = (IOperation)(Marshal.PtrToStructure(ptr, typeof(IOperation)));
// The above line throws the exception
Console.WriteLine("{0}", operation.parseValue);
Console.WriteLine("{0}", operation.stOutput);
}
catch (Exception e)
{
throw e;
// Cannot marshal 'parameter #1': Invalid managed/unmanaged type combination
// (Int/UInt must be paired with SysInt or SysUInt).
}
}
Again I changed the IntPtr to object in GetOperationPtr definition as follows:
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall)]
private static extern void GetOperationPtr([Out] [MarshalAs(UnmanagedType.Struct] out object ptr);
and in the Main method:
Object ptr;
GetOperationPtr(ptr);
which caused the application terminated instantly without being executed further.
Again when I omitted the MarshalAs attribute from the GetOperationPtr definition, the parseValue
returns garbage value something like 䕃洭獥慳敧 or 옧ﺧ㲨Ѹ㲨Ѹ or 멄攓�ѵ�ѵ rather any visible result.
To get rid of this I added the Charset parameter to DllImport attribute for GetOperation definition, as:
[DllImport(#"unmanaged_operation.dll"), CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern IntPtr GetOperation();
and used the same code in Main method as described earlier; which in such case shuffled the output value for each instance of IOperation field, as:
operation.parseValue returned "The strip value." for the method Parse("The parse value.");
operation.stripValue returned "The range value." for the method Strip("The strip value.");
operation.rangeValue returned "The parse value." for the method Range("The range value.");
Any suggestion with code example will highly be solicited.
Overall
It appears that your goal here is to call some C++ code from C#. In that case, it is generally better to write a C++/CLI managed class (keywords public ref class), and call the C++ code directly from there. You can access the managed class from C# in the normal way, just add a .Net reference and instantiate the class with C# new.
Specific issues
BSTR* value = Do_Something_With_BSTR_Input_Value(input);
String^ _output = gcnew String(*value);
IntPtr ptr = Marshal::StringToBSTR(_output);
operation->parseValue = (BSTR*)ptr.ToPointer();
Marshal::FreeBSTR(ptr);
If you're accessing a managed type (String^), it's not unmanaged code.
The way you're assigning the string is incorrect. You're allocating a new BSTR object in StringToBSTR, saving a pointer to it, and then freeing the BSTR object. You now have a pointer to deallocated/invalid memory! That memory can be re-used for anything at any time.
public struct IOperation
Don't start things with I unless they're an interface. That's the naming convention, stick with it.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct IOperation
{
/* MarshalAs(UnmanagedType.R8)] */
public double stOutput;
public double[] dblPtrValue;
/* MarshalAs(UnmanagedType.BStr)] */
public string parseValue;
};
If you're copying from unmanaged to managed, how big is the array of doubles? Which of the multitude of string representations is it supposed to use?
Recommendation
I recommend one of two things:
If you're interfacing to an unmanaged library which you are the author, consider changing that struct to be something easier to have the automatic marshaller deal with.
If you're not the author of the unmanaged library, or if you have other reasons for the struct to look like that, or if you just don't want to deal with the automatic marshaller, then do the marshalling manually: Write a C++/CLI managed class (public ref class) that takes the managed struct as a parameter, manually converts everything to the unmanaged struct, calls the unmanaged functions, and then copies everything back.
Related
i'm getting a very peculiar error when i include libevent.h.
Its not able to find redisAsyncContext struct.
This is my header file
#include <hiredis/hiredis.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libevent.h>
class RedisMgr :Thread{
public:
static RedisMgr *getRedisMgr ();
int Init();
void Start();
int End();
void* run();
int Publish(int type);
private:
static RedisMgr s_instance;
bool exitThread;
redis_t Pub_Redis;
sem_t redis_publock;
RedisMgr();
~RedisMgr ();
static void pubCallback(redisAsyncContext *c, void *r, void *privdata);
void pubCallback_Handler(redisAsyncContext *c, void *r, void *privdata);
static void connectCallback(const redisAsyncContext *c, int status);
void connectCallback_Handler(const redisAsyncContext *c, int status);
static void disconnectCallback(const redisAsyncContext *c, int status);
void disconnectCallback_Handler(const redisAsyncContext *c, int status);
};
The error is thrown from both included file libevent.h and also refisAsyncContext reference i have made in my .h
This is the error:
/usr/include/hiredis/adapters/libevent.h:11:5: error: 'redisAsyncContext' does not name a type
redisAsyncContext *context;
src/headers/RedisMgr.h:36:5: error: 'redisAsyncContext' does not name a type
redisAsyncContext *c;
I found the problem.
Somehow the async.h was replaced/changed and it no longer had definition of redisAsyncContext struct.
I downloaded the corresponding file from internet and the build just worked fine.
i should have thoroughly checked it prior to posting question- mybad
I am trying to hook outgoing connections with c#. I found this question:
Windows Filtering Platform - How can I block incoming connections based on local port?
But at sample some error with code and some missing classes to use.
I am trying to generate structs with p/invoke signature toolkit, but I have some very big class-generated code, where 90% calling dependence.
So I think I must realise external prototypes and then call them.
Here is my code:
public static class WpfProvider
{
private static void Test()
{
var RemotePort = 8080; //port to block
// connect to engine
var session = new FWPM_SESSION0_();
session.flags = 0xFFF;
IntPtr engineHandle;
FwpmEngineOpen0(null, RPC.RPC_C_AUTHN_WINNT, IntPtr.Zero, session, ref engineHandle);
// create a subLayer to attach filters to
var subLayerGuid = Guid.NewGuid();
var subLayer = new FWPM_SUBLAYER0_();
subLayer.subLayerKey = subLayerGuid;
subLayer.displayData.name = DisplayName;
subLayer.displayData.description = DisplayName;
subLayer.flags = 0;
subLayer.weight = 0x100;
FwpmSubLayerAdd0(engineHandle, subLayer, IntPtr.Zero);
var condition = new FWPM_FILTER_CONDITION0
{
fieldKey = Fwpm.FWPM_CONDITION_IP_REMOTE_PORT,
matchType = Fwpm.FWP_MATCH_TYPE.FWP_MATCH_EQUAL,
conditionValue =
{
type = Fwpm.FWP_DATA_TYPE.FWP_UINT16,
uint16 = RemotePort
}
};
// create the filter itself
var fwpFilter = new FWPM_FILTER0();
fwpFilter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
fwpFilter.action.type = FWP_ACTION_BLOCK;
fwpFilter.subLayerKey = subLayerGuid;
fwpFilter.weight.type = Fwpm.FWP_DATA_TYPE.FWP_EMPTY; // auto-weight.
fwpFilter.numFilterConditions = (uint)1;
var condsArray = new[] { condition };
var condsPtr = SafeNativeMethods.MarshalArray(condsArray); // helper to create a native array from a C# one
fwpFilter.filterCondition = condsPtr;
fwpFilter.displayData.name = DisplayName;
fwpFilter.displayData.description = DisplayName;
Microsoft.Win32.UnsaveNativeMethods
// add the filter
UInt64 filterId = 0L;
FwpmFilterAdd0(engineHandle, ref fwpFilter, IntPtr.Zero, out filterId));
}
/// Return Type: DWORD->unsigned int
///serverName: wchar_t*
///authnService: UINT32->unsigned int
///authIdentity: SEC_WINNT_AUTH_IDENTITY_W*
///session: FWPM_SESSION0*
///engineHandle: HANDLE*
[System.Runtime.InteropServices.DllImportAttribute("FWPUClnt.dll", EntryPoint = "FwpmEngineOpen0")]
public static extern uint FwpmEngineOpen0([System.Runtime.InteropServices.In()] [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string serverName, uint authnService, [System.Runtime.InteropServices.In()] IntPtr authIdentity, [System.Runtime.InteropServices.In()] IntPtr session, ref IntPtr engineHandle);
/// Return Type: DWORD->unsigned int
///engineHandle: HANDLE->void*
///subLayer: FWPM_SUBLAYER0*
///sd: PSECURITY_DESCRIPTOR->PVOID->void*
[System.Runtime.InteropServices.DllImportAttribute("FWPUClnt.dll", EntryPoint = "FwpmSubLayerAdd0")]
public static extern uint FwpmSubLayerAdd0([System.Runtime.InteropServices.In()] IntPtr engineHandle, [System.Runtime.InteropServices.In()] ref FWPM_SUBLAYER0 subLayer, [System.Runtime.InteropServices.In()] IntPtr sd);
/// Return Type: DWORD->unsigned int
///engineHandle: HANDLE->void*
///filter: FWPM_FILTER0*
///sd: PSECURITY_DESCRIPTOR->PVOID->void*
///id: UINT64*->UInt64
[System.Runtime.InteropServices.DllImportAttribute("FWPUClnt.dll", EntryPoint = "FwpmFilterAdd0")]
public static extern uint FwpmFilterAdd0([System.Runtime.InteropServices.In()] IntPtr engineHandle, [System.Runtime.InteropServices.In()] ref FWPM_FILTER0 filter, [System.Runtime.InteropServices.In()] IntPtr sd, UInt64 id);
}
static class RPC
{
public static uint RPC_C_AUTHN_NONE = 0;//No authentication.
public static uint RPC_C_AUTHN_DCE_PRIVATE = 1;//DCE private key authentication.
public static uint RPC_C_AUTHN_DCE_PUBLIC = 2;//DCE public key authentication.
public static uint RPC_C_AUTHN_DEC_PUBLIC = 4;//DEC public key authentication.Reserved for future use.
public static uint RPC_C_AUTHN_GSS_NEGOTIATE = 9;//Snego security support provider.
public static uint RPC_C_AUTHN_WINNT = 10;//NTLMSSP
public static uint RPC_C_AUTHN_GSS_SCHANNEL = 14;//Schannel security support provider. This authentication service supports SSL 2.0, SSL 3.0, TLS, and PCT.
public static uint RPC_C_AUTHN_GSS_KERBEROS = 16;//Kerberos security support provider.
public static uint RPC_C_AUTHN_DPA = 17;//DPA security support provider.
public static uint RPC_C_AUTHN_MSN = 18;//MSN security support provider.
public static uint RPC_C_AUTHN_KERNEL = 20;//Kernel security support provider.
public static uint RPC_C_AUTHN_DIGEST = 21;//Digest security support provider.
public static uint RPC_C_AUTHN_NEGO_EXTENDER = 30;//NEGO extender security support provider.
public static uint RPC_C_AUTHN_PKU2U = 31;//PKU2U security support provider.
public static uint RPC_C_AUTHN_MQ = 100;//MQ security support provider.
public static uint RPC_C_AUTHN_DEFAULT = 0xFFFFFFFF; //The system default authentication service. When this value is specified, COM uses its normal security blanket negotiation algorithm to pick an authentication service.For more information, see Security Blanket Negotiation.
}
#region WPF imports
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct GUID
{
public uint Data1;/// unsigned int
public ushort Data2;/// unsigned short
public ushort Data3;/// unsigned short
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 8)]
public string Data4;// unsigned char[8]
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SID_IDENTIFIER_AUTHORITY
{
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I1)]
public byte[] Value;// BYTE[6]
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SID
{
public byte Revision;/// BYTE->unsigned char
public byte SubAuthorityCount;/// BYTE->unsigned char
public SID_IDENTIFIER_AUTHORITY IdentifierAuthority;/// SID_IDENTIFIER_AUTHORITY->_SID_IDENTIFIER_AUTHORITY
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = System.Runtime.InteropServices.UnmanagedType.U4)]
public uint[] SubAuthority;// DWORD[1]
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SEC_WINNT_AUTH_IDENTITY_W
{
public IntPtr User;/// unsigned short*
public uint UserLength;/// unsigned int
public IntPtr Domain;/// unsigned short*
public uint DomainLength;/// unsigned int
public IntPtr Password;/// unsigned short*
public uint PasswordLength;/// unsigned int
public uint Flags;// unsigned int
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct FWP_BYTE_BLOB
{
public uint size; /// UINT32->unsigned int
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string data;// UINT8*
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct FWPM_DISPLAY_DATA0
{
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public string name;// wchar_t*
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public string description;// wchar_t*
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct FWPM_SESSION0
{
public GUID sessionKey;/// GUID->_GUID
public FWPM_DISPLAY_DATA0 displayData;/// FWPM_DISPLAY_DATA0->FWPM_DISPLAY_DATA0_
public uint flags;/// UINT32->unsigned int
public uint txnWaitTimeoutInMSec;/// UINT32->unsigned int
public uint processId;/// DWORD->unsigned int
public IntPtr sid;/// SID*
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
public string username;/// wchar_t*
public int kernelMode;// BOOL->int
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct FWPM_SUBLAYER0
{
public GUID subLayerKey;/// GUID->_GUID
public FWPM_DISPLAY_DATA0 displayData;/// FWPM_DISPLAY_DATA0->FWPM_DISPLAY_DATA0_
public ushort flags;/// UINT16->unsigned short
public IntPtr providerKey;/// GUID*
public FWP_BYTE_BLOB providerData;/// FWP_BYTE_BLOB->FWP_BYTE_BLOB_
public ushort weight;// UINT16->unsigned short
}
Thanks
This is the first time I try to hook windows API. My goal is to monitor all files that a process is going to create/open/read/write.
In order to be the most verbose possible, I decided to hook the ntdll.dll API such as NtCreateFile() and NtOpenFile(). So, in order to acheive this goal, I went on EasyHook, which seems easy and robust.
I've essetially followed the FileMon example, changing what I really wanted: the Hooked function.
When I try to read information about the file that is going to be opened, I try to read information from the OBJECT_ATTRIBUTES structure, such as
the ObjectName. Those are integer pointers, so I expected to use the function Marshal.PtrToStringAuto(attributes.objectName) in order to get the string value. However, the result is I can only have bad strings, without any meaning. Also, the File access seems to be not working. I guess there's something wrong with this
code, maybe in the DllImport signatures. Be adviced I had to replace SafeHandle with IntPtr, because of EasyHook was complaining about marshaling them.
Can someone help me?
Here's my specific code of the injected DLL:
Here's the Run method code
public void Run(RemoteHooking.IContext InContext, String inChannelName)
{
// First of all, install all the hooks
try
{
// NtCreateFile
fileCreationHook = LocalHook.Create(
LocalHook.GetProcAddress("ntdll.dll", "NtCreateFile"),
new CreateFileDelegate(CreateFile_Hooked),
this
);
fileCreationHook = LocalHook.Create(
LocalHook.GetProcAddress("ntdll.dll", "NtOpenFile"),
new OpenFileDelegate(OpenFile_Hooked),
this
);
fileCreationHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
remoteIf.Log("File creation Hook correctly installed on pid "+RemoteHooking.GetCurrentProcessId());
}
catch (Exception e)
{
remoteIf.Log(e.Message);
remoteIf.Log(e.StackTrace);
return;
}
// Wake up the process
remoteIf.Log("Waiking up process...");
RemoteHooking.WakeUpProcess();
while (true)
{
Thread.Sleep(500);
if (queue.Count > 0)
{
String[] package = null;
lock (queue)
{
package = queue.ToArray();
queue.Clear();
}
remoteIf.OnCreateFile(RemoteHooking.GetCurrentProcessId(), package);
}
else
remoteIf.Ping();
}
}
Here's the contructor code:
public InjectedDLL(RemoteHooking.IContext InContext, String inChannelName)
{
// Create the structure which will contain all the messages
queue = new Stack<string>();
// Initiate the connection to the Injector process, getting back its interface
remoteIf = RemoteHooking.IpcConnectClient<IPCInterface>(inChannelName);
// Try invocating a method to test the connection.
remoteIf.Ping();
}
Here there are the Hook delegate and the hook function
public delegate int CreateFileDelegate(out IntPtr handle,
System.IO.FileAccess access,
ref OBJECT_ATTRIBUTES objectAttributes,
out IO_STATUS_BLOCK ioStatus,
ref long allocSize,
uint fileAttributes,
System.IO.FileShare share,
uint createDisposition,
uint createOptions,
IntPtr eaBuffer,
uint eaLength);
public int CreateFile_Hooked(
out IntPtr handle,
System.IO.FileAccess access,
ref OBJECT_ATTRIBUTES objectAttributes,
out IO_STATUS_BLOCK ioStatus,
ref long allocSize,
uint fileAttributes,
System.IO.FileShare share,
uint createDisposition,
uint createOptions,
IntPtr eaBuffer,
uint eaLength)
{
//string s = Marshal.PtrToStringAuto(objectAttributes.ObjectName);
int res = NtCreateFile(out handle, access,ref objectAttributes,out ioStatus, ref allocSize,fileAttributes, share,createDisposition,createOptions,eaBuffer,eaLength);
return res;
}
Here there are the NtDll.Dll native functions:
[DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
public static extern int NtCreateFile(
out IntPtr handle,
System.IO.FileAccess access,
ref OBJECT_ATTRIBUTES objectAttributes,
out IO_STATUS_BLOCK ioStatus,
ref long allocSize,
uint fileAttributes,
System.IO.FileShare share,
uint createDisposition,
uint createOptions,
IntPtr eaBuffer,
uint eaLength);
[DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)]
public static extern int NtOpenFile(
out IntPtr handle,
System.IO.FileAccess access,
ref OBJECT_ATTRIBUTES objectAttributes,
out IO_STATUS_BLOCK ioStatus,
System.IO.FileShare share,
uint openOptions
);
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct OBJECT_ATTRIBUTES
{
public Int32 Length;
public IntPtr RootDirectory;
public IntPtr ObjectName;
public uint Attributes;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct IO_STATUS_BLOCK
{
public uint status;
public IntPtr information;
}
ObjectName is a pointer to a UNICODE_STRING struct. A managed equivalent looks like this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)]
public String Buffer;
}
You need to use marshalling to get a managed copy of the struct.
var us = Marshal.PtrToStructure<UNICODE_STRING>(objectAttributes.ObjectName);
Once you have the managed struct you can access the Buffer field to get the name of the object.
This is a class library clr/c++ project.
Class A is unmanaged c++, class B managed c++.
I would like to create an object of B from a C# application and call the "void Sign" with that object and catch the StatusEvent in C#.
How to call B::Showsts from A::call_A in order to achieve this? Please keep in mind that call_A is called from a delegate of the B class object.
Thank you in advance!
public class A{
public:
int call_A();
};
public ref class B{
private:
A* a1;
public:
void Sign(String^ ufile);
void Showsts(string sts);
delegate void GetResult(String^);
event GetResult^ StatusEvent;
SpyrusLib(void){
a1=new A();
}
protected: ~SpyrusLib(){
delete a1;
}
private:
String^ str;
delegate int MySignDelegate(String^);
int MySign(String^ file);
void Callbacksign(IAsyncResult ^ar);
};
void B::Sign(String^ ufile){
MySignDelegate^ signDel = gcnew MySignDelegate( this, &B::MySign );
AsyncCallback^ cb = gcnew AsyncCallback( this, &B::Callbacksign);
signDel->BeginInvoke( ufile , cb, signDel );
}
int B::MySign(String^ file){
stdstr=msclr::interop::marshal_as<std::string>(file);
a1->call_A(stdstr);
}
void B::Showsts(string sts){
str = gcnew String(sts.c_str());
StatusEvent(str);
}
int A::call_A(string stat){
?-Showsts(stat);
}
I'm not sure it's the best solution but I solved it adding the following things to the classes:
typedef void (__stdcall * Unmanagedstatus)(string sts);
using namespace std;
public class A{
private:
Unmanagedstatus sendmsg;
public:
int call_A();
spyrus(Unmanagedstatus unm)
{
sendmsg=unm;
}
};
public ref class B
{
private:
delegate void Managedstatus(string);
Managedstatus^ managed;
IntPtr unmanaged;
A* a1;
public:
SpyrusLib(void)
{
managed = gcnew Managedstatus(this, &B::Showsts);
unmanaged = Marshal::GetFunctionPointerForDelegate(managed);
a1=new A((Unmanagedstatus)(void*)unmanaged);
}
}
int A::call_A(string stat){
sendmsg(stat); // this will call B::Showsts and the events raised
//from Showsts are also working in the C# app
}
I have an interface, and I was trying an example on dynamic polymorphism as follows:
#include <iostream>
using namespace std;
class foo{
public:
virtual void set();
virtual void printValue();
};
class fooInt : public foo{
private:
int i;
public:
int get(){
return i;
}
void set(int val){ //override the set
i = val;
}
void printValue(){
cout << i << endl;
}
};
int main(){
foo *dt; //Create a base class pointer
dt = new fooInt; //Assign a sub class reference
dt->set(9);
}
However when I compile this, I get no matching function for call to ‘foo::set(int)’. Where am I going wrong? I tried to read this article, and I still couldn't figure out the mistake.
class foo has no method set(int). It has a method set(), but no method set(int).
If you intend to override an inherited method, the superclass method and your method must have the same signature:
class foo {
...
// If you really want an abstract class, the `= 0`
// ensures no instances can be created (makes it "pure virtual")
virtual void set(int) = 0;
...
}
This is because your definition of
virtual void set();
Should be
virtual void set(int val);
The corrected program is given here
#include <iostream>
using namespace std;
class foo {
public:
virtual void set(int val)=0;////////here you have void set() function with no argument but you tried to override void set(int val) which take one argument.
virtual void printValue()=0;
};
class fooInt : public foo{
private:
int i;
public:
fooInt()
{
cout<<"constructor called\n";
}
int get(){
return i;
}
void set(int val){ //override the set
i = val;
}
void printValue(){
cout << i << endl;
}
};
int main(){
foo *dt; //Create a base class pointer
dt=new fooInt;
dt->set(9);
dt->printValue();
}
Fault of the previous program were
1.You tried to override set() {no argument} with set(int val){one argument}.
2.When a class contain a pure virtual function,it must be implemented by its derived classes.
3. No object can be created of a class which contain a pure virtual function.But ref can be created.
Thanks