0

既存の 32 ビット アプリケーションを 64 ビットに変換しようとしているときに、COM 相互運用コードを正しく動作させるのに問題が発生しました。このコードは、さまざまな Windows SDK ヘッダー/IDL ファイルから変換したマネージ コードを使用して、構造化ストレージ API にアクセスしています。

を に呼び出そうとすると、コードが失敗IPropertyStorage.ReadMultiple()STG_E_INVALIDPARAMETERます。以前の相互運用呼び出し toStgOpenStorageExおよびは正常に機能IPropertySetStorage.Openしているようです。MSDN は、このエラーは PROPSPEC パラメータに問題があることを意味すると主張していますが、32 ビット アプリケーションとしてコンパイルすると同じパラメータ値が正常に機能し、返される値は指定されたプロパティの正しい文字列値です。

関連するビットは次のとおりです。

// PropertySpecKind enumeration.
public enum PropertySpecKind : uint
{
    Lpwstr = 0,
    PropId = 1
}

// PropertySpec structure:
[StructLayout(LayoutKind.Explicit)]
public struct PropertySpec
{
    [FieldOffset(0)] public PropertySpecKind kind;
    [FieldOffset(4)] public uint propertyId;
    [FieldOffset(4)] public IntPtr name;
}

// PropertyVariant Structure:
[StructLayout(LayoutKind.Explicit)]
public struct PropertyVariant
{
    [FieldOffset(0)] public Vartype vt;
    [FieldOffset(8)] public IntPtr pointerValue;
}

// IPropertyStorage interface
[ComImport]
[Guid("00000138-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyStorage
{
    int ReadMultiple(
        uint count,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 0)] PropertySpec[] properties,
        [Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 0)] PropertyVariant[] values);

    void WriteMultiple(
        uint count,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 0)] PropertySpec[] properties,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 0)] PropertyVariant[] values,
        uint miniumumPropertyId);
}

var properties = new PropertySpec[1];
properties[0].kind = PropertySpecKind.PropId; 
properties[0].propertyId = 2;

var propertyValues = new PropertyVariant[1];

// This helper method just calls StgOpenStorageEx with appropriate parameters.
var propertySetStorage = StorageHelper.GetPropertySetStorageReadOnly(fileName);
var propertyStorage = propertySetStorage.Open(StoragePropertySets.PSGUID_SummaryInformation, StorageMode.Read | StorageMode.ShareExclusive);    
propertyStorage.ReadMultiple(1, properties, propertyValues); // Exception is here.
4

3 に答える 3

0

次のようにインターフェイスを定義する必要があります。

[ComImport]
[Guid("00000138-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyStorage
{
    [PreserveSig]
    uint ReadMultiple(
        uint count,
        [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] PropertySpec[] properties,
        [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] PropertyVariant[] values);

    [PreserveSig]
    uint WriteMultiple(
        uint count,
        [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] PropertySpec[] properties,
        [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]  PropertySpec[] values,
        uint miniumumPropertyId);

        // other methods left as an exercise to the reader...
}

PreserveSig 属性の使用法に注意してください。まあ、それはあなたが今戻り値をテストしなければならないことを意味します:-)

注: 複合ストレージの p/invoke 宣言がさらに必要な場合は、この 100% 無料の Nuget ツールである CodeFluent Runtime Clientを参照してください。これには、使用できる CompoundStorage クラス ユーティリティが含まれています。または、.NET Reflector または ILSpy を使用して検査し、含まれている p/invoke 定義を取得するだけです。32 ビットと 64 ビットの世界をサポートする必要があります。

于 2013-06-02T10:28:29.543 に答える