I try to implement interoperating with unmanaged code and c#.
I've decided to use winmm.dll for this.
There is need for get joystick unique guid and identify devise status (connected or not)
After some investigation i believe that founded out function that should to do it (joyGetDevCapsA). But there is not clear what value should be pass as int id parameter
public static class InputControllerInteroperator
{
private const string WINMM_NATIVE_LIBRARY = "winmm.dll";
private const CallingConvention CALLING_CONVENTION = CallingConvention.StdCall;
[DllImport(WINMM_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
public static extern int joyGetPosEx(int uJoyID, ref JOYINFOEX pji);
[DllImport(WINMM_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
public static extern int joyGetPos(int uJoyID, ref JOYINFO pji);
[DllImport(WINMM_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
public static extern int joyGetNumDevs();
[DllImport(WINMM_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION, EntryPoint = "joyGetDevCaps"), SuppressUnmanagedCodeSecurity]
public static extern int joyGetDevCapsA(int id, ref JOYCAPS lpCaps, int uSize);
}
There is not lot information about winmm API for C# thought internet, so if someone have experience please share it.
Q: How can be detected attached or not joystick at current moment and get device unique Guid?
According to the #Hans Passant (https://stackoverflow.com/users/17034/hans-passant) comments below question:
There is no guid, there is no connection state. The specific joystick is identified with a simple uint. 0 is the first joystick, 1 is the second, etc.
It works for me
Related
This may be a stupid beginners question but I do not get it. I have a DLL which declares a function
int get_state(const unsigned char n,unsigned int *state)
What is the related C# import statement? Is
public static extern int get_card(byte n,ref uint state);
[DllImport(#"my.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
correct?
And when using this function, how do I have to call get_card() in order to get the data out of the parameter returned in state?
Thanks!
Well, DllImportAttribute must be put before the method it describes:
public static class MyClass {
...
// Since you don't use String, StringBuilder etc.
// CharSet = CharSet.Ansi is redundant and can be omitted
[DllImport(#"my.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int get_card(byte n, ref uint state);
...
}
Having get_card method declared, you can use it as usual, as any other method (and .Net will marshall the arguments):
...
byte n = 123;
uint state = 456;
int result = MyClass.get_card(n, ref state);
...
I've got a vaguely Java background and just installed Visual Studio Community 2015. Playing about with it so have a console app up and running and wanted to use above function after attaching to a different Console. Trouble is I have no idea about the appropriate declaration for this function - can someone tell me what it should be in this instance but also a good pointer for me in future so I can work it out on my own. The IDE doesn't seem to help much
using System.Runtime.InteropServices;
namespace ConsoleStuff
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetConsoleHistoryInfo();
static void Main(string[] args)
{
GetConsoleHistoryInfo(); // <-- PInvokeStackImbalance occurred
}
}
}
You should declare it like this:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetConsoleHistoryInfo(ref CONSOLE_HISTORY_INFO ConsoleHistoryInfo);
You will need the CONSOLE_HISTORY_INFO type too for this to work:
[StructLayout(LayoutKind.Sequential)]
public struct CONSOLE_HISTORY_INFO
{
uint cbSize;
uint HistoryBufferSize;
uint NumberOfHistoryBuffers;
uint dwFlags;
}
A lot of useful PInvoke information can be found at PInvoke.net. You should however double check it against the MSDN to see if it fits.
I know that there are many solutions for my problem. I have tried them all; however, I still get error.
These are original functions from DLL 'KeygenLibrary.dll' :
bool dfcDecodeMachineID(char* sEncodeMachineID, int iInLen, char* sMachineID, int& iOutLen);
bool dfcCreateLicense(char* sMachineID, int iLen, char* sLicenseFilePath);
To import this DLL, I have tried:
Way 1:
unsafe public class ImportDLL
{
[DllImport("KeygenLibrary.dll", EntryPoint = "dfcDecodeMachineID")]
unsafe public static extern bool dfcDecodeMachineID(char* sEncodeMachineID, int iInLen, char* sMachineID, ref int iOutLen);
[DllImport("KeygenLibrary.dll", EntryPoint = "dfcCreateLicense")]
unsafe public static extern bool dfcCreateLicense(char* sMachineID, int iLen, char* sLicenseFilePath);
}
Way 2:
public class ImportDLL
{
[DllImport("KeygenLibrary.dll", EntryPoint = "dfcDecodeMachineID")]
public static extern bool dfcDecodeMachineID([MarshalAs(UnmanagedType.LPStr)] string sEncodeMachineID, int iInLen, [MarshalAs(UnmanagedType.LPStr)] string sMachineID, ref int iOutLen);
[DllImport("KeygenLibrary.dll", EntryPoint = "dfcCreateLicense")]
public static extern bool dfcCreateLicense([MarshalAs(UnmanagedType.LPStr)] string sMachineID, int iLen, [MarshalAs(UnmanagedType.LPStr)] string sLicenseFilePath);
}
However, both above ways give me error:
Unable to find an entry point named 'function name' in DLL 'KeygenLibrary.dll'.
How can I fix my problem? Thanks a lot.
SUGGESTION:
1) Run "dumpbin" on your .dll to confirm the problem is indeed name mangling.
2) If so, try the suggestion in this link:
Entry Point Not Found Exception
a) Use undname to get the undecorated name
b) Set EntryPointy == the mangled name
c) Set CallingConvention = CallingConvention.Cdecl
d) Use the unmangled name and signature for your C# method signature
See also this link:
http://bytes.com/topic/c-sharp/answers/428504-c-program-calling-c-dll
Laurent.... You can call the function using the mangled name as in:
To call a function using its fully decorated name
"?fnWin32Test2##YAJXZ" as
"Win32Test2" you can specify the static entry point as
"?fnWin32Test2##YAJXY":
[DllImport("Win32Test.dll", EntryPoint= "?fnWin32Test2##YAJXZ")]
public static extern int fnWin32Test2();
And call it as:
System.Console.WriteLine(fnWin32Test2());
To look at the undecorated name use the undname tool as in:
`undname ?fnWin32Test##3HA`
This converts the decorated name to "long fnWin32Test".
Regards, Jeff
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;
}
When I want get total value of memory in C# I found a kernel32 function in MSDN to invoke data from system. MSDN declare function this way:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
but this don't work correctly. I change "ref" to "[In, Out]" then it work correctly.
How can tell me what is [In, Out] parameters in C#?
In: http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.inattribute.aspx
Out: http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.outattribute.aspx
Short: They control the way data is marshalled. In this case, where you specify both of them, it means that data is marshalled to both sides (caller and callee).
The out and the ref parameters are used to return values in the same variables, ref is enough if you don't know you will use it in or out.
Out if you just want to use the variable to receive data from the function, In if you just want to send data to the function.
ref if you want to send and receive data from a function, if you put nothing so it will be In by default
Note: ref and out parameters are very useful when your method needs to return more than one values.
The following definition works (define the MEMORYSTATUSEX as a class):
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GlobalMemoryStatusEx(MEMORYSTATUSEX lpBuffer);
[StructLayout(LayoutKind.Sequential)]
public sealed class MEMORYSTATUSEX {
public uint dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
}
Usage
var status = new MEMORYSTATUSEX();
GlobalMemoryStatusEx(status);
If you look at the function definition on MSDN it will tell you whether the parameters are In/Out:
BOOL WINAPI GlobalMemoryStatusEx(
__inout LPMEMORYSTATUSEX lpBuffer
);
In general if it says out, you should use a ref parameter, it makes is easier on any future developers trying to figure out how the code is working. When looking at the function call, you know the developer meant for the argument to be affected.