Giter Club home page Giter Club logo

pinvoke's Introduction

P/Invoke

โš  NOTICE: Check out CsWin32: A new, preferred approach for Win32 p/invokes now exists for C# developers.

This repo is no longer maintained.


A collection of libraries intended to contain all P/Invoke method signatures for popular operating systems. Think of it as https://pinvoke.net, but proven to compile and work properly, and often with sample usage in the form of unit tests.

A unique C# project wraps each native library. The C# project may multi-target in order to support many versions of .NET Framework, .NET Core and .NET Standard.

Win32 APIs for all Windows versions are welcome. Special Windows Store targeted assemblies omit p/invoke signatures to banned APIs so your Store apps can depend on these libraries without getting rejected by the Store certification process.

This project is supported by the .NET Foundation.

Usage

Install the NuGet package(s) for the DLLs you want to P/Invoke into. For example, if you want to P/Invoke into Win32's BCrypt.dll, install this package:

Install-Package PInvoke.BCrypt

Then import the following namespaces, as demonstrated below (if using C# 6):

using PInvoke;
using static PInvoke.BCrypt; // Supported in C# 6 (VS2015) and later.

This will allow you to conveniently call these methods directly by method name:

var error = BCryptOpenAlgorithm(AlgorithmIdentifiers.BCRYPT_SHA256_ALGORITHM); // C# 6 syntax
var error = BCrypt.BCryptOpenAlgorithm(BCrypt.AlgorithmIdentifiers.BCRYPT_SHA256_ALGORITHM); // C# 5 syntax

Sometimes a PInvoke method may have multiple overloads. For example every method that accepts struct* parameters has an overload that accepts IntPtr in its place. In other cases there may be overloads that accept struct* and struct?. In some of these cases that can lead to compiler errors if you pass in null because both struct* and struct? overloads can match. To resolve the issue, add a cast to your null: (struct?)null to resolve the ambiguity.

What if I need custom uint value not provided in enum?

Cast any uint to specific enum type and pass as parameter.

Design goals

Provide a slightly higher than lowest level API for P/Invoke signatures. For example, instead of IntPtr parameters and uint flags, you'll see SafeHandle-derived types as parameters and flags enum types. API documentation will be provided via XML doc comments for easy reading with Intellisense, along with links to the describing pages on MSDN or elsewhere as applicable.

In some cases we offer several overloads of a given native method to offer native pointer and IntPtr access. We encourage folks to try writing C# unsafe code before using IntPtr because it (ironically) can often be easier to write correct and efficient code using native pointers than all the casting and Marshal call overhead that IntPtr requires. Note that when a method's only use of a native pointer is its return type, the IntPtr returning variant must be given a different method name by CLR overloading rules, so look for the same method but with an _IntPtr suffix.

Distribution

This library should be available on NuGet for easy consumption by your projects. You may also copy and paste the P/Invoke signatures you need directly into your projects if desired.

Packages:

Library Package name NuGet Description
advapi32.dll PInvoke.AdvApi32 NuGet Windows Advanced Services
bcrypt.dll PInvoke.BCrypt NuGet Windows Cryptography API: Next Generation
cabinet.dll PInvoke.Cabinet NuGet Cabinet API Functions
cfgmgr32.dll PInvoke.CfgMgr32 NuGet Device and Driver Installation
crypt32.dll PInvoke.Crypt32 NuGet Windows Cryptography API
DwmApi.dll PInvoke.DwmApi NuGet Desktop Window Manager
fusion.dll PInvoke.Fusion NuGet .NET Framework Fusion
gdi32.dll PInvoke.Gdi32 NuGet Windows Graphics Device Interface
hid.dll PInvoke.Hid NuGet Windows Human Interface Devices
iphlpapi.dll PInvoke.IPHlpApi NuGet IP Helper
kernel32.dll PInvoke.Kernel32 NuGet Windows Kernel API
magnification.dll PInvoke.Magnification NuGet Windows Magnification API
mscoree.dll PInvoke.MSCorEE NuGet .NET Framework CLR host
msi.dll PInvoke.Msi NuGet Microsoft Installer
ncrypt.dll PInvoke.NCrypt NuGet Windows Cryptography API: Next Generation
netapi32.dll PInvoke.NetApi32 NuGet Network Management
newdev.dll PInvoke.NewDev NuGet Device and Driver Installation
ntdll.dll PInvoke.NTDll NuGet Windows NTDll
psapi.dll PInvoke.Psapi NuGet Windows Process Status API
setupapi.dll PInvoke.SetupApi NuGet Windows setup API
SHCore.dll PInvoke.SHCore NuGet Windows Shell
shell32.dll PInvoke.Shell32 NuGet Windows Shell
user32.dll PInvoke.User32 NuGet Windows User Interface
userenv.dll PInvoke.Userenv NuGet Windows User Environment
uxtheme.dll PInvoke.UxTheme NuGet Windows Visual Styles
winusb.dll PInvoke.WinUsb NuGet USB Driver
WtsApi32.dll PInvoke.WtsApi32 NuGet Windows Remote Desktop Services

Check out the P/Invoke coverage we have for each library.

If you need a P/Invoke that is in our source code but not yet released to nuget.org, you can consume the packages directly from our CI feed by adding this package source to your nuget.config file

<add key="PInvoke" value="https://pkgs.dev.azure.com/andrewarnott/OSS/_packaging/PublicCI/nuget/v3/index.json" />

Contribution

Please consider contributing more P/Invoke method signatures to this project. Once you contribute, you can immediately consume your additions without waiting for another public release of the library.

This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. For more information see the .NET Foundation Code of Conduct.

pinvoke's People

Contributors

aarnott avatar aluferyochay avatar arlm avatar barrynolte avatar bintoss avatar dbremner avatar dependabot[bot] avatar enovales avatar ffmathy avatar gitter-badger avatar hmemcpy avatar jmelosegui avatar jnm2 avatar luke-dixon avatar mckunda avatar melvingr avatar msmshazan avatar nn--- avatar notcoffee418 avatar qmfrederik avatar sardelka9515 avatar stevebush avatar vatsan-madhavan avatar vbfox avatar weitzhandler avatar willibrandon avatar xuachen avatar yyjdelete avatar zabulus avatar zgabi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pinvoke's Issues

Add native pointer overloads of methods that accept IntPtr

IntPtr parameters are harder to deal with than native pointer types (in C# anyway), and they express less in terms of type safety than pointers can.

We should consider changing our policy and code to use pointers instead of IntPtr.

One possibility is that we maintain two overloads of applicable P/Invoke methods: one that takes IntPtr and one that takes pointers, so that folks can call without using unsafe code. I don't have much sympathy for any anxiety over writing unsafe code since it's actually simpler, and partial trust is irrelevant for consumers of this library anyway. So the only reason to keep IntPtr around is for languages that don't support pointers (e.g. Powershell).

  • AdvApi32
  • BCrypt
  • DbgHelp
  • Gdi32
  • Hid
  • ImageHlp
  • Kernel32
  • NCrypt
  • Psapi
  • SetupApi
  • User32

Finalizing whole libraries at a time?

Is there any pattern to how we write the PInvoke classes? It doesn't seem like there are any of the libraries that are 100% done yet.

Wouldn't it be a good idea to finish entire DLL imports for whole DLL files at a time, for instance finishing user32.dll first before working on others?

To use this library, I need to know that it has everything I need before downloading it. As long as it isn't 100% done, I am not using it (due to the fear of something missing).

Also, I think there are some areas that are more used than others (for instance shell32.dll, kernel32.dll and user32.dll). Could we start with these?

Code generation should also create byte[] parameter overloads where byte* is observed

For example, in the below p/invoke method, we want to generate both an overload that takes IntPtr for all native pointer parameters, and another overload where the byte* parameter type is treated specially by replacing it with byte[].

It seems useful to generate byte[] overloads both with native pointers for the other parameters as well as of course the IntPtr variety. Meaning that we generate 3 overloads instead of 1.

So this hand-written method:

public static unsafe extern SECURITY_STATUS NCryptDecrypt(
    SafeKeyHandle hKey,
    byte* pbInput,
    int cbInput,
    void* pPaddingInfo,
    byte* pbOutput,
    int cbOutput,
    out int pcbResult,
    NCryptEncryptFlags dwFlags);

Would generate these three overloads: (the first is already generated, the rest are proposed)

public static unsafe extern SECURITY_STATUS NCryptDecrypt(
    SafeKeyHandle hKey,
    IntPtr pbInput,
    int cbInput,
    IntPtr pPaddingInfo,
    IntPtr pbOutput,
    int cbOutput,
    out int pcbResult,
    NCryptEncryptFlags dwFlags);

public static unsafe extern SECURITY_STATUS NCryptDecrypt(
    SafeKeyHandle hKey,
    byte[] pbInput,
    int cbInput,
    IntPtr pPaddingInfo,
    byte[] pbOutput,
    int cbOutput,
    out int pcbResult,
    NCryptEncryptFlags dwFlags);

public static unsafe extern SECURITY_STATUS NCryptDecrypt(
    SafeKeyHandle hKey,
    byte[] pbInput,
    int cbInput,
    void* pPaddingInfo,
    byte[] pbOutput,
    int cbOutput,
    out int pcbResult,
    NCryptEncryptFlags dwFlags);

AdvApi32: Define SERVICE_TRIGGER_SPECIFIC_DATA_ITEM

The AdvApi32+ServiceTrigger struct has a member that points to a SERVICE_TRIGGER_SPECIFIC_DATA_ITEM struct, but that struct isn't defined. Once we define it, we'll probably want to change pDataItems to be typed as SERVICE_TRIGGER_SPECIFIC_DATA_ITEM[] so that would be an API breaking change.

Can we fit it in before the API goes stable?

Fix build break on VS2015 update 1 RTW

With update 1 RTW, the build breaks. It seems Nuproj.common in Windows.Core's project.json file no longer propagates. This may be a bug in Update 1 RTW, and we should follow up on that as well.

C:\Users\andarno\git\pinvoke\src\Kernel32.Desktop\Kernel32.Desktop.csproj : error MSB4057: The target "_NuProjGetProjectClosure" does not exist in the project.
C:\Users\andarno\git\pinvoke\src\Kernel32\Kernel32.csproj : error MSB4057: The target "_NuProjGetProjectClosure" does not exist in the project.

Define our own Win32Exception type (for portable profiles)

We should make our type derive from Win32Exception as defined by the BCL when it's available (on desktop profile) so that folks can 'catch' these exceptions by its base type.

When this change is in place, NTStatus.ThrowOnError() and other related methods should use it instead of throwing COMException.

[OfferFriendlyOverloads] incorrect for Bidirectional code gen

When applying the FriendlyAttribute to the second parameter of Process32First:

[DllImport(nameof(Kernel32), SetLastError = true, CharSet = CharSet.Unicode)]
public static extern unsafe bool Process32First(
    SafeObjectHandle hSnapshot,
    [Friendly(FriendlyFlags.Bidirectional)] PROCESSENTRY32* lppe);

The code gen'd friendly overload is typed as ref PROCESSENTRY32* instead of ref PROCESSENTRY32.

Add a constructor with preexistingHandle and ownsHandle to all SafeHandles

Some of our SafeHandle have it but others don't. I think that we should be consistent and always provide this constructor that is really useful when interacting with other code (Like passing handles created by WPF or winforms to PInvoke methods)

/// <summary>
/// Initializes a new instance of the <see cref="SafeThemeHandle"/> class.
/// </summary>
/// <param name="preexistingHandle">An object that represents the pre-existing handle to use.</param>
/// <param name="ownsHandle">
///     <see langword="true" /> to have the native handle released when this safe handle is disposed or finalized;
///     <see langword="false" /> otherwise.
/// </param>
public SafeThemeHandle(IntPtr preexistingHandle, bool ownsHandle = true)
    : base(IntPtr.Zero, ownsHandle)
{
    this.SetHandle(preexistingHandle);
}

(The info should also be added to CONTRIBUTING in this case)

See #197 for a PR adding 2 such constructors.

Reconsider where we use class instead of struct

We use class instead of struct on some types because it makes it possible to pass in null for optional pointer parameters. But this has some negative side effects:

  1. The user may expect the type is a struct and be surprised that a lack of ref or out still produces changes from native code into the managed code.
  2. A memory allocation is required to initialize one.
  3. The optional vs. required trait that drives use of class is not a characteristic of the type, but rather of a particular use of it in a method. So if some methods require it and other methods make it optional, the type cannot be both.

Now that we're more pointer friendly, I wonder if we should just use structs. We can use native pointers to structs instead of ref or classes for optional parameters.

Structs currently masquerading as classes:

  • SP_DEVINFO_DATA
  • NullableGuid
  • NullableUInt32
  • NullablePipeMode
  • PROCESSENTRY32
  • SECURITY_ATTRIBUTES

Display badges for amount of work completed for a native binary

We should display badges in HTML rendered versions of our README.md file indicating how many exported functions of each native binary we have P/Invoke methods for. For example, if Kernel32.dll has 533 exported functions and we have p/invoke methods for 12 of them, the badge might look like this:

P/Invokes

Benefits

  1. Set expectations appropriately with consumers of the packages as to the likelihood that what they care about is already in there.
  2. I think it may help motivate contributors to drive the numbers higher as it will make a visible different on our landing page and make the project more compelling.

Design

There are two halves to the analysis we need to do:

  1. We need to create a maintainable list of documented, exported methods from a native binary.
  2. We need to create a maintainable list of [DllImport] methods in the managed P/Invoke library for that native binary.

The process should involve extracting the right set of method names from the native binary and maintaining them in a list. Then assembling a similar list from the managed binary. These lists should be created such that method names will match for each list if they exist in both.

Native binary analysis

The following command will print out all exported functions (i.e. candidates for P/Invokes)

dumpbin /exports LIBNAME.dll

Once we have this list, we'll need to de-duplicate for ansi vs. Unicode versions. We should recognize when a method ends with A or W, and if so, check for another method with the same name except the alternate final letter. When we see this, we report the root method name (without the A or W suffix). If we don't recognize such a pattern, we report the full method name.

The resulting list should be checked into source control as a text file with exactly one function name per line. Its content should be sorted alphabetically. The filename should be LIBNAME.exports.txt. While we should have a script that can produce this file, as its results would only vary with the version of the native DLL, and as we want a consistent target to aim for across dev and build machines, we should check in the result and only update it when a new version of the native library is released. This also lets us (potentially) hand edit the 'target' file to remove functions that are undocumented and thus not intended to be P/Invoked into.

The build should copy this LIBNAME.exports.txt file as a build output.

Managed P/Invoke assembly analysis

Use reflection on the managed P/Invoke library to find all static methods (independent of their visibility) that have [DllImport] attributes on them. When the DllImportAttribute.Entrypoint property is set on the attribute, report that as the native function name. Otherwise report the method name itself.

This list should be generated at build time and saved to a text file named LIBNAME.pinvokes.txt and dropped as a build output. Each line should contain exactly one of the names reported as described above and these lines should be sorted alphabetically.

Producing shields/badges

The LIBNAME.exports.txt and LIBNAME.pinvokes.txt files should be found side-by-side as build outputs. Perhaps in a dedicated directory such as bin\debug\exports. These files should be captured by AppVeyor as artifacts.

A simple build-time script will compare the LIBNAME.exports.txt and LIBNAME.pinvokes.txt file to count how many lines each contains to formulate a string with the form X/Y where X is the number of lines in the LIBNAME.pinvokes.txt file and Y is the number of lines in the LIBNAME.exports.txt file. This string can then be injected into this URL to replace PLACEHOLDER:

https://img.shields.io/badge/P%2FInvokes-PLACEHOLDER-orange.svg

We might even change the color based on how X and Y compare to each other. For example:

Condition Color Example
X = Y Green P/Invokes
else X > Y * 8/10 YellowGreen P/Invokes
else X > Y * 4/10 Orange P/Invokes
else X > 0 Red P/Invokes
else LightGrey P/Invokes

These badges should act as hyperlinks to a document with a table that compares the LIBNAME.pinvokes.txt and LIBNAME.exports.txt file so users can quickly discover whether the functions they need are already available.

Unsolved

  1. Is executing dumpbin /exports and parsing the output really the best way to go or is there a programmatic approach we can take instead?
  2. Somehow we need to get this X/Y string or URL into an such that it appears in renderings of README.md.
  3. We could also produce a Markdown table listing all the exported functions and a column showing whether we have a P/Invoke method for it. But where/how would this Markdown file be hosted/viewed?

ReadFile/WriteFile OVERLAPPED tests should use Pipes

See #40 for some background.

The current tests use files but we have no way to control whenever the IO will really be asynchronous or not, we should use pipes instead where we can ensure that a synchronous answer is impossible.

It would also allow to correctly test IO Cancelation support.

I implies adding support for CreatePipe or CreateNamedPipe.

Don't mix helpers and non-helpers

I don't think it's a good idea to mix helpers and non-helpers in the same class name. Others have no clear indication of when something is a helper method, and typically beforehand they are either looking for the "barebone low-level" native API approach, or a high-level assisted approach to solving a problem.

I say we change the name of the helper classes to something else or use a specific naming convention for helpers, so that people can clearly tell the difference.

Ideally, we could even put the helpers in a separate NuGet package. I never want high-level stuff and I think it pollutes my API if they are mixed.

Imagine 3 packages:

  • PInvoke.BCrypt
  • PInvoke.BCrypt.Mockables (this one could also be included as discussed other places)
  • PInvoke.BCrypt.Helpers

I think that's the right approach and the convention that we see elsewhere.

An error while building nuproj projects.

I'm getting the following exception on my machine:

Error   MSB4018 The "ReadPdbSourceFiles" task failed unexpectedly.
System.IO.FileNotFoundException: Retrieving the COM class factory for component with CLSID {3BFCEA48-620F-4B6B-81F7-B9AF75454C7D} failed due to the following error: 8007007e The specified module could not be found. (Exception from HRESULT: 0x8007007E).
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)
   at NuProj.Tasks.PdbReader.ReadSourceFiles(String pdbPath) in C:\git\nuproj\src\NuProj.Tasks\ReadPdbSourceFiles.cs:line 36
   at NuProj.Tasks.ReadPdbSourceFiles.Execute() in C:\git\nuproj\src\NuProj.Tasks\ReadPdbSourceFiles.cs:line 25
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext() MSCorEE.NuGet   C:\Users\hmemcpy\.nuget\packages\NuProj\0.10.27-beta-g2363d7cd98\tools\NuProj.targets   963 

This happens for every nuproj project. Perhaps this is more of a question/issue for the nuproj repo...

Windows 10, VS2015. Any ideas?

Build error (that doesn't break the build?) in Create-PInvokeTxtFile.ps1

From this AppVeyor build

PInvoke.Win32 -> C:\projects\pinvoke\bin\Release\Packages\PInvoke.Win32.0.1.286-beta-ge68a656187.nupkg
 420  C:\projects\pinvoke\tools\Create-PInvokeTxtFile.ps1 : Cannot bind argument to 
 421  parameter 'AssemblyPath' because it is an empty string.
 422  At line:1 char:68
 423  + & { & 'C:\projects\pinvoke\src\..\tools\Create-PInvokeTxtFile.ps1' '' }
 424  +                                                                    ~~
 425      + CategoryInfo          : InvalidData: (:) [Create-PInvokeTxtFile.ps1], Pa 
 426     rameterBindingValidationException
 427      + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAl 
 428     lowed,Create-PInvokeTxtFile.ps1
 429   
 430  CodeGeneration.Debugging -> C:\projects\pinvoke\src\CodeGeneration.Debugging\bin\Release\CodeGeneration.Debugging.exe

I wonder if this is because the specialized build scripts aren't prepared to skip processing of the code generation projects.

Powershell scripts are significantly slowing down the build

It turns out that building is a lot slower now. Task Manager shows powershell spending a lot of time during the build. I don't yet know whether it's one of the ps1 scripts with a bad algorithm or (more likely) just spawning powershell.exe itself taking a long time. But we should see what we can do to reduce the time.

Generate p/invoke methods automatically

There is a library out there called SharpDX. They allow full DirectX 11 support for C# through PInvoke-ish APIs, but the cool thing is that they are all auto-generated and auto-converted to C#.

Could we instead of what we are doing now get inspiration from them, and make a tool which auto-generates all C# code?

It would also make it a lot easier to maintain.

Provide a meta-package in NuGet

I'm thinking of a package in the same spirit as Microsoft.CodeAnalysis or xunit that could be named PInvoke

One consideration is that for now the library contains only pinvoke for windows dlls (delivered with the operating system) so the package would be named more exactly PInvoke.Windows.

The main advantage for the package I see is for easy prototyping (For example in LINQPad) where searching beforehand for all necessary packages might be more complex than just referencing a meta package.

What do you think ?

HResult is missing a method to get an exception from it

We already have ThrowOnFailure calling Marshal.ThrowExceptionForHR but don't have any equivalent to Marshal.GetExceptionForHR.

Foo Function()
{
    Foo result;
    HResult hr = SomePInvoke(out result);
    if (hr.Succeeded)
    {
        return result;
    }
    else
    {
        if (hr == /*Some value*/)
        {
            throw MyError();
        }
        throw hr.GetException();
    }
}

It's often possible to do without but it's sometimes preferable to have explicit throw for control-flow and it ease porting code using the Mashal class

How do I find Windows headers?

I installed the Windows 10 standalone SDK, and I can't find my header files for PInvoke based operations. Do you know where they are?

I like where this is going

Hey @AArnott!

Glad you had time when I didn't and took this idea further than ever. I also like where it's going, and I will be monitoring it closely over the upcoming weeks. Maybe I'll even contribute once in a while!

Keep up the great effort.

Offer PInvoke.ILMerge NuGet package the merge P/Invokes into consuming assembly

I expect some folks will more readily consume the work of this project if they can merge the P/Invokes they use into their assembly rather than shipping all the unused ones as well in a separate assembly.

A NuGet package that uses ILMerge as a build step may allow this process to be very easy for consumers to opt into.

Settle on helpful pattern for HRESULT, NTSTATUS and Win32 errors

We should consider defining enums or structs to assist with all three of these, and then use them instead of int32 in all our interop code. Also (where possible) offer conversion between them and exception throwing routines for them where the portable profile lacks them.

Here are some good resources for getting started:

Add AllowUnsafeBlocks to all projects

As an increasing number of PInvoke assemblies need to allow unsafe blocks, and we're p/invoking into native code, after all, it makes sense to just allow it for all projects.

Let's add it to EnlistmentInfo.props, and remove the explicit property definition from the individual projects that already have them added.

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

Make it that Audio Switcher can use our lib

Audio Switcher by @davkean is a cool project that use quite a bit of P/Invoke and it would be nice to have enough API available that we can send it a PR to use our library.

What we miss as APIs :

  • Kernel32\EnumResourceNames
  • Kernel32\FindResource
  • Kernel32\LoadResource
  • Kernel32\LockResource
  • Kernel32\SizeofResource
  • Kernel32\LoadLibraryEx
  • User32\LookupIconIdFromDirectory
  • User32\LookupIconIdFromDirectoryEx
  • User32\GetDC
  • User32\ReleaseDC
  • Gdi32\GetDeviceCaps
  • Uxtheme\GetThemeMargins

Except for the last one it's on dlls we already have in the codebase and the license of the project is also MIT so we can reuse directly the declaration after adaptation.

We also need a few types :

  • GRPICONDIR
  • GRPICONDIRENTRY
  • ICONDIR
  • ICONDIRENTRY
    Even if the lib is never used in Audio Switcher in the end we will have gained a few more functions.

Codegen IntPtr-accepting overloads of methods with native pointers

#76 should be done first. See that issue for the rationale.

For now we'll use only a few pointers when deemed necessary and hand-craft IntPtr alternatives, but what would really be interesting is to only have to write the pointer versions and have the IntPtr overload auto-generated.

Code generation will also be needed for #55 so both issues would need the same infrastructure.

We should have every API backed up by an interface, in a non-static way

Hi there.

Often when working with PInvoke code, you have a function like this:

public void DoSomething() { MyApi.SomePInvokeCall(); SomeOtherCodeThatIsRelevant(); }

But then you can't unit test DoSomething because it uses a PInvoke API. In other words, it would be an integration test, and if the API in question does something nasty, you would never want it to run.

What if we (from every static class of APIs) backed them up by an interface, which was then injectable through IOC?

Yes, it would require an instance of the class (maybe we could add a Singleton pattern if some people wouldn't ever want to instantiate each API). But it would make huge amounts of code easier to test, and take PInvoke a step further.

So instead of:

public static class SomeExampleApi
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct BITMAP
        {
            public int Type;
            public int Width;
            public int Height;
            public int WidthBytes;
            public ushort Planes;
            public ushort BitsPixel;
            public IntPtr Bits;
        }

        [DllImport("gdi32", CharSet = CharSet.Auto)]
        public static extern int GetObject(
            IntPtr hgdiobj,
            int cbBuffer,
            out BITMAP lpvObject
            );
}

We would have:

private class SomeExampleApi : ISomeExampleApi
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct BITMAP
        {
            public int Type;
            public int Width;
            public int Height;
            public int WidthBytes;
            public ushort Planes;
            public ushort BitsPixel;
            public IntPtr Bits;
        }

        public int GetObject(
            IntPtr hgdiobj,
            int cbBuffer,
            out BITMAP lpvObject
            ) {
               return GetObjectApi(hgdiobj, cbBuffer, out lpvObject);
        }

        [DllImport("gdi32", EntryPoint = "GetObject", CharSet = CharSet.Auto)]
        private static extern int GetObjectApi(
            IntPtr hgdiobj,
            int cbBuffer,
            out BITMAP lpvObject
            );
}

And then the ISomeExampleApi would look like:

public interface ISomeExampleApi {
     public int GetObject(
            IntPtr hgdiobj,
            int cbBuffer,
            out BITMAP lpvObject
            );
}

That way, I could inject an ISomeExampleApi whenever I wanted to use it, and then when testing, fake it out with my favorite mocking framework, and still test other functionality.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.