System detection (Windows, Mac OS X or Linux) - mono

i try to develop an app that accesses a COM Port. To select a matching COM Port it would be good to recognize the system automatically.
Is there a way to read the system (Windoews, Linux or MAC) as a string or something similar?
Later I would like to select a Virtual Com port using the USB VID or PID.
It would be great if you could give me one or two or even three ... advice.
I am currently start working with Mono and would be glad about something help ;)
thx Thommy

I have found a solution and have created a few lines of code:
/// <summary>
/// Get Execution Platform / OS
/// return value
/// 0: nicht erkannt/Error
/// 1: Windows
/// 2: MacOSX
/// 2: Unix (Linux)
/// </summary>
static public int DetectingExecutionPlatform()
{
OperatingSystem os = Environment.OSVersion;
PlatformID pid = os.Platform;
switch (pid)
{
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
return 1;
case PlatformID.MacOSX:
return 2;
case PlatformID.Unix:
return 3;
default:
return 0;
}
}
Unfortunately, OS X (macOS 10.12.3 Sierra) is displayed as UNIX :|
It would be great if someone could test the code and present me the result. Or who knows a solution is also welcome ;)
thx and cya Thommy

Related

Get USB disk drive letter by device path or handle

My goal is to write a c-dll (compiled with MinGW) that is able to search for certain models of USB sticks connected to the computer and deliver the serial number, the vendor ID, the product ID and the drive letter.
I have searched on the internet for several hours know but could not find an approach that works for me.
I am using the Setup Api to get a list of all connected USB devices. For each USB device I get a path that looks like this:
\?\usb#vid_048d&pid_1172#00000020370220#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
From that string I can get the vendor ID, product ID and the serial number I am looking for.
My problem is now to determine the drive letter of the USB drive that is related to this device path.
During my internet research I found the following approach multiple times (for example here http://oroboro.com/usb-serial-number/):
Once the device path is found, the USB drive must be opened by CreateFile. The handle returned by that function can be used to get the device number by function DeviceIOControl with IOCTL_STORAGE_GET_DEVICE_NUMBER.
After that, the CreateFile function could be used to open each drive letter (starting from a:) and try to get the device number the same way like described above. Once the same device number is found again, the relation between device path and drive letter is made.
My Problem is that the IOCTL_STORAGE_GET_DEVICE_NUMBER call is not working. The DeviceIOControl function returns error code 50 which means "The request is not supported".
I am not able to create a link between the device path of a USB stick and the drive letter. I have tried several IOCTL_STORAGE and IOCTL_VOLUME calls but none worked for the USB sticks I tried.
I also read in another Forum that people had problems with the results of the DeviceIOControl function. It was returning the desired result on some PCs while it was making trouble on others.
Is there another way of achieving my goal?
I already had a look into the registry where I can also find the desired data. But again I had the problem to create the connection between device path and drive letter.
I would not like to use the WMI. I have read that it is still not really supported by MinGW.
I have a implementaion for all this with C# where it is really easy to get the desired information, but now I also need one that is created with unmanaged code and can be used to replace a c-dll also included in Delphi projects.
I would appreciate any suggestions for a solution to my problem.
Best regards,
Florian
And here the code if someone is interested. The position with this comment "//HERE IS WHERE I WOULD LIKE TO GET THE DEVICE NUMBER!!!" is where the request of the device number would be used if it would work.
typedef struct ty_TUSB_Device
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData;
char devicePath[300];
}TUSB_Device;
int
GetUSBDevices (TUSB_Device *devList[], int size)
{
HANDLE hHCDev;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA deviceInfoData;
ULONG index;
ULONG requiredLength;
int devCount = 0;
//SP_DEVINFO_DATA DevInfoData;
// Now iterate over host controllers using the new GUID based interface
//
deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
NULL,
NULL,
(DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
if (deviceInfo != INVALID_HANDLE_VALUE)
{
deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for (index=0;
SetupDiEnumDeviceInterfaces(deviceInfo,
0,
(LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
index,
&deviceInfoData);
index++)
{
SetupDiGetDeviceInterfaceDetail(deviceInfo,
&deviceInfoData,
NULL,
0,
&requiredLength,
NULL);
//allocate memory for pointer to TUSB_Device structure
devList[devCount] = malloc(sizeof(TUSB_Device));
devList[devCount]->deviceDetailData = GlobalAlloc(GPTR, requiredLength);
devList[devCount]->deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail(deviceInfo,
&deviceInfoData,
devList[devCount]->deviceDetailData,
requiredLength,
&requiredLength,
NULL);
//open the usb device
hHCDev = CreateFile(devList[devCount]->deviceDetailData->DevicePath,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
// If the handle is valid, then we've successfully found a usb device
//
if (hHCDev != INVALID_HANDLE_VALUE)
{
strncpy(devList[devCount]->devicePath, devList[devCount]->deviceDetailData->DevicePath, sizeof(devList[devCount]->devicePath));
//HERE IS WHERE I WOULD LIKE TO GET THE DEVICE NUMBER!!!
CloseHandle(hHCDev);
devCount++;
}
//GlobalFree(devList[devCount]->deviceDetailData);
}
SetupDiDestroyDeviceInfoList(deviceInfo);
}
return devCount;
}
I found out what my problem was. From what I read on the internet it seems there where other people having the same problems like me, so I will post my solution.
The whole point is that there are obviously different path values one can obtain for a USB device using the SetupApi. All path values can be used to get a handle to that device, but there are obviously differences about what can be done with the handle.
My failure was to use GUID_DEVINTERFACE_USB_DEVICE to list the devices. I found out that when I use GUID_DEVINTERFACE_DISK, I get a different path value that lets me request the device number. That way I am able to get the link to the drive letter.
That path value obtained with GUID_DEVINTERFACE_DISK also contains the serial number but not the vendor and product IDs. But since both path values do contain the serial, it is no problem to get them both and build the relation.
I tested the code with Windows XP, 7 and 8 and it works fine. Only the FileCreate code of the code sample above must be adjusted (replace GENERIC_WRITE by 0). Otherwise Administrator rights or compatibility mode are required.
I did not try to find out what these different GUID values really stand for. Someone with a deeper knowledge in this area could probably provide a better explanation.
Best regards,
Florian

Desktop.isDesktopSupported returning null in windows

I have the following code
desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
url = new URL("http://www.facebook.com");
if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
try {
desktop.browse(url.toURI());
} catch (Exception e) {
e.printStackTrace();
}
and desktop is returning null for Windows 7. Can anyone suggest what to be done ?
Not sure it's not working with Windows 7 (it worked at me), but Desktop can return false negatives anyway. I had a similar problem and the only way around I could find, is opening the system browser the hard way, using java.lang.Runtime
for windows, your code will be
Runtime.getRuntime().exec( "rundll32 url.dll,FileProtocolHandler " + url);
a very nice fully working code that covers OSX and Linux too can be be found here
From the documentation:
public static boolean isDesktopSupported()
Tests whether this class is supported on the current platform. If it's supported, use getDesktop() to retrieve an instance.
Returns:
true if this class is supported on the current platform; false otherwise
To make it short:
Windows 7 does not support this class
See also: similar question
See also: desktop api documentation

Linux serial communication with unusual port names

I'm trying to do some simple stuff with serial ports in Linux. Specifically:
Platform - BeagleBone Black
OS - Angstrom Linux
Mono version 2.10.8.1 (Arm)
The board implements it's six serial ports as ttyO0 through ttyO5 instead of ttyS0.
It actually has ttyS0 through ttyS3.
When I enumerate the ports it finds the ttyS0 etc but not the ttyO0 etc. Unfortunately it is the ttyO0 etc ports that actually have the real serial ports. Is there any way to make Mono able to use these?
Thanks!
Phil
Figured it out myself.
Simple really. They are specifically scanning for port names starting with /dev/ttyS:
public static string [] GetPortNames ()
{
int p = (int) Environment.OSVersion.Platform;
List<string> serial_ports = new List<string>();
// Are we on Unix?
if (p == 4 || p == 128 || p == 6) {
string[] ttys = Directory.GetFiles("/dev/", "tty*");
foreach (string dev in ttys) {
if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB"))
serial_ports.Add(dev);

STATUS_ACCESS_DENIED with CallNtPowerInformation()

I'm trying to get the current processor speeds/throttlings through CallNtPowerInformation() with the ProcessorInformation input:
SYSTEM_INFO systemInfo;
GetSystemInfo( &systemInfo );
numProcessors = (unsigned char)systemInfo.dwNumberOfProcessors;
powerInformations = new PROCESSOR_POWER_INFORMATION[numProcessors];
long status = CallNtPowerInformation( ProcessorInformation, NULL, 0, powerInformations, numProcessors*sizeof(PROCESSOR_POWER_INFORMATION) );
Unfortunately, status is always equal to STATUS_ACCESS_DENIED. I can't find any documentation on why this would be, can anyone point me to some reasons why I would not be able to get the current processor information?
This is running on Windows 8, on a Surface Pro (using Desktop APIs), and I've tried starting VS2012 with elevated permissions to no effect.
It turns out that if I run this code in a Console application, it works, but if I run it inside of a Metro application, it fails. I will ask a new question on how to execute code like this inside of a windows store app.

Detecting the platform of a Windows Store App

Is there a possibility to ask at runtime if a Windows Store app (compiled for ARM and x86/64) is executed currently on an ARM-device or more specific on a Microsoft Surface Tablet from within c# or is it necessary to compile two Versions of the same app to behave different on different plattforms?
This can be done via the following code (according to this SO post):-
[DllImport("kernel32.dll")]
internal static extern void GetNativeSystemInfo(ref SystemInfo lpSystemInfo);
internal static bool IsArmBased()
{
var sysInfo = new SystemInfo();
GetNativeSystemInfo(ref sysInfo);
return sysInfo.wProcessorArchitecture == ProcessorArchitectureArm; //ushort 5
}
This does pass the WACK test, test I wouldn't count on it being around forever. Think very hard about why you need this information (is it just for stats, or are you changing the behaviour of your app, if so why!?)
using Windows.ApplicationModel;
Package package = Package.Current;
PackageId packageId = package.Id;
String arch = String.Format("{0}", packageId.Architecture);
This will return "X86" or "ARM", depending on the underlying hardware.