Error when invoking a method through .NET COM interop - c#

I am trying to use the IOfficeAntiVirus COM interface to invoke a scan using the Microsoft security essentials virus scanner.
I am doing early binding because the documentation says that IOfficeAntiVirus interface inherits from IUknown and does not support IDispatch.
[Guid("56FFCC30-D398-11d0-B2AE-00A0C908FA49"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
public interface IOfficeAntiVirus
{
void Scan(IntPtr info);
}
[ComImport, Guid("2781761E-28E1-4109-99FE-B9D127C57AFE")]
class SecurityEssentialsAntiVirus
{
}
The parameter for the scan method is a type that comes from this example. That example does the opposite of what I want because it implements the IOfficeAntiVirus interface using a .NET class rather than invoking the scan method. The marshalling and types in the example seem to match the documentation as far as I can tell.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MSOAVINFO
{
public int cbsize;
[MarshalAs(UnmanagedType.U4)]
public uint uFlags;
public IntPtr hwnd;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzFullPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzHostname;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzOrigURL;
}
This is the code I'm trying to use to invoke the scan method:
var antivirus = (IOfficeAntiVirus)new SecurityEssentialsAntiVirus();
var file = new MSOAVINFO();
file.pwzFullPath = #"test.txt";
IntPtr lParam = Marshal.AllocHGlobal(Marshal.SizeOf(file));
Marshal.StructureToPtr(file, lParam, false);
antivirus.Scan(lParam);
It fails on the call to the scan method. I get an exception that says:
"Attempted to read or write protected memory. This is often an
indication that other memory is corrupt."
I'm running this from a 32 bit command line app on a 64 bit system. I have experimented with running the command line program in both 32 bit and 64 bit with no success.
I am sure that the IOfficeAntiVirus guid is correct because I got it from the documentation. Also trying a random GUID that isn't a COM interface causes an error when I try to cast the object to the interface.
I am sure that the SecurityEssentialsAntiVirus guid implements the IOfficeAntiVirus because when I tried casting a different type of COM object to that interface I got an error.
I think the problem might be that the Scan method on the interface hasn't been correctly declared (declaring a random method on the interface gives the same error). I am not working from documentation for the security essentials assembly so it might not implement the interface in the way I imagine (or at all). Does anyone have any idea how to check that?
I can see a MpOAv.dll file in its directory and that is the same name as the header file in the IOfficeAntiVirus documentation, I know that's not a lot to go on. I can't open that dll up in ole-com object viewer to see what is inside. I get a message saying:
IMoniker::BindToObject failed on the file moniker created from (
"C:\Program Files\Microsoft Security Client\MpOAv.dll" ). Bad
extension for file
MK_E_INVALIDEXTENSION ($800401E6)
It also could be that I'm not passing the struct correctly to the Scan method. I have tried about a hundred variations without any luck including using AllocCoTaskMem() and passing the struct by reference.
I'm really not had much experience doing interop (learnt a heap today trying to figure this out!) so I'd really appreciate a push in the right direction. :)

I'm was also spent a couple of days on the same problem but without any results. The maximum what I was able to do it run check without any errors but even for malware it returns OK status, in my case
So, I continued research and found that Mozilla uses IAttachmentExecute antivirus API for checks. And Save method, of it, doing same job like
Scan of IOfficeAntiVirus
IAttachmentExecute::Save may run virus scanners or other trust
services to validate the file before saving it. Note that these
services can delete or alter the file.
and implementation of it on codeples http://antivirusscanner.codeplex.com/

One thing I notice is that you didn't set cbsize. file.cbsize=Marshal.SizeOf(file);

Related

C# interop with complex C++ library (STMCubeProgrammer)

I am trying to wrap the public API in a DLL file for the STMCubeProgrammer in C#. There is header file, documentation, and some C++ examples provided for the library.
The examples projects works well, so I can connect, read, write the target with them.
When I try to wrap the first function which is used in the example from the DLL, and I try to call it from C# simply just nothing happens.
This is the example code (important part):
debugConnectParameters *stLinkList;
int getStlinkListNb = getStLinkList(&stLinkList, 0);
This is from the header file for the DLL:
int getStLinkList(debugConnectParameters** stLinkList, int shared);
With this I get for getStlinkListNb = 1 as 1 STLink is connected
Here is the C# Dll import part:
[DllImport(#"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\api\lib\CubeProgrammer_API.dll")]
public static extern int getStLinkList(ref IntPtr stLinkList, int shared);
And here is my code in my test method:
IntPtr list = IntPtr.Zero;
var count = CubeProgrammerAPI.getStLinkList(ref list ,0);
But nothing happens, count is zero, list is zero, there is no error. I tried different verisons like this with ref, also out, used the In, Out attributes in the method prototype.
I tried with unsafe and pointers:
[DllImport(#"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\api\lib\CubeProgrammer_API.dll")]
public static unsafe extern int getStLinkList(debugConnectParameters** stLinkList, int shared);
CubeProgrammerAPI.debugConnectParameters *dbgParams;
var count = CubeProgrammerAPI.getStLinkList(&dbgParams, 0);
But nothing again
I tried with safe code also, ref array of the struct itself, but nothing happens, no error.
Can somebody help me? Is it normal, that I do not get any error but it is not working either?
Thanks for the help!
Okay I found the problem on an other topic. It is not interop related but related to the DLL I wanted to wrap (mostly).
This is the solution: https://stackoverflow.com/a/62924001/6330997

C# wrapper (pinvoke) for Debian apt library libapt-pkg

I need to retrieve package information in my C# application running on Linux.
I've tried to use Python.NET which wrap python-apt which wrap libapt-pkg.so, and it works but I would prefer to go more direct by pinvoke libapt-pkg.
But I need help on my DLLImport statement.
When using python-apt I first initialize the apt module, then instantiat the Cache() class and then called the Cache.keys() function which retrieve all package-names as a string array.
If I can get this to work using pinvoke I believe I have a good chance getting the rest working too (retrieve the more advanced stuff)
Just to show some code which doesn't work, but just to get started:
[DllImport("libapt-pkg")]
public static extern dynamic GetPkgCache();
dynamic AptCache = GetPkgCache();
I get the error:
System.Runtime.InteropServices.MarshalDirectiveException: 'Cannot
marshal 'return value': Invalid managed/unmanaged type combination
(Marshaling to and from COM VARIANTs isn't supported).'
I've been looking in the header file cachefile.h of the apt project. Maybe these lines are useable for my DllImport statement?
..
inline operator pkgCache &() const {return *Cache;};
inline operator pkgCache *() const {return Cache;};
..
inline pkgCache* GetPkgCache() { BuildCaches(NULL, false); return Cache; };
..
But I'm new to C/C++ so it doesn't make much sense for me at present.
UPDATE:
Thanks for the feedback.
[DllImport("libapt-pkg")]
public static extern IntPtr GetPkgCache();
Now I get the error
System.EntryPointNotFoundException: 'Unable to find an entry point
named 'GetPkgCache' in shared library 'libapt-pkg'.'

The return value of methods when adding a COM Reference generated proxy stub in C#

I have this method in my ATL project which exposes a COM object (snippet taken from my *.idl file):
[id(1)] HRESULT Create([in, string] CHAR* location, [out] CerberusErrorDetails* details);
After registering my object and adding a reference to it from my managed C# code, it generates the following proxy stub C# code for this method:
[DispId(1)]
void Create(string location, out CerberusErrorDetails details);
There are a few problems with this stub for me which I have been unable to sort out. Firstly, it does not return an int value (with respect to the returned HRESULT) in managed code to tell me what error has actually occurred. Secondly, the method will throw an exception instead of returning the error code. Is there a way to have the function return an int such that I can then parse the details object if it does not return 0, or are there any alternatives to get the behavior I want? Any help is greatly appreciated. If you need more details, feel free to ask and I'll update the question. Thank you!
Yes, it's possible to bypass the default exception translation behavior of the COM interop layer. However, you'll have to redefine your native COM interface and decorate all methods with the PreserveSig attribute:
[ComImport]
[Guid("xxx-yyy-zzz")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICOMInterfaceImp
{
[PreserveSig]
int Create(string location, out CerberusErrorDetails details);
}
You can then use this interface in your client:
ICOMInterfaceImp obj = (ICOMInterfaceImp)new CoClassImpl();
As an alternative, you may also use the updated type library importer (tlbimp.exe) from here and pass the /PreserveSig flag.

Is it possible to use RoGetMetaDataFile from non Windows Store App

After reading Larry Osterman's response on the very same issue I am trying to solve at the moment, I thought I had found the answer to my question.
For the record, the question was : how can I from .Net (non-WinRT) list the types in a WinRT assembly ( mine are .dll files apparently, not .Winmd)
I therefore used the following code snippet :
//note, this wrapper function returns the metadata file name and token
// it immediately releases the importer pointer
static Tuple<string, UInt32> ResolveTypeName(string typename)
{
string path;
object importer = null;
UInt32 token;
try
{
var hr = RoGetMetaDataFile(typename, IntPtr.Zero, out path, out importer, out token);
//TODO: check HR for error
return Tuple.Create(path, token);
}
finally
{
Marshal.ReleaseComObject(importer);
}
}
[DllImport("WinTypes.dll")]
static extern UInt32 RoGetMetaDataFile(
[MarshalAs(UnmanagedType.HString)] string name,
IntPtr metaDataDispenser,
[MarshalAs(UnmanagedType.HString)] out string metaDataFilePath,
[MarshalAs(UnmanagedType.Interface)] out object metaDataImport,
out UInt32 typeDefToken);
( found on https://gist.github.com/2920743)
Unfortunately, I get a non-zero HResult.
I referred to the documentation and found this :
HR_RESULT_FROM_WIN32(ERROR_NO_PACKAGE) The function was called from a
process that is not in a Windows Store app.
Does that mean it is not possible to list the types from .Net (non-WinRT) at all ?
RoGetMetaDataFile is used to load a metadata file from within an app package. It locates the metadata file in which the named type is defined, loads that metadata file, and returns an IMetaDataImport interface pointer that represents that metadata file.
From ordinary .NET code you can call RuntimeEnvironment.GetRuntimeInterfaceAsIntPtr (or GetRuntimeInterfaceAsObject) to get the current runtime's IMetaDataDispenser interface pointer, which can be used to load arbitrary modules for inspection.
From native code, you can call ICLRMetaHost::GetRuntime to load a runtime, then from that object call ICLRRuntimeInfo::GetInterface to get its IMetaDataDispenser interface pointer.
RoGetMetaDataFile can be used from outside the app package, however it will only resolve system windows runtime types.
In order to resolve app specific types, you need to be running with "package identity" - in other words, in the context of a running application.

Access Violation Exception

I am having some strange problem. I have written a small module in VC++ using OpenCV.
It works fine. The code aggregates feed from the CCTV camera connected to the USB port.
however, I had to write the rest of my application in C#, so I made a DLL of the VC++ code and called the VC++ method from C#.
Now, I have ended up getting an error
Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
Can anyone please suggest me any solution to this. Is there any Access Violation while accessing it in a managed code?
If TrackBlob returns a string, you should be able to define your dllimport as such:
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static string TrackBlob();
and skip trying to marshal it.
By returning it as an IntPtr, you're trying to get a pointer into memory owned by the unmanaged DLL... returning it as a string will return a copy of the string for you to work with.
Let me know if that works!
James
* Edit *
Try one of these:
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static [MarshalAs(UnmanagedType.BStr)] string TrackBlob();
or
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static [MarshalAs(UnmanagedType.AnsiBStr)] string TrackBlob();
Check out this MSDN link on string marshalling:
http://msdn.microsoft.com/en-us/library/s9ts558h.aspx

Categories

Resources