Merge pull request #2452 from shrah/master
Implement SetLastError DllImport flag functionality
This commit is contained in:
Коммит
058296779d
|
@ -0,0 +1,22 @@
|
|||
// 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;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal unsafe partial class Sys
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
[RuntimeImport(Interop.Libraries.CoreLibNative, "CoreLibNative_GetLastErrNo")]
|
||||
internal static extern int GetLastErrNo();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
[RuntimeImport(Interop.Libraries.CoreLibNative, "CoreLibNative_SetLastErrNo")]
|
||||
internal static extern void SetLastErrNo(int error);
|
||||
}
|
||||
}
|
|
@ -2,13 +2,16 @@
|
|||
// 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;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal partial class mincore
|
||||
{
|
||||
[DllImport("api-ms-win-core-errorhandling-l1-1-0.dll")]
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
[RuntimeImport(Interop.Libraries.ErrorHandling, "GetLastError")]
|
||||
internal extern static int GetLastError();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
// 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;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal partial class Interop
|
||||
{
|
||||
internal partial class mincore
|
||||
{
|
||||
[DllImport("api-ms-win-core-errorhandling-l1-1-0.dll")]
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
[RuntimeImport(Interop.Libraries.ErrorHandling, "SetLastError")]
|
||||
internal extern static void SetLastError(uint dwErrCode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -413,6 +413,7 @@ namespace Internal.TypeSystem.Ecma
|
|||
Debug.Assert((int)MethodImportAttributes.CallingConventionStdCall == (int)PInvokeAttributes.CallingConventionStdCall);
|
||||
Debug.Assert((int)MethodImportAttributes.CharSetAuto == (int)PInvokeAttributes.CharSetAuto);
|
||||
Debug.Assert((int)MethodImportAttributes.CharSetUnicode == (int)PInvokeAttributes.CharSetUnicode);
|
||||
Debug.Assert((int)MethodImportAttributes.SetLastError == (int)PInvokeAttributes.SetLastError);
|
||||
|
||||
return new PInvokeMetadata(moduleName, name, (PInvokeAttributes)import.Attributes);
|
||||
}
|
||||
|
@ -422,11 +423,11 @@ namespace Internal.TypeSystem.Ecma
|
|||
MetadataReader metadataReader = MetadataReader;
|
||||
|
||||
// Spot check the enums match
|
||||
Debug.Assert((int)ParameterAttributes.In == (int)ParameterAttributes.In);
|
||||
Debug.Assert((int)ParameterAttributes.Out == (int)ParameterAttributes.Out);
|
||||
Debug.Assert((int)ParameterAttributes.Optional == (int)ParameterAttributes.Optional);
|
||||
Debug.Assert((int)ParameterAttributes.HasDefault == (int)ParameterAttributes.HasDefault);
|
||||
Debug.Assert((int)ParameterAttributes.HasFieldMarshal == (int)ParameterAttributes.HasFieldMarshal);
|
||||
Debug.Assert((int)ParameterAttributes.In == (int)ParameterMetadataAttributes.In);
|
||||
Debug.Assert((int)ParameterAttributes.Out == (int)ParameterMetadataAttributes.Out);
|
||||
Debug.Assert((int)ParameterAttributes.Optional == (int)ParameterMetadataAttributes.Optional);
|
||||
Debug.Assert((int)ParameterAttributes.HasDefault == (int)ParameterMetadataAttributes.HasDefault);
|
||||
Debug.Assert((int)ParameterAttributes.HasFieldMarshal == (int)ParameterMetadataAttributes.HasFieldMarshal);
|
||||
|
||||
|
||||
ParameterHandleCollection parameterHandles = metadataReader.GetMethodDefinition(_handle).GetParameters();
|
||||
|
@ -436,7 +437,7 @@ namespace Internal.TypeSystem.Ecma
|
|||
{
|
||||
Parameter parameter = metadataReader.GetParameter(parameterHandle);
|
||||
TypeDesc marshalAs = null; // TODO: read marshalAs argument;
|
||||
ParameterMetadata data = new ParameterMetadata(parameter.SequenceNumber, (ParameterAttributes)parameter.Attributes, marshalAs);
|
||||
ParameterMetadata data = new ParameterMetadata(parameter.SequenceNumber, (ParameterMetadataAttributes)parameter.Attributes, marshalAs);
|
||||
parameterMetadataArray[index++] = data;
|
||||
}
|
||||
return parameterMetadataArray;
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Internal.IL.Stubs
|
|||
if (parameterIndex == parameterMetadataArray.Length || i < parameterMetadataArray[parameterIndex].Index)
|
||||
{
|
||||
// if we don't have metadata for the parameter, create a dummy one
|
||||
parameterMetadata = new ParameterMetadata(i, ParameterAttributes.None, null);
|
||||
parameterMetadata = new ParameterMetadata(i, ParameterMetadataAttributes.None, null);
|
||||
}
|
||||
else if (i == parameterMetadataArray[parameterIndex].Index)
|
||||
{
|
||||
|
@ -97,6 +97,13 @@ namespace Internal.IL.Stubs
|
|||
PInvokeMetadata importMetadata = _methodData.ImportMetadata;
|
||||
PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration = _methodData.PInvokeILEmitterConfiguration;
|
||||
|
||||
// if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
|
||||
if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError)
|
||||
{
|
||||
callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
|
||||
_methodData.PInvokeMarshal.GetKnownMethod("ClearLastWin32Error", null)));
|
||||
}
|
||||
|
||||
if (MarshalHelpers.UseLazyResolution(targetMethod, importMetadata.Module, pinvokeILEmitterConfiguration))
|
||||
{
|
||||
MetadataType lazyHelperType = targetMethod.Context.GetHelperType("InteropHelpers");
|
||||
|
@ -128,6 +135,14 @@ namespace Internal.IL.Stubs
|
|||
|
||||
callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod));
|
||||
}
|
||||
|
||||
// if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later
|
||||
// by calling PInvokeMarshal.GetLastWin32Error
|
||||
if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError)
|
||||
{
|
||||
callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
|
||||
_methodData.PInvokeMarshal.GetKnownMethod("SaveLastWin32Error", null)));
|
||||
}
|
||||
|
||||
unmarshallingCodestream.Emit(ILOpcode.ret);
|
||||
|
||||
|
|
|
@ -67,7 +67,6 @@ namespace Internal.TypeSystem.Interop
|
|||
Debug.Assert(method.IsPInvoke);
|
||||
|
||||
// TODO: true if there are any custom marshalling rules on the parameters
|
||||
// TODO: true if SetLastError is true
|
||||
|
||||
TypeDesc returnType = method.Signature.ReturnType;
|
||||
if (!MarshalHelpers.IsBlittableType(returnType) && !returnType.IsVoid)
|
||||
|
@ -81,7 +80,12 @@ namespace Internal.TypeSystem.Interop
|
|||
}
|
||||
}
|
||||
|
||||
if (UseLazyResolution(method, method.GetPInvokeMethodMetadata().Module, configuration))
|
||||
PInvokeMetadata methodData = method.GetPInvokeMethodMetadata();
|
||||
if (UseLazyResolution(method, methodData.Module, configuration))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ((methodData.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,15 @@ namespace Internal.TypeSystem.Interop
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsSafeHandle(TypeDesc type)
|
||||
public MetadataType PInvokeMarshal
|
||||
{
|
||||
get
|
||||
{
|
||||
return Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "PInvokeMarshal");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSafeHandle(TypeDesc type)
|
||||
{
|
||||
var safeHandleType = this.SafeHandleType;
|
||||
while (type != null)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Internal.TypeSystem
|
|||
}
|
||||
|
||||
[Flags]
|
||||
public enum ParameterAttributes
|
||||
public enum ParameterMetadataAttributes
|
||||
{
|
||||
None = 0,
|
||||
In = 1,
|
||||
|
@ -51,19 +51,19 @@ namespace Internal.TypeSystem
|
|||
|
||||
public struct ParameterMetadata
|
||||
{
|
||||
private readonly ParameterAttributes _attributes;
|
||||
private readonly ParameterMetadataAttributes _attributes;
|
||||
public readonly TypeDesc MarshalAs;
|
||||
public readonly int Index;
|
||||
|
||||
public bool In { get { return (_attributes & ParameterAttributes.In) == ParameterAttributes.In; } }
|
||||
public bool Out { get { return (_attributes & ParameterAttributes.Out) == ParameterAttributes.Out; } }
|
||||
public bool In { get { return (_attributes & ParameterMetadataAttributes.In) == ParameterMetadataAttributes.In; } }
|
||||
public bool Out { get { return (_attributes & ParameterMetadataAttributes.Out) == ParameterMetadataAttributes.Out; } }
|
||||
public bool Return { get { return Index == 0; } }
|
||||
public bool Optional { get { return (_attributes & ParameterAttributes.Optional) == ParameterAttributes.Optional; } }
|
||||
public bool HasDefault { get { return (_attributes & ParameterAttributes.HasDefault) == ParameterAttributes.HasDefault; } }
|
||||
public bool HasFieldMarshal { get { return (_attributes & ParameterAttributes.HasFieldMarshal) == ParameterAttributes.HasFieldMarshal; } }
|
||||
public bool Optional { get { return (_attributes & ParameterMetadataAttributes.Optional) == ParameterMetadataAttributes.Optional; } }
|
||||
public bool HasDefault { get { return (_attributes & ParameterMetadataAttributes.HasDefault) == ParameterMetadataAttributes.HasDefault; } }
|
||||
public bool HasFieldMarshal { get { return (_attributes & ParameterMetadataAttributes.HasFieldMarshal) == ParameterMetadataAttributes.HasFieldMarshal; } }
|
||||
|
||||
|
||||
public ParameterMetadata(int index, ParameterAttributes attributes, TypeDesc marshalAs)
|
||||
public ParameterMetadata(int index, ParameterMetadataAttributes attributes, TypeDesc marshalAs)
|
||||
{
|
||||
Index = index;
|
||||
_attributes = attributes;
|
||||
|
|
|
@ -36,9 +36,12 @@ extern "C"
|
|||
|
||||
extern "C"
|
||||
{
|
||||
// TODO: Remove this when when we replace the references of
|
||||
// Interop.mincore.GetLastError with Marsha.GetLastWin32Error
|
||||
// CoreLib System.Text and System.Threading in CoreLib
|
||||
uint32_t GetLastError()
|
||||
{
|
||||
return 1;
|
||||
throw "GetLastError";
|
||||
}
|
||||
|
||||
uint32_t WaitForMultipleObjectsEx(uint32_t, void*, uint32_t, uint32_t, uint32_t)
|
||||
|
|
|
@ -94,12 +94,6 @@ inline UInt32 PalGetEnvironmentVariable(__in_z_opt LPCSTR arg1, __out_z_opt LPST
|
|||
}
|
||||
#endif
|
||||
|
||||
extern "C" UInt32 __stdcall GetLastError();
|
||||
inline UInt32 PalGetLastError()
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
extern "C" void * __stdcall GetProcAddress(HANDLE, const char *);
|
||||
inline void * PalGetProcAddress(HANDLE arg1, const char * arg2)
|
||||
{
|
||||
|
|
|
@ -880,38 +880,33 @@ EXTERN_C void FASTCALL RhpUnsuppressGcStress()
|
|||
// Standard calling convention variant and actual implementation for RhpWaitForSuspend
|
||||
EXTERN_C NOINLINE void FASTCALL RhpWaitForSuspend2()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// PInvoke must not trash win32 last error. The wait operations below never should trash the last error,
|
||||
// but we keep some debug-time checks around to guard against future changes to the code. In general, the
|
||||
// wait operations will call out to Win32 to do the waiting, but the API used will only modify the last
|
||||
// error in an error condition, in which case we will fail fast.
|
||||
UInt32 uLastErrorOnEntry = PalGetLastError();
|
||||
#endif // _DEBUG
|
||||
// The wait operation below may trash the last win32 error. We save the error here so that it can be
|
||||
// restored after the wait operation;
|
||||
Int32 lastErrorOnEntry = PalGetLastError();
|
||||
|
||||
ThreadStore::GetCurrentThread()->WaitForSuspend();
|
||||
|
||||
ASSERT_MSG(uLastErrorOnEntry == PalGetLastError(), "Unexpectedly trashed last error on PInvoke path!");
|
||||
|
||||
// Restore the saved error
|
||||
PalSetLastError(lastErrorOnEntry);
|
||||
}
|
||||
|
||||
// Standard calling convention variant and actual implementation for RhpWaitForGC
|
||||
EXTERN_C NOINLINE void FASTCALL RhpWaitForGC2(PInvokeTransitionFrame * pFrame)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// PInvoke must not trash win32 last error. The wait operations below never should trash the last error,
|
||||
// but we keep some debug-time checks around to guard against future changes to the code. In general, the
|
||||
// wait operations will call out to Win32 to do the waiting, but the API used will only modify the last
|
||||
// error in an error condition, in which case we will fail fast.
|
||||
UInt32 uLastErrorOnEntry = PalGetLastError();
|
||||
#endif // _DEBUG
|
||||
|
||||
Thread * pThread = pFrame->m_pThread;
|
||||
|
||||
if (pThread->IsDoNotTriggerGcSet())
|
||||
return;
|
||||
|
||||
// The wait operation below may trash the last win32 error. We save the error here so that it can be
|
||||
// restored after the wait operation;
|
||||
Int32 lastErrorOnEntry = PalGetLastError();
|
||||
|
||||
pThread->WaitForGC(pFrame);
|
||||
|
||||
ASSERT_MSG(uLastErrorOnEntry == PalGetLastError(), "Unexpectedly trashed last error on PInvoke path!");
|
||||
// Restore the saved error
|
||||
PalSetLastError(lastErrorOnEntry);
|
||||
}
|
||||
|
||||
void Thread::PushExInfo(ExInfo * pExInfo)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
// Implementation of Redhawk PAL inline functions
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
FORCEINLINE Int32 PalInterlockedIncrement(_Inout_ _Interlocked_operand_ Int32 volatile *pDst)
|
||||
{
|
||||
return __sync_add_and_fetch(pDst, 1);
|
||||
|
@ -89,3 +91,13 @@ FORCEINLINE void PalMemoryBarrier()
|
|||
}
|
||||
|
||||
#define PalDebugBreak() __builtin_trap()
|
||||
|
||||
FORCEINLINE Int32 PalGetLastError()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
FORCEINLINE void PalSetLastError(Int32 error)
|
||||
{
|
||||
errno = error;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,20 @@ FORCEINLINE void * PalInterlockedCompareExchangePointer(_Inout_ _Interlocked_ope
|
|||
|
||||
#endif // BIT64
|
||||
|
||||
#if defined(_X86_) || defined(_AMD64_)
|
||||
EXTERN_C __declspec(dllimport) unsigned long __stdcall GetLastError();
|
||||
FORCEINLINE int PalGetLastError()
|
||||
{
|
||||
return (int)GetLastError();
|
||||
}
|
||||
|
||||
EXTERN_C __declspec(dllimport) void __stdcall SetLastError(unsigned long error);
|
||||
FORCEINLINE void PalSetLastError(int error)
|
||||
{
|
||||
SetLastError((unsigned long)error);
|
||||
}
|
||||
|
||||
|
||||
#if defined(_X86_) || defined(_AMD64_)
|
||||
|
||||
// fxsave/fxrstor instruction support, CpuIdEx Function: 1, EDX:24
|
||||
#define X86_FXSR (1<<24)
|
||||
|
|
|
@ -7,6 +7,7 @@ set(NATIVE_SOURCES
|
|||
pal_datetime.cpp
|
||||
pal_dynamicload.cpp
|
||||
pal_random.cpp
|
||||
pal_errno.cpp
|
||||
)
|
||||
|
||||
add_library(System.Private.CoreLib.Native
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// 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.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
extern "C" int32_t CoreLibNative_GetLastErrNo()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
extern "C" void CoreLibNative_SetLastErrNo(int32_t error)
|
||||
{
|
||||
errno = error;
|
||||
}
|
|
@ -742,6 +742,7 @@
|
|||
<Compile Include="System\Text\Normalization.Windows.cs" />
|
||||
<Compile Include="System\DateTime.Windows.cs" />
|
||||
<Compile Include="System\Globalization\FormatProvider.FormatAndParse.Windows.cs" />
|
||||
<Compile Include="System\Runtime\InteropServices\PInvokeMarshal.Windows.cs" />
|
||||
<Compile Include="..\..\Common\src\Interop\Windows\Interop.BOOL.cs">
|
||||
<Link>Interop\Windows\Interop.BOOL.cs</Link>
|
||||
</Compile>
|
||||
|
@ -940,6 +941,7 @@
|
|||
<Compile Include="System\IO\PathInternal.Unix.cs" />
|
||||
<Compile Include="System\Threading\ThreadPool.Unix.cs" />
|
||||
<Compile Include="System\Threading\Timer.Unix.cs" />
|
||||
<Compile Include="System\Runtime\InteropServices\PInvokeMarshal.Unix.cs" />
|
||||
<Compile Include="..\..\Common\src\Interop\Unix\Interop.Libraries.cs">
|
||||
<Link>Interop\Unix\Interop.Libraries.cs</Link>
|
||||
</Compile>
|
||||
|
@ -979,6 +981,9 @@
|
|||
<Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.SysConf.cs">
|
||||
<Link>Interop\Unix\System.Private.CoreLib.Native\Interop.SysConf.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.ErrNo.cs">
|
||||
<Link>Interop\Unix\System.Private.CoreLib.Native\Interop.ErrNo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\Common\src\Interop\Unix\System.Native\Interop.Close.cs">
|
||||
<Link>Interop\Unix\System.Native\Interop.Close.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// 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.CompilerServices;
|
||||
|
||||
namespace System.Runtime.InteropServices
|
||||
{
|
||||
/// <summary>
|
||||
/// This PInvokeMarshal class should provide full public Marshal
|
||||
/// implementation for all things related to P/Invoke marshalling
|
||||
/// </summary>
|
||||
public partial class PInvokeMarshal
|
||||
{
|
||||
public static void SaveLastWin32Error()
|
||||
{
|
||||
s_lastWin32Error = Interop.Sys.GetLastErrNo();
|
||||
}
|
||||
|
||||
internal static void ClearLastWin32Error()
|
||||
{
|
||||
Interop.Sys.SetLastErrNo(0);
|
||||
}
|
||||
|
||||
public static unsafe String PtrToStringAnsi(IntPtr ptr)
|
||||
{
|
||||
if (IntPtr.Zero == ptr)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int len = Internal.Runtime.CompilerHelpers.InteropHelpers.strlen((byte*)ptr);
|
||||
if (len == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return System.Text.Encoding.UTF8.GetString((byte*)ptr, len);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// 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.CompilerServices;
|
||||
|
||||
namespace System.Runtime.InteropServices
|
||||
{
|
||||
/// <summary>
|
||||
/// This PInvokeMarshal class should provide full public Marshal
|
||||
/// implementation for all things related to P/Invoke marshalling
|
||||
/// </summary>
|
||||
public partial class PInvokeMarshal
|
||||
{
|
||||
public static void SaveLastWin32Error()
|
||||
{
|
||||
s_lastWin32Error = Interop.mincore.GetLastError();
|
||||
}
|
||||
|
||||
internal static void ClearLastWin32Error()
|
||||
{
|
||||
Interop.mincore.SetLastError(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,16 +10,11 @@ namespace System.Runtime.InteropServices
|
|||
/// This PInvokeMarshal class should provide full public Marshal
|
||||
/// implementation for all things related to P/Invoke marshalling
|
||||
/// </summary>
|
||||
public sealed class PInvokeMarshal
|
||||
public partial class PInvokeMarshal
|
||||
{
|
||||
[ThreadStatic]
|
||||
internal static int s_lastWin32Error;
|
||||
|
||||
public static void SaveLastWin32Error()
|
||||
{
|
||||
s_lastWin32Error = Interop.mincore.GetLastError();
|
||||
}
|
||||
|
||||
public static int GetLastWin32Error()
|
||||
{
|
||||
return s_lastWin32Error;
|
||||
|
@ -29,23 +24,5 @@ namespace System.Runtime.InteropServices
|
|||
{
|
||||
s_lastWin32Error = errorCode;
|
||||
}
|
||||
|
||||
#if PLATFORM_UNIX
|
||||
public static unsafe String PtrToStringAnsi(IntPtr ptr)
|
||||
{
|
||||
if (IntPtr.Zero == ptr)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int len = Internal.Runtime.CompilerHelpers.InteropHelpers.strlen((byte*)ptr);
|
||||
if (len == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return System.Text.Encoding.UTF8.GetString((byte*)ptr, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,10 @@ namespace PInvoke
|
|||
private static extern int VerifyStringBuilder(StringBuilder sb);
|
||||
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool SafeHandleTest(SafeFileHandle sh1, Int32 sh1Value);
|
||||
public static extern bool SafeHandleTest(SafeMemoryHandle sh1, Int64 sh1Value);
|
||||
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
public static extern bool LastErrorTest();
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
|
@ -43,8 +46,8 @@ namespace PInvoke
|
|||
TestArrays();
|
||||
TestByRef();
|
||||
TestString();
|
||||
TestLastError();
|
||||
TestSafeHandle();
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
|
@ -97,45 +100,35 @@ namespace PInvoke
|
|||
ThrowIfNotEquals(1, VerifyUnicodeString("Hello World"), "Unicode String marshalling failed.");
|
||||
}
|
||||
|
||||
private static void TestLastError()
|
||||
{
|
||||
Console.WriteLine("Testing last error");
|
||||
ThrowIfNotEquals(true, LastErrorTest(), "GetLastWin32Error is not zero");
|
||||
ThrowIfNotEquals(12345, Marshal.GetLastWin32Error(), "Last Error test failed");
|
||||
}
|
||||
|
||||
private static void TestSafeHandle()
|
||||
{
|
||||
Console.WriteLine("Testing marshalling SafeHandle");
|
||||
String lpFileName = "A.txt";
|
||||
uint dwDesiredAccess = 0x40000000; // GENERIC_WRITE
|
||||
uint dwShareMode = 0x00000002; // FILE_SHARE_WRITE
|
||||
IntPtr lpSecurityAttributes = IntPtr.Zero;
|
||||
uint dwCreationDisposition = 2;// CREATE_ALWAYS;
|
||||
uint dwFlagsAndAttributes = 0x04000000; //FILE_FLAG_DELETE_ON_CLOSE
|
||||
IntPtr hTemplateFile = IntPtr.Zero;
|
||||
|
||||
//create the handle
|
||||
SafeFileHandle hnd = SafeFileHandle.CreateFile(lpFileName, dwDesiredAccess, dwShareMode,
|
||||
lpSecurityAttributes, dwCreationDisposition,
|
||||
dwFlagsAndAttributes, hTemplateFile);
|
||||
SafeMemoryHandle hnd = SafeMemoryHandle.AllocateMemory(1000);
|
||||
|
||||
IntPtr hndIntPtr = hnd.DangerousGetHandle(); //get the IntPtr associated with hnd
|
||||
int intVal = hndIntPtr.ToInt32(); //return the 32-bit value associated with hnd
|
||||
long val = hndIntPtr.ToInt64(); //return the 64-bit value associated with hnd
|
||||
|
||||
ThrowIfNotEquals(true, SafeHandleTest(hnd, intVal), "Ansi String marshalling failed.");
|
||||
ThrowIfNotEquals(true, SafeHandleTest(hnd, val), "SafeHandle marshalling failed.");
|
||||
}
|
||||
}
|
||||
|
||||
public class SafeFileHandle : SafeHandle //SafeHandle subclass
|
||||
public class SafeMemoryHandle : SafeHandle //SafeHandle subclass
|
||||
{
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern SafeMemoryHandle AllocateMemory(int size);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool ReleaseMemory(IntPtr handle);
|
||||
|
||||
|
||||
//each SafeHandle subclass will expose a static method for instance creation
|
||||
[DllImport("kernel32", EntryPoint = "CreateFileW", SetLastError = true, CharSet =CharSet.Unicode)]
|
||||
public static extern SafeFileHandle CreateFile(String lpFileName,
|
||||
uint dwDesiredAccess, uint dwShareMode,
|
||||
IntPtr lpSecurityAttributes, uint dwCreationDisposition,
|
||||
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
|
||||
//default constructor which just calls the base class constructor
|
||||
public SafeFileHandle()
|
||||
public SafeMemoryHandle()
|
||||
: base(IntPtr.Zero, true)
|
||||
{
|
||||
}
|
||||
|
@ -149,8 +142,8 @@ namespace PInvoke
|
|||
|
||||
override protected bool ReleaseHandle()
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
return ReleaseMemory(handle);
|
||||
}
|
||||
} //end of SafeFileHandle class
|
||||
} //end of SafeMemoryHandle class
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
<NativeObjectExt Condition="'$(OS)' == 'Windows_NT'">.obj</NativeObjectExt>
|
||||
<NativeObjectExt Condition="'$(OS)' != 'Windows_NT'">.o</NativeObjectExt>
|
||||
<PInvokeNativeObject>$(IntermediateOutputPath)$(OutputName)$(NativeObjectExt)</PInvokeNativeObject>
|
||||
<DefineConstants>$(DefineConstants);$(OS)</DefineConstants>
|
||||
<UseDebugCrt Condition="'$(Configuration)' == 'Debug'">true</UseDebugCrt>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -30,6 +32,7 @@
|
|||
<PInvokeCompilerArg Include="/Fo$(PInvokeNativeObject)" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
<PInvokeCompilerArg Include="-o $(PInvokeNativeObject)" Condition="'$(OS)' != 'Windows_NT'" />
|
||||
<PInvokeCompilerArg Include="@(CppCompilerAndLinkerArg)" />
|
||||
<PInvokeCompilerArg Include="-D $(OS)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(IntermediateOutputPath)" />
|
||||
|
|
|
@ -4,22 +4,32 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef Windows_NT
|
||||
#include <windows.h>
|
||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#include<errno.h>
|
||||
#define HANDLE size_t
|
||||
#define DLL_EXPORT extern "C" __attribute((visibility("default")))
|
||||
#endif
|
||||
|
||||
#if !defined(__stdcall)
|
||||
#define __stdcall
|
||||
#endif
|
||||
|
||||
extern "C" __declspec(dllexport) int __stdcall Square(int intValue)
|
||||
DLL_EXPORT int __stdcall Square(int intValue)
|
||||
{
|
||||
return intValue * intValue;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int __stdcall IsTrue(bool value)
|
||||
DLL_EXPORT int __stdcall IsTrue(bool value)
|
||||
{
|
||||
if (value == true)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int __stdcall CheckIncremental(int *array, int sz)
|
||||
DLL_EXPORT int __stdcall CheckIncremental(int *array, int sz)
|
||||
{
|
||||
if (array == NULL)
|
||||
return 1;
|
||||
|
@ -32,7 +42,7 @@ extern "C" __declspec(dllexport) int __stdcall CheckIncremental(int *array, int
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int __stdcall Inc(int *val)
|
||||
DLL_EXPORT int __stdcall Inc(int *val)
|
||||
{
|
||||
if (val == NULL)
|
||||
return -1;
|
||||
|
@ -41,7 +51,7 @@ extern "C" __declspec(dllexport) int __stdcall Inc(int *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int __stdcall VerifyAnsiString(char *val)
|
||||
DLL_EXPORT int __stdcall VerifyAnsiString(char *val)
|
||||
{
|
||||
if (val == NULL)
|
||||
return 1;
|
||||
|
@ -56,17 +66,17 @@ extern "C" __declspec(dllexport) int __stdcall VerifyAnsiString(char *val)
|
|||
q++;
|
||||
}
|
||||
|
||||
return *p == NULL && *q == NULL;
|
||||
return *p == 0 && *q == 0;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) int __stdcall VerifyUnicodeString(wchar_t *val)
|
||||
DLL_EXPORT int __stdcall VerifyUnicodeString(unsigned short *val)
|
||||
{
|
||||
if (val == NULL)
|
||||
return 1;
|
||||
|
||||
wchar_t expected[] = L"Hello World";
|
||||
wchar_t *p = expected;
|
||||
wchar_t *q = val;
|
||||
unsigned short expected[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0};
|
||||
unsigned short *p = expected;
|
||||
unsigned short *q = val;
|
||||
|
||||
while (*p && *q && *p == *q)
|
||||
{
|
||||
|
@ -74,11 +84,35 @@ extern "C" __declspec(dllexport) int __stdcall VerifyUnicodeString(wchar_t *val)
|
|||
q++;
|
||||
}
|
||||
|
||||
return *p == NULL && *q == NULL;
|
||||
return *p == 0 && *q == 0;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) bool __stdcall SafeHandleTest(HANDLE sh, int shValue)
|
||||
DLL_EXPORT bool __stdcall LastErrorTest()
|
||||
{
|
||||
return (int)sh == shValue;
|
||||
int lasterror;
|
||||
#ifdef Windows_NT
|
||||
lasterror = GetLastError();
|
||||
SetLastError(12345);
|
||||
#else
|
||||
lasterror = errno;
|
||||
errno = 12345;
|
||||
#endif
|
||||
return lasterror == 0;
|
||||
}
|
||||
|
||||
DLL_EXPORT void* __stdcall AllocateMemory(int bytes)
|
||||
{
|
||||
void *mem = malloc(bytes);
|
||||
return mem;
|
||||
}
|
||||
|
||||
DLL_EXPORT bool __stdcall ReleaseMemory(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
return true;
|
||||
}
|
||||
|
||||
DLL_EXPORT bool __stdcall SafeHandleTest(HANDLE sh, long shValue)
|
||||
{
|
||||
return (long)((size_t)(sh)) == shValue;
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Doesn't work on OSX.
|
Загрузка…
Ссылка в новой задаче