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);
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?
I have a C# application which needs to import a function from a C++ dll. I use DLLImport to load the function. It works fine in English and Chinese environment, but it always raise 'Module not found' exception in French operating system.
The code snapshot:
[DllImport("abcdef.dll", CallingConvention = CallingConvention.StdCall)]
public static extern string Version();
Note that letters in the name of module have been replaced but the name itself is in the same format and the same length.
And a screenshot:
Any ideas?
I have tried all methods you proposed, however the problem still exists.
Here is an alternative way which could avoid that error. It uses Win32 APIs to load the library and find the address of the function, then invoke it. Demo code follows:
class Caller
{
[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);
[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);
[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
private IntPtr _hModule;
public Caller(string dllFile)
{
_hModule = LoadLibrary(dllFile);
}
~Caller()
{
FreeLibrary(_hModule);
}
delegate string VersionFun();
int main()
{
Caller caller = new Caller("abcdef.dll");
IntPtr hFun = GetProcAddress(_hModule, "Version");
VersionFun fun = Marshal.GetDelegateForFunctionPointer(hFun, typeof(VersionFun)) as VersionFun;
Console.WriteLine(fun());
return 0;
}
}
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;
}
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.