Using Span<T> on ARM gives "System.DataMisalignedException:" - c#

I am trying to read data and convert it from a Modbus RTU sensor using .NET 7. Everything is working on my Linux-x64 machine but not when i try to run it on the RevPi core S linux-arm...
Modbus RTU config
Sensor Instructions
I am using FluentModbus version 5.0.2:
fluentClient = new ModbusRtuClient()
{
BaudRate = 9600,
Parity = Parity.None,
StopBits = StopBits.One
};
fluentClient.Connect("/dev/ttyUSB" + port, ModbusEndianness.LittleEndian);
Console.WriteLine("Reading Calibration");
var calibration = fluentClient.ReadHoldingRegisters(1, 8704, 4);
var hexCalibration = Convert.ToHexString(calibration);
foreach (var item in calibration)
{
Console.Write(item);
}
foreach (var item in hexCalibration)
{
Console.Write(item);
}
//The code below works perfect on my machine running Ubuntu 22.04(linux-x64) but does not work //on RevPi Core running Debian custom Buster image (Linux-arm).
var floatCalibration = fluentClient.ReadHoldingRegisters<float>(1, 8704, 4);
Console.WriteLine("calibration K: " + floatCalibration[0]);
Console.WriteLine("calibration B: " + floatCalibration[1]);
Terminal output My computer:
Reading Calibration
000631541535764
0000003F9A993940
calibration K: 0.5
calibration B: 2.9
Terminal output RevPi Core:
Reading Calibration
000631541535764
0000003F9A993940
Unhandled exception. System.DataMisalignedException: A datatype misalignment was detected in a load or store instruction.
at exsys.Program.Main(String[] args) in /home/user/FunctionTest/Program.cs:line 179
Aborted
And this is line 179: Console.WriteLine("calibration K: " + floatCalibration[0]);
Is it not possible to use .Net7 Span<float> on linux Arm? I have tried different setups, but no luck yet. Maybe someone else have run in to this issue?
Tried dotnet publish to self contained linux-x64 and everything works fine. i only get the error when compiling to linux-arm and running it.
Tried different converting setups but no luck.
I have updated the image on the RevPi Core S released in November 2022, but it did not help.
Tried first running on .NET 6 and now on .NET 7. Same error on both.

FluentModbus is breaking alignment here:
https://github.com/Apollo3zehn/FluentModbus/blob/master/src/FluentModbus/Client/ModbusClient.cs#L155
and then calls MemoryMarshal.Cast which is a problem on ARM, because the documentation says
This method is supported only on platforms that support misaligned memory access or when the memory block is aligned by other means.
ARM is not a platform that supports misaligned memory access.
A good workaround would be to allocate a float[], call the version of ReadHoldingRegisters that returns Span<byte>, and call CopyTo(MemoryMarshal.AsBytes(destFloatArray)).

Related

How can I find the Windows product name in Windows 11?

Windows 11, released yesterday, reports itself as Windows 10.0 just about everywhere - RtlGetVersion says 10.0, and if you ask VerifyVersionInfo if you are 11.0 or greater, it says no.
There seems to be no new GUID to shove into app.manifest to say "hey I support Windows 11" like there was for Windows 7, 8, 8.1, and 10.
Currently I rely on HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName to tell me what the current version of Windows is, but on my machine that I've upgraded, it still says "Windows 10 Enterprise", not "Windows 11 Enterprise".
There appears to only be a single place in the registry that contains the text "Windows 11" and that is the BCD section (boot configuration), which can also be renamed so I don't want to touch that.
So far I have only identified a handful of methods to tell if I am running on Windows 11:
Invoke WMI to query Win32_OperatingSystem and check the Name property, which simply says "Windows 11". This is incomplete (it does not include the SKU such as "Enterprise"), and WMI is relatively slow and slightly brittle, so it's not an acceptable solution for my use-case.
Check the build number to see if it is above 21996 (beta builds) or 22000 (first public release). As above, this won't include the SKU, and would require some manual jiggery-pokery in order to build the full string.
Run sysinfo and parse the output. This is quite slow, and possibly brittle (I haven't checked but the output might be localised into different languages).
winver knows, but it's a GUI application so I can't exactly query it programmatically.
Does anyone have any other ideas on how to get the string "Windows 11 Enterprise" (or "Windows 11 Pro", etc. as the case may be) out of my operating system in a performant and complete manner? Where do WMI, sysinfo, and winver get it from?
I need to do this from a .NET library, but P/Invokes / native function calls are acceptable solutions.
Leaving this here so that I can find it later:
It seems that Windows itself (e.g. winver) gets this information from Windows branding - specifically from the resource table in %WinDir%\Branding\Basebrd\en-US\basebrd.dll.mui.
To access this one could use the private APIs in %WinDir%\System32\winbrand.dll. Specifically, the function BrandingFormatString which accepts a wide string (LPW[C]STR) and returns a wide string.
e.g. BrandingFormatString("%WINDOWS_LONG%") returns "Windows 11 Pro" on my home PC.
I do not know the lifecycle semantics of the resulting string, i.e. if/when/how it should be freed.
The following code serves as a functional proof-of-concept (C# 9.0):
using System;
using System.Runtime.InteropServices;
[DllImport("winbrand.dll", CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
static extern string BrandingFormatString(string format);
Console.WriteLine(BrandingFormatString("Hello World from %WINDOWS_LONG%!"));
tldr - Using the EditionID and the CurrentBuild from the CurrentVersion in the registry seems to be a reliable way to determine Win10 vs Win11 and the "edition" of the software. EditionID is "Professional" on Windows 10 Pro and Windows 11 Pro, and CurrentBuild >= ~22000 tells you if it is 10 or 11.
The collection of registry values in the HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion reveals what feels like a lack of planning on Microsoft's part. There's ReleaseId, which is a number that changed with each Windows 10 release (e.g., 1903, 1909, 2004,...) until its last change for Windows 10 20H2, where it changed to 2009. At the same time, DisplayVersion was added, and was set to 20H2.
Then Windows 10 21H1 released, and ReleaseId inexplicably stayed at 2009.
The fact that both current Windows 10 and Windows 11 releases can have the same DisplayVersion (e.g., 21H2 when Windows 10 21H2 releases soon) and ProductName (e.g., Windows 10 Pro) is really head-scratching. (Thanks #yaakov for catching my mistake saying it was 21H1.)
The following code has been tested on Windows XP, 7, 10, 11. It works on 32 bit and 64 bit operating systems. It works inside 32 bit and 64 bit applications.
The following strings will be generated:
"Microsoft Windows XP, Build 2600, 32 bit"
"Windows 7 Ultimate, Build 7601, 64 bit"
"Windows 10 Enterprise LTSC 2019, Version 1809, Build 17763, 64 bit"
"Windows 10 Pro, Version 1909, Build 18362, 64 bit"
"Windows 11 Professional, Version 21H2, Build 22000, 64 bit"
Put the code into a static constructor so it executes only once and writes the version into a static variable.
static String ms_OperatingSystem;
static Constructor()
{
try
{
String s_KernelPath = Path.Combine(Environment.SystemDirectory,"Kernel32.dll");
FileVersionInfo k_Kernel = FileVersionInfo.GetVersionInfo(s_KernelPath);
// on 32 bit Windows this will read the 32 bit hive instead
using (RegistryKey i_HKLM = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
using (RegistryKey i_RegVer = i_HKLM.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion", false))
{
// Kernel32.dll on Windows 11 has Product Version 10.0.22000.120
if (k_Kernel.ProductMajorPart == 10 && k_Kernel.ProductBuildPart >= 22000)
{
ms_OperatingSystem = "Windows 11";
Object o_Edition = i_RegVer.GetValue("EditionID"); // "Professional"
if (o_Edition is String)
ms_OperatingSystem += " " + o_Edition;
}
else
{
// "Microsoft Windows XP"
// "Windows 7 Ultimate"
// "Windows 10 Pro" (same string on Windows 11. Microsoft SUCKS!)
ms_OperatingSystem = (String)i_RegVer.GetValue("ProductName");
}
// See: https://en.wikipedia.org/wiki/Windows_10_version_history
// Windows 10 older releases --> "2009" (invalid if DisplayVersion exists)
Object o_ReleaseID = i_RegVer.GetValue("ReleaseId");
// Windows 10 latest release --> "21H1"
// Windows 11 first release --> "21H2"
Object o_DispVer = i_RegVer.GetValue("DisplayVersion");
// Use ReleaseID ONLY if DisplayVersion does not exist in registry!
if (o_DispVer is String) ms_OperatingSystem += ", Version " + o_DispVer;
else if (o_ReleaseID is String) ms_OperatingSystem += ", Version " + o_ReleaseID;
ms_OperatingSystem += ", Build " + k_Kernel.ProductBuildPart;
if (Environment.Is64BitOperatingSystem) ms_OperatingSystem += ", 64 bit";
else ms_OperatingSystem += ", 32 bit";
}
}
}
catch (Exception Ex)
{
ms_OperatingSystem = Ex.Message;
}
}
I created a remote support tool for desktop admins (see http://www.appslife-rdt.appspot.com) In VB.Dot.Net i used a call to the WMI space Win32_OperatingSystem and got the "Name" value back. This then needs to be split to get the first object which is what you require. i.e.
Dim query2 As New SelectQuery("SELECT * FROM Win32_OperatingSystem")
Dim searcher2 As New ManagementObjectSearcher(objManagementScope2, query2, QueryOptions)
For Each mo As ManagementObject In searcher2.[Get]()
OSname = mo("Name")
Next
Dim array1 As Array = Nothing
array1 = Split(OSname, "|")
OSname = array1(0).ToString
OSname then gives you the "Windows 11 Pro" or "Windows XP Professional" that you require.
I also get the OSVersion with the latest patch update info from registry as follows if needed...
THIS IS FOR CLIENT VERSIONS 10/11 :-
.SetPropertyValue("sSubKeyName", "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Update\TargetingInfo\Installed\Client.OS.rs2.amd64")
.SetPropertyValue("sValueName", "Version")
THIS IS FOR SERVER VERSIONS 2019 :-
.SetPropertyValue("sSubKeyName", "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Update\TargetingInfo\Installed\Server.OS.amd64")
.SetPropertyValue("sValueName", "Version")
Hope this is of help.

Image capturing via SNAPI.dll API for Symbol barcode scanner DS4208

I want to capture image via SNAPI API from Symbol (currently Zebra) barcode scanner, model DS4208 (we're also using another but compatible models from Zebra).
Barcode capturing/recognition works pretty well, but looks like SnapiDLL.SNAPI_SnapShot(hScanner) call don't work correctly: no WM_XFERSTATUS message received at all.
Here is small & simplified code snippet:
// Set image format
short[] parms = new short[2] { (short)SnapiParamIds.ImageFileType, (short)SnapiImageTypes.Jpeg };
var retCode = SnapiDLL.SNAPI_SetParameters(parms, 2, _devHandles[0]);
Debug.WriteLine($"SNAPI_SetParameters retCode={retCode}");
Application.DoEvents();
Thread.Sleep(50);
retCode = SnapiDLL.SNAPI_SnapShot(_devHandles[0]);
Debug.WriteLine($"SNAPI_SnapShot retCode={retCode}");
Application.DoEvents();
Thread.Sleep(50);
retCode = SnapiDLL.SNAPI_PullTrigger(_devHandles[0]);
Debug.WriteLine($"SNAPI_PullTrigger retCode={retCode}");
Application.DoEvents();
Thread.Sleep(50);
Return codes always 0 (i.e. no error), but no WM_XFERSTATUS message received by my message handler.
P.S. C# application from Zebra's SDK which is using CoreScanner driver and OCX, is working fine and able to capture images and video. But I'd like to avoid CoreScanner driver installation for some reasons; for barcode scanning small and simple SNAPI.dll works pretty fine, and I expect to get it work for image capturing too - probably, I'm doing something wrong...
P.P.S. Guys, please DO NOT COMMENT if you have NO EXPERIENCE WORKING WITH SYMBOL BARCODE SCANNERS & SNAPI, and CAN NOT PROVIDE a working snippet!
After contacting Zebra tech support (they are successors of Symbol/Motorola barcode scanner business), I figured out that the imaging/video functionality is broken in SNAPI.dll for the x64 OSes (but most of the rest API calls are working properly). Unfortunately, SNAPI isn't supported by Zebra anymore, and I should use Zebra's CoreScanner API. The good news is: this API is working fine, as it supposed to be. Not a very good news: I should use additional installation package from Zebra.

Communication between Python and C#

I have a Python backend running machine learning algorithms. I want to use the same backend for both an Excel plugin (C#) and a website. I want both interfaces to send my training data (thousands of lines of numbers in arrays) to the same Python application and retrieve the results in the form of another array up to a few thousand lines.
The website would fetch data from a SQL database and send that data to Python, while the Excel plugin would take the data that is in the current worksheet and send that data to Python. I need to be able to create numpy arrays in Python before continuing to process the data. Note that the website would be running on the same machine where the Python application resides. I still haven't decided what I will use to code the website, but I was leaning towards Node.js.
I have done some research and found a few options:
1- Named pipes
2- Sockets
3- RPC server such as gRPC or XML-RPC.
4- Writing the data to a file and reading it back in Python
5- Web Service
Note: I would need the Python "server" to be stateful and keep the session running between calls. So I would need to have a kind of daemon running, waiting for calls.
Which one would you experts recommend and why? I need flexibility to handle several parameters and also large arrays of numbers. Using IronPython is not an option because I am running Keras on Python, which apparently does not support IronPython.
I had the same problem recently.
I used a named pipe to transport data from python to my c# server, hope it helps you.
Python:
import win32pipe, win32file
class PipeServer():
def __init__(self, pipeName):
self.pipe = win32pipe.CreateNamedPipe(
r'\\.\pipe\\'+pipeName,
win32pipe.PIPE_ACCESS_OUTBOUND,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
1, 65536, 65536,
0,
None)
#Carefull, this blocks until a connection is established
def connect(self):
win32pipe.ConnectNamedPipe(self.pipe, None)
#Message without tailing '\n'
def write(self, message):
win32file.WriteFile(self.pipe, message.encode()+b'\n')
def close(self):
win32file.CloseHandle(self.pipe)
t = PipeServer("CSServer")
t.connect()
t.write("Hello from Python :)")
t.write("Closing now...")
t.close()
For this code to work you need to install pywin32 (best choice is from binarys): https://github.com/mhammond/pywin32
C#-Server:
using System;
using System.IO;
using System.IO.Pipes;
class PipeClient
{
static void Main(string[] args)
{
using (NamedPipeClientStream pipeClient =
new NamedPipeClientStream(".", "CSServer", PipeDirection.In))
{
// Connect to the pipe or wait until the pipe is available.
Console.Write("Attempting to connect to pipe...");
pipeClient.Connect();
Console.WriteLine("Connected to pipe.");
Console.WriteLine("There are currently {0} pipe server instances open.",
pipeClient.NumberOfServerInstances);
using (StreamReader sr = new StreamReader(pipeClient))
{
// Display the read text to the console
string temp;
while ((temp = sr.ReadLine()) != null)
{
Console.WriteLine("Received from server: {0}", temp);
}
}
}
Console.Write("Press Enter to continue...");
Console.ReadLine();
}
}
You can use Python for .NET (Python.NET). It may require some changes to your code, but then it should work very well, once everything is in good shape.
Python.NET allows two-way communication between CPython and CLR.
Let me give you a neat and quick recipe, in the form of example code.
There are basically two ways to tie python in the backend of C# (or a C# winform app or gui or something similar).
Method1: Iron Python. In this method you install a .net package in your visual studio called IronPython. I would not prefer this, because assuming your machine learning model uses keras or a lot of other libraries. It would be another quest to get you installations ready and working in IronPython. And most importantly, it is not as good as your common virtual env or conda environment.
Method2: (The Good Method): Create a Custom Process in your C# that takes arguments from your GUI, knows the path to your script and your python env. Using all these things, it calls your python code exactly the way you would call it in your terminal and pass arguments to it.
Now the tasty example code (I have used this simple trick and it always helps make my black screen python stuff look good with the cover of C# apps).
Python Part
import sys
a = sys.argv[1]
b = sys.argv[2]
print("The Sum = ", float(a)+float(b))
The C# Part
So here is the python process/function that you need to call on the click event of your sum button in the application
static void PythonProcess()
{
//1) Create Process Info
var psi = new ProcessStartInfo();
//Conda Env Path
psi.FileName = #"C:\Users\jd\.conda\pkgs\py\python.exe";
//2) Provide Script and the Arguments
var script = #"C:\Users\jd\Desktop\script.py";
var a = "15";
var b = "18";
psi.Arguments = $"\"{script}\" \"{a}\" \"{b}\"";
//3) Process Configuration
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
//4) Execute Process and get Output.
var errors = "";
var results = "";
using(var process = Process.Start(psi))
{
errors = process.StandardError.ReadToEnd();
results = process.StandardOutput.ReadToEnd();
}
//5) Display Output
Console.WriteLine("ERRORS: ");
Console.WriteLine(errors);
Console.WriteLine();
Console.WriteLine("RESULTS: ");
Console.WriteLine(results);
}
Calling Python from C# is easily possible via Pyrolite where your Python code is running as a Pyro4 server. It should be fast enough to handle "large arrays of numbers" however you didn't specify any performance constraints.
I had the same issue and seem to end up with named pipes. Here is a nice example of how to set it up to talk C# => Python, assuming C# is the server.
It can use the same way to talk back or just Python.net to call directly through CLR as shown here. I use the latter.

Programmatically create/destroy network bridges with .NET on Windows 7

I am trying to programmatically create and destroy a network bridge on Windows 7. Technologically I would love to stay within the .Net 4 realm (PInvokes are fine, ofc), but utilizing C++ is an option.
My research so far turned up that for configuration, netsh-commands are the route to go. However, there seems to be no option to actually spin up a new bridge with them.
I am currently investigating this program that uses the INetCfg APIs, but it appears that the program or, more specifically, the APIs, are not able to (again) build a new bridge.
If anyone can contribute to solving the problem, any kind of help is greatly appreciated.
[Update:] It seems that newtork bridges are implemented using a driver which then binds to both devices. I cannot yet make much of that information, so still any help is appreciated.
I've found a solution that works for both bridge service and bridge adapter driver. I don't use UpdateDriverForPlugAndPlayDevices like devcon but I'm using DiInstallDevice instead.
However, installing the drivers for the first time in non interactive mode (without user interaction) is not possible. This is because there are no corresponding .cat files for the builtin bridge .inf files. Neither UpdateDriverForPlugAndPlayDevices nor DiInstallDevice nor DiInstallDriver is intended for manual driver installation where .inf file is already contained in %SystemRoot%\inf but not yet in %SystemRoot%\System32\DriverStore.
The files should be on the distribution media or in a vendor-created directory, not in a system location such as %SystemRoot%\inf
All of the mentioned installation methods will create a OEM copy of the .inf file and will install it in driver store. Because this OEM copy is initially not part of the driver store, windows will show a prompt dialog and ask for user interaction either force installing the driver or canceling. Subsequent driver installations is possible without any user interaction by the way. Also preinstalled drivers (see pnputil -a) can be installed in non interactive mode.
So this is my solution:
First a device entry in HKLM\System\CurrentControlSet\Enum\Root is created with the given hardware id as device name (ms_bridge, ms_bridgemp) with the help of SetupDiCreateDeviceInfo
The hardware id is assigned with SetupDiSetDeviceRegistryProperty
The driver list is builded by exactly the given single .inf file with the help of SetupDiSetDeviceInstallParams
Enumerating and preselecting driver with SetupDiSetSelectedDriver
Registering device with SetupDiCallClassInstaller(DIF_REGISTERDEVICE...)
Installing with DiInstallDevice
This is the full code:
HRESULT InstallDriver(const wchar_t* DriverInfFile, const wchar_t* HardwareId) {
HRESULT Hr = S_OK;
GUID ClassGUID;
wchar_t ClassName[MAX_CLASS_NAME_LEN] = {0};
if (SetupDiGetINFClass(DriverInfFile, &ClassGUID, ClassName, sizeof(ClassName) / sizeof(wchar_t), nullptr) == FALSE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
return Hr;
}
HDEVINFO DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID, nullptr);
if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
return Hr;
}
SP_DEVINFO_DATA DeviceInfoData = {
sizeof(SP_DEVINFO_DATA), 0
};
if (SetupDiCreateDeviceInfo(DeviceInfoSet, HardwareId, &ClassGUID, nullptr, nullptr, DICD_GENERATE_ID, &DeviceInfoData) == FALSE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return Hr;
}
if (SetupDiSetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, (LPBYTE) HardwareId, (DWORD) (wcslen(HardwareId) + 1) * sizeof(wchar_t)) == FALSE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return Hr;
}
SP_DEVINSTALL_PARAMS InstallParams = {sizeof(SP_DEVINSTALL_PARAMS), 0};
InstallParams.FlagsEx = DI_FLAGSEX_ALLOWEXCLUDEDDRVS | DI_FLAGSEX_ALWAYSWRITEIDS;
InstallParams.Flags = DI_QUIETINSTALL | DI_ENUMSINGLEINF;
wcscpy_s(InstallParams.DriverPath, DriverInfFile);
if (SetupDiSetDeviceInstallParams(DeviceInfoSet, &DeviceInfoData, &InstallParams) == FALSE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return Hr;
}
SP_DRVINFO_DATA DriverInfoData = {sizeof(SP_DRVINFO_DATA), 0};
if (SetupDiBuildDriverInfoList(DeviceInfoSet, &DeviceInfoData, SPDIT_COMPATDRIVER) == FALSE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
SetupDiDestroyDriverInfoList(DeviceInfoSet, &DeviceInfoData, SPDIT_COMPATDRIVER);
}
// Use first best driver (since specified by inf file)
if (SetupDiEnumDriverInfo(DeviceInfoSet, &DeviceInfoData, SPDIT_COMPATDRIVER, 0, &DriverInfoData)) {
SetupDiSetSelectedDriver(DeviceInfoSet, &DeviceInfoData, &DriverInfoData);
}
if (SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DeviceInfoSet, &DeviceInfoData) == FALSE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
}
// TODO: Allow non interactive mode for drivers already contained in %SystemRoot%\inf directory
//BOOL PreviousMode = SetupSetNonInteractiveMode(TRUE);
if (Hr == S_OK) {
if (DiInstallDevice(nullptr, DeviceInfoSet, &DeviceInfoData, &DriverInfoData, 0, nullptr) == FALSE) {
Hr = HRESULT_FROM_SETUPAPI(GetLastError());
// Ensure that the device entry in \ROOT\ENUM\ will be removed...
SetupDiRemoveDevice(DeviceInfoSet, &DeviceInfoData);
}
}
//SetupSetNonInteractiveMode(PreviousMode);
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return Hr;
}
Todo's: Find a way to install this bridge drivers from within %SystemRoot%\inf without creating OEM copies and without any user interaction.
You can gain read/write access to subversion repository at Sourceforge
Any additional information or suggestion for improvement is appreciated! Everyone please feel free to checkout/modify the code.
Basic commands:
bridgeutil.exe /install
bridgeutil.exe /uninstall
bridgeutil.exe /attach
bridgeutil.exe /detach
Examples:
bridgeutil.exe /attach "PCI\VEN_10EC&DEV_8169" /attach {5d624f94-8850-40c3-a3fa-a4fd2080baf3}\vwifimp
Attaches each Realtek 8169 Network Interface Cards and Microsoft Virtual Wifi Adapter to bridge. If the bridge is not installed yet, it will be installed first.
bridgeutil.exe /detach 1
Detaches adapter with id 1 from bridge.
To see a list of bridgeable adapters, just call bridgeutil.exe without any arguments.
It is actually possible to create and network bridges via the SetupAPI.
Using the DevCon Tool, destroying them is as easy as this...
devcon.exe remove ms_bridgemp
...while building bridges can be done with this command:
devcon.exe install "C:\Windows\inf\netbrdgm.inf" ms_bridgemp
DevCon is open source, so you can dig into the sources to see how it implements those commands (the DevCon Tool is essentially a CLI to the SetupAPI).
Please note: The commands relate to Windows 7. The approach is said to work on XP and I suppose it works on other Windows Versions, too, but the .INF-File might have a different name or the device ID might differ.
After much unsuccessful searching on the Internet I wrote and have been successfully using the following Windows Script Host script "BridgeConnections.vbs" to create a network bridge on Windows XP (this method also works on Windows 7 and Windows 8 with slight modifications). It can be run from the command prompt or from a batch file as follows:
C:\Temp> cscript BridgeConnections.vbs
File BridgeConnections.vbs:
' This VBScript opens the "Network Connections" control panel window,
' sends Ctrl+A ("Select All") and Alt+N ("Advanced" menu) and
' C ("Bridge Connections" menu command) keystrokes to it and then waits
' until the splash window "Please wait while Windows bridges the connections..."
' disappears from the screen
Dim WshShell, Count
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Exec("rundll32.exe shell32.dll,Control_RunDLL ncpa.cpl")
Count = 0
Do While Not WshShell.AppActivate("Network Connections") And Count < 10
Count = Count + 1
WScript.Sleep 1000
WScript.Echo "Waiting for the 'Network Connections' window... " & CStr(Count) & "s"
Loop
WshShell.SendKeys "^(a)"
WshShell.SendKeys "%(n)"
WshShell.SendKeys "c"
Count = 0
Do While Not WshShell.AppActivate("Network Bridge") And Count < 10
Count = Count + 1
WScript.Sleep 1000
WScript.Echo "Waiting for the 'Network Bridge' splash window... " & CStr(Count) & "s"
Loop
Count = 0
Do While WshShell.AppActivate("Network Bridge") And Count < 120
Count = Count + 1
WScript.Sleep 1000
WScript.Echo "Waiting for the 'Network Bridge' splash window to disappear... " & CStr(Count) & "s"
Loop
Likewise one could modify the script to "Delete" the bridge if required (make a single selection with Shift and navigate keys and send a different keystroke command). In my case I only need to bridge all available ethernet adapters from a batch file so the above method works just fine.
In my experience, the "slight" problem with the
devcon.exe install "C:\Windows\inf\netbrdgm.inf" ms_bridgemp
approach posted here earlier is that it would create an empty, "half-backed" bridge with no adapters in it. So you will still have to go to the Windows GUI and "Add" adapters it one by one manually before it becomes really usable.
The only fully automated solution that really works for me it the above script.
To do the same actions from a C++ or C# code without the script you'd need to know and call undocumented Shell Network Interfaces (NETSHELL.DLL) functions which in turn are called by the Explorer Shell when the user initiates the actions via list view item selection and context menu command in the Windows GUI. A C++ sample of calling into the Shell Network Interface for programmatically disabling/enabling a Network Adapter can be seen here. Unfortunately there is no sample yet for creating/removing the Network Bridge adapter. So until it becomes available I'll stick with the script.
Based on the bindview example, I put up an utilitary called bindbridge, which works as following:
Usage: bindbridge <deviceId> <bind|unbind>
The source can be found at https://github.com/OurGrid/OurVirt/tree/master/tools/win32/bindbridge, and it assumes the bridge device already exists - which can be created with devcon, as per previous answers - and its name to be ms_bridge, what can be easily changed in the sources.
I'm using it to programatically add tap interfaces to the bridge, so my command line is something in the lines of:
bindbridge ROOT\NET\0001 bind
It turns out that, unfortunately, there is no documented way of setting up a network bridge.
The code which does that is located inside hnetcfg.dll, and is invoked only by Windows Explorer. It installs bridge driver, and configures bridge interface.
It might be possible to call it yourself (using COM), but that would require reverse engineering and may break on any system update, so I recommend against doing that.

Twitterizer on Mono - call to UpdateWithMedia hangs

I have been using mono and the excellent Twitterizer libraries to post tweets from my Raspberry Pi. The goal being to tweet pictures captured by a webcam periodically.
The problem I have is that when I make a call to "UpdateWithMedia" on mono it just hangs - seemingly forever. Works fine on Windows.
I've created the following unit tests to demonstrate. Both pass on Windows. On Mono/linux "SimpleTwitterPost" passes but "ImagePost" hangs just after writing the filename to the console.
[Test]
public void SimpleTwitterPost()
{
var response = TwitterStatus.Update(tokens, "Here's an automated tweet from my new Raspberry Pi Brain");
Console.WriteLine(response.ErrorMessage);
Assert.That(response.Result, Is.EqualTo(RequestResult.Success));
}
[Test]
public void ImagePost()
{
string filename = "Pics" + Path.DirectorySeparatorChar + "DukeInABush.jpg";
Assert.That(File.Exists(filename));
Console.WriteLine("File to open: {0}", filename);
var response = TwitterStatus.UpdateWithMedia(tokens, "Me in a bush", filename);
Console.WriteLine("Did it!");
Assert.That(response.Result, Is.EqualTo(RequestResult.Success));
}
I have tried the overload of "UpdateWithMedia" which takes a byte array but no luck. I can read the file into the byte array fine but the call to "UpdateWithMedia" hangs as before.
For ref, using mono/.NET 4.0 on Archlinux on raspberry pi (arm).
Anyone got any experience with Twitterizer on this platform?

Categories

Resources