should I just set SuppressUnmanagedCodeSecurity for maximum performance? - c#

Am I correct that if I need maximum performance, and I have trusted library I should just set SuppressUnmanagedCodeSecurity attribute to all Dll imports I have?
I.e. convert such import:
[DllImport("srl.dll", CharSet = CharSet.Ansi)]
private static extern string ErrorMsg(int ErrCode);
to such import:
[DllImport("srl.dll", CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity]
private static extern string ErrorMsg(int ErrCode);
everywhere.
Are there any reasons not to set SuppressUnmanagedCodeSecurity?

Related

How to call c++ unmanaged code in C# wrapper?

I have C# wrapper project that uses C++ unmanaged dll code with help of [DllImport] attribute and static extern methods. This is the preferred method described by MSDN.
The problem is that we can have only one of the c++ runner, which means we can't run tasks in parallel.
How to call the unmanaged C++ without using the dllimport + static extern methods so that when we instantiate one of the c# objects it instantiates a new c++ dll object
This is how we are calling C++ code right now.
public class FMU : IDisposable
{
[DllImport("FMU.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
private static extern IntPtr Load(string fmuFileName, bool isCoSimulation, AddMessageDelegate messageDelegate, int arrayLocation);
[DllImport("FMU.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Instantiate(IntPtr fmu, bool isCoSimulation, bool loggingOn, int nCategories, string[] categories);
[DllImport("kernel32", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);

Why do I need to define DLLImport with EntryPoint attribute

While going through SWig generated wrappers, I find that the PInvokes don't have any entry point defined, but some places do have an entry point. So what is the difference between them? When do I need to define an EntryPoint, and when do I not need to?
Defined without EntryPoint:
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
public static extern bool ReadFile(
HandleRef hndRef,
StringBuilder buffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
int flag);
Defined with Entrypoint:
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "ReadFile")]
public static extern bool ReadFile2(
HandleRef hndRef,
StringBuilder buffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
Overlapped2 flag);
Also why does the function have to be static as in public static extern? I assume that extern is telling the compiler that this method is defined externally?
The EntryPoint field serves to tell the .NET runtime which function to call from the DLL being invoked; if it's not set, the default is the same name that the .NET method declaration has. In your second example, omitting EntryPoint = "ReadFile" would result in the runtime trying to call a function named ReadFile2 (which does not exist).
The prototype needs to have the static and extern modifiers because the specification says so. It does not need to be public; controlling the visibility of the method is entirely up to you.

How do you format an SD card using the Storage Manager API via Windows Mobile 6

Background:
I'm trying to create a utility that will allow our customers to easily format an SD card (actually mini-SD) directly on a Windows Mobile 6 device (Intermec CK3). This would be preferred over a thrid party tool such as FlashFormat or having to provide card readers to the customers (which would require them to remove the battery, pull out the mini-SD card which is held in by a flimsy metal housing, and then run the Windows formatting utility via the file management control). Most of our customers are not very tech-savvy, so a utility that can be run automatically or via a couple clicks would be ideal.
I've tried the following so far:
Looked at this question. The answers in here do not seem to work for Windows Mobile (e.g. no WMI support or format.com utility).
Tried using CreateFile and DeviceIoControlCE. This one seemed promising, but the SD card would never seem to actually format. From what I could tell, it was because the card needed to be dismounted first.
Tried using CreatFile and FormatVolumeEx (along with the other variants, FormatVolume and FormateVolumeUI). The result seemed to be similar in that I could not format the card unless it was first dismounted.
After doing some searching an running into this thread (answer near bottom by paraGOD) and this blog, I decided to go down a new path of using the Store Manager API, which has such functions as FindFirstStore, FindNextStore, OpenStore, DismountStore and so on.
I'm trying to do this in C#, so I created the necessary supporting structs to represent the typdefs used in the API. Here is a sample one:
using System.Runtime.InteropServices;
// Try to match the struct typedef exactly (all caps, exact type names).
using DWORD = System.UInt32;
using TCHAR = System.String;
namespace SDFormatter
{
// http://msdn.microsoft.com/en-us/library/ee490035(v=WinEmbedded.60).aspx
// STORAGEDEVICEINFO (Storage Manager)
[StructLayout(LayoutKind.Sequential)]
public struct StorageDeviceInfo
{
public DWORD cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public TCHAR szProfile;
public DWORD dwDeviceClass;
public DWORD dwDeviceType;
public DWORD dwDeviceFlags;
}
}
Then I created a static storage manager class to hold all of the storage manager functions (which are supposed to be available in coredll for windows mobile 6... or so I thought):
using System.Runtime.InteropServices;
// Try to match the Coredll functions exactly (all caps, exact type names, etc.).
using BOOL = System.Boolean;
using BYTE = System.Byte;
using DWORD = System.UInt32;
using HANDLE = System.IntPtr;
using LPCE_VOLUME_INFO = System.IntPtr;
using LPCSTR = System.String;
using LPCTSTR = System.String;
using LPCWSTR = System.String;
using PPARTINFO = System.IntPtr;
using PSTOREINFO = System.IntPtr;
using SECTORNUM = System.UInt64;
// ReSharper disable InconsistentNaming
namespace SDFormatter
{
// http://msdn.microsoft.com/en-us/library/ee490420(v=WinEmbedded.60).aspx
public static class StorageManager
{
[DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CeGetVolumeInfo(LPCWSTR pszRootPath, CE_VOLUME_INFO_LEVEL InfoLevel,
LPCE_VOLUME_INFO lpVolumeInfo);
[DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CreatePartition(HANDLE hStore, LPCTSTR szPartitionName, SECTORNUM snNumSectors);
[DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CreatePartitionEx(HANDLE hStore, LPCTSTR szPartitionName, BYTE bPartType,
SECTORNUM snNumSectors);
[DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool DeletePartition(HANDLE hStore, LPCTSTR szPartitionName);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool DismountPartition(HANDLE hPartition);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool DismountStore(HANDLE hStore);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool FindClosePartition(HANDLE hSearch);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool FindCloseStore(HANDLE hSearch);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern HANDLE FindFirstPartition(HANDLE hStore, PPARTINFO pPartInfo);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern HANDLE FindFirstStore(PSTOREINFO pStoreInfo);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool FindNextPartition(HANDLE hSearch, PPARTINFO pPartInfo);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool FindNextStore(HANDLE hSearch, PSTOREINFO pStoreInfo);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool FormatPartition(HANDLE hPartition);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool FormatPartitionEx(HANDLE hPartition, BYTE bPartType, BOOL bAuto);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool FormatStore(HANDLE hStore);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool GetPartitionInfo(HANDLE hPartition, PPARTINFO pPartInfo);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool GetStoreInfo(HANDLE hStore, PSTOREINFO pStoreInfo);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool MountPartition(HANDLE hPartition);
[DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern HANDLE OpenPartition(HANDLE hStore, LPCTSTR szPartitionName);
[DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern HANDLE OpenStore(LPCSTR szDeviceName);
[DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool RenamePartition(HANDLE hPartition, LPCTSTR szNewName);
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool SetPartitionAttributes(HANDLE hPartition, DWORD dwAttrs);
// http://msdn.microsoft.com/en-us/library/ee490442(v=winembedded.60).aspx
[DllImport("Coredll.dll", SetLastError = true)]
public static extern bool CloseHandle(HANDLE hObject);
}
public enum CE_VOLUME_INFO_LEVEL
{
CeVolumeInfoLevelStandard = 0
}
}
// ReSharper restore InconsistentNaming
So I went to test some of these functions, such as simply enumerating through the stores via the FindFirstStore and FindNextStore functions and then I get the dreaded, Can't find an Entry Point 'FindFirstStore' in a PInvoke DLL 'Coredll.dll' error (in the debugger output I also get A first chance exception of type 'System.MissingMethodException' occurred in SDFormatter.exe, which makes sense). Some more research hinted that in Windows Mobile, these functions aren't exposed, even though they are part of Coredll. They are however part of Windows CE 6 and can be accessed via platform builder.
So here are the main questions I have:
Can I access the Storage Manager API via C# in Windows Mobile 6 some how?
If not, can I write a utility via managed C++ (I'm don't know much, but I'll stumble through it if necessary), but without having to use platform builder (it's not free)?
If it is only possible via platform builder, does that mean I'm either stuck building my own SDK or will have to ask Intermec to expose the functionality for me?
I'm also open to doing this another way entirely (preferrably via C#) if anyone has suggestions. I was thinking maybe having the customer mount the device in the cradle and running a desktop utility. Not sure if this is possible and it can't rely on ActiveSync (we don't want to support yet another tool, so we send data to and from the SD card via a network adapter connected to the cradle using sockets to talk between our custom server program and our mobile application).
Thanks
We had the exact same requirement, but on Windows CE. Our solution was to create a small C++ application, which is then called from the C# code. Here is the most important part of the C++ application:
#include <windows.h>
#include <Storemgr.h>
int _tmain( int /*argc*/, _TCHAR* /*argv*/[] )
{
WCHAR szDisk[] = L"DSK0";
hDsk = OpenStore(szDisk);
if(hDsk == INVALID_HANDLE_VALUE)
// ERROR : Opening Store
if (!GetStoreInfo(hDsk, &si))
// ERROR : Getting Store Info
if(!DismountStore(hDsk))
// ERROR : Dismounting Store
if(!FormatStore(hDsk))
// ERROR : Formatting Store
CloseHandle(hDsk);
}
FindFirstStore is available on Windows Mobile 5.0 and later devices in the public API, so you shouldn't need anything fancy like platform builder.
I think I read somewhere that FindFirstStore was only moved to coredll.dll in CE6 (I can't remember where I saw that). So, your Windows Mobile 6 device will probably have it exported from somewhere else. (possibly storeapi.dll?)
Try creating a C++ project with this code and see if it works for you:
#pragma comment( lib, "storeapi.lib" )
int _tmain( int /*argc*/, _TCHAR* /*argv*/[] )
{
STOREINFO si = { 0 };
si.cbSize = sizeof( STOREINFO );
HANDLE ffs = ::FindFirstStore( &si );
if( INVALID_HANDLE_VALUE != ffs )
{
::FindCloseStore( ffs );
}
return 0;
}

Create an API in C# which can be called from it's DLL

I know the title is bit confusing for my question.
Let me explain:-
There are some DLLs written by my seniors and I use them in C# as follows:
Say, Existing DLL name is SeniorDLL and I want to use function SeniorFunc from that DLL.
What I do is:-
private delegate int SeniorFunc(IntPtr Blah);
[DllImport("kernel32")]
public extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
SeniorFunc fp_Senior;
and in function where I want to use this function, Before first function call I write:
IntPtr handle;
handle = IntPtr.Zero;
handle = LoadLibrary("<DLL Path>");
IntPtr fPtr = GetProcAddress(handle, "SeniorFunc");
fp_Senior = (SeniorFunc)Marshal.GetDelegateForFunctionPointer(fPtr, typeof(SeniorFunc));
and then I use this function via fp_Senior(<Parameter>);
Now I want to create such DLL for me in C# by which I'll be able to call functions from DLL.
Currently I created a DLL but I have create an instance of class in DLL and then have to access like ClassInstance.MyFunction(<Parameters>);
How can I get directly function calls without creating an instance?
In other words, (I don't know I am correct or wrong) How can I create APIs??
Thanks!!
You don't need an instance here, everything can be static. Something like this, with the necessary error checking added:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
internal static class NativeMethods {
public static void SeniorFunc(IntPtr arg) {
if (fp_Senior == null) lookUpSenior();
fp_Senior(arg);
}
private static void lookUpSenior() {
loadSenior();
IntPtr addr = GetProcAddress(SeniorModule, "seniorfunc");
if (addr == IntPtr.Zero) throw new Win32Exception();
fp_Senior = (SeniorFuncDelegate)Marshal.GetDelegateForFunctionPointer(addr, typeof(SeniorFuncDelegate));
}
private static void loadSenior() {
if (SeniorModule == IntPtr.Zero) {
SeniorModule = LoadLibrary("mumble.dll");
if (SeniorModule == IntPtr.Zero) throw new Win32Exception();
}
}
private static IntPtr SeniorModule;
private delegate int SeniorFuncDelegate(IntPtr Blah);
private static SeniorFuncDelegate fp_Senior;
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
private extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
}
The point of keeping lookupSenior in a separate method is to allow SeniorFunc() to get inlined so it is fast. If you know you'll always use these functions in your program then you can also write a static constructor for the class and do the lookup there. Saves the null check but makes an exception a bit harder to interpret.
There is no such a thing as a method outside a class in C#. So if you must call a method, you have to specify the class name.
The difference with the DLLs you are currently using is that those DLLs are written in C/C++ or other non-.NET language which does not enforce a strict object-oriented approach like C# does.
Thus, nothing forces you to create an instance of a class when calling a method from a .NET library. If a method is declared as static, you can call it directly through ClassName.MethodName().

C# EntryPointNotFoundException Unable to find an entry point named 'SetDllDirectory' in DLL 'kernel32.dll'

I am trying to use several functions from kernal32.dll. However, when my application tries to call the first function it throws an EntryPointNotFoundException Unable to find an entry point named 'SetDllDirectory' in DLL 'kernel32.dll'.
public class MyClass
{
/// <summary>
/// Use to interface to kernel32.dll for dynamic loading of similar DLLs.
/// </summary>
internal static class UnsafeNativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
internal static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
}
private void MyFunc()
{
if (UnsafeNativeMethods.SetDllDirectory(_location) == false) // <-- Exception thrown here.
{
throw new FileNotFoundException(_location);
}
/* Some code. */
_dllHandle = UnsafeNativeMethods.LoadLibrary(_fullPath);
/* Some more code. */
_fptr = UnsafeNativeMethods.GetProcAddress(_dllHandle, _procName);
/* Yet even more code. */
}
}
Any thoughts on what I am doing wrong and how I can get it working would be greatly appreciated. Thanks.
You will have to remove the ExactSpelling property. The real name of the function is SetDllDirectoryW. I also recommend you use CharSet.Auto, using Ansi is a lossy conversion that can cause subtle problems. The export is not available in any Windows version prior to XP SP1.
I do not know much about DllImport, but on my machine removing ExactSpelling attribute just do it.

Categories

Resources