I would like to use NAudio for a record program, but I'm hitting an unexpected limitation. NAudio.Wave.WaveIn.GetCapabilities(deviceNumber) returns a WaveInCapabilities structure, but only a few fields of that structure are public.
In particular I need to know which formats are supported by the device. That information is in:
private SupportedWaveFormat supportedFormats;
I can change that to public and build NAaudio.dll, but I'm wondering if there is some reason that field is marked private? Or is there another place I can find that information?
there was an example on the web, i edited it, and this works for me to get all the capabilites from different devices (it's quite ugly, but it works...):
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections;
namespace _4ch_stream
{
class clsRecDevices
{
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct WaveInCaps
{
public short wMid;
public short wPid;
public int vDriverVersion;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szPname;
public uint dwFormats;
public short wChannels;
public short wReserved1;
}
[DllImport("winmm.dll")]
public static extern int waveInGetNumDevs();
[DllImport("winmm.dll", EntryPoint = "waveInGetDevCaps")]
public static extern int waveInGetDevCapsA(int uDeviceID,
ref WaveInCaps lpCaps, int uSize);
public ArrayList arrLst = new ArrayList();
//using to store all sound recording devices strings
static int devcount = waveInGetNumDevs();
public static short[] Mid = new short[devcount];
public static short[] Pid = new short[devcount];
public static int[] DriverVersion = new int[devcount];
public static uint[] Formats = new uint[devcount];
public static short[] Channels = new short[devcount];
public static short[] Reserved1 = new short[devcount];
public int Count
//to return total sound recording devices found
{
get { return arrLst.Count; }
}
public string this[int indexer]
//return spesipic sound recording device name
{
get { return (string)arrLst[indexer]; }
}
public clsRecDevices() //fill sound recording devices array
{
int waveInDevicesCount = waveInGetNumDevs(); //get total
if (waveInDevicesCount > 0)
{
for (int uDeviceID = 0; uDeviceID < waveInDevicesCount; uDeviceID++)
{
WaveInCaps waveInCaps = new WaveInCaps();
waveInGetDevCapsA(uDeviceID, ref waveInCaps,
Marshal.SizeOf(typeof(WaveInCaps)));
arrLst.Add(new string(waveInCaps.szPname).Remove(
new string(waveInCaps.szPname).IndexOf('\0')).Trim());
Mid[uDeviceID] = waveInCaps.wMid;
Pid[uDeviceID] = waveInCaps.wPid;
Formats[uDeviceID] = waveInCaps.dwFormats;
Channels[uDeviceID] = waveInCaps.wChannels;
Reserved1[uDeviceID] = waveInCaps.wReserved1;
//clean garbage
}
}
}
}
}
Hope it helped.
Related
I am very confused about something in java. So the project I was given is write stacks in java, and the program begins with public class Stack<T extends Comparable<? super T>>. However, when trying to run it in my testing program, no matter the kind of Object I throw at it (Integer, String), it all return the error Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable. My question is how does this sort of generics that implement generic T but also extends Comparable work, and why String still returned the error message (I thought String already implemented Comparable<String>?). Thanks in advance for taking the time to read the question! Here is the rough outline of the code:
public class Stack <T extends Comparable<? super T>>{
private T[] arr;
private int ptr;
private int size;
public Stack(){
this.size = 20;
arr = (T[]) new Object[size];
ptr = -1;
}
public boolean push(T element){
try {
arr[ptr+1] = element;
ptr++;
return true;
}
catch (Exception e) {
return false;
}
}
public T[] toArray(){
return arr;
}
}
I got this error from creating a JUnit testing class, with the implementation of something like:
import static org.junit.Assert.assertEquals;
public class StackTester{
#Test
public void testPush(){
Stack<String> st = new Stack<String>();
for (int i = 0; i < 5; i++){
String var = new Integer(i).toString();
st.push(var);
}
assertEquals(new Integer[]{"3","4","5"}, st.toArray());
}
}
public class StackTester{
#Test
public void testPush(){
Stack<String> st = new Stack<String>();
//normal case
for (int i = 0; i < 5; i++){
String var = new Integer(i).toString();
st.push(var);
}
assertEquals(new Integer[]{3,4,5}, st.toArray());
}
}
Also, I have not added a compareTo method as I don't know what it should compare to, and I don't think there's a particular use case for adding that method. I should add that the goal of this project is to use stacks to manipulate Strings (such as going from infix to postfix).
P.S: I would also mention that I don't really need to compare stacks in my project, which is why the stack class itself is not implementing the Comparable interface.
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker1>();
services.AddHostedService<Worker2>();
})
.Build();
await host.RunAsync();
In VS2022, inside Program.cs(the above is its whole content), I couldn't even declare the gloabal static variables (to be shared and updated by the two Worker), how to do that so that I can use Locks to sync updates between the two Workers. Any help will be appreciated.
It's resolved based on #AndrewSilver suggestions, put shared variable in a separate file:
public static class AK_Configs
{
public static bool notOK = false;
public static object _lock = new object();
public static Flags flags = new Flags();
public static Random random = new Random();
public static int countInc = 0;
public static int countDec = 0;
public static int countCheck = 0;
}
public class Flags
{
public int I { get; set; }
public int J { get; set; }
public override string ToString()
{
return $"I={I},J={J}";
}
}
Program:
services.AddHostedService<Worker1>();//read/wite Worker
services.AddHostedService<Worker2>();//read/wite Worker
services.AddHostedService<Worker3>();//readonly Worker
Worker1: increment both I and J
while (!stoppingToken.IsCancellationRequested)
{
lock (AK_Configs._lock)
{
AK_Configs.countInc++;
Thread.Sleep(AK_Configs.random.Next(10) * 100);
AK_Configs.flags.I++;
Thread.Sleep(AK_Configs.random.Next(10) * 100);
AK_Configs.flags.J++;
_logger.LogInformation($"===Increase {AK_Configs.countInc}:{AK_Configs.flags}");
}
await Task.Delay(15, stoppingToken);
}
Work2: decrement both I and J
while (!stoppingToken.IsCancellationRequested)
{
lock (AK_Configs._lock)
{
AK_Configs.countDec++;
Thread.Sleep(AK_Configs.random.Next(10)*100);
AK_Configs.flags.I--;
Thread.Sleep(AK_Configs.random.Next(10)*100);
AK_Configs.flags.J--;
_logger.LogInformation($"---Decrease {AK_Configs.countDec}:{AK_Configs.flags}");
}
await Task.Delay(15, stoppingToken);
}
Worker3:read only and watch for data inconsitence
while (!stoppingToken.IsCancellationRequested)
{
lock (AK_Configs._lock)
{
AK_Configs.countCheck++;
if (AK_Configs.flags.I != AK_Configs.flags.J)
{
_logger.LogInformation("Data corrupted! flags:" + (AK_Configs.flags));
_appLifetime.StopApplication();
}
}
await Task.Delay(15, stoppingToken);
}
I'm trying to start a UI application from a java based Windows Service. If figured out so far, that the only approach to make this work is to get a list of sessions, find the one thats currently active, get the user handle for that session and finally create a new process for the given user.
I'm starting off by implementing the session enumeration using WTSEnumerateSessions, yet I'm struggling to get this working. The problem seems to be my mapping of the "_Out_ PWTS_SESSION_INFO *ppSessionInfo" parameter. I wrote the following code:
public interface Wtsapi32 extends StdCallLibrary {
Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
boolean WTSEnumerateSessions(IntByReference hServer, int Reserved, int Version, WTS_SESSION_INFO.ByReference[] ppSessionInfo, IntByReference pCount) throws LastErrorException;
class WTS_SESSION_INFO extends Structure {
public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}
public int sessionId;
public String pWinStationName;
public int state;
#Override
protected List getFieldOrder() {
return Arrays.asList("sessionId", "pWinStationName", "state");
}
}
}
On trying invoking the code with something like this:
public static void main(String[] argv) {
Wtsapi32.WTS_SESSION_INFO.ByReference[] sessionInfo = null;
IntByReference sessionCount = new IntByReference();
try {
if (Wtsapi32.INSTANCE.WTSEnumerateSessions(new IntByReference(0), 0, 1, sessionInfo, sessionCount)) {
System.out.println("success :-)");
}
} catch (LastErrorException ex) {
ex.printStackTrace();
}
}
I get a error code 1784 - ERROR_INVALID_USER_BUFFER. What would be the correct mapping for said API call from JNA?
Update:
I have tried a version suggested Remy Lebeau, but this gives me an Invalid memory access exception:
public interface Wtsapi32 extends StdCallLibrary {
Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
boolean WTSEnumerateSessions(IntByReference hServer, int Reserved, int Version, PointerByReference ppSessionInfo, IntByReference pCount) throws LastErrorException;
class WTS_SESSION_INFO extends Structure {
public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}
public int sessionId;
public String pWinStationName;
public int state;
#Override
protected List getFieldOrder() {
return Arrays.asList("sessionId", "pWinStationName", "state");
}
public WTS_SESSION_INFO() {}
public WTS_SESSION_INFO(Pointer p) {
super(p);
}
}
}
Main:
PointerByReference sessionInfoPtr = new PointerByReference();
IntByReference sessionCount = new IntByReference();
try {
if (Wtsapi32.INSTANCE.WTSEnumerateSessions(new IntByReference(0), 0, 1, sessionInfoPtr, sessionCount)) {
System.out.println("success :-)");
}
} catch (LastErrorException ex) {
ex.printStackTrace();
}
WTSEnumerateSessions() returns:
a pointer to an array of WTS_SESSION_INFO structures
a pointer to a DWORD of the number of elements in the the array.
So you need to pass a PointerByReference for the ppSessionInfo parameter, and a IntByReference for the pCount parameters. You can then use the values being pointed at by those pointers to access the array elements as needed. There is an example of this documented here:
JNA Example #7: Retrieve an Array of Structs from C
Also, your code is using an IntByReference for the hServer parameter. It needs to be a com.sun.jna.platform.win32.WinNT.HANDLE instead, or at least a Pointer. In C, a Win32 HANDLE is just a void* pointer. You need to set the first parameter to Pointer.NULL (which is what WTS_CURRENT_SERVER_HANDLE is defined as in C) to enumerate the sessions of the local server. IntByReference(0) is not the same thing as Pointer.NULL.
And don't forget to call WTSFreeMemory() to free the array data when you are done using it.
Try something like this:
public interface Wtsapi32 extends StdCallLibrary {
Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
boolean WTSEnumerateSessions(Pointer hServer, int Reserved, int Version, PointerByReference ppSessionInfo, IntByReference pCount) throws LastErrorException;
void WTSFreeMemory(Pointer pMemory);
class WTS_SESSION_INFO extends Structure {
public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}
public int sessionId;
public String pWinStationName;
public int state;
public WTS_SESSION_INFO() {}
public WTS_SESSION_INFO(Pointer p) {
super(p);
}
#Override
protected List getFieldOrder() {
return Arrays.asList("sessionId", "pWinStationName", "state");
}
}
}
public static void main(String[] argv) {
PointerByReference sessionInfoPtr = new PointerByReference();
IntByReference sessionCount = new IntByReference();
try {
if (Wtsapi32.INSTANCE.WTSEnumerateSessions(Pointer.NULL, 0, 1, sessionInfoPtr, sessionCount)) {
Pointer sessionInfo = sessionInfoPtr.getValue();
int count = sessionCount.getValue();
Wtsapi32.INSTANCE.WTS_SESSION_INFO arrRef = new Wtsapi32.INSTANCE.WTS_SESSION_INFO(sessionInfo);
arrRef.read(); // <-- not sure why this is here
Wtsapi32.INSTANCE.WTS_SESSION_INFO[] sessions = (Wtsapi32.INSTANCE.WTS_SESSION_INFO[])arrRef.toArray(count);
for (Wtsapi32.INSTANCE.WTS_SESSION_INFO session : sessions) {
// use session as needed...
}
WTSFreeMemory(sessionInfo);
}
} catch (LastErrorException ex) {
ex.printStackTrace();
}
}
I'm writing a Metro app in Windows 8 Consumer Preview.
However, I'm unable to use the TcpClient in .NET 4.5, there doesn't seem to be a place to add the assembly reference.
http://msdn.microsoft.com/en-us/library/1612451t(v=vs.110).aspx
TcpClient is not supported on the metro side. You can use StreamSocket class instead. Here is a sample on how to use it to create a TCP Socket, make a connection, send and receive data. The samples are in JS and C++ but the same class will work for C#.
Ultimately, we should probably use the new Metro NET stuff. However, if porting a lot of code and depending on how much of the TcpClient members you are using, it might not be so bad to just create a limited implementation around the Metro objects. I wanted to do a quick port of a bunch of code over to Metro in a hurry (just to try out some stuff), so I slapped together something that seemed to work, but most certainly not ideal. (You end up doing some sync-ing of async methods which is commonly frowned upon.)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
namespace MetroNetHelper
{
public class IPAddress // assumes IPv4 currently
{
public string IP_String;
public IPAddress() { }
public IPAddress(string IP) { IP_String = IP; }
public static IPAddress Broadcast { get { return new IPAddress("255.255.255.255"); } }
public static IPAddress Parse(string IP) { return new IPAddress(IP); }
public static bool TryParse(string V, out IPAddress Addr)
{
try
{
Addr = IPAddress.Parse(V);
return true;
}
catch { Addr = null; return false; }
}
public HostName GetHostNameObject() { return new HostName(IP_String); }
public byte[] GetAddressBytes()
{
string[] Fields = IP_String.Split('.');
byte[] temp = new byte[4];
for (int i = 0; i < temp.Length; i++) temp[i] = byte.Parse(Fields[i]);
return temp;
}
}
public class IPEndPoint
{
public IPAddress Address;
public int Port;
public IPEndPoint() { }
public IPEndPoint(IPAddress Addr, int PortNum)
{
Address = Addr; Port = PortNum;
}
}
public class NetworkStream
{
private DataReader Reader;
private DataWriter Writer;
public void Set(StreamSocket HostClient)
{
Reader = new DataReader(HostClient.InputStream);
Reader.InputStreamOptions = InputStreamOptions.Partial;
Writer = new DataWriter(HostClient.OutputStream);
}
public int Write(byte[] Buffer, int Offset, int Len)
{
if (Offset != 0 || Len != Buffer.Length) throw new ArgumentException("Can only write whole byte array");
Writer.WriteBytes(Buffer);
Task Tk = Writer.StoreAsync().AsTask();
Tk.Wait();
return Buffer.Length;
}
public int Read(byte[] Buffer, int Offset, int Len)
{
if (Offset != 0 || Len != Buffer.Length) throw new ArgumentException("Can only read whole byte array");
Task<uint> Tk = Reader.LoadAsync((uint)Len).AsTask<uint>();
Tk.Wait();
uint Count = Tk.Result;
for (int i=0;i<Count;i++)
{
Buffer[i] = Reader.ReadByte();
}
return (int)Count;
}
public bool DataAvailable
{
get
{
return true; // Read() will still work if no data; could we do read ahead 1 byte to determine?
}
}
}
public class TcpClient
{
private StreamSocket sock;
public void Connect(IPEndPoint EndPt)
{
try
{
sock = new StreamSocket();
HostName Hst = EndPt.Address.GetHostNameObject();
Task Tsk = sock.ConnectAsync(Hst, EndPt.Port.ToString()).AsTask();
Tsk.Wait();
}
catch (Exception ex) { MetroHelpers.UnpeelAggregate(ex); }
}
public void Close()
{
sock.Dispose();
sock = null;
}
public NetworkStream GetStream()
{
var N = new NetworkStream();
N.Set(sock);
return N;
}
}
public static class MetroHelpers
{
public static void UnpeelAggregate(Exception Ex)
{
AggregateException Ag_Ex = Ex as AggregateException;
if (Ag_Ex == null) throw Ex;
if (Ag_Ex.InnerExceptions.Count > 0)
{
if (Ag_Ex.InnerExceptions.Count == 1) throw Ag_Ex.InnerExceptions[0];
StringBuilder Str = new StringBuilder();
foreach (Exception X in Ag_Ex.InnerExceptions)
{
Str.AppendLine(X.Message);
}
throw new Exception(Str.ToString(), Ag_Ex);
}
else throw Ag_Ex;
}
}
} // END NAMESPACE
This was just something I did quick and dirty in a morning. If it helps anyone with ideas, great. Again, we are most likely better off developing the way Microsoft wants us for Metro apps. It just gets frustrating when they keep changing the ruddy framework. (If Xamarin can keep consistent frameworks on iOS/Android/etc, why can't MS on their own OS's!)
I have a 64-bit Win7 Ultimate machine that I'm calling GetPwrCapabilities on. However it tells me that sleep state 4 (hibernation) is not available and that there is no hibernation file. I can hibernate the machine and there is a hibernation file. Am i doing something wrong? Is there anything else I can call to get accurate supported sleep states
Thanks
EDIT
It's interesting that powercfg -AVAILABLESTATES provides the correct information. Does anyone know what API it calls or why there is a discrepency
Adding Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using System.IO;
using System.Diagnostics;
class Program
{
[DllImport("PowrProf.dll")]
public static extern bool GetPwrCapabilities(out SYSTEM_POWER_CAPABILITIES lpSystemPowerCapabilities);
static void Main(string[] args)
{
SYSTEM_POWER_CAPABILITIES spc;
bool well = GetPwrCapabilities(out spc);
Stream stdOut = System.Console.OpenStandardOutput();
XmlSerializer x = new XmlSerializer(typeof(SYSTEM_POWER_CAPABILITIES));
x.Serialize(stdOut, spc);
}
}
[Serializable]
public struct SYSTEM_POWER_CAPABILITIES
{
public bool PowerButtonPresent;
public bool SleepButtonPresent;
public bool LidPresent;
public bool SystemS1;
public bool SystemS2;
public bool SystemS3;
public bool SystemS4;
public bool SystemS5;
public bool HiberFilePresent;
public bool FullWake;
public bool VideoDimPresent;
public bool ApmPresent;
public bool UpsPresent;
public bool ThermalControl;
public bool ProcessorThrottle;
public byte ProcessorMinThrottle;
public byte ProcessorMaxThrottle;
public bool FastSystemS4;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] spare2;
public bool DiskSpinDown;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] spare3;
public bool SystemBatteriesPresent;
public bool BatteriesAreShortTerm;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public BATTERY_REPORTING_SCALE[] BatteryScale;
public SYSTEM_POWER_STATE AcOnLineWake;
public SYSTEM_POWER_STATE SoftLidWake;
public SYSTEM_POWER_STATE RtcWake;
public SYSTEM_POWER_STATE MinDeviceWakeState;
public SYSTEM_POWER_STATE DefaultLowLatencyWake;
}
public struct BATTERY_REPORTING_SCALE
{
public UInt32 Granularity;
public UInt32 Capacity;
}
public enum SYSTEM_POWER_STATE
{
PowerSystemUnspecified = 0,
PowerSystemWorking = 1,
PowerSystemSleeping1 = 2,
PowerSystemSleeping2 = 3,
PowerSystemSleeping3 = 4,
PowerSystemHibernate = 5,
PowerSystemShutdown = 6,
PowerSystemMaximum = 7
}
bool is marshalled as 4 byte. This matches Win32 BOOL. But Win32 BOOLEAN is one byte, so you need to flag all your SYSTEM_POWER_CAPABILITIES bool members with [MarshalAs(UnmanagedType.I1)].