I'm attempting to make a C# script to send CPU temp and usage statistics to a raspberry pi (it's an LED cube project). I tried to use Python to do it, but the library it used, psutil, does not support sensor readings on Windows.
I'm using the OpenHardwareMonitorLib dll file to try and get the CPU stats. owever, it throws an error won the lines "Computer computer = new Computer(); computer.Open();". The error is:
"System.MissingMethodException: 'Method not found: 'System.Threading.Mutex System.Threading.Mutex.OpenExisting(System.String, System.Security.AccessControl.MutexRights)'.'"
I've tried everything I can think of and everything I have found on google. I can't remember them all, but these are some of them:
Installing Powershell 7
Adding the SystemManagement.dll file to the project (which got me past the previous error to this one)
Installing the newest .NET 4.8 and all of the extras around it.
Added a requirement to run as Admin to the app manifest.
I've put the code on Github (https://github.com/verdammte/led_cube), but here's the C# code in question:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using OpenHardwareMonitor.Hardware;
namespace Get_CPU_Temp5
{
class Program
{
public class UpdateVisitor : IVisitor
{
public void VisitComputer(IComputer computer)
{
computer.Traverse(this);
}
public void VisitHardware(IHardware hardware)
{
hardware.Update();
foreach (IHardware subHardware in hardware.SubHardware) subHardware.Accept(this);
}
public void VisitSensor(ISensor sensor) { }
public void VisitParameter(IParameter parameter) { }
}
static void GetSystemInfo()
{
UpdateVisitor updateVisitor = new UpdateVisitor();
Computer computer = new Computer();
computer.Open();
computer.CPUEnabled = true;
computer.Accept(updateVisitor);
for (int i = 0; i < computer.Hardware.Length; i++)
{
if (computer.Hardware[i].HardwareType == HardwareType.CPU)
{
for (int j = 0; j < computer.Hardware[i].Sensors.Length; j++)
{
if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature)
Console.WriteLine(computer.Hardware[i].Sensors[j].Name + ":" + computer.Hardware[i].Sensors[j].Value.ToString() + "\r");
}
}
}
computer.Close();
}
static void Main(string[] args)
{
while (true)
{
GetSystemInfo();
}
}
}
}
All I want to do is get the CPU usage and CPU temperature and send them to a remote IP. I feel like this shouldn't be this hard.
Based off your repository it looks like your console app is targeting .NET Core but that .dll you are referencing is in .NET Framework. Try creating your project in .NET Framework 4.5+.
Related
I'm trying to pass messages with NetMQ in C# UWP to python.
The python acts as Subscriber, and the C# as Publisher.
When I use C# .Net Core, I can see messages get to the python subscriber, but when I use C# UWP, nothing happens, though the code is exactly the same and I can see Publisher is sending the messages.
The code in python: (Working)
import zmq
import time
def subscribe():
port = "6789"
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://localhost:%s" % port)
topicfilter = "abcde"
socket.setsockopt(zmq.SUBSCRIBE, topicfilter)
while True:
string = socket.recv()
print string
subscribe()
The code in .Net Core: (Working)
using System.Threading;
using System.Threading.Tasks;
using NetMQ;
using NetMQ.Sockets;
namespace Examples
{
static partial class Program
{
public static void Main(string[] args)
{
Publisher();
}
public static void Publisher()
{
Task.Run(async () =>
{
using (var pubSocket = new PublisherSocket())
{
pubSocket.Bind("tcp://*:6789");
for (var i = 0; i < 10; i++)
{
pubSocket.SendFrame("abcde" + i.ToString());
Thread.Sleep(1000);
}
}
});
}
}
}
But the code in UWP (Not working):
using NetMQ;
using NetMQ.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using System;
namespace test_NetMQ_UWP
{
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
DataContext = this;
}
// this event happen when I click on a button in MainPage.xaml
private void Publisher_Click(object sender, RoutedEventArgs e)
{
Task.Run(async () =>
{
using (var pubSocket = new PublisherSocket())
{
pubSocket.Bind("tcp://*:6789");
for (var i = 0; i < 10; i++)
{
pubSocket.SendFrame("abcde" + i.ToString());
Thread.Sleep(1000);
}
}
});
}
}
}
What am I doing wrong?
It's normal behavior. You're using an IP loopback address for Network communications between a UWP app and a different process (a different UWP app or a desktop app). This is restricted by network isolation.
You could run your server and client on different machine to test. Please see the document How to enable loopback and troubleshoot network isolation (Windows Runtime apps). It has explained this scenario:
Loopback is permitted only for development purposes. Usage by a Windows Runtime app installed outside of Visual Studio is not permitted. Further, a Windows Runtime app can use an IP loopback only as the target address for a client network request. So a Windows Runtime app that uses a DatagramSocket or StreamSocketListener to listen on an IP loopback address is prevented from receiving any incoming packets.
In your case, if you just want to test if the UWP app can send message to your python subscriber successfully. You could run the UWP app on another machine. I used your code to make a UWP app to send message and make a console application as subscriber which is run on a different machine. The console application can receive the message.
Please note that because your UWP app need to access the Network at runtime, you need to enable the Netwrok capabilities(Internet(Client) Internet(Client & Server) Private Networks(Client & Server)) in Package.appxmanifest file.
This is using stackexchange.redis v1.1.603, .net 4.6, console application.
Here is my codes:
using System;
using System.Collections.Generic;
using StackExchange.Redis;
namespace RedisClusterTesting
{
class Program
{
static void Main(string[] args)
{
string ip = "192.168.1.20:30001,192.168.1.20:30002,192.168.1.20:30003,resolvedns=1";
var conf = ConfigurationOptions.Parse(ip);
conf.CommandMap = CommandMap.Create(new HashSet<string> {
"INFO", "CONFIG", "CLUSTER","PING", "ECHO", "CLIENT"
}, false);
using (ConnectionMultiplexer conn = ConnectionMultiplexer.Connect(conf))
{
var db = conn.GetDatabase();
Do(db);
}
Console.ReadKey();
}
private static void Do(IDatabase db)
{
/*here throws MOVED Exception:MOVED 12182 192.168.1.20:30003*/
db.StringSet("foo", "changed");
Console.WriteLine("foo now:" + db.StringGet("foo").ToString());
}
}
}
Always show the message "MOVED: 12586[192.168.1.20:30003]".
I search all the offcial document and on the Internet, can't find the right answer. It's OK while I use redis-cli.
How to fix this?Do I need process the exception in my code?If, how?
Seems like you may be running into this issue: https://github.com/StackExchange/StackExchange.Redis/issues/248. If you put a 1 second sleep between your Connect() call and your Do() call, I would guess that you will see the issue go away.
I developed a .NET windows application which worked both on Windows 7 and 8.1. Then I added the Toast notification feature that came with Windows 8 (from this question: How can I use the Windows.UI namespace from a regular (Non-Store) Win32 .NET application?).
This also worked, I just had to add:
<PropertyGroup>
<TargetPlatformVersion>8.0</TargetPlatformVersion>
</PropertyGroup>
to the project file.
As I referenced the Windows.winmd file from the Windows 8.1 SDK C:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Windows.winmd, the executable does not start on Windows 7 anymore! I double-click and that's it. No errors, no messages.
As I did not find any solution online, that's where my question comes up: How do I manage to do both: Offer the toast feature to my users AND make the same .exe run on Windows 7?
Thank you in advance!
EDIT
It turns out that though TargetPlatformVersion is set to 8.0, the executable starts on Windows 7 anyway, but crashes as soon as the program tries to load the Windows 8 libraries:
An unhandled exception of type 'System.TypeLoadException' occurred in ToastTester.exe.
Additional information: Could not find Windows Runtime type 'Windows.UI.Notifications.ToastNotificationManager'.
on line Application.Run(new Form1());
In Form1.cs in line 9 I've got using Windows.UI.Notifications;
What is the best way to avoid this exception during runtime, even though it is expected that this executable will run in environments like Windows 7 where the Windows.UI.Notifications namespace is definitely not available?
I designed my own workaround for being able to support Windows 8 toasts and at the same time prevent application crashes due to missing libraries when running on Windows 7. Note: I am using the Singleton design pattern (member INSTANCE), but you can always do it otherwise.
ShellLink.cs is taken from here
Win8Toaster.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
namespace ToastManager
{
class Win8Toaster
{
public const string APPUSERMODELID = "YourCompany.YourApplicationName";
public static string ShortcutLocation;
public static ToastNotifier ToastNotifier;
private static Win8Toaster _INSTANCE = null;
public static Win8Toaster INSTANCE
{
get
{
if (_INSTANCE == null)
{
_INSTANCE = new Win8Toaster();
}
return _INSTANCE;
}
}
public Win8Toaster()
{
ShortcutLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + #"\Microsoft\Windows\Start Menu\Programs\YourCompany\YourApplication.lnk");
//We need a start menu shortcut (a ShellLink object) to show toasts.
if (!File.Exists(ShortcutLocation))
{
string directory = Path.GetDirectoryName(ShortcutLocation);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (ShellLink shortcut = new ShellLink())
{
shortcut.TargetPath = System.Reflection.Assembly.GetEntryAssembly().Location;
shortcut.Arguments = "";
shortcut.AppUserModelID = APPUSERMODELID;
shortcut.Save(ShortcutLocation);
}
}
ToastNotifier = ToastNotificationManager.CreateToastNotifier(APPUSERMODELID);
}
public void ShowToast(ToastContent Content)
{
XmlDocument ToastContent = new XmlDocument();
ToastContent.LoadXml("<toast><visual><binding template=\"ToastImageAndText02\"><image id=\"1\" src=\"file:///" + Content.ImagePath + "\"/><text id=\"1\">" + Content.Text1 + "</text><text id=\"2\">" + Content.Text2 + "</text></binding></visual></toast>");
ToastNotification thisToast = new ToastNotification(ToastContent);
ToastNotifier.Show(thisToast);
}
}
}
Toaster.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace ToastManager
{
public static class Toaster
{
private static Win8Toaster ActiveToaster;
public static bool Win8ToasterAvailable = true;
public static void ShowToast(ToastContent Content)
{
if (Win8ToasterAvailable)
{
if (ActiveToaster == null)
{
if (Environment.OSVersion.Version.Major > 6 || Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2)
{
try
{
ActiveToaster = Win8Toaster.INSTANCE;
}
catch (Exception ex)
{
Win8ToasterAvailable = false;
}
}
else
{
Win8ToasterAvailable = false;
}
}
ActiveToaster.ShowToast(Content);
}
else
{
//Use alternative notifications because Windows 8 Toasts are not available
}
}
}
//I also wrote my own toast content structure:
public class ToastContent
{
public string ImagePath, Text1, Text2;
public ToastContent(string ImagePath, string Text1, string Text2)
{
this.ImagePath = ImagePath;
this.Text1 = Text1;
this.Text2 = Text2;
}
}
}
Now that you've got the necessary classes, here is how to use it (pretty simple, huh?):
ToastManager.Toaster.ShowToast(new ToastManager.ToastContent(#"..\path\toyour\image.png", "Your Application Name", "Time: " + DateTime.Now.ToLongTimeString()));
This example shows a toast notification with the current system time or nothing if you are on Windows 7.
A design suggestion:
I used WinForms to design a notification window which looks similar to that in Windows 8 and simulates the same functions, just with my own forms. Alternatively you can also implement a tray icon and show some notification bubbles.
I have to create a class that will load all the dll's from repository and check whether
they are inheriting from IMFServicePlugin interface and returns the
valid dlls.
that I have done using this...
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Windows.Forms.ComponentModel;
using MFDBAnalyser;
namespace MFDBAnalyserAssemblyValidator
{
public class MFDBAnalyserAssemblyValidator
{
static void Main(string[] args)
{
List<string> assemblyNames = new List<string>();
Assembly[] oAssemblies = new Assembly[args.Length];
for (int assemblyCount = 0; assemblyCount < args.Length; assemblyCount++)
{
oAssemblies[assemblyCount] = Assembly.LoadFile(args[assemblyCount]);
try
{
foreach (Type oType in oAssemblies[assemblyCount].GetTypes())
{
// Check whether class is inheriting from IMFServicePlugin.
if (oType.GetInterface("IMFDBAnalyserPlugin") == typeof(IMFDBAnalyserPlugin))
{
assemblyNames.Add(args[assemblyCount].Substring(args[assemblyCount].LastIndexOf("\\") + 1));
}
}
}
catch (Exception ex)
{
lblError.Text = "ERROR";
}
}
// Passing data one application domain to another.
AppDomain.CurrentDomain.SetData("AssemblyNames", assemblyNames.ToArray());
}
}
}
but this was for loading the dll from the repository but I also want to store these dll in another ORM class.
Can anybody help me out...
If possible plz provide some links so that I can get a sufficient idea of how dll works for an windows/desktop application.
At a first tip you should use Assembly.ReflectionOnlyLoad(). Cause if you load the assembly by using Assembly.LoadFile() the assembly will automatically be put into your local AppDomain!
Let's say I have a windows service called "MyService" and an executable called "MyEXE"
Is it possible (from within "MyService") to start several instances of "MyEXE" running in seperate application domains in parallel?
I would apprecaiate if some one can also provide a small sample using .net.
As long as it is a managed program then, yes, you can run it in its own AppDomain. You'll need a thread to run the code, AppDomain.ExecuteAssembly() is the handy one that automatically starts running the Main() method of that program. Here's an example that uses two console mode applications:
using System;
using System.Threading;
using System.IO;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
string exePath = #"c:\projects\consoleapplication2\bin\debug\consoleapplication2.exe";
for (int ix = 0; ix < 10; ++ix) {
var setup = new AppDomainSetup();
setup.ApplicationBase = Path.GetDirectoryName(exePath);
var ad = AppDomain.CreateDomain(string.Format("Domain #{0}", ix + 1), null, setup);
var t = new Thread(() => {
ad.ExecuteAssembly(exePath);
AppDomain.Unload(ad);
});
t.Start();
}
Console.ReadLine();
}
}
}
And the one that's ran 10 times:
using System;
namespace ConsoleApplication2 {
class Program {
static void Main(string[] args) {
Console.WriteLine("Hello from {0}", AppDomain.CurrentDomain.FriendlyName);
}
}
}
One thing I didn't count on and stuck under a table a bit, the AppDomainSetup.ApplicationBase property didn't work as I expected. I had to pass the full path of the EXE to ExecuteAssembly() instead of just passing "consoleapplication2.exe". That was odd.