我试图通过使用Silverlight的注册表找到分配给USB设备的COM端口,并尝试了以下操作:
dynamic WshShell = AutomationFactory.CreateObject("WScript.Shell");
string strRegKeyUSB = @"HKLM\HARDWARE\DEVICEMAP\SERIALCOMM\\Device\USB_COM";
string strCOMValue = WshShell.RegRead(strRegKeyUSB);
这种方法通常100%有效,但DEVICEMAP Key下的所有Value名称都是“\ Device \ XXX” 这导致找不到“路径”,因为SERIALCOMM和Device之间的“\\”不被视为有效(引发错误:“找不到指定的文件”)
据我所知,这只能给我一个选项--P / Invoke,在Silverlight 5中
我正在使用P / Invoke作为SerialWrapper类,打开,读取,写入COM端口,并且只想包含仅从注册表中读取这一个键值所需的最小值 - 我试过了一些我发现的例子,但在Interop,P / Invoke等方面并不强大。我很难找到我需要的部分。
如果有人可以请给我一个基本的例子,只做到这一点(我不需要写入注册表,或阅读QWORDS,或其他任何东西 - 只从这个特定的键读取此字符串值)
我已经尝试过以下帖子(Marshal.PtrToStructure in Silverlight)并且答案与此相关(http://www.pinvoke.net/default.aspx/winspool.enumports),但未能实现这一点,很可能形成缺乏真正的理解; - )
答案 0 :(得分:1)
这是一个读取REG_SZ
值的简单桌面应用程序。它粗糙而简单。它将读取您想要的值。您可能必须使其适应Silverlight。我无法帮助你!
我希望这很有用:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApplication1
{
internal static class NativeMethods
{
public const int ERROR_SUCCESS = 0;
public const uint HKEY_LOCAL_MACHINE = 0x80000002;
public const int KEY_READ = 0x20019;
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegOpenKeyEx(
UIntPtr hKey,
string subKey,
int ulOptions,
int samDesired,
out UIntPtr hkResult
);
[DllImport("advapi32.dll")]
public static extern int RegCloseKey(
UIntPtr hKey
);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegQueryValueEx(
UIntPtr hKey,
string lpValueName,
int lpReserved,
IntPtr type,
IntPtr lpData,
ref int lpcbData
);
}
internal static class RegistryWrapper
{
private static void checkErrorCode(int errorCode)
{
if (errorCode != NativeMethods.ERROR_SUCCESS)
throw new Win32Exception(errorCode);
}
public static string ReadRegString(UIntPtr rootKey, string subKey, string name)
{
UIntPtr hkey;
checkErrorCode(NativeMethods.RegOpenKeyEx(rootKey, subKey, 0, NativeMethods.KEY_READ, out hkey));
try
{
int cbData = 0;
checkErrorCode(NativeMethods.RegQueryValueEx(hkey, name, 0, IntPtr.Zero, IntPtr.Zero, ref cbData));
IntPtr ptr = Marshal.AllocHGlobal(cbData);
try
{
checkErrorCode(NativeMethods.RegQueryValueEx(hkey, name, 0, IntPtr.Zero, ptr, ref cbData));
return Marshal.PtrToStringUni(ptr, cbData / sizeof(char)).TrimEnd('\0');
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
finally
{
checkErrorCode(NativeMethods.RegCloseKey(hkey));
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(RegistryWrapper.ReadRegString((UIntPtr)NativeMethods.HKEY_LOCAL_MACHINE, @"HARDWARE\DEVICEMAP\SERIALCOMM", @"\Device\Serial0"));
}
}
}
<强>更新强>
在Silverlight上似乎无法使用AllocHGlobal
和FreeHGlobal
。您可以改为调用LocalAlloc
和LocalFree
。或者您可以使用CoTaskMemAlloc
和CoTaskMemFree
。这是前者的样子:
[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr LocalAlloc(uint uFlags, UIntPtr uBytes);
[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr LocalFree(IntPtr hMem);
像这样定义LMEM_FIXED
:
const uint LMEM_FIXED = 0x0000;
然后将对AllocHGlobal
的调用替换为:
IntPtr ptr = LocalAlloc(LMEM_FIXED, cbData);
将FreeHGlobal
的调用替换为:
LocalFree(ptr);
答案 1 :(得分:0)
非常感谢@Dave Heffernan, 我最终让这个工作......
我在Dave的答案中的RegistryWrapper类中添加了以下代码:
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LocalAlloc(uint uFlags, int size);
internal static IntPtr AllocHGlobal(int size)
{
uint LPTR = (uint)0x0040;
IntPtr hGlobal = LocalAlloc(LPTR, size);
if (hGlobal == IntPtr.Zero)
{
throw new OutOfMemoryException("Unmanaged memory was not allocated.");
}
return hGlobal;
}
这解决了Marshal.AllocHGlobal在Silverlight中无法使用的限制。 然后我还将Marshal.AllocHGlobal的引用更改为上面的本地AllocHGlobal方法。