Git Product home page Git Product logo

cswin32's Introduction

C#/Win32 P/Invoke Source Generator

A source generator to add a user-defined set of Win32 P/Invoke methods and supporting types to a C# project.

NuGet (prerelease) NuGet (daily)

Build Status

Features

  • Rapidly add P/Invoke methods and supporting types to your C# project.
  • No bulky assemblies to ship alongside your application.
  • SafeHandle-types automatically generated.
  • Generates xml documentation based on and links back to docs.microsoft.com

Animation demonstrating p/invoke code generation

Prerequisites

The .NET 5 SDK or Visual Studio 2019 Update 8 (16.8) for the C# compiler that added support for Source Generators. The experience with source generators in Visual Studio is still improving, and is noticeably better in VS 16.9. WPF projects have additional requirements.

In addition, some generated code may require use of the C# 9 language version (<LangVersion>9</LangVersion>) in your project file. See issue #4 for more on this.

See dotnet/pinvoke for precompiled NuGet packages with Win32 P/Invokes.

Usage

Install the Microsoft.Windows.CsWin32 package:

dotnet add package Microsoft.Windows.CsWin32 --prerelease

Tip: Remove the IncludeAssets metadata from the package reference so that you get better code generation by allowing nuget to bring in the System.Memory package as a transitive dependency.

 <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.647-beta">
   <PrivateAssets>all</PrivateAssets>
-  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 </PackageReference>

Your project must allow unsafe code to support the generated code that will likely use pointers. This does not automatically make all your code unsafe. Use of the unsafe keyword is required anywhere you use pointers. The source generator NuGet package sets the default value of the AllowUnsafeBlocks property for your project to true, but if you explicitly set it to false in your project file, generated code may produce compiler errors.

Create a NativeMethods.txt file in your project directory that lists the APIs to generate code for. Each line may consist of one of the following:

  • Exported method name (e.g. CreateFile). This may include the A or W suffix, where applicable. This may be qualified with a namespace but is only recommended in cases of ambiguity, which CsWin32 will prompt where appropriate.
  • A macro name (e.g. HRESULT_FROM_WIN32). These are generated into the same class with extern methods. Macros must be hand-authored into CsWin32, so let us know if you want to see a macro added.
  • A namespace to generate all APIs from (e.g. Windows.Win32.Storage.FileSystem would search the metadata for all APIs within that namespace and generate them).
  • Module name followed by .* to generate all methods exported from that module (e.g. Kernel32.*).
  • The name of a struct, enum, constant or interface to generate. This may be qualified with a namespace but is only recommended in cases of ambiguity, which CsWin32 will prompt where appropriate.
  • A prefix shared by many constants, followed by *, to generate all constants that share that prefix (e.g. ALG_SID_MD*).
  • A comment (i.e. any line starting with //) or white space line, which will be ignored.

When generating any type or member, all supporting types will also be generated.

Generated code is added directly in the compiler. An IDE may make this generated code available to view through code navigation commands (e.g. Go to Definition) or a tree view of source files that include generated source files.

Assuming default settings and a NativeMethods.txt file with content that includes CreateFile, the P/Invoke methods can be found on the Windows.Win32.PInvoke class, like this:

using Windows.Win32;

PInvoke.CreateFile(/*args*/);

Constants are defined on the same class as the p/invoke methods (by default, the Windows.Win32.PInvoke class).

Other supporting types are defined within or under the Windows.Win32 namespace. Discovery of the namespace for a given type can be done with the Go To All feature (Ctrl+T) in Visual Studio with the type name as the search query.

A project may include many NativeMethods.txt files (each one necessarily in its own directory). CsWin32 will read them all to generate APIs, provided these files are included as AdditionalFiles in the project. A NativeMethods.txt file directly in the project directory is added automatically to AdditionalFiles. Files in other directories must be added to the project file manually.

Whether API requests are all in a single NativeMethods.txt file or split across many makes no difference to the generated result. We recommend using just one NativeMethods.txt file and keeping it sorted for easy bookkeeping. Multiple files perhaps makes the most sense in a Shared Project scenario where several API requests will be common across many projects, so sharing a NativeMethods.txt file with those same projects that contain all the necessary APIs for the set of shared source files make maintenance easier.

Some APIs require targeting a specific architecture and are not available when your C# project compiles as "Any CPU". Learn more about how this manifests and what your options are.

Customizing generated code

Several aspects of the generated code can be customized, including:

  • The name of the class(es) that declare p/invoke methods
  • Whether to emit interop types as public or internal
  • Whether to emit ANSI functions as well where Wide character functions also exist
  • Set PreserveSig for COM interfaces or individual members
  • Force generation of blittable structs, COM structs instead of interfaces (for super high performance with 0 GC pressure), etc.

To configure these settings, create a NativeMethods.json file in your project directory. Specifying the $schema property that points to the schema adds completions, descriptions and validation in many JSON editors, and in fact is where all the documentation for the available settings is found.

{
  "$schema": "https://aka.ms/CsWin32.schema.json",
  "emitSingleFile": false
}

Most generated types include the partial modifier so you can add your own members to that type within your code.

When you need to replace a generated type, simply copy and paste it from generated code into your own source files and remove the partial modifier. Be sure to keep the name and namespace exactly the same. CsWin32 will notice that your project already declares the type and skip generating it, but generate everything else. Note that if that type is the only thing that references some other generated type, CsWin32 will stop generating that type too. To keep CsWin32 generating the referred types you need, add them explicitly to NativeMethods.txt.

Newer metadata

To update the metadata used as the source for code generation, you may install a newer Microsoft.Windows.SDK.Win32Metadata package:

dotnet add package Microsoft.Windows.SDK.Win32Metadata --prerelease

CsWin32 also consumes the WDK from a similarly named package: Microsoft.Windows.WDK.Win32Metadata.

Consuming daily builds

Can't wait for the next release to try out a bug fix? Follow these steps to consume directly from our daily build.

Just add this package feed to your nuget.config file:

<add key="winsdk" value="https://pkgs.dev.azure.com/azure-public/winsdk/_packaging/CI/nuget/v3/index.json" />

cswin32's People

Contributors

0xced avatar aarnott avatar arahaan avatar bchavez avatar cbenghi avatar davidegiacometti avatar dependabot[bot] avatar eilon avatar elachlan avatar georg-jung avatar hydroh avatar jnm2 avatar juchom avatar kartheekp-ms avatar marysaka avatar matteo-prosperi avatar mikebattista avatar odalet avatar pziezio avatar russkie avatar sharwell avatar sotteson1 avatar stevebush avatar trevors20 avatar vivlimmsft avatar xuachen avatar youssef1313 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

cswin32's Issues

Specialize generation of GetLastError

It should call Marshal.GetLastWin32Error() instead.

This is an accuracy thing, because the only way to reliably get the last error from a recent p/invoke is to ask .NET for it, since .NET "backed up the value" you want before potentially overwriting it with another call within the runtime.

Filter generated output based on target WinSDK version

When a project's properties indicate the WinSDK version it is targeting, we should generate only those APIs that are available on that Windows version.
When the app specifies a band of versions (a preferred target + a minimum required), we can provide the higher version's APIs, but may want to annotate them somehow to help the developer realize when "light up" version checks are required.

Add unit tests for code generation

We ideally should have tests that exercise our source generator by way of the C# compiler so we're testing everything. Short of that, we should directly test the Generator class and verify that the C# compiler produces no diagnostics given the emitted .cs files.

Structs and constants are not generated

In the README.md it is mentioned that the structs and constants should be generated when the name is written in the NativeMethods.txt

I added the following structs, but they are not generated:
CWPRETSTRUCT
CWPSTRUCT

I checked in the winmd file, it is there.

Constants are also not generated, see: https://github.com/microsoft/win32metadata/issues/150
The can be found in the winmd, too.
For example:

namespace Windows.Win32.WindowsProgramming
{
  public enum PROCESS_CREATION_FLAGS : uint

Idiomatic bool marshalling

Win32 BOOL should be represented as [MarshalAs(UnmanagedType.Bool)] bool. C bool should be represented as [MarshalAs(UnmanagedType.U1)] bool.

The Boolean data type has multiple representations in unmanaged code. When the MarshalAsAttribute is not specified, the default marshaling behavior for the Boolean data type is System.Runtime.InteropServices.UnmanagedType. This is a 32-bit integer, which is not appropriate in all circumstances. The Boolean representation that is required by the unmanaged method should be determined and matched to the appropriate System.Runtime.InteropServices.UnmanagedType. UnmanagedType.Bool is the Win32 BOOL type, which is always 4 bytes. UnmanagedType.U1 should be used for C++ bool or other 1-byte types.

Source: https://docs.microsoft.com/en-us/visualstudio/code-quality/ca1414?view=vs-2019

Suggestions for readme.txt

Current text:
Microsoft Windows SDK Win32 API Source Generator

This package contains source generator to add a user-defined set of Win32 p/invoke
methods and supporting types to a C# project.

To get started, create a "NativeMethods.txt" file in your project directory
that lists the names of methods you need p/invoke methods generated for, one per line.

Learn more from our README on GitHub: https://github.com/microsoft/CsWin32#readme

Proposed text:
Microsoft Windows SDK Win32 API Source Generator

This package contains a source generator to add a user-defined set of Win32 P/Invoke
methods and supporting types to a C# project.

To get started, create a "NativeMethods.txt" file in your project directory
that lists the names of methods for which you need P/Invoke methods generated, one per line.

Learn more from our README on GitHub.

Add โ€œpartialโ€ modifier to generated members

I was trying to update a non-trivial project (x_input gamepad library) to use this generator. The methods were generating properly, but I found that many of my existing data structs had custom members. It would be nice to have a way to extend the capabilities of auto-generated structs. I think adding the partial modifier could be an easy fix, but I'm not sure if that would cause any issues for marshaled objects

Types are not generated when referenced project already defines them, even though they are inaccessible

VS is throwing an error during compilation because of a backend file that I cannot see. Here are the details that I can see

CS0122: 'BOOL' is inaccessible due to its protection level

File: PInvoke.User32.cs, Line 36

The method endpoint is generated properly, Pinvoke.LockWorkStation() is available and no errors appear in my app code. "LockWorkStation" is the only method in my NativeMethods.txt

COM interfaces should be *interfaces*, and structs should be marshable

In consideration of projects that are maintained by developers that prefer to avoid pointers and the unsafe keyword in C#, we might offer a setting to generate code that does not use pointers. In particular, code generation would:

  1. Generate only the "friendly overloads" as the direct extern methods. Instead of getting pointer-based extern methods with pointer-free friendly overloads, we would generate just the extern methods with the friendly signatures.
  2. Use delegates instead of function pointers.
  3. Use marshalled structs instead of blittable structs.
  4. Use interfaces for COM instead of structs.

Note that mixing the two varieties where marshalled structs and pointer-based extern methods coexist is a non-goal as it would be very complex to maintain and perhaps generate confusing code as well.

Source Generator Generates Structs Instead of Interfaces

The source generator currently generates structs instead of interfaces. This makes things a little difficult when an API relies on being able to use inheritance and multiple interfaces, for example DWriteCreateFactory:

NativeMethods.txt

DWRITE.*
IUnknown
IDWriteFactory
IDWriteFactory1
IDWriteFactory2
IDWriteFactory3
IDWriteFactory4
IDWriteFactory5
IDWriteFactory6
IDWriteFactory7

Program.cs

using Microsoft.Windows.Sdk;

namespace InterFaceGenerationRepro
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            IDWriteFactory factory;
            HRESULT result = PInvoke.DWriteCreateFactory(DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_SHARED, typeof(IDWriteFactory).GUID, out factory);
        }
    }
}

The IDWriteFactory interface is based off of IUnknown, and has seven other interfaces that can be swapped in to provide additional methods that can be called, by changing the GUID in the DWriteCreateFactory iid parameter to communicate which interface to use.

Expected:
The source generator should generate interfaces with full inheritance hierarchy for interfaces.

Actual:
The source generator currently generates structs in place of interfaces, causing DWriteCreateFactory's factory out parameter to not be able to cast to any of the IDWriteFactory interfaces to the defined IUnknown type.

Workaround for WPF PackageReference and source generators bug

When developing a WPF project, dotnet/wpf#810 and dotnet/wpf#3963 will cause the WPF "inner build" to omit important elements to source generators, leading to build breaks anywhere you use the generated code as reported by a *_wpftmp.csproj project file.

For example you may see a compiler error as if the generated types do not exist:

D:\temp\WpfApp1\WpfApp1\MainWindow.xaml.cs(15,25): error CS0234: The type or namespace name 'Sdk' does not exist in the namespace 'Microsoft.Windows' (are you missing an assembly reference?) [D:\temp\WpfApp1\WpfApp1\WpfApp1_2gbqycls_wpftmp.csproj]

To fix this you must use the .NET 5.0.102 SDK and set the following property in your project:

<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>

To make sure you are using the SDK with the fix, you may need to add a global.json file with this content to the root of your repo:

{
  "sdk": {
    "version": "5.0.102",
    "allowPrerelease": false,
    "rollForward": "major"
  }
}

Here is a fully working minimal sample: wpfsample.zip

Ensure wrapper structs are generated in a safe and compatible way

Wrapper structs are convenient. However, they are not always efficient nor compatible with the underlying ABI.

The best known case of this is with C++ instance members, where (on Windows) class C { MyStruct M(...); } is actually MyStruct* M(C* pThis, MyStruct* retVal, ...) and where this holds true for any struct, not just complex structs.
This means that if the native signature is, for example, class C { LRESULT M(...); }; where typedef intptr_t LRESULT; then the C# side function pointer must be delegate* unmanaged[Thiscall]<T*, ..., nint> and not delegate* unmanaged[Thiscall]<T*, ..., LRESULT>

This, in particular, crops up frequently when working with COM bindings, such as for DirectX and while I am not presently aware of any other OS/Architectures where this shows, it is not guaranteed that it never will.
This is likewise why the new CallConvMemberFunction modifier is being introduced, so function pointers for COM and other scenarios can be correctly annotated as delegate* unmanaged[Stdcall, MemberFunction] and the JIT can automatically handle the required differences from the non-member function calling convention.

These differences can lead to subtle pit of failures, particularly when working with delegates and function pointers, and as such CsWin32 should ensure that its own generated signatures and exposed types are compatible (both with known cases today and potential future cases as more platforms are supported and more ABIs to support exist; such as the support for ARM32/ARM64 or future COM support).

FreeLibrarySafeHandle.Null uses the wrong pointer value

I'm trying to call the method LoadIcon. The first parameter is documented to be null if you want a system resource.
However if I call it with the following:

var handle = PInvoke.LoadIcon(FreeLibrarySafeHandle.Null, resource_name);

I'll get an access violation exception, because it sets the pointer to -1 which becomes 0xffffffff.
The workaround is to set it to the correct pointer value for a null:

var handle = PInvoke.LoadIcon(new FreeLibrarySafeHandle(IntPtr.Zero), resource_name);

It seems to me the Null should be using 0 instead of -1.

LARGE_INTEGER/ULARGE_INTEGER should map to Int64/UInt64

These structs date back to a time where C compilers didn't natively support 64-bit integers. I think these should be represented as System.Int64 and System.UInt64 in the metadata.

I tried having a go at this myself by adding:

LARGE_INTEGER=Int64
_LARGE_INTEGER=Int64
ULARGE_INTEGER=UInt64
_ULARGE_INTEGER=UInt64

To generation/baseRemap.rsp, but to my surprise it just resulted in Microsoft.Windows.Sdk.Int64 and Microsoft.Windows.Sdk.UInt64 types being generated.

Do you think this is a reasonable change?

Comments in NativeMethods.txt

It would be helpful to add comments to the NativeMethods.txt file to make the list of lines more expressive.

For example, something like:

// GetLastInputInfo is used to determine if the user is idle in module xxx
GetLastInputInfo
// todo: remove SetWindowsHookEx and use class yyy instead
SetWindowsHookEx

Having read the code

foreach (TextLine line in nativeMethodsTxt.Lines)
{
context.CancellationToken.ThrowIfCancellationRequested();
string name = line.ToString();
if (string.IsNullOrWhiteSpace(name))
{
continue;
}

this seems easy... I'll post a PR shortly.

Support code generation targeting C# < 9

Source generators work in projects that target less than the C# 9 language version, so the generator should take the LangVersion into account and generate valid code given that target version.

Examples of C# features the generated code may rely on that require newer language versions include:

  1. Nullable ref annotations (C# 8)
  2. Function pointers (C# 9)
  3. 'null pointer constant pattern':

    Windows.Win32.PCWSTR.g.cs(52,15,52,19): error CS8370: Feature 'null pointer constant pattern' is not available in C# 7.3. Please use language version 8.0 or greater.

  4. 'readonly members'

    Windows.Win32.D2D_MATRIX_4X4_F.g.cs(66,22,66,30): error CS8370: Feature 'readonly members' is not available in C# 7.3. Please use language version 8.0 or greater.

Note that C# 9 does work on projects that target .NET Framework as well as .NET Core 3.1. But there are features of C# 8+ that do not work on .NET Framework, such as default interface methods from C# 8 or certain calling conventions of function pointers. By avoiding use of such features, many projects have successfully targeted .NET Framework while compiling with the C# 9 language version.

Touch-up whitespace issues

  • Some methods get a blank line between them while others do not.
  • dotnet/roslyn#49733 NormalizeWhitespace should put * next to the type rather than the identifier
  • SafeHandle-derived types' Null property looks terrible

Source is not generated for .NET Framework 3.5

Is there a technical reason why a library targeting net35;net48;netcoreapp5.0-windows is adding generated source to only the net48 and netcoreapp5.0-windows compilations? I didn't spot anything in the generated source that would not work on net35.

I hoped to replace https://github.com/Techsola/InstantReplay/tree/main/src/Techsola.InstantReplay/Native.

.NET Framework 3.5 is in active support by Microsoft. Some of the projects at my day job integrate with a platform that still requires net35, unfortunately, in a place where we would really benefit from using https://github.com/Techsola/InstantReplay.

I love the generated source! This is an awesome concept!

Can't work in WinUI 3 project

Start from WinUI 3 Preview 3 template project

Add package reference to Microsoft.Windows.CsWin32, with GetActiveWindow in NativeMethods.txt
Make a call to the method anywhere.

The IDE can correctly analysis all the occurrence and references of the method. However, when building the project, the command line output shows error CS0234: No member 'Windows' in namespace 'Microsoft'.

I think this is dotnet/roslyn#46420 , in another way.

Setting MicrosoftWindowsSdkWin32MetadataBasePath property breaks project

I created a project and was able to successfully use the methods generated by CsWin32. However, when I try specifying a different metadata file, it no longer works -- Visual Studio gives an error on the using Microsoft.Windows.Sdk; statement that says The type or namespace name 'Sdk' does not exist in the namespace 'Microsoft.Windows' (are you missing an assembly reference?).

To verify that it was not an issue with the metadata file, I extracted the metadata file from the NuGet package and pointed it to that, but I still get the same error about the namespace.

The generated `D3D12GetDebugInterface` method is wrong ?

// dxgi.h
HRESULT WINAPI CreateDXGIFactory1(REFIID riid, _COM_Outptr_ void **ppFactory);

// d3d12.h
HRESULT WINAPI D3D12GetDebugInterface( _In_ REFIID riid, _COM_Outptr_opt_ void** ppvDebug );

Generated C#

internal static unsafe HRESULT CreateDXGIFactory1(in System.Guid riid, out void *ppFactory)
internal static unsafe HRESULT D3D12GetDebugInterface(in System.Guid riid, void **ppvDebug)

Notice that both ppFactory and ppvDebug have _COM_Outptr_ or _COM_Outptr_opt_, but in the generated file, only ppFactory is out, ppvDebug should be too.

Therefore this always fails :

ID3D12Debug* debugController = null;
PInvoke.D3D12GetDebugInterface(typeof(ID3D12Debug).GUID, (void**) debugController);
debugController->EnableDebugLayer();

because debugController stays null


EDIT : Should have done this instead

ID3D12Debug* debugController = null;
PInvoke.D3D12GetDebugInterface(typeof(ID3D12Debug).GUID, (void**) &debugController);
debugController->EnableDebugLayer();

Hard time getting CopyFileEx to work

First of all I'm terrible at C++ and interop, so excuse me for any dumb remarks in this issue. I've used pinvoke.net before to use CopyFileEx in our code base. I tried replacing the dllimport with CsWin32. I ran into several issues.

The callback argument lpProgressRoutine is of type LPPROGRESS_ROUTINE. When opening the reference of CopyFileEx in Visual Studio after generating it by adding it to NativeMethods.txt the type LPPROGRESS_ROUTINE remains white and cannot be opened using Go To Definition. In addition to this Visual Studio was unable to generate a method for the callback routine using quick actions. The only option was to create a field/property/variable as type object. Finally I found out that Go To Definition does work when you write out the type in a C# file in source file.

The generated type LARGE_INTEGER cannot be casted to int making it impossible to make heads or tails from the progress values in the LPPROGRESS_ROUTINE calls.

The types LPVOID and LPBOOL are generated as void* and bool* correspondingly. Since these values aren't needed passing in null for both should work (should it?), but I was unable to use the argument types I was used to: IntPtr.Zero and a bool by ref.

The last problem is that enum values in the return type of LPPROGRESS_ROUTINE seem to be missing, for which I created the issue microsoft/win32metadata#170 in the win32metadata repository.

After messing around a bit it seems the CsWin32 source generator has stopped working entirely and even after a VS restart and NuGet uninstall/install it did not seem to want to generate any more code. I'm not sure what's going on and where to look for log files.

Source Generator not installed for packages.config projects

Repro steps:

  1. Start Visual Studio 2019 (16.8.3)
  2. File > New > Project > Console App (.NET Framework), select framework .NET Framework 4.8, then click the Create button
  3. Add Microsoft.Windows.CsWin32 nuget prerelease package
  4. Add NativeMethods.txt file, with single line containing CreateFileW
  5. Rebuild
  6. Observe parent Microsoft.Windows namespace does not exist per documentation

Included in .NetFramework Libraries

Will it be added to .NetFrameork Libraries or just a third-party Nuget Package?
It's too inconvient to pack these libraries as I want to construct a one-file application.

(c#) Why now struct HWND instead of IntPtr ?

Hi,
outside of this project the parameter type for handles is IntPtr, e.g.:
GetWindow(IntPtr hWnd, ...)
SetFocus(IntPtr hWnd)

That fits to the return type of functions which deliver these arguments like:
IntPtr Process.MainWindowHandle { get; }
IntPtr System.Windows.Interop.WindowInteropHelper.Handle { get; }

But win32metadata generates functions with Microsoft.Windows.Sdk.HWND as parameter type. E.g.:
PInvoke.GetWindow( HWND hwnd, ... );
PInvoke.SetFocus( HWND hwnd );
With the consequence, that we first have to convert IntPtr returns to HWND, before we can use win32metadata stuff.

What is the intension behind that type change ?
Whatever disadvantage is removed at HWND site isn't completely gone, its presumably just moved to that convert place.

thank you in advance for any candle light

Improve startup perf

In the IDE the perf is ok, but build times noticeably suffer do the the startup cost of the source generator. What can be done to speed this up?

Ideas to evaluate:

  • Encode the docs in a more performant format than YAML. MessagePack, perhaps?
  • Tests should reuse metadata references collection across tests
  • Cache the indexed metadata and reuse it across invocations (test perf fix at least, and possibly SG scenario as well)
  • Pre-index the metadata so we don't have to build up all the collections at runtime. (not a significant perf hit)

`[In, Out] char*` parameter MUST NOT generate `string` as a friendly overload

This API takes in a LPWStr, scribbles a NUL on it, and returns the numeric component.

Shlwapi!PathParseIconLocationW per headers is defined as such:

int PathParseIconLocationW(
  LPWSTR pszIconFile
);

Win32 metadata describes it as such:

[DllImport("SHLWAPI", ExactSpelling = true)]
public unsafe static extern int PathParseIconLocationW(
  [In] [Out] [NativeTypeInfo(UnmanagedType.LPWStr)] ushort* pszIconFile);

CsWin32 generated:

[DllImport("ShlwApi", ExactSpelling = true, EntryPoint = "PathParseIconLocationW")]
internal static extern unsafe int PathParseIconLocation([In, Out] char *pszIconFile);
// ...
internal static unsafe int PathParseIconLocation(string pszIconFile)
{
    fixed (char *pszIconFileLocal = pszIconFile)
    {
        return PInvoke.PathParseIconLocation(pszIconFileLocal);
    }
}

A simpler, safer approach:

[DllImport("shlwapi.dll", ExactSpelling = true, PreserveSig = true)]
internal static extern int PathParseIconLocationW(
    [MarshalAs(UnmanagedType.LPWStr)]
    StringBuilder pszIconFile);

We might be able to get away with using StringBuilder in all cases where metadata describes a parameter as [In, Out] char *. But I haven't had my coffee yet to say so definitively.

This is also a great example of how these wrappers dangerously hide the side effects of unsafe, in this case mutating what was expected to be an immutable string.

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.