Merge pull request #2452 from shrah/master

Implement SetLastError DllImport flag functionality
This commit is contained in:
Faizur Rahman 2017-01-07 23:26:25 -08:00 коммит произвёл GitHub
Родитель 2fa81459e9 1ed5178661
Коммит 058296779d
23 изменённых файлов: 280 добавлений и 113 удалений

Просмотреть файл

@ -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.