将字符串指针的LPWSTR*数组转换为C# 我试图把下面的方法从C++转换成C<< /p>

将字符串指针的LPWSTR*数组转换为C# 我试图把下面的方法从C++转换成C<< /p>,c#,interop,pinvoke,arrays,C#,Interop,Pinvoke,Arrays,MSDN文件中指出: PPNPDeviceID[输入,输出] 由调用方分配的字符串指针数组,其中包含所有连接设备的即插即用名称。要了解此参数所需的大小,请首先调用此方法,将此参数设置为NULL并将pcPnPDeviceIDs设置为零,然后根据pcPnPDeviceIDs检索的值分配缓冲区 PCPnPDeviceID[输入,输出] 输入时,ppnpDeviceID可以保存的值的数量。在输出时,指向实际写入ppnpdeviceid的设备数的指针 到目前为止,我有这个定义: [PreserveSig]

MSDN文件中指出:

PPNPDeviceID[输入,输出]
由调用方分配的字符串指针数组,其中包含所有连接设备的即插即用名称。要了解此参数所需的大小,请首先调用此方法,将此参数设置为
NULL
并将
pcPnPDeviceIDs
设置为零,然后根据
pcPnPDeviceIDs
检索的值分配缓冲区

PCPnPDeviceID[输入,输出] 输入时,
ppnpDeviceID
可以保存的值的数量。在输出时,指向实际写入
ppnpdeviceid
的设备数的指针

到目前为止,我有这个定义:

[PreserveSig]        
int GetDevices(    
    [In, Out] IntPtr pPnPDeviceIDs,
    [In, Out] ref uint pcPnPDeviceIDs
);
我已尝试使用
Marshal.allocTaskMem
ppnpDeviceID
分配一些内存,但在尝试调用该方法时,我收到了AccessViolationException

当它是一个字符串指针数组时,有人能告诉我转换
LPWSTR*
的正确方法吗

编辑: 以下是我的定义:

[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("a1567595-4c2f-4574-a6fa-ecef917b9a40")]
public interface IPortableDeviceManager
{
    [PreserveSig]
    HRESULT GetDeviceDescription(
        [In] string pszPnpDeviceID,
        [In, Out] ref StringBuilder pDeviceDescription,
        [In, Out] ref uint pcchDeviceDescription);

    [PreserveSig]
    HRESULT GetDeviceFriendlyName(
        [In] string pszPnPDeviceID,
        [In, Out] ref StringBuilder pDeviceFriendlyName,
        [In, Out] ref uint pcchDeviceFriendlyName);

    [PreserveSig]
    HRESULT GetDeviceManufacturer(
        [In] string pszPnPDeviceID,
        [In, Out] ref StringBuilder pDeviceManufacturer,
        [In, Out] ref uint pcchDeviceManufacturer);

    [PreserveSig]
    HRESULT GetDeviceProperty(
        [In] string pszPnPDeviceID,
        [In] string pszDevicePropertyName,
        [In, Out] IntPtr pData,
        [In, Out] ref uint pcbData,
        [In, Out] ref uint pdwType);

    [PreserveSig]        
    HRESULT GetDevices(     
        [In, Out] IntPtr pPnPDeviceIDs,
        [In, Out] ref uint pcPnPDeviceIDs);


    [PreserveSig]
    HRESULT GetPrivateDevices(
        [In, Out] IntPtr pPnPDeviceIDs,
        [In, Out] ref uint pcPnPDeviceIDs);

    [PreserveSig]
    HRESULT RefreshDeviceList();
}

/// <summary>
/// CLSID_PortableDeviceManager
/// </summary>
[ComImport, Guid("0af10cec-2ecd-4b92-9581-34f6ae0637f3")]
public class CLSID_PortableDeviceManager { }
[ComImport,System.Security.SuppressUnmanagedCodeSecurity,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid(“a1567595-4c2f-4574-a6fa-ECEF917B9A4”)]
公共接口IPortableDeviceManager
{
[信号]
HRESULT GetDeviceDescription(
[In]字符串pszPnpDeviceID,
[In,Out]参考StringBuilder pDeviceDescription,
[In,Out]参考单元pcchDeviceDescription);
[信号]
HRESULT GetDeviceFriendlyName(
[In]字符串pszPnPDeviceID,
[In,Out]参考StringBuilder pDeviceFriendlyName,
[In,Out]参考单元pcchDeviceFriendlyName);
[信号]
HRESULT GetDeviceManufacturer(
[In]字符串pszPnPDeviceID,
[In,Out]参考StringBuilder pDeviceManufacturer,
[In,Out]参考设备pcchDeviceManufacturer);
[信号]
HRESULT GetDeviceProperty(
[In]字符串pszPnPDeviceID,
[In]字符串pszDevicePropertyName,
[In,Out]IntPtr pData,
[In,Out]参考电路板数据,
[In,Out]参考单元pdwType);
[信号]
HRESULT GetDevices(
[In,Out]IntPtr PPNPDeviceID,
[In,Out]参考单元PCPnPDeviceID);
[信号]
HRESULT GetPrivateDevices(
[In,Out]IntPtr PPNPDeviceID,
[In,Out]参考单元PCPnPDeviceID);
[信号]
HRESULT RefreshDeviceList();
}
/// 
///CLSID_便携式设备管理器
/// 
[ComImport,Guid(“0af10cec-2ecd-4b92-9581-34f6ae0637f3”)]
公共类CLSID_PortableDeviceManager{}
这是我的测试代码:

var devManager = Activator.CreateInstance(
            typeof(CLSID_PortableDeviceManager)) as IPortableDeviceManager;

        uint pcPnPDeviceIDs = 0;
        var res1 = devManager.GetDevices(IntPtr.Zero, ref pcPnPDeviceIDs);
        // check for errors in res1
        IntPtr ptr = IntPtr.Zero;

        try
        {
            ptr = Marshal.AllocCoTaskMem((int)(IntPtr.Size * pcPnPDeviceIDs));
            var res2 = devManager.GetDevices(ptr, ref pcPnPDeviceIDs);
            // check for errors in res2

            IntPtr ptr2 = ptr;

            for (uint i = 0; i < pcPnPDeviceIDs; i++)
            {
                string str = Marshal.PtrToStringUni(ptr2);
                ptr2 += IntPtr.Size;
            }
        }
        finally
        {
            if (ptr != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(ptr);
            }
        }

        Marshal.ReleaseComObject(devManager);
var devManager=Activator.CreateInstance(
作为IPortableDeviceManager的(CLSID_PortableDeviceManager))类型;
uint pcPnPDeviceIDs=0;
var res1=devManager.GetDevices(IntPtr.Zero,ref pcPnPDeviceIDs);
//检查res1中的错误
IntPtr ptr=IntPtr.0;
尝试
{
ptr=Marshal.allocTaskMem((int)(IntPtr.Size*pcpnpdeviceId));
var res2=devManager.GetDevices(ptr,ref pcpnpdeviceid);
//检查res2中的错误
IntPtr ptr2=ptr;
对于(uint i=0;i
我在第二次调用GetDevices()时收到AccessViolationException,请尝试以下操作:

uint pcPnPDeviceIDs = 0;
int res1 = GetDevices(IntPtr.Zero, ref pcPnPDeviceIDs);
// check for errors in res1

IntPtr ptr = IntPtr.Zero;

try
{
    ptr = Marshal.AllocCoTaskMem((int)(IntPtr.Size * pcPnPDeviceIDs));
    int res2 = GetDevices(ptr, ref pcPnPDeviceIDs);
    // check for errors in res2

    IntPtr ptr2 = ptr;

    for (uint i = 0; i < pcPnPDeviceIDs; i++)
    {
        string str = Marshal.PtrToStringUni(Marshal.ReadIntPtr(ptr2));
        ptr2 += IntPtr.Size;
    }
}
finally
{
    if (ptr != IntPtr.Zero)
    {
        IntPtr ptr2 = ptr;

        for (uint i = 0; i < pcPnPDeviceIDs; i++)
        {
            Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(ptr2));
            ptr2 += IntPtr.Size;
        }

        Marshal.FreeCoTaskMem(ptr);
    }
}
其余代码:

var devManager = Activator.CreateInstance(typeof(CLSID_PortableDeviceManager)) as IPortableDeviceManager;
uint pcPnPDeviceIDs = 0;
HRESULT res1 = devManager.GetDevices(null, ref pcPnPDeviceIDs);
// check for errors in res1

IntPtr[] ptr = null;

try
{
    ptr = new IntPtr[pcPnPDeviceIDs];

    HRESULT res2 = devManager.GetDevices(ptr, ref pcPnPDeviceIDs);
    // check for errors in res2

    for (uint i = 0; i < pcPnPDeviceIDs; i++)
    {
        string str = Marshal.PtrToStringUni(ptr[i]);
    }
}
finally
{
    if (ptr != null)
    {
        for (uint i = 0; i < pcPnPDeviceIDs; i++)
        {
            Marshal.FreeCoTaskMem(ptr[i]);
        }
    }
}
var devManager=Activator.CreateInstance(typeof(CLSID_PortableDeviceManager))作为IPortableDeviceManager;
uint pcPnPDeviceIDs=0;
HRESULT res1=devManager.GetDevices(null,ref pcpnpdeviceid);
//检查res1中的错误
IntPtr[]ptr=null;
尝试
{
ptr=新的IntPtr[pcpnpdeviceid];
HRESULT res2=devManager.GetDevices(ptr,ref pcpnpdeviceid);
//检查res2中的错误
对于(uint i=0;i

这样,您就不必在非托管内存中分配主数组。

我仍然得到AccessViolationException。我将编辑我的帖子以显示我的所有代码,这样您就可以重现问题。Thanks@user2648561哪里第一次通话还是第二次通话?或者在各种PtrToStringUni?@user2648561中,如果您通过将GetDevices放在第一位来修复接口,并修改Marshal.PtrToStringUni,那么它可以工作(我添加了一个Marshal.ReadIntPtr)。@user2648561甚至修复了字符串的释放。我没有意识到您必须按照与原始头文件相同的顺序定义方法!你每天都能学到新东西!谢谢。你的问题是界面。。。如果您尝试对devManager.RefreshDeviceList()执行以下操作:;例如,所有人都发现了问题。。。您的接口具有错误的方法顺序。。。你是怎么产生的?将GetDevices作为第一个方法。接口方法的正确顺序是:GetDevices、RefreshDeviceList、GetDeviceFriendlyName、GetDeviceDescription、GetDeviceManufacturer、GetDeviceProperty、GetPrivateDevices
[PreserveSig]
HRESULT GetDevices(
    [In][MarshalAs(UnmanagedType.LPArray)] IntPtr[] pPnPDeviceIDs,
    [In, Out] ref uint pcPnPDeviceIDs);
var devManager = Activator.CreateInstance(typeof(CLSID_PortableDeviceManager)) as IPortableDeviceManager;
uint pcPnPDeviceIDs = 0;
HRESULT res1 = devManager.GetDevices(null, ref pcPnPDeviceIDs);
// check for errors in res1

IntPtr[] ptr = null;

try
{
    ptr = new IntPtr[pcPnPDeviceIDs];

    HRESULT res2 = devManager.GetDevices(ptr, ref pcPnPDeviceIDs);
    // check for errors in res2

    for (uint i = 0; i < pcPnPDeviceIDs; i++)
    {
        string str = Marshal.PtrToStringUni(ptr[i]);
    }
}
finally
{
    if (ptr != null)
    {
        for (uint i = 0; i < pcPnPDeviceIDs; i++)
        {
            Marshal.FreeCoTaskMem(ptr[i]);
        }
    }
}