Preventing GC from taking my delegate in C# - c#

I'm referring back to a post i made a long time ago as i've only just got back to working with this WRG305API.dll.
With referral to: calling C++ functions containing callbacks in C#
Ive been trying to write an app that interfaces with this DLL and thanks to the guys that helped me back then. I've been able to get it working for a short period of time.
Ive been stopped by this annoying issue which is stated as:
A callback was made on a garbage collected delegate of type 'WinFFT!WinFFT.winradioIO.winRadioIOWrapper+CallbackFunc::Invoke'. This may cause application crashes ...
Here is the wrapper code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace WinFFT.winradioIO
{
class winRadioIOWrapper
{
private const string APIDLL_PATH = "WRG305API.dll";
public delegate void CallbackFunc(IntPtr p);
public CallbackFunc mycallback;
[StructLayout(LayoutKind.Sequential)]
public struct Features
{
public uint feature;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RadioInfo
{
public uint length;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string serialNumber;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string productName;
public UInt64 minFrequency;
public UInt64 maxFrequency;
public Features feature;
}
[DllImport(APIDLL_PATH)]
public static extern int OpenRadioDevice(int deviceNumber);
[DllImport(APIDLL_PATH)]
public static extern bool CloseRadioDevice(int radioHandle);
[DllImport(APIDLL_PATH)]
public static extern int GetRadioList(ref RadioInfo info, int bufferSize, ref int infoSize);
[DllImport(APIDLL_PATH)]
public static extern bool IsDeviceConnected(int radioHandle);
[DllImport(APIDLL_PATH)]
public static extern bool GetInfo(int radioHandle, ref RadioInfo info);
[DllImport(APIDLL_PATH)]
public static extern int GetFrequency(int radioHandle);
[DllImport(APIDLL_PATH)]
public static extern bool SetFrequency(int radioHandle, int frequency);
[DllImport(APIDLL_PATH)]
private static extern bool CodecStart(int hRadio, CallbackFunc func, IntPtr CallbackTarget);
[DllImport(APIDLL_PATH)]
private static extern uint CodecRead(int hRadio, byte[] Buf, uint Size);
[DllImport(APIDLL_PATH)]
private static extern bool CodecStop(int hRadio);
public static bool startIFStream(int radioHandle)
{
bool bStarted = CodecStart(radioHandle, MyCallbackFunc, IntPtr.Zero);
return bStarted;
}
// Note: this method will be called from a different thread!
private static void MyCallbackFunc(IntPtr pData)
{
// Sophisticated work goes here...
}
public static void readIFStreamBlock(int radioHandle, byte[] streamDumpLocation, uint blockSize)
{
CodecRead(radioHandle, streamDumpLocation, blockSize);
}
public static bool stopIFStream(int radioHandle)
{
bool bStoped = CodecStop(radioHandle);
return bStoped;
}
}
}
Here is my Application interfacing class layer which provides the friendly methods to use the dll interface:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace WinFFT.winradioIO
{
class radioInterface
{
enum DeviceStatus { Disconnected, Connected, Unknown };
private static DeviceStatus deviceStatus = DeviceStatus.Unknown;
public static string radioName, serialNumber;
public static int minimumFreq, maximumFreq;
static int radioHandle;
static radioInterface()
{
InitializeDeviceConnection();
}
public static void duffMethod(IntPtr ptr)
{
}
private static void InitializeDeviceConnection()
{
winRadioIOWrapper.CloseRadioDevice(radioHandle);
deviceStatus = DeviceStatus.Disconnected;
// Get Radio Info
winRadioIOWrapper.RadioInfo radioInfo = new winRadioIOWrapper.RadioInfo();
int aStructSize = Marshal.SizeOf(radioInfo), anInfoSize = 0;
radioInfo.length = (uint)aStructSize;
if (winRadioIOWrapper.GetRadioList(ref radioInfo, aStructSize, ref anInfoSize) == 1)
{
radioName = radioInfo.productName;
serialNumber = radioInfo.serialNumber;
minimumFreq = (int)radioInfo.minFrequency;
maximumFreq = (int)radioInfo.maxFrequency;
}
// Open device
radioHandle = winRadioIOWrapper.OpenRadioDevice(0);
CheckDeviceConnection();
}
private static void CheckDeviceConnection()
{
bool anIsDeviceConnected = winRadioIOWrapper.IsDeviceConnected(radioHandle);
if (deviceStatus == DeviceStatus.Unknown ||
deviceStatus == DeviceStatus.Disconnected && anIsDeviceConnected ||
deviceStatus == DeviceStatus.Connected && !anIsDeviceConnected)
{
if (anIsDeviceConnected)
{
deviceStatus = DeviceStatus.Connected;
winRadioIOWrapper.startIFStream(radioHandle);
}
else
{
winRadioIOWrapper.CloseRadioDevice(radioHandle);
deviceStatus = DeviceStatus.Disconnected;
}
}
}
public static void ReadIFStream(ref byte[] bufferLocation)
{
winRadioIOWrapper.readIFStreamBlock(radioHandle, bufferLocation, (uint)bufferLocation.Length);
}
public static void SetFreq(int valueInHz)
{
winRadioIOWrapper.SetFrequency(radioHandle, valueInHz);
}
public static void ShutDownRadio()
{
winRadioIOWrapper.CloseRadioDevice(radioHandle);
}
}
}
I Understand why AVIDeveloper chose the path, its is brilliant for continuously streaming out the data from the WinRadio Reciever (which is what the DLL is for), but the function CodecRead in the DLL allows one to copy a specified number of bytes from the radio's buffer. This is the path I went as I want to control how regularly I take the data and hence why I left the delegate function alone. But with this as it is at the moment, I am loosing the delegate in the wrapper to the GC and I am really stumped on how to prevent this.
Thanks in Advance guys.

Store the delegate as a field.
private static CallbackFunc _callback = new CallbackFunc(MyCallbackFunc);
public static bool startIFStream(int radioHandle)
{
bool bStarted = CodecStart(radioHandle, _callback, IntPtr.Zero);
return bStarted;
}

Related

AccessViolationException when calling vkEnumeratePhysicalDevices via pInvoke from c#

I have the keen idea to write a wrapper for Vulkan in c#.
Unfortunately the second call of the Vulkan API already fails unexplainably.
The code below is taken from Sascha Willems' Vulkan examples and converted into c# code:
Vk.ApplicationInfo applicationInfo = new Vk.ApplicationInfo();
applicationInfo.sType = Vk.StructureType.STRUCTURE_TYPE_APPLICATION_INFO;
applicationInfo.pApplicationName = "Example";
applicationInfo.pEngineName = "Example";
applicationInfo.apiVersion = (uint)Math.Pow(2, 22) + 2;
string[] enabledExtensions = new string[] { "VK_KHR_surface", "VK_KHR_win32_surface" };
Vk.InstanceCreateInfo instanceCreateInfo = new Vk.InstanceCreateInfo();
instanceCreateInfo.sType = Vk.StructureType.STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pNext = null;
instanceCreateInfo.pApplicationInfo = applicationInfo;
instanceCreateInfo.enabledExtensionCount = (uint)enabledExtensions.Count();
instanceCreateInfo.ppEnabledExtensionNames = enabledExtensions;
Vk.Instance theInstance = new Vk.Instance();
Vk.Result vr = Vk.vkCreateInstance(instanceCreateInfo, IntPtr.Zero, theInstance);
// vr = SUCCESS
uint gpuCount = 0;
vr = Vk.vkEnumeratePhysicalDevices(theInstance, ref gpuCount, IntPtr.Zero);
//Fails with System.AccessViolationException
with
public static class Vk
{
public enum Result
{
SUCCESS = 0,
...
};
public enum StructureType
{
...
}
static Vk()
{
List<string> path = new List<string>() { #"C:\VulkanSDK\1.0.3.1\Source\lib32\" };
AddEnvironmentPaths(path);
}
static void AddEnvironmentPaths(IEnumerable<string> paths)
{
var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty };
string newPath = string.Join(Path.PathSeparator.ToString(), path.Concat(paths));
Environment.SetEnvironmentVariable("PATH", newPath);
}
[DllImport("vulkan-1.dll")]
public static extern Result vkCreateInstance(InstanceCreateInfo instanceCreateInfo, IntPtr pAllocator, Instance instance);
[StructLayout(LayoutKind.Sequential)]
public class InstanceCreateInfo
{
public StructureType sType;
public object pNext;
public uint flags;
public ApplicationInfo pApplicationInfo;
public uint enabledLayerCount;
public string[] ppEnabledLayerNames;
public uint enabledExtensionCount;
public string[] ppEnabledExtensionNames;
}
[StructLayout(LayoutKind.Sequential)]
public class ApplicationInfo
{
public StructureType sType;
public object pNext;
public string pApplicationName;
public uint applicationVersion;
public string pEngineName;
public uint engineVersion;
public uint apiVersion;
}
[StructLayout(LayoutKind.Sequential)]
public class Instance
{
}
[DllImport("vulkan-1.dll")]
public static extern Result vkEnumeratePhysicalDevices(Instance instance, ref uint pPhysicalDeviceCount, PhysicalDevice pPhysicalDevices);
[DllImport("vulkan-1.dll")]
public static extern Result vkEnumeratePhysicalDevices(Instance instance, ref uint pPhysicalDeviceCount, IntPtr pPhysicalDevices);
public class PhysicalDevice
{
}
}
My Suspicion is that Vk.Instance should be something else than just an empty class. VkInstance is in the official vulkan.h defined as typedef struct VkInstance_T* VkInstance. My understanding of this line is unfortunately very limited. I already tried exchanging the type Vk.Instance with IntPtr and object but without success.
Theses are important segments from vulkan.h
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkInstance)
VK_DEFINE_HANDLE(VkPhysicalDevice)
VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
VkInstance instance,
uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices);
Zastai answered my question.
It had to be
[DllImport("vulkan-1.dll")]
public static extern Result vkCreateInstance(InstanceCreateInfo instanceCreateInfo, IntPtr pAllocator, out IntPtr instance);
because it were indeed pointers to pointers.
IntPtr instance;
Vk.Result vr = Vk.vkCreateInstance(instanceCreateInfo, IntPtr.Zero, out instance);
uint gpuCount = 0;
vr = Vk.vkEnumeratePhysicalDevices(instance, ref gpuCount, IntPtr.Zero);
Thanks a lot!

Get total amount of memory from WinXP and above

There are already many answers about this topic, but is there a single way to get the the total amount of memory on a windows system from XP and above including Windows Server 2003?
What I have found:
Win32_LogicalMemoryConfiguration (Deprecated)
Win32_ComputerSystem (Minimum supported client: Vista)
Microsoft.VisualBasic.Devices.ComputerInfo (no XP support according to platforms)
thx
Add reference to Microsoft.VisualBasic and
var info = new Microsoft.VisualBasic.Devices.ComputerInfo();
Debug.WriteLine(info.TotalPhysicalMemory);
Debug.WriteLine(info.AvailablePhysicalMemory);
Debug.WriteLine(info.TotalVirtualMemory);
Debug.WriteLine(info.AvailableVirtualMemory);
edit : How can I get the total physical memory in C#?
or
You can make use of GlobalMemoryStatusEx : Example Here
private void DisplayMemory()
{
// Consumer of the NativeMethods class shown below
long tm = System.GC.GetTotalMemory(true);
NativeMethods oMemoryInfo = new NativeMethods();
this.lblMemoryLoadNumber.Text = oMemoryInfo.MemoryLoad.ToString();
this.lblIsMemoryTight.Text = oMemoryInfo.isMemoryTight().ToString();
if (oMemoryInfo.isMemoryTight())
this.lblIsMemoryTight.Text.Font.Bold = true;
else
this.lblIsMemoryTight.Text.Font.Bold = false;
}
Native class wrapper.
[CLSCompliant(false)]
public class NativeMethods {
private MEMORYSTATUSEX msex;
private uint _MemoryLoad;
const int MEMORY_TIGHT_CONST = 80;
public bool isMemoryTight()
{
if (_MemoryLoad > MEMORY_TIGHT_CONST )
return true;
else
return false;
}
public uint MemoryLoad
{
get { return _MemoryLoad; }
internal set { _MemoryLoad = value; }
}
public NativeMethods() {
msex = new MEMORYSTATUSEX();
if (GlobalMemoryStatusEx(msex)) {
_MemoryLoad = msex.dwMemoryLoad;
//etc.. Repeat for other structure members
}
else
// Use a more appropriate Exception Type. 'Exception' should almost never be thrown
throw new Exception("Unable to initalize the GlobalMemoryStatusEx API");
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint) Marshal.SizeOf(typeof( MEMORYSTATUSEX ));
}
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx( [In, Out] MEMORYSTATUSEX lpBuffer);
}

Get Multiple Cell IDs for location using Cellular Towers C# Windows Mobile

Following Microsoft's documentation on RIL I've been able to implement a code that retrieves Cell ID, LAC, MCC, MNC and Signal Strength. Using these data and http://www.opencellid.org/ I'm able to retrieve latitude and longitude of that cell tower. The problem is that I need to implement some kind of triangulation algorithm to get a more accurate position. But before even thinking in triangulation, I'm going to need more than one tower ID to work with. How can I get them? I tried to create an array of towerIDs and populate it in a loop, while a tower id does not exist in the array then add it, but if it exists then ignore it and keep looking for another one. Obviously it did not work, once it gets one it keeps it and if I delete the object and create a new one it gets the same tower. How can I get a different one?
Thanks in advance.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace GPS_Test
{
public class CellTower
{
public int CellID { get; set; }
// LAC (Local Area Code)
public int LAC { get; set; }
// MCC (Mobile Country Code)
public int MCC { get; set; }
// MNC (Mobile Network Code)
public int MNC { get; set; }
// Received signal strength
public int signalStrength { get; set; }
// Base Station ID
//public int baseStationID { get; set; }
}
public class RIL
{
public delegate void RILRESULTCALLBACK(uint dwCode,
IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam);
public delegate void RILNOTIFYCALLBACK(uint dwCode,
IntPtr lpData, uint cbData, uint dwParam);
[DllImport("ril.dll")]
public static extern IntPtr RIL_Initialize(uint dwIndex,
RILRESULTCALLBACK pfnResult,
RILNOTIFYCALLBACK pfnNotify,
uint dwNotificationClasses,
uint dwParam,
out IntPtr lphRil);
[DllImport("ril.dll", EntryPoint = "RIL_GetCellTowerInfo")]
public static extern IntPtr RIL_GetCellTowerInfo(IntPtr hril);
[DllImport("ril.dll")]
public static extern IntPtr RIL_Deinitialize(IntPtr hril);
[DllImport("ril.dll", EntryPoint = "RIL_GetSignalQuality")]
public static extern IntPtr RIL_GetSignalQuality(IntPtr hRil);
[StructLayout(LayoutKind.Explicit)]
internal class RILCELLTOWERINFO
{
[FieldOffset(0)]
uint dwSize;
[FieldOffset(4)]
uint dwParams;
[FieldOffset(8)]
public uint dwMobileCountryCode;
[FieldOffset(12)]
public uint dwMobileNetworkCode;
[FieldOffset(16)]
public uint dwLocationAreaCode;
[FieldOffset(20)]
public uint dwCellID;
[FieldOffset(28)]
public uint dwBaseStationID;
[FieldOffset(36)]
public uint dwRxLevel;
}
[StructLayout(LayoutKind.Explicit)]
internal class RILSIGNALQUALITY
{
[FieldOffset(0)]
uint dwSize;
[FieldOffset(4)]
uint dwParams;
[FieldOffset(8)]
public int nSignalStrength;
[FieldOffset(12)]
public uint nMinSignalStrength;
[FieldOffset(16)]
public uint nMaxSignalStrength;
[FieldOffset(20)]
public uint dwBitErrorRate;
[FieldOffset(24)]
public uint nLowSignalStrength;
[FieldOffset(28)]
public uint nHighSignalStrength;
}
}
public class CellTowerInfo
{
private static AutoResetEvent dataReceived = new AutoResetEvent(false);
private static AutoResetEvent whSignalQuality = new AutoResetEvent(false);
private static RIL.RILCELLTOWERINFO towerInfo;
private static RIL.RILSIGNALQUALITY signalQuality;
public static CellTower GetCellTowerInfo()
{
IntPtr hRil = IntPtr.Zero;
IntPtr hResult = IntPtr.Zero;
hResult = RIL.RIL_Initialize(1,
new RIL.RILRESULTCALLBACK(CellTowerData),
null, 0, 0, out hRil);
if (hResult != IntPtr.Zero)
return null;
hResult = RIL.RIL_GetCellTowerInfo(hRil);
dataReceived.WaitOne();
RIL.RIL_Deinitialize(hRil);
CellTower ct = new CellTower();
ct.LAC = (int)towerInfo.dwLocationAreaCode;
ct.MCC = (int)towerInfo.dwMobileCountryCode;
ct.MNC = (int)towerInfo.dwMobileNetworkCode;
ct.CellID = (int)towerInfo.dwCellID;
ct.signalStrength = GetSignalQuality();
return ct;
}
public static int GetSignalQuality()
{
IntPtr hRes = IntPtr.Zero;
IntPtr hSignalQ = IntPtr.Zero;
hRes = RIL.RIL_Initialize(1, new RIL.RILRESULTCALLBACK(SignalQualityCallback),
null, 0, 0, out hSignalQ);
hRes = RIL.RIL_GetSignalQuality(hSignalQ);
whSignalQuality.WaitOne();
RIL.RIL_Deinitialize(hSignalQ);
return signalQuality.nSignalStrength;
}
private static void CellTowerData(uint dwCode, IntPtr hrCmdID,
IntPtr lpData, uint cbData, uint dwPara)
{
towerInfo = new RIL.RILCELLTOWERINFO();
Marshal.PtrToStructure(lpData, (object)towerInfo);
dataReceived.Set();
}
private static void SignalQualityCallback(uint dwCode, IntPtr hrCmdID,
IntPtr lpData, uint cbData, uint dwPara)
{
signalQuality = new RIL.RILSIGNALQUALITY();
Marshal.PtrToStructure(lpData, (object)signalQuality);
whSignalQuality.Set();
}
}
}
Try to save all the info regarding the current signal, after doing so restart the service looking to another signal but first check the one you had stored, if it's the same disregard and keep looking.
Good luck!

Get all directories and catch permissions exception and continue

public void newestFile(string path)
{
try
{
foreach (var item in dir.GetDirectories("*.*", SearchOption.AllDirectories))
{
var file = item.GetFiles().OrderByDescending(f => f.LastWriteTime).First();
}
}
catch (Exception ex)
{
}
}
I want to get the newest file from each directory from specific path and continue after catch the permission exception, currently my code stuck in catch and not continue.
Unfortunately Microsoft's implementation of GetDirectories() is extremely poor, and doesn't handle IO exceptions relating to access rights.
If you want to just skip over directories that you don't have access to (such as the special Recycle Bin folder, for example), then you have to write your own wrapper for the Windows API functions FindFirstFile() and FindNextFile().
Here's a complete example. If you run it, you'll see that it lists all the accessible directories on your C: drive.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
namespace Demo
{
public class Program
{
private void run()
{
string root = "C:\\";
foreach (var folder in FolderEnumerator.EnumerateFoldersRecursively(root))
Console.WriteLine(folder);
}
private static void Main()
{
new Program().run();
}
}
public static class FolderEnumerator
{
public static IEnumerable<string> EnumerateFoldersRecursively(string root)
{
foreach (var folder in EnumerateFolders(root))
{
yield return folder;
foreach (var subfolder in EnumerateFoldersRecursively(folder))
yield return subfolder;
}
}
public static IEnumerable<string> EnumerateFolders(string root)
{
WIN32_FIND_DATA findData;
string spec = Path.Combine(root, "*");
using (SafeFindHandle findHandle = FindFirstFile(spec, out findData))
{
if (!findHandle.IsInvalid)
{
do
{
if ((findData.cFileName != ".") && (findData.cFileName != "..")) // Ignore special "." and ".." folders.
{
if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
{
yield return Path.Combine(root, findData.cFileName);
}
}
}
while (FindNextFile(findHandle, out findData));
}
}
}
internal sealed class SafeFindHandle: SafeHandleZeroOrMinusOneIsInvalid
{
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public SafeFindHandle(): base(true)
{
}
protected override bool ReleaseHandle()
{
if (!IsInvalid && !IsClosed)
{
return FindClose(this);
}
return (IsInvalid || IsClosed);
}
protected override void Dispose(bool disposing)
{
if (!IsInvalid && !IsClosed)
{
FindClose(this);
}
base.Dispose(disposing);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
public long ToLong()
{
return dwLowDateTime + ((long)dwHighDateTime) << 32;
}
};
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct WIN32_FIND_DATA
{
public FileAttributes dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public int nFileSizeHigh;
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_ALTERNATE)]
public string cAlternate;
}
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern SafeFindHandle FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FindNextFile(SafeHandle hFindFile, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FindClose(SafeHandle hFindFile);
private const int MAX_PATH = 260;
private const int MAX_ALTERNATE = 14;
}
}
Note: This code uses FindFirstFile() and FindNextFile() which iterate through all folders AND files. The code above is just ignoring the files and only returning the folders.
It would be more efficient to use FindFirstFileEx() and specify a flag to return only directories. I leave that change as the proverbial exercise for the reader. ;)
public string[] newestFile(string path){
IEnumerable<string> files = new string[]{};
foreach (var item in dir.GetDirectories(Path.Combine(path,"*.*"), SearchOption.AllDirectories))
{
try {
files = files.Concat(item.GetFiles().OrderByDescending(f => f.LastWriteTime).First());
}
catch {}
}
return files.ToArray();
}

how to use RegisterHotKey() in C#? [duplicate]

This question already has answers here:
Global hotkey in console application
(4 answers)
Closed 8 years ago.
I'm trying to register a hot key, I'm translating this C++ code into C#:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("user32.dll")]
public static extern
bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, int vk);
[DllImport("user32")]
public static extern
bool GetMessage(ref Message lpMsg, IntPtr handle, uint mMsgFilterInMain, uint mMsgFilterMax);
public const int MOD_ALT = 0x0001;
public const int MOD_CONTROL = 0x0002;
public const int MOD_SHIFT = 0x004;
public const int MOD_NOREPEAT = 0x400;
public const int WM_HOTKEY = 0x312;
public const int DSIX = 0x36;
static void Main(string[] args)
{
if (!RegisterHotKey(IntPtr.Zero, 1, MOD_ALT | MOD_NOREPEAT, DSIX))
{
Console.WriteLine("failed key register!");
}
Message msg = new Message();
while (!GetMessage(ref msg, IntPtr.Zero, 0, 0))
{
if (msg.message == WM_HOTKEY)
{
Console.WriteLine("do work..");
}
}
Console.ReadLine();
}
}
public class Message
{
public int message { get; set; }
}
}
but RegisterHotKey() never returns false.
I'm not sure about the arguments passed in the method, IntPtr.Zero should be null, and message class constructor's second argument requires an object. any help is very appreciated!
This might help:
Hotkey in console app
Basically, you have to create a "hidden" form to make it work

Categories