使用p / invoke从Silverlight获取字符串值(Silverlight)

时间:2013-09-13 14:27:53

标签: c# pinvoke silverlight-5.0

我试图通过使用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),但未能实现这一点,很可能形成缺乏真正的理解; - )

enter image description here

enter image description here

enter image description here

2 个答案:

答案 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上似乎无法使用AllocHGlobalFreeHGlobal。您可以改为调用LocalAllocLocalFree。或者您可以使用CoTaskMemAllocCoTaskMemFree。这是前者的样子:

[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方法。