зеркало из https://github.com/dotnet/winforms.git
Fix VARIANT implementation and align with CLR (#3197)
This commit is contained in:
Родитель
6fd4ae643d
Коммит
fd49490709
|
@ -133,12 +133,6 @@
|
|||
<data name="InheritanceServiceReadOnlyCollection" xml:space="preserve">
|
||||
<value>Read-Only</value>
|
||||
</data>
|
||||
<data name="CannotConvertDoubleToDate" xml:space="preserve">
|
||||
<value>Double cannot be converted to a date.</value>
|
||||
</data>
|
||||
<data name="CannotConvertIntToFloat" xml:space="preserve">
|
||||
<value>Integer cannot be converted to a float.</value>
|
||||
</data>
|
||||
<data name="COM2UnhandledVT" xml:space="preserve">
|
||||
<value>Unhandled VT: {0}.</value>
|
||||
</data>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">Nezpracovaná hodnota VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Nelze převést typ Double na typ Date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Nelze převést typ Integer na typ Float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Výběr přiřazení</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">Unbehandelter VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">"Double" kann nicht in "Date" konvertiert werden.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">"Integer" kann nicht in "Float" konvertiert werden.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Ausrichtungsauswahl</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">VT no controlado: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">No se puede convertir double en date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">No se puede convertir integer en float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Selector de alineación</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">VT non géré : {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Impossible de convertir une valeur double en date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Impossible de convertir une valeur integer en float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Sélecteur d'alignement</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">VT non gestito: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Impossibile convertire un tipo double in un tipo date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Impossibile convertire un numero intero in un valore float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Selezione allineamento</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">ハンドルされていない VT: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">double を date に変換できません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">integer を float に変換できません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">配置ピッカー</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">처리되지 않은 VT입니다. {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">double 형식을 date 형식으로 변환할 수 없습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">integer 형식을 float 형식으로 변환할 수 없습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">맞춤 선택</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">Nieobsługiwany VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Nie można przekonwertować typu double na typ date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Nie można przekonwertować typu integer na typ float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Selektor wyrównania</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">VT não tratado: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Não é possível converter duplo em data.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Não é possível converter inteiro em flutuante.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Seletor de Alinhamento</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">Необработанный VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Тип double нельзя привести к типу date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Тип integer нельзя привести к типу float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Выбор выравнивания</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">İşlenmemiş VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Double tarihe dönüştürülemez.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Tam sayı kayan noktalıya dönüştürülemez.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">Hizalama Seçici</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">未处理的 VT: {0}。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">无法将 double 转换为 date。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">无法将 integer 转换为 float。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">对齐方式选择器</target>
|
||||
|
|
|
@ -406,16 +406,6 @@
|
|||
<target state="translated">未處理的 VT: {0}。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Double 無法轉換為 Date。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Integer 無法轉換為 Float。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ContentAlignmentEditorAccName">
|
||||
<source>Alignment Picker</source>
|
||||
<target state="translated">對齊選擇器</target>
|
||||
|
|
|
@ -18,6 +18,7 @@ internal static partial class Interop
|
|||
DISP_E_UNKNOWNNAME = unchecked((int)0x80020006),
|
||||
DISP_E_EXCEPTION = unchecked((int)0x80020009),
|
||||
DISP_E_UNKNOWNLCID = unchecked((int)0x8002000C),
|
||||
DISP_E_DIVBYZERO = unchecked((int)0x80020012),
|
||||
TYPE_E_BADMODULEKIND = unchecked((int)0x800288BD),
|
||||
E_NOTIMPL = unchecked((int)0x80004001),
|
||||
E_NOINTERFACE = unchecked((int)0x80004002),
|
||||
|
|
|
@ -17,6 +17,7 @@ internal static partial class Interop
|
|||
public const string Oleacc = "oleacc.dll";
|
||||
public const string Oleaut32 = "oleaut32.dll";
|
||||
public const string Powrprof = "Powrprof.dll";
|
||||
public const string Propsys = "Propsys.dll";
|
||||
public const string RichEdit41 = "MsftEdit.DLL";
|
||||
public const string SHCore = "SHCore.dll";
|
||||
public const string Shell32 = "shell32.dll";
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static partial class Kernel32
|
||||
{
|
||||
public struct FILETIME
|
||||
{
|
||||
public FILETIME(DateTime date)
|
||||
{
|
||||
long ft = date.ToFileTime();
|
||||
dwLowDateTime = (uint)(ft & 0xFFFFFFFF);
|
||||
dwHighDateTime = (uint)(ft >> 32);
|
||||
}
|
||||
|
||||
public uint dwLowDateTime;
|
||||
public uint dwHighDateTime;
|
||||
|
||||
public DateTime ToDateTime()
|
||||
{
|
||||
return DateTime.FromFileTime(((long)dwHighDateTime << 32) + dwLowDateTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using static Interop.Oleaut32;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Ole32
|
||||
{
|
||||
[DllImport(Libraries.Ole32, ExactSpelling = true)]
|
||||
public unsafe static extern HRESULT PropVariantClear(VARIANT* pvarg);
|
||||
|
||||
public unsafe static HRESULT PropVariantClear(ref VARIANT varg)
|
||||
{
|
||||
fixed (VARIANT* pvarg = &varg)
|
||||
{
|
||||
return PropVariantClear(pvarg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
public struct DECIMAL
|
||||
{
|
||||
public ushort wReserved;
|
||||
public byte scale;
|
||||
public byte sign;
|
||||
public uint Hi32;
|
||||
public uint Lo32;
|
||||
public uint Mid32;
|
||||
|
||||
public decimal ToDecimal()
|
||||
{
|
||||
return new decimal((int)Lo32, (int)Mid32, (int)Hi32, sign == 0x80, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
[Flags]
|
||||
public enum FADF : ushort
|
||||
{
|
||||
AUTO = 0x0001,
|
||||
STATIC = 0x0002,
|
||||
EMBEDDED = 0x0004,
|
||||
FIXEDSIZE = 0x0010,
|
||||
RECORD = 0x0020,
|
||||
HAVEIID = 0x0040,
|
||||
HAVEVARTYPE = 0x0080,
|
||||
BSTR = 0x0100,
|
||||
UNKNOWN = 0x0200,
|
||||
DISPATCH = 0x0400,
|
||||
VARIANT = 0x0800
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,8 +28,8 @@ internal partial class Interop
|
|||
[PreserveSig]
|
||||
HRESULT GetPredefinedStrings(
|
||||
DispatchID dispID,
|
||||
CA* pCaStringsOut,
|
||||
CA* pCaCookiesOut);
|
||||
Ole32.CA* pCaStringsOut,
|
||||
Ole32.CA* pCaCookiesOut);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetPredefinedValue(
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
[ComImport]
|
||||
[Guid("0000002F-0000-0000-C000-000000000046")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public unsafe interface IRecordInfo
|
||||
{
|
||||
[PreserveSig]
|
||||
HRESULT RecordInit(
|
||||
void* pvNew);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT RecordClear(
|
||||
void* pvExisting);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT RecordCopy(
|
||||
void* pvExisting,
|
||||
void* pvNew);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetGuid(
|
||||
Guid* pguid);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetName(
|
||||
BSTR* pbstrName);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetSize(
|
||||
uint* pcbSize);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetTypeInfo(
|
||||
out ITypeInfo ppTypeInfo);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetField(
|
||||
void* pvData,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
|
||||
VARIANT* pvarField);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetFieldNoCopy(
|
||||
void* pvData,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
|
||||
VARIANT* pvarField,
|
||||
void* ppvDataCArray);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT PutField(
|
||||
Ole32.INVOKEKIND wFlags,
|
||||
void* pvData,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
|
||||
VARIANT* pvarField);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT PutFieldNoCopy(
|
||||
Ole32.INVOKEKIND wFlags,
|
||||
void* pvData,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
|
||||
VARIANT* pvarField);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetFieldNames(
|
||||
uint* pcNames,
|
||||
BSTR* rgBstrNames);
|
||||
|
||||
[PreserveSig]
|
||||
BOOL IsMatchingType(
|
||||
ref IRecordInfo pRecordInfo);
|
||||
|
||||
[PreserveSig]
|
||||
void* RecordCreate();
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT RecordCreateCopy(
|
||||
void* pvSource,
|
||||
void** ppvDest);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT RecordDestroy(
|
||||
void* pvRecord);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static Interop.Ole32;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
public unsafe struct SAFEARRAY
|
||||
{
|
||||
public ushort cDims;
|
||||
public FADF fFeatures;
|
||||
public uint cbElements;
|
||||
public uint cLocks;
|
||||
public void* pvData;
|
||||
public SAFEARRAYBOUND _rgsabound;
|
||||
|
||||
public ReadOnlySpan<SAFEARRAYBOUND> rgsabound => TrailingArray<SAFEARRAYBOUND>.GetBuffer(ref _rgsabound, cDims);
|
||||
|
||||
public VARENUM VarType
|
||||
{
|
||||
get
|
||||
{
|
||||
// Match CLR behaviour.
|
||||
FADF hardwiredType = fFeatures & (FADF.BSTR | FADF.UNKNOWN | FADF.DISPATCH | FADF.VARIANT);
|
||||
if (hardwiredType == FADF.BSTR && cbElements == sizeof(char*))
|
||||
{
|
||||
return VARENUM.BSTR;
|
||||
}
|
||||
else if (hardwiredType == FADF.UNKNOWN && cbElements == sizeof(IntPtr))
|
||||
{
|
||||
return VARENUM.UNKNOWN;
|
||||
}
|
||||
else if (hardwiredType == FADF.DISPATCH && cbElements == sizeof(IntPtr))
|
||||
{
|
||||
return VARENUM.DISPATCH;
|
||||
}
|
||||
else if (hardwiredType == FADF.VARIANT && cbElements == sizeof(VARIANT))
|
||||
{
|
||||
return VARENUM.VARIANT;
|
||||
}
|
||||
|
||||
// Call native API.
|
||||
VARENUM vt = VARENUM.EMPTY;
|
||||
fixed (SAFEARRAY* pThis = &this)
|
||||
{
|
||||
SafeArrayGetVartype(pThis, &vt);
|
||||
return vt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T GetValue<T>(Span<int> indices)
|
||||
{
|
||||
// SAFEARRAY is laid out in column-major order.
|
||||
// See https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/array-manipulation-functions
|
||||
int indicesIndex = 0;
|
||||
int c1 = indices[indicesIndex++];
|
||||
uint dimensionSize = 1;
|
||||
|
||||
ReadOnlySpan<SAFEARRAYBOUND> bounds = rgsabound;
|
||||
int boundIndex = cDims - 1;
|
||||
|
||||
uint cell = 0;
|
||||
for (ushort dim = 1; dim < cDims; dim++)
|
||||
{
|
||||
dimensionSize *= bounds[boundIndex--].cElements;
|
||||
|
||||
int diff = (indices[indicesIndex++] - bounds[boundIndex].lLbound);
|
||||
cell += (uint)diff * dimensionSize;
|
||||
}
|
||||
|
||||
cell += (uint)(c1 - bounds[cDims - 1].lLbound);
|
||||
|
||||
void* v = Unsafe.Add<T>(pvData, (int)cell);
|
||||
return Unsafe.AsRef<T>(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
public struct SAFEARRAYBOUND
|
||||
{
|
||||
public uint cElements;
|
||||
public int lLbound;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
public unsafe static extern uint SafeArrayGetElemsize(SAFEARRAY* psa);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
public unsafe static extern HRESULT SafeArrayGetRecordInfo(SAFEARRAY* psa, out IRecordInfo pRecInfo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
public unsafe static extern HRESULT SafeArrayGetVartype(SAFEARRAY* psa, Ole32.VARENUM* pvt);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
@ -10,6 +10,6 @@ internal partial class Interop
|
|||
internal static partial class Oleaut32
|
||||
{
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
public unsafe static extern HRESULT VariantClear(VARIANT* pvarg);
|
||||
public unsafe static extern HRESULT SafeArrayLock(SAFEARRAY* psa);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
public unsafe static extern HRESULT SafeArrayUnlock(SAFEARRAY* psa);
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,17 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using static Interop;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal static partial class Oleaut32
|
||||
{
|
||||
internal enum VARIANT_BOOL : short
|
||||
{
|
||||
FALSE = 0,
|
||||
TRUE = -1,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
/// <summary>
|
||||
/// Used for trailing native unsized (ANYSIZE) arrays of <typeparamref name="T"/>. Native example:
|
||||
/// UCHAR UniqueId[1];
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Accessing the values is only safe when you have a pointer to the containing struct in
|
||||
/// a buffer. If you have an actual struct (Foo, not Foo*), the trailing array will have been
|
||||
/// truncated as the values aren't actually part of the struct.
|
||||
/// </remarks>
|
||||
internal readonly struct TrailingArray<T> where T : unmanaged
|
||||
{
|
||||
private readonly T _firstItem;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe static ReadOnlySpan<T> GetBuffer(ref T first, uint count, uint offset = 0)
|
||||
=> Unsafe.As<T, TrailingArray<T>>(ref first).GetBuffer(count, offset);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public unsafe static ReadOnlySpan<T> GetBufferInBytes(ref T first, uint countInBytes, uint offsetInBytes = 0)
|
||||
=> Unsafe.As<T, TrailingArray<T>>(ref first).GetBuffer(countInBytes / (uint)sizeof(T), offsetInBytes / (uint)sizeof(T));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe ReadOnlySpan<T> GetBuffer(uint count, uint offset = 0)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
return new ReadOnlySpan<T>();
|
||||
}
|
||||
|
||||
fixed (T* t = &_firstItem)
|
||||
{
|
||||
return new ReadOnlySpan<T>(t + offset, (int)(count));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -117,12 +117,6 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="CannotConvertIntToFloat" xml:space="preserve">
|
||||
<value>Integer cannot be converted to a float.</value>
|
||||
</data>
|
||||
<data name="CannotConvertDoubleToDate" xml:space="preserve">
|
||||
<value>Double cannot be converted to a date.</value>
|
||||
</data>
|
||||
<data name="COM2UnhandledVT" xml:space="preserve">
|
||||
<value>Unhandled VT: {0}.</value>
|
||||
</data>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">Nezpracovaná hodnota VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Nelze převést typ Double na typ Date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Nelze převést typ Integer na typ Float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Nejméně jedna položka není platná v parametru IDictionary. Ověřte, zda všechny hodnoty odpovídají vlastnostem objektu.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">Unbehandelter VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">"Double" kann nicht in "Date" konvertiert werden.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">"Integer" kann nicht in "Float" konvertiert werden.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Mindestens ein Eintrag im IDictionary-Parameter ist ungültig. Stellen Sie sicher, dass alle Werte den Eigenschaften des Objekts entsprechen.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">VT no controlado: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">No se puede convertir double en date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">No se puede convertir integer en float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Una o más entradas no son válidas en el parámetro IDictionary. Compruebe que todos los valores coinciden con las propiedades del objeto.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">VT non géré : {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Impossible de convertir une valeur double en date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Impossible de convertir une valeur integer en float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Le paramètre IDictionary contient au moins une entrée non valide. Vérifiez que toutes les valeurs correspondent aux propriétés de l'objet.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">VT non gestito: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Impossibile convertire un tipo double in un tipo date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Impossibile convertire un numero intero in un valore float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Una o più voci non valide nel parametro IDictionary. Verificare che tutti i valori corrispondano alle proprietà dell'oggetto.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">ハンドルされていない VT: {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">double を date に変換できません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">integer を float に変換できません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">1 つ以上の有効ではないエントリが IDictionary パラメーターにあります。すべての値がオブジェクトのプロパティに一致していることを確認してください。</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">처리되지 않은 VT입니다. {0}</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">double 형식을 date 형식으로 변환할 수 없습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">integer 형식을 float 형식으로 변환할 수 없습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">IDictionary 매개 변수에 잘못된 항목이 하나 이상 있습니다. 모든 값이 개체의 속성과 일치하는지 확인하십시오.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">Nieobsługiwany VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Nie można przekonwertować typu double na typ date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Nie można przekonwertować typu integer na typ float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Jeden lub kilka wpisów jest nieprawidłowych w parametrze IDictionary. Sprawdź, czy wszystkie wartości pasują do właściwości obiektu.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">VT não tratado: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Não é possível converter duplo em data.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Não é possível converter inteiro em flutuante.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Uma ou mais entradas não são válidas no parâmetro IDictionary. Verifique se todos os valores correspondem às propriedades do objeto.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">Необработанный VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Тип double нельзя привести к типу date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Тип integer нельзя привести к типу float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">Недействительны одна или больше записей в параметре IDictionary. Проверьте, все ли значения соответствуют свойствам этого объекта.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">İşlenmemiş VT: {0}.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Double tarihe dönüştürülemez.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Tam sayı kayan noktalıya dönüştürülemez.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">IDictionary parametresindeki bir veya daha fazla girdi geçerli değil. Tüm değerlerin nesnenin özellikleriyle eşleştiğini doğrulayın.</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">未处理的 VT: {0}。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">无法将 double 转换为 date。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">无法将 integer 转换为 float。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">在 IDictionary 参数中有一个或多个无效项。请验证所有值均与对象的属性匹配。</target>
|
||||
|
|
|
@ -7,16 +7,6 @@
|
|||
<target state="translated">未處理的 VT: {0}。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Double 無法轉換為 Date。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Integer 無法轉換為 Float。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="PropertyValueInvalidEntry">
|
||||
<source>One or more entries are not valid in the IDictionary parameter. Verify that all values match up to the object's properties.</source>
|
||||
<target state="translated">IDictionary 參數中有一或多個無效的項目。請確認所有值都符合物件的屬性。</target>
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Xunit;
|
||||
using static Interop;
|
||||
using static Interop.Kernel32;
|
||||
using static Interop.Ole32;
|
||||
using static Interop.Oleaut32;
|
||||
|
||||
namespace System.Windows.Forms.Tests.Interop.Oleaut32
|
||||
{
|
||||
public unsafe class VARIANTTests : IClassFixture<ThreadExceptionFixture>
|
||||
{
|
||||
[ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is32bit))]
|
||||
public void VARIANT_Sizeof_InvokeX86_ReturnsExpected()
|
||||
{
|
||||
Assert.Equal(16, Marshal.SizeOf<VARIANT>());
|
||||
Assert.Equal(16, sizeof(VARIANT));
|
||||
}
|
||||
|
||||
[ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is64bit))]
|
||||
public void VARIANT_Sizeof_InvokeX64_ReturnsExpected()
|
||||
{
|
||||
Assert.Equal(24, Marshal.SizeOf<VARIANT>());
|
||||
Assert.Equal(24, sizeof(VARIANT));
|
||||
}
|
||||
|
||||
[WinFormsTheory]
|
||||
[InlineData((ushort)VARENUM.EMPTY, false)]
|
||||
[InlineData((ushort)VARENUM.BOOL, false)]
|
||||
[InlineData((ushort)(VARENUM.BYREF), true)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF), true)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF | VARENUM.ARRAY), true)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF | VARENUM.VECTOR), true)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.ARRAY), false)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.VECTOR), false)]
|
||||
public void VARIANT_Byref_Get_ReturnsExpected(ushort vt, bool expected)
|
||||
{
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = (VARENUM)vt
|
||||
};
|
||||
Assert.Equal(expected, variant.Byref);
|
||||
}
|
||||
|
||||
[WinFormsTheory]
|
||||
[InlineData((ushort)VARENUM.EMPTY, (ushort)VARENUM.EMPTY)]
|
||||
[InlineData((ushort)VARENUM.BOOL, (ushort)VARENUM.BOOL)]
|
||||
[InlineData((ushort)(VARENUM.BYREF), (ushort)VARENUM.EMPTY)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF), (ushort)VARENUM.BOOL)]
|
||||
public void VARIANT_Type_Get_ReturnsExpected(ushort vt, ushort expected)
|
||||
{
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = (VARENUM)vt
|
||||
};
|
||||
Assert.Equal((VARENUM)expected, variant.Type);
|
||||
}
|
||||
|
||||
[WinFormsTheory]
|
||||
[InlineData((ushort)VARENUM.EMPTY)]
|
||||
[InlineData((ushort)(VARENUM.EMPTY | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.UNKNOWN)]
|
||||
[InlineData((ushort)(VARENUM.UNKNOWN | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.DISPATCH)]
|
||||
[InlineData((ushort)(VARENUM.DISPATCH | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.BSTR)]
|
||||
[InlineData((ushort)(VARENUM.BSTR | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.BOOL)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF))]
|
||||
public void VARIANT_Clear_InvokeDefault_Success(ushort vt)
|
||||
{
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = (VARENUM)vt
|
||||
};
|
||||
variant.Clear();
|
||||
Assert.Equal(VARENUM.EMPTY, variant.vt);
|
||||
Assert.Equal(IntPtr.Zero, variant.data1);
|
||||
Assert.Equal(IntPtr.Zero, variant.data2);
|
||||
}
|
||||
|
||||
[WinFormsFact]
|
||||
public void VARIANT_Clear_InvokeCustom_Success()
|
||||
{
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = VARENUM.BOOL,
|
||||
data1 = (IntPtr)1
|
||||
};
|
||||
variant.Clear();
|
||||
Assert.Equal(VARENUM.EMPTY, variant.vt);
|
||||
Assert.Equal(IntPtr.Zero, variant.data1);
|
||||
Assert.Equal(IntPtr.Zero, variant.data2);
|
||||
}
|
||||
|
||||
[WinFormsFact]
|
||||
public void VARIANT_Clear_InvokeBSTR_Success()
|
||||
{
|
||||
IntPtr data = Marshal.StringToBSTR("abc");
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = VARENUM.BSTR,
|
||||
data1 = data
|
||||
};
|
||||
variant.Clear();
|
||||
Assert.Equal(VARENUM.EMPTY, variant.vt);
|
||||
Assert.Equal(IntPtr.Zero, variant.data1);
|
||||
Assert.Equal(IntPtr.Zero, variant.data2);
|
||||
}
|
||||
|
||||
[WinFormsTheory]
|
||||
[InlineData((ushort)VARENUM.EMPTY)]
|
||||
[InlineData((ushort)(VARENUM.EMPTY | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.UNKNOWN)]
|
||||
[InlineData((ushort)(VARENUM.UNKNOWN | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.DISPATCH)]
|
||||
[InlineData((ushort)(VARENUM.DISPATCH | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.BSTR)]
|
||||
[InlineData((ushort)(VARENUM.BSTR | VARENUM.BYREF))]
|
||||
[InlineData((ushort)VARENUM.BOOL)]
|
||||
[InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF))]
|
||||
public void VARIANT_Dispose_InvokeDefault_Success(ushort vt)
|
||||
{
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = (VARENUM)vt
|
||||
};
|
||||
variant.Dispose();
|
||||
Assert.Equal(VARENUM.EMPTY, variant.vt);
|
||||
Assert.Equal(IntPtr.Zero, variant.data1);
|
||||
Assert.Equal(IntPtr.Zero, variant.data2);
|
||||
}
|
||||
|
||||
[WinFormsFact]
|
||||
public void VARIANT_Dispose_InvokeCustom_Success()
|
||||
{
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = VARENUM.BOOL,
|
||||
data1 = (IntPtr)1
|
||||
};
|
||||
variant.Dispose();
|
||||
Assert.Equal(VARENUM.EMPTY, variant.vt);
|
||||
Assert.Equal(IntPtr.Zero, variant.data1);
|
||||
Assert.Equal(IntPtr.Zero, variant.data2);
|
||||
}
|
||||
|
||||
[WinFormsFact]
|
||||
public void VARIANT_Dispose_InvokeBSTR_Success()
|
||||
{
|
||||
IntPtr data = Marshal.StringToBSTR("abc");
|
||||
using var variant = new VARIANT
|
||||
{
|
||||
vt = VARENUM.BSTR,
|
||||
data1 = data
|
||||
};
|
||||
variant.Dispose();
|
||||
Assert.Equal(VARENUM.EMPTY, variant.vt);
|
||||
Assert.Equal(IntPtr.Zero, variant.data1);
|
||||
Assert.Equal(IntPtr.Zero, variant.data2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Xunit;
|
||||
using static Interop.Kernel32;
|
||||
|
||||
namespace System.Windows.Forms.Tests.Interop.Kernel32
|
||||
{
|
||||
// NB: doesn't require thread affinity
|
||||
public class FILETIMETests
|
||||
{
|
||||
[Fact]
|
||||
public unsafe void FILETIME_Sizeof_Invoke_ReturnsExpected()
|
||||
{
|
||||
Assert.Equal(8, Marshal.SizeOf<FILETIME>());
|
||||
Assert.Equal(8, sizeof(FILETIME));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FILETIME_Ctor_Default()
|
||||
{
|
||||
var ft = new FILETIME();
|
||||
Assert.Equal(0u, ft.dwLowDateTime);
|
||||
Assert.Equal(0u, ft.dwHighDateTime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FILETIME_Ctor_DateTime()
|
||||
{
|
||||
var dt = new DateTime(2020, 05, 13, 13, 3, 12);
|
||||
var ft = new FILETIME(dt);
|
||||
Assert.Equal(3680495616u, ft.dwLowDateTime);
|
||||
Assert.Equal(30812454u, ft.dwHighDateTime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FILETIME_ToDateTime_Invoke_ReturnsExpected()
|
||||
{
|
||||
var ft = new FILETIME()
|
||||
{
|
||||
dwLowDateTime = 3680495616u,
|
||||
dwHighDateTime = 30812454u
|
||||
};
|
||||
Assert.Equal(new DateTime(2020, 05, 13, 13, 3, 12), ft.ToDateTime());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Xunit;
|
||||
using static Interop;
|
||||
using static Interop.Oleaut32;
|
||||
|
||||
namespace System.Windows.Forms.Tests.Interop.Oleaut32
|
||||
{
|
||||
// NB: doesn't require thread affinity
|
||||
public class DECIMALTests
|
||||
{
|
||||
[Fact]
|
||||
public unsafe void DECIMAL_Sizeof_Invoke_ReturnsExpected()
|
||||
{
|
||||
Assert.Equal(16, Marshal.SizeOf<DECIMAL>());
|
||||
Assert.Equal(16, sizeof(DECIMAL));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DECIMAL_ToDecimal_InvokeEmpty_ReturnsExpected()
|
||||
{
|
||||
var dec = new DECIMAL();
|
||||
Assert.Equal(0m, dec.ToDecimal());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData((double)int.MinValue)]
|
||||
[InlineData(-1.2)]
|
||||
[InlineData(0)]
|
||||
[InlineData(1.2)]
|
||||
[InlineData((double)int.MaxValue)]
|
||||
public void DECIMAL_ToDecimal_InvokeCustom_ReturnsExpected(double value)
|
||||
{
|
||||
HRESULT hr = VarDecFromR8(value, out DECIMAL dec);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal((decimal)value, dec.ToDecimal());
|
||||
}
|
||||
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
private static extern HRESULT VarDecFromR8(double dblIn, out DECIMAL pdecOut);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,416 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Xunit;
|
||||
using static Interop;
|
||||
using static Interop.Ole32;
|
||||
using static Interop.Oleaut32;
|
||||
|
||||
namespace System.Windows.Forms.Tests.Interop.Oleaut32
|
||||
{
|
||||
public unsafe class SAFEARRAYTests
|
||||
{
|
||||
[ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is32bit))]
|
||||
public void SAFEARRAY_Sizeof_InvokeX86_ReturnsExpected()
|
||||
{
|
||||
Assert.Equal(24, Marshal.SizeOf<SAFEARRAY>());
|
||||
Assert.Equal(24, sizeof(SAFEARRAY));
|
||||
}
|
||||
|
||||
[ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is64bit))]
|
||||
public void SAFEARRAY_Sizeof_InvokeX64_ReturnsExpected()
|
||||
{
|
||||
Assert.Equal(32, Marshal.SizeOf<SAFEARRAY>());
|
||||
Assert.Equal(32, sizeof(SAFEARRAY));
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Create_TestData()
|
||||
{
|
||||
yield return new object[] { VARENUM.I4, FADF.HAVEVARTYPE, 4 };
|
||||
yield return new object[] { VARENUM.I8, FADF.HAVEVARTYPE, 8 };
|
||||
yield return new object[] { VARENUM.BSTR, FADF.HAVEVARTYPE | FADF.BSTR, IntPtr.Size };
|
||||
yield return new object[] { VARENUM.UNKNOWN, FADF.HAVEIID | FADF.UNKNOWN, IntPtr.Size };
|
||||
yield return new object[] { VARENUM.DISPATCH, FADF.HAVEIID | FADF.DISPATCH, IntPtr.Size };
|
||||
}
|
||||
|
||||
[StaTheory]
|
||||
[MemberData(nameof(Create_TestData))]
|
||||
public void SAFEARRAY_CreateSingleDimension_GetProperties_Success(ushort vt, ushort expectedFeatures, uint expectedCbElements)
|
||||
{
|
||||
var saBound = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 10,
|
||||
lLbound = 1
|
||||
};
|
||||
SAFEARRAY *psa = SafeArrayCreate((VARENUM)vt, 1, &saBound);
|
||||
Assert.True(psa != null);
|
||||
|
||||
try
|
||||
{
|
||||
Assert.Equal(1u, psa->cDims);
|
||||
Assert.Equal((FADF)expectedFeatures, psa->fFeatures);
|
||||
Assert.Equal((uint)expectedCbElements, psa->cbElements);
|
||||
Assert.Equal(0u, psa->cLocks);
|
||||
Assert.True(psa->pvData != null);
|
||||
Assert.Equal(10u, psa->rgsabound[0].cElements);
|
||||
Assert.Equal(1, psa->rgsabound[0].lLbound);
|
||||
|
||||
VARENUM arrayVt = VARENUM.EMPTY;
|
||||
HRESULT hr = SafeArrayGetVartype(psa, &arrayVt);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal((VARENUM)vt, arrayVt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
HRESULT hr = SafeArrayDestroy(psa);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
}
|
||||
}
|
||||
|
||||
[StaFact]
|
||||
public void SAFEARRAY_CreateSingleDimensionRECORD_GetProperties_Success()
|
||||
{
|
||||
var saBound = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 10,
|
||||
lLbound = 1
|
||||
};
|
||||
var record = new CustomRecordInfo();
|
||||
IntPtr pRecord = Marshal.GetComInterfaceForObject<CustomRecordInfo, IRecordInfo>(record);
|
||||
try
|
||||
{
|
||||
SAFEARRAY *psa = SafeArrayCreateEx(VARENUM.RECORD, 1, &saBound, pRecord);
|
||||
Assert.True(psa != null);
|
||||
|
||||
try
|
||||
{
|
||||
Assert.Equal(1u, psa->cDims);
|
||||
Assert.Equal(FADF.RECORD, psa->fFeatures);
|
||||
Assert.Equal((uint)sizeof(int), psa->cbElements);
|
||||
Assert.Equal(0u, psa->cLocks);
|
||||
Assert.True(psa->pvData != null);
|
||||
Assert.Equal(10u, psa->rgsabound[0].cElements);
|
||||
Assert.Equal(1, psa->rgsabound[0].lLbound);
|
||||
|
||||
VARENUM arrayVt = VARENUM.EMPTY;
|
||||
HRESULT hr = SafeArrayGetVartype(psa, &arrayVt);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(VARENUM.RECORD, arrayVt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
HRESULT hr = SafeArrayDestroy(psa);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.Release(pRecord);
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomRecordInfo : IRecordInfo
|
||||
{
|
||||
HRESULT IRecordInfo.RecordInit(void* pvNew) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.RecordClear(void* pvExisting) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.RecordCopy(void* pvExisting, void* pvNew) => throw new NotImplementedException();
|
||||
|
||||
public Func<(Guid, HRESULT)> GetGuidAction { get; set; }
|
||||
|
||||
HRESULT IRecordInfo.GetGuid(Guid* pguid)
|
||||
{
|
||||
(Guid guid, HRESULT hr) = GetGuidAction();
|
||||
*pguid = guid;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT IRecordInfo.GetName(BSTR* pbstrName) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.GetSize(uint* pcbSize)
|
||||
{
|
||||
*pcbSize = (uint)sizeof(int);
|
||||
return HRESULT.S_OK;
|
||||
}
|
||||
|
||||
HRESULT IRecordInfo.GetTypeInfo(out ITypeInfo ppTypeInfo) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.GetField(void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.GetFieldNoCopy(void* pvData, out string szFieldName, VARIANT* pvarField, void* ppvDataCArray) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.PutField(INVOKEKIND wFlags, void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.PutFieldNoCopy(INVOKEKIND wFlags, void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.GetFieldNames(uint* pcNames, BSTR* rgBstrNames) => throw new NotImplementedException();
|
||||
|
||||
BOOL IRecordInfo.IsMatchingType(ref IRecordInfo pRecordInfo) => throw new NotImplementedException();
|
||||
|
||||
void* IRecordInfo.RecordCreate() => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.RecordCreateCopy(void* pvSource, void** ppvDest) => throw new NotImplementedException();
|
||||
|
||||
HRESULT IRecordInfo.RecordDestroy(void* pvRecord) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[StaTheory]
|
||||
[MemberData(nameof(Create_TestData))]
|
||||
public void SAFEARRAY_CreateMultipleDimensions_GetProperties_Success(ushort vt, ushort expectedFeatures, uint expectedCbElements)
|
||||
{
|
||||
SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[2];
|
||||
saBounds[0] = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 10,
|
||||
lLbound = 1
|
||||
};
|
||||
saBounds[1] = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 20,
|
||||
lLbound = 0
|
||||
};
|
||||
SAFEARRAY *psa = SafeArrayCreate((VARENUM)vt, 2, saBounds);
|
||||
Assert.True(psa != null);
|
||||
|
||||
try
|
||||
{
|
||||
Assert.Equal(2u, psa->cDims);
|
||||
Assert.Equal((FADF)expectedFeatures, psa->fFeatures);
|
||||
Assert.Equal(expectedCbElements, psa->cbElements);
|
||||
Assert.Equal(0u, psa->cLocks);
|
||||
Assert.True(psa->pvData != null);
|
||||
Assert.Equal(20u, psa->rgsabound[0].cElements);
|
||||
Assert.Equal(0, psa->rgsabound[0].lLbound);
|
||||
Assert.Equal(10u, psa->rgsabound[1].cElements);
|
||||
Assert.Equal(1, psa->rgsabound[1].lLbound);
|
||||
|
||||
VARENUM arrayVt = VARENUM.EMPTY;
|
||||
HRESULT hr = SafeArrayGetVartype(psa, &arrayVt);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal((VARENUM)vt, arrayVt);
|
||||
}
|
||||
finally
|
||||
{
|
||||
HRESULT hr = SafeArrayDestroy(psa);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
}
|
||||
}
|
||||
|
||||
[StaFact]
|
||||
public void SAFEARRAY_GetValue_InvokeSingleDimensional_ReturnsExpected()
|
||||
{
|
||||
var saBound = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 10,
|
||||
lLbound = 0
|
||||
};
|
||||
SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 1, &saBound);
|
||||
Assert.True(psa != null);
|
||||
|
||||
try
|
||||
{
|
||||
Span<int> indices1 = stackalloc int[] { 0 };
|
||||
Span<int> indices2 = stackalloc int[] { 1 };
|
||||
|
||||
fixed (int* pIndices1 = indices1)
|
||||
fixed (int* pIndices2 = indices2)
|
||||
{
|
||||
int value1 = 1;
|
||||
HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int value2 = 2;
|
||||
hr = SafeArrayPutElement(psa, pIndices2, &value2);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int result = -1;
|
||||
hr = SafeArrayGetElement(psa, pIndices1, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(1, result);
|
||||
|
||||
hr = SafeArrayGetElement(psa, pIndices2, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(2, result);
|
||||
}
|
||||
|
||||
Assert.Equal(1, psa->GetValue<int>(indices1));
|
||||
Assert.Equal(2, psa->GetValue<int>(indices2));
|
||||
}
|
||||
finally
|
||||
{
|
||||
SafeArrayDestroy(psa);
|
||||
}
|
||||
}
|
||||
|
||||
[StaFact]
|
||||
public void SAFEARRAY_GetValue_InvokeSingleDimensionalNonZeroLowerBound_ReturnsExpected()
|
||||
{
|
||||
var saBound = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 10,
|
||||
lLbound = -5
|
||||
};
|
||||
SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 1, &saBound);
|
||||
Assert.True(psa != null);
|
||||
|
||||
try
|
||||
{
|
||||
Span<int> indices1 = stackalloc int[] { -5 };
|
||||
Span<int> indices2 = stackalloc int[] { -4 };
|
||||
|
||||
fixed (int* pIndices1 = indices1)
|
||||
fixed (int* pIndices2 = indices2)
|
||||
{
|
||||
int value1 = 1;
|
||||
HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int value2 = 2;
|
||||
hr = SafeArrayPutElement(psa, pIndices2, &value2);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int result = -1;
|
||||
hr = SafeArrayGetElement(psa, pIndices1, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(1, result);
|
||||
|
||||
hr = SafeArrayGetElement(psa, pIndices2, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(2, result);
|
||||
}
|
||||
|
||||
Assert.Equal(1, psa->GetValue<int>(indices1));
|
||||
Assert.Equal(2, psa->GetValue<int>(indices2));
|
||||
}
|
||||
finally
|
||||
{
|
||||
SafeArrayDestroy(psa);
|
||||
}
|
||||
}
|
||||
|
||||
[StaFact]
|
||||
public void SAFEARRAY_GetValue_InvokeMultiDimensional_ReturnsExpected()
|
||||
{
|
||||
SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[2];
|
||||
saBounds[0] = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 10,
|
||||
lLbound = 0
|
||||
};
|
||||
saBounds[1] = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 20,
|
||||
lLbound = 0
|
||||
};
|
||||
SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 2, saBounds);
|
||||
Assert.True(psa != null);
|
||||
|
||||
try
|
||||
{
|
||||
Span<int> indices1 = stackalloc int[] { 0, 0 };
|
||||
Span<int> indices2 = stackalloc int[] { 1, 2 };
|
||||
|
||||
fixed (int* pIndices1 = indices1)
|
||||
fixed (int* pIndices2 = indices2)
|
||||
{
|
||||
int value1 = 1;
|
||||
HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int value2 = 2;
|
||||
hr = SafeArrayPutElement(psa, pIndices2, &value2);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int result = -1;
|
||||
hr = SafeArrayGetElement(psa, pIndices1, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(1, result);
|
||||
|
||||
hr = SafeArrayGetElement(psa, pIndices2, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(2, result);
|
||||
}
|
||||
|
||||
Assert.Equal(1, psa->GetValue<int>(indices1));
|
||||
Assert.Equal(2, psa->GetValue<int>(indices2));
|
||||
}
|
||||
finally
|
||||
{
|
||||
SafeArrayDestroy(psa);
|
||||
}
|
||||
}
|
||||
|
||||
[StaFact]
|
||||
public void SAFEARRAY_GetValue_InvokeMultiDimensionalNonZeroLowerBound_ReturnsExpected()
|
||||
{
|
||||
SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[2];
|
||||
saBounds[0] = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 10,
|
||||
lLbound = -5
|
||||
};
|
||||
saBounds[1] = new SAFEARRAYBOUND
|
||||
{
|
||||
cElements = 20,
|
||||
lLbound = -4
|
||||
};
|
||||
SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 2, saBounds);
|
||||
Assert.True(psa != null);
|
||||
|
||||
try
|
||||
{
|
||||
Span<int> indices1 = stackalloc int[] { -5, -4 };
|
||||
Span<int> indices2 = stackalloc int[] { -4, -3 };
|
||||
|
||||
fixed (int* pIndices1 = indices1)
|
||||
fixed (int* pIndices2 = indices2)
|
||||
{
|
||||
int value1 = 1;
|
||||
HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int value2 = 2;
|
||||
hr = SafeArrayPutElement(psa, pIndices2, &value2);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
|
||||
int result = -1;
|
||||
hr = SafeArrayGetElement(psa, pIndices1, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(1, result);
|
||||
|
||||
hr = SafeArrayGetElement(psa, pIndices2, &result);
|
||||
Assert.Equal(HRESULT.S_OK, hr);
|
||||
Assert.Equal(2, result);
|
||||
}
|
||||
|
||||
Assert.Equal(1, psa->GetValue<int>(indices1));
|
||||
Assert.Equal(2, psa->GetValue<int>(indices2));
|
||||
}
|
||||
finally
|
||||
{
|
||||
SafeArrayDestroy(psa);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
private static unsafe extern SAFEARRAY* SafeArrayCreate(VARENUM vt, uint cDims, SAFEARRAYBOUND* rgsabound);
|
||||
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
private static unsafe extern SAFEARRAY* SafeArrayCreateEx(VARENUM vt, uint cDims, SAFEARRAYBOUND* rgsabound, IntPtr pvExtra);
|
||||
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
private static unsafe extern HRESULT SafeArrayDestroy(SAFEARRAY* psa);
|
||||
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
private unsafe static extern HRESULT SafeArrayPutElement(SAFEARRAY* psa, int* rgIndices, void* pv);
|
||||
|
||||
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
|
||||
private unsafe static extern HRESULT SafeArrayGetElement(SAFEARRAY* psa, int* rgIndices, void* pv);
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -436,12 +436,6 @@
|
|||
<data name="CannotChangePrintedDocument" xml:space="preserve">
|
||||
<value>You cannot alter the document or add to it once you have printed it.</value>
|
||||
</data>
|
||||
<data name="CannotConvertDoubleToDate" xml:space="preserve">
|
||||
<value>Double cannot be converted to a date.</value>
|
||||
</data>
|
||||
<data name="CannotConvertIntToFloat" xml:space="preserve">
|
||||
<value>Integer cannot be converted to a float.</value>
|
||||
</data>
|
||||
<data name="CantNestMessageLoops" xml:space="preserve">
|
||||
<value>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</value>
|
||||
</data>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">Po vytištění nelze dokument upravovat ani do něj již nelze přidávat položky.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Nelze převést typ Double na typ Date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Nelze převést typ Integer na typ Float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Vytvoření druhé smyčky zpráv v jednom vlákně je neplatná operace. Použijte místo toho funkci Application.RunDialog nebo Form.ShowDialog.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">Das Dokument kann nach dem Drucken nicht mehr geändert oder ergänzt werden.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">"Double" kann nicht in "Date" konvertiert werden.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">"Integer" kann nicht in "Float" konvertiert werden.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Das Starten einer zweiten Meldungsschleife auf einem einzelnen Thread ist ein ungültiger Vorgang. Verwenden Sie Form.ShowDialog.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">No se puede modificar el documento ni agregarle información una vez impreso.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">No se puede convertir double en date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">No se puede convertir integer en float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">No se permite empezar un bucle de segundo mensaje en un subproceso sencillo. Utilice en su lugar Form.ShowDialog.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">Vous ne pouvez modifier ni ajouter le document une fois que vous l'avez imprimé.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Impossible de convertir une valeur double en date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Impossible de convertir une valeur integer en float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Le démarrage d'une deuxième boucle de messages sur un seul thread n'est pas une opération valide. Utilisez Form.ShowDialog à la place.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">Impossibile eseguire modifiche o aggiunte al documento dopo la stampa.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Impossibile convertire un tipo double in un tipo date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Impossibile convertire un numero intero in un valore float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Non è possibile avviare un secondo ciclo di messaggi su un thread singolo. Usare Form.ShowDialog.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">ドキュメントが印刷された後にドキュメントの変更やドキュメントへの追加はできません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">double を date に変換できません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">integer を float に変換できません。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">単一スレッド上で 2 回目のメッセージ ループを開始することは有効な操作ではありません。Form.ShowDialog を使用してください。</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">문서를 인쇄한 후에는 문서를 변경하거나 문서에 추가할 수 없습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">double 형식을 date 형식으로 변환할 수 없습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">integer 형식을 float 형식으로 변환할 수 없습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">단일 스레드에서 두 번째 메시지 루프를 시작할 수 없습니다. 대신 Form.ShowDialog를 사용하십시오.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">Po wydrukowaniu dokumentu nie można już go zmieniać ani dodawać do niego.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Nie można przekonwertować typu double na typ date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Nie można przekonwertować typu integer na typ float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Rozpoczynanie drugiej pętli komunikatów w pojedynczym wątku nie jest prawidłową operacją. Użyj zamiast tego elementu Form.ShowDialog.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">Não é possível alterar o documento ou adicioná-lo após imprimi-lo.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Não é possível converter duplo em data.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Não é possível converter inteiro em flutuante.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Iniciar um segundo loop de mensagens em um único thread não é uma operação válida. Use Form.ShowDialog.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">После печати внесение изменений или добавление данных в документ невозможно.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Тип double нельзя привести к типу date.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Тип integer нельзя привести к типу float.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Запуск второго цикла сообщения в единичном потоке является недопустимой операцией. Вместо этого используйте Form.ShowDialog.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">Belgeyi yazdırdıktan sonra belgeyi değiştiremez ya ek yapamazsınız.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Double tarihe dönüştürülemez.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Tam sayı kayan noktalıya dönüştürülemez.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">Tek bir iş parçacığı üzerinde ikinci ileti döngüsünü başlatmak geçerli bir işlem değildir. Yerine Form.ShowDialog kullanın.</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">打印文档后将无法更改文档或向其中添加内容。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">无法将 double 转换为 date。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">无法将 integer 转换为 float。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">在单个线程上开始另一个消息循环是无效操作。请改用 Form.ShowDialog。</target>
|
||||
|
|
|
@ -687,16 +687,6 @@
|
|||
<target state="translated">一旦列印文件之後,您就不能變更或增加文件內容。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertDoubleToDate">
|
||||
<source>Double cannot be converted to a date.</source>
|
||||
<target state="translated">Double 無法轉換為 Date。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CannotConvertIntToFloat">
|
||||
<source>Integer cannot be converted to a float.</source>
|
||||
<target state="translated">Integer 無法轉換為 Float。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="CantNestMessageLoops">
|
||||
<source>Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.</source>
|
||||
<target state="translated">在單一執行緒上啟動第二個訊息迴圈不是有效的作業。請使用 Form.ShowDialog 代替。</target>
|
||||
|
|
|
@ -265,8 +265,8 @@ namespace System.Windows.Forms.ComponentModel.Com2Interop
|
|||
{
|
||||
try
|
||||
{
|
||||
using var variant = ptr[i];
|
||||
objects[i] = Marshal.GetObjectForNativeVariant((IntPtr)(&variant));
|
||||
using Oleaut32.VARIANT variant = ptr[i];
|
||||
objects[i] = variant.ToObject();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче