1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
namespace Microsoft.Interop
{
public abstract class StubCodeContext
{
/// <summary>
/// Code generation stage
/// </summary>
public enum Stage
{
/// <summary>
/// Invalid stage
/// </summary>
Invalid,
/// <summary>
/// Perform any setup required
/// </summary>
Setup,
/// <summary>
/// Convert managed data to native data
/// </summary>
Marshal,
/// <summary>
/// Pin data in preparation for calling the generated P/Invoke
/// </summary>
Pin,
/// <summary>
/// Call the generated P/Invoke
/// </summary>
/// <remarks>
/// <see cref="IMarshallingGenerator.AsArgument(TypePositionInfo)"/> should provide the
/// argument to pass to the P/Invoke
/// </remarks>
Invoke,
/// <summary>
/// Convert native data to managed data
/// </summary>
Unmarshal,
/// <summary>
/// Perform any cleanup required
/// </summary>
Cleanup,
/// <summary>
/// Keep alive any managed objects that need to stay alive across the call.
/// </summary>
KeepAlive,
/// <summary>
/// Convert native data to managed data even in the case of an exception during
/// the non-cleanup phases.
/// </summary>
GuaranteedUnmarshal
}
public Stage CurrentStage { get; set; } = Stage.Invalid;
/// <summary>
/// The stub emits code that runs in a single stack frame and the frame spans over the native context.
/// </summary>
/// <remarks>
/// Stubs that emit code into a single frame that spans the native context can do two things:
/// <list type="bullet">
/// <item> A <c>fixed</c> statement can be used on an individual value in the <see cref="Stage.Pin"/> stage and the pointer can be passed to native code.</item>
/// <item>Memory can be allocated via the <c>stackalloc</c> keyword and will live through the full native context of the call.</item>
/// </list>
/// </remarks>
public abstract bool SingleFrameSpansNativeContext { get; }
/// <summary>
/// Additional variables other than the {managedIdentifier} and {nativeIdentifier} variables can be added to the stub to track additional state for the marshaller in the stub in the Setup phase, and they will live across all phases of the stub.
/// </summary>
/// <remarks>
/// When this property is <c>false</c>, any additional variables can only be considered to have the state they had immediately after the Setup phase.
/// </remarks>
public abstract bool AdditionalTemporaryStateLivesAcrossStages { get; }
/// <summary>
/// If this context is a nested context, return the parent context. Otherwise, return <c>null</c>.
/// </summary>
public StubCodeContext? ParentContext { get; protected set; }
public const string GeneratedNativeIdentifierSuffix = "_gen_native";
/// <summary>
/// Get managed and native instance identifiers for the <paramref name="info"/>
/// </summary>
/// <param name="info">Object for which to get identifiers</param>
/// <returns>Managed and native identifiers</returns>
public virtual (string managed, string native) GetIdentifiers(TypePositionInfo info)
{
return (info.InstanceIdentifier, $"__{info.InstanceIdentifier.TrimStart('@')}{GeneratedNativeIdentifierSuffix}");
}
public virtual string GetAdditionalIdentifier(TypePositionInfo info, string name)
{
return $"{GetIdentifiers(info).native}__{name}";
}
}
}
|