|
//-----------------------------------------------------------------------------------------------
// <copyright file="BidPrivateBase.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
// Last Modified: 6-November-2008
//-----------------------------------------------------------------------------------------------
//
// Define the symbol below to enable automatic generation of strongly typed
// overloads for 'Bid.Trace' and 'Bid.ScopeEnter'.
//
//#define BID_AUTOSIG
//#define BID_USE_SCOPEAUTO
//#define BID_USE_EXTENSIONS
//#define BID_USE_IDENT
//#define BID_USE_INSTANCE_TRACKING
//#define BID_USE_CONTROL
//#define BID_USE_PUTSTRLINE
//#define BID_USE_ALL_APIGROUP
using System;
using System.IO;
using System.Text;
using System.Security;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Security.Permissions;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Versioning;
#if BID_AUTOSIG
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
#endif
//
// The C# interface for the BID (Built-In Diagnostics) infrastructure consistis of two files that
// implement the wrapper class Bid:
//
// internal sealed partial class Bid
//
// The main part is implemented in BidPrivateBase.cs and is supposed to be considered
// as invariant part of the interface.
//
// The second part is implemented in assembly (module) specific file, created from
// AssemblyTemplate_BID.cs and usually renamed to <AssemblyName>_BID.cs. It is supposed to contain
// overloaded methods Trace and ScopeEnter with exact signatures used in the given assembly.
//
// SignatureGenerator (available in development cycle when BID_AUTOSIG symbol is defined)
// can be used to help generate assembly specific, strongly typed overloads.
//
// NOTE:
// The current technique with two "include" files most likely will be changed,
// so don't make strong assumptions regarding implementation details.
//
// However, the intention is to keep used APIs unchanged, so the upcoming update(s) of the
// BID infrastructure should not enforce any changes in already instrumented product code.
//
[ComVisible(false)]
internal static partial class Bid
{
//+//////////////////////////////////////////////////////////////////////////////////////////
// //
// INTERFACE //
// //
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// ApiGroup control flags are accessible from attached diagnostic subsystem via corresponding
// delegate, so the output can be enabled/disabled on the fly.
//
internal enum ApiGroup : uint
{
Off = 0x00000000,
Default = 0x00000001, // Bid.TraceEx (Always ON)
Trace = 0x00000002, // Bid.Trace, Bid.PutStr
Scope = 0x00000004, // Bid.Scope{Enter|Leave|Auto}
Perf = 0x00000008, // TBD..
Resource = 0x00000010, // TBD..
Memory = 0x00000020, // TBD..
StatusOk = 0x00000040, // S_OK, STATUS_SUCCESS, etc.
Advanced = 0x00000080, // Bid.TraceEx
Pooling = 0x00001000,
Dependency = 0x00002000,
StateDump = 0x00004000,
Correlation = 0x00040000,
MaskBid = 0x00000FFF,
MaskUser = 0xFFFFF000,
MaskAll = 0xFFFFFFFF
}
//
// These wrappers simplify coding when/if we want direct access
// to the ApiGroup Control Bits.
//
#if BID_USE_ALL_APIGROUP
internal static bool DefaultOn {
get { return (modFlags & ApiGroup.Default) != 0; }
}
#endif
internal static bool TraceOn {
[BidMethod(Enabled = false)] // Ignore this method in FXCopBid rule
get { return (modFlags & ApiGroup.Trace) != 0; }
}
internal static bool ScopeOn {
get { return (modFlags & ApiGroup.Scope) != 0; }
}
#if BID_USE_ALL_APIGROUP
internal static bool PerfOn {
get { return (modFlags & ApiGroup.Perf) != 0; }
}
internal static bool ResourceOn {
get { return (modFlags & ApiGroup.Resource) != 0; }
}
internal static bool MemoryOn {
get { return (modFlags & ApiGroup.Memory) != 0; }
}
internal static bool StatusOkOn {
get { return (modFlags & ApiGroup.StatusOk) != 0; }
}
#endif
internal static bool AdvancedOn {
get { return (modFlags & ApiGroup.Advanced) != 0; }
}
internal static bool IsOn(ApiGroup flag) {
return (modFlags & flag) != 0;
}
#if BID_USE_ALL_APIGROUP
internal static bool AreOn(ApiGroup flags) {
return (modFlags & flags) == flags;
}
#endif
private static IntPtr __noData;
internal static IntPtr NoData {
get { return __noData; }
}
internal static IntPtr ID {
get { return modID; }
}
internal static bool IsInitialized {
get { return modID != NoData; }
}
//=//////////////////////////////////////////////////////////////////////////////////////////
//
// ModeFlags to be used with 'Ex' flavor of API functions (argument "uint flags")
//
internal struct ModeFlags
{
internal const uint
Default = 0x00,
SmartNewLine= 0x01,
NewLine = 0x02,
Enabled = 0x04,
/*DemandSrc = 0x08,*/
Blob = 0x10,
BlobCopy = 0x12,
BlobBinMode = 0x14;
}
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// PLAIN STRING OUTPUT
//
internal static void PutStr (string str) {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)ModeFlags.Default, str);
}
#if BID_USE_PUTSTRLINE
internal static void PutStrLine (string str) {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)ModeFlags.SmartNewLine, str);
}
internal static void PutNewLine() {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)ModeFlags.NewLine, string.Empty);
}
internal static void PutStrEx (uint flags, string str) {
if (modID != NoData)
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)flags, str);
}
internal static void PutSmartNewLine() {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)ModeFlags.SmartNewLine, string.Empty);
}
//
// for( i = 0; i < strArray.Length; i++ ){
// Bid.PutStrEx( Bid.NewLineEx((i % 10) == 0), strArray[idx] );
// }
// Bid.PutSmartNewLine();
//
internal static uint NewLineEx(bool addNewLine) {
return addNewLine ? ModeFlags.SmartNewLine : ModeFlags.Default;
}
#endif
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// Main Tracing Facility (More overloads to be provided in assembly-specific file)
//
#if BID_AUTOSIG
internal static void Trace(string fmtPrintfW, params object[] args) {
SignatureGenerator.Trace (fmtPrintfW, args);
}
internal static void TraceEx(uint flags, string fmtPrintfW, params object[] args) {
SignatureGenerator.TraceEx (flags, fmtPrintfW, args);
}
#endif
[BidMethod]
internal static void Trace(string strConst) {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.Trace(modID, UIntPtr.Zero, UIntPtr.Zero, strConst);
}
[BidMethod]
internal static void TraceEx(uint flags, string strConst) {
if (modID != NoData)
NativeMethods.Trace(modID, UIntPtr.Zero, (UIntPtr)flags, strConst);
}
[BidMethod]
internal static void Trace(string fmtPrintfW, string a1) {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.Trace(modID, UIntPtr.Zero, UIntPtr.Zero, fmtPrintfW, a1);
}
[BidMethod]
internal static void TraceEx(uint flags, string fmtPrintfW, string a1) {
if (modID != NoData)
NativeMethods.Trace(modID, UIntPtr.Zero, (UIntPtr)flags, fmtPrintfW, a1);
}
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// Scope Tracking
//
internal static void ScopeLeave(ref IntPtr hScp) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
if (hScp != NoData) NativeMethods.ScopeLeave(modID, UIntPtr.Zero, UIntPtr.Zero, ref hScp);
} else {
hScp = NoData; // NOTE: This assignment is necessary, even it may look useless
}
}
//
// (More overloads to be provided in assembly-specific file)
//
#if BID_AUTOSIG
[BidMethod]
internal static void ScopeEnter(out IntPtr hScp, string fmtPrintfW, params object[] args) {
SignatureGenerator.ScopeEnter (out hScp, fmtPrintfW, args);
}
#endif
[BidMethod]
internal static void ScopeEnter(out IntPtr hScp, string strConst) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out hScp, strConst);
} else {
hScp = NoData;
}
}
[BidMethod]
internal static void ScopeEnter(out IntPtr hScp, string fmtPrintfW, int a1) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out hScp, fmtPrintfW, a1);
} else {
hScp = NoData;
}
}
[BidMethod]
internal static void ScopeEnter(out IntPtr hScp, string fmtPrintfW, int a1, int a2) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out hScp, fmtPrintfW, a1, a2);
} else {
hScp = NoData;
}
}
#if BID_USE_SCOPEAUTO
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// Automatic Scope Tracking
// NOTEs:
// - This is 'struct', so there are NO HEAP operations and associated perf. penalty;
// - Though use it for significant methods, so relative overhead will be inconsiderable;
// - Use 'short' syntax of 'using' expression (no local variable needed):
// void Foo() {
// using(new Bid.ScopeAuto("<MyClass.Foo>")) {
// // method's body...
// }
// }
//
internal struct ScopeAuto : IDisposable
{
internal ScopeAuto (string strScopeName) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out _hscp, strScopeName);
} else {
_hscp = NoData;
}
}
[BidMethod]
internal ScopeAuto (string fmtPrintfW, string arg) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out _hscp, fmtPrintfW, arg);
} else {
_hscp = NoData;
}
}
[BidMethod]
internal ScopeAuto (string fmtPrintfW, IntPtr arg) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out _hscp, fmtPrintfW, arg);
} else {
_hscp = NoData;
}
}
[BidMethod]
internal ScopeAuto (string fmtPrintfW, int arg) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out _hscp, fmtPrintfW, arg);
} else {
_hscp = NoData;
}
}
[BidMethod]
internal ScopeAuto (string fmtPrintfW, int a1, int a2) {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {
NativeMethods.ScopeEnter(modID, UIntPtr.Zero, UIntPtr.Zero, out _hscp, fmtPrintfW, a1, a2);
} else {
_hscp = NoData;
}
}
public void Dispose() {
if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData && _hscp != NoData) {
NativeMethods.ScopeLeave(modID, UIntPtr.Zero, UIntPtr.Zero, ref _hscp);
}
// NOTE: In contrast with standalone ScopeLeave,
// there is no need to assign "NoData" to _hscp.
}
private IntPtr _hscp;
} // ScopeAuto
#endif
#if BID_USE_CONTROL
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// Output Control
//
internal static bool Enabled(string traceControlString) {
return ((modFlags & ApiGroup.Trace) == 0 || modID == NoData)
? false
: NativeMethods.Enabled(modID, UIntPtr.Zero, UIntPtr.Zero, traceControlString);
}
#endif
#if BID_USE_IDENT
//
// Indentation
//
internal struct Indent : IDisposable
{
internal Indent(int oneLevel){
DASSERT(oneLevel == 1); // We need fake argument (struct can't have ctor with no args)
In();
}
public void Dispose(){
Out();
}
internal static void In(){
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.Indent(modID, indentIn);
}
internal static void Out(){
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)
NativeMethods.Indent(modID, indentOut);
}
}
private const int indentIn = -1,
indentOut = -3;
#endif
//=//////////////////////////////////////////////////////////////////////////////////////////
//
// Binary output
//
// FXCopBid does not support validation of buffer versus length at this stage, disable testing
// of this method by this rule
[BidMethod(Enabled = false)]
internal static void TraceBin(string constStrHeader, byte[] buff, UInt16 length) {
if (modID != NoData) {
if (constStrHeader != null && constStrHeader.Length > 0) {
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)ModeFlags.SmartNewLine, constStrHeader);
}
if( (UInt16)buff.Length < length ){
length = (UInt16)buff.Length;
}
NativeMethods.TraceBin( modID, UIntPtr.Zero, (UIntPtr)Bid.ModeFlags.Blob,
"<Trace|BLOB> %p %u\n", buff, length );
}
}
// FXCopBid does not support validation of buffer versus length at this stage, disable testing
// of this method by this rule
[BidMethod(Enabled = false)] // do not validate calls to this method in FXCopBid
internal static void TraceBinEx(byte[] buff, UInt16 length) {
if (modID != NoData) {
if( (UInt16)buff.Length < length ){
length = (UInt16)buff.Length;
}
NativeMethods.TraceBin( modID, UIntPtr.Zero, (UIntPtr)Bid.ModeFlags.Blob,
"<Trace|BLOB> %p %u\n", buff, length );
}
}
#if BID_USE_EXTENSIONS
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// STRUCTURED EXTENSION
//
internal delegate void ExtDelegate(IntPtr modID, IntPtr objRef, int attr, IntPtr data);
internal static ExtDelegate AddExtension(string extName, ExtDelegate extProc) {
AddExtension(extName, extProc, IntPtr.Zero);
return extProc;
}
internal static ExtDelegate AddExtension(string extName, ExtDelegate extProc, IntPtr extData) {
if( modID != NoData ){
NativeMethods.AddExtension( modID, DefaultCmdSpace, CtlCmd.AddExtension,
extData, extName, extProc );
}
return extProc;
}
internal struct Details
{
internal const int
Min = 1,
Std = 2,
Max = 7,
LevelMask = 0x07,
ModeDisco = 0x08,
ModeBinary = 0x10;
}
internal static int LevelOfDetailsEx(int attr) {
return (attr & Details.LevelMask);
}
internal static bool InBinaryModeEx(int attr) {
return ((attr & Details.ModeBinary) != 0);
}
internal static bool InDiscoveryModeEx(int attr) {
return ((attr & Details.ModeDisco) != 0);
}
//
// WriteEx to be used in BidExtensions
// (More overloads to be provided in assembly-specific file)
//
#if BID_AUTOSIG
internal static void WriteEx(IntPtr hCtx, uint flags, string fmtPrintfW, params object[] args) {
SignatureGenerator.WriteEx (hCtx, flags, fmtPrintfW, args);
}
#endif
internal static void WriteEx(IntPtr hCtx, uint flags, string strConst) {
NativeMethods.Trace(hCtx, UIntPtr.Zero, (UIntPtr)flags, strConst);
}
internal static void WriteEx(IntPtr hCtx, uint flags, string fmtPrintfW, string a1) {
NativeMethods.Trace(hCtx, UIntPtr.Zero, (UIntPtr)flags, fmtPrintfW, a1);
}
internal static void WriteBinEx(IntPtr hCtx, byte[] buff, UInt16 length) {
if (hCtx != NoData) {
if( (UInt16)buff.Length < length ) {
length = (UInt16)buff.Length;
}
NativeMethods.TraceBin( hCtx, UIntPtr.Zero, (UIntPtr)Bid.ModeFlags.Blob,
"<Trace|BLOB> %p %u\n", buff, length );
}
}
//
// Indentation to be used in BidExtensions
//
internal struct WriteIndentEx
{
private WriteIndentEx(int noData){ } // no instances, only static methods
internal static void In(IntPtr hCtx){
NativeMethods.Indent(hCtx, indentIn);
}
internal static void Out(IntPtr hCtx){
NativeMethods.Indent(hCtx, indentOut);
}
}
//
// Small helpers wrap all the work with GCHandle that we have to do in order to avoid
// object marshalling in P/Invoke.
//
// NOTE: Make sure that MakeRef/DelRef are perfectly balanced in order to not leak
// GCHandles. DelRef must be called in 'Dispose|Finalize' or 'finally' block.
//
internal static IntPtr MakeRef(object obj) {
return (IntPtr)GCHandle.Alloc(obj, GCHandleType.Normal);
}
internal static object GetObj(IntPtr objRef) {
return ((GCHandle)objRef).Target;
}
internal static void DelRef(IntPtr objRef) {
((GCHandle)objRef).Free();
}
#endif // BID_USE_EXTENSIONS
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// SERVICES
//
//
// MODULE-WIDE APIGROUP BITS
//
#if BID_USE_ALL_APIGROUP
internal static ApiGroup GetApiGroupBits (ApiGroup mask) {
return modFlags & mask;
}
#endif
internal static ApiGroup SetApiGroupBits (ApiGroup mask, ApiGroup bits) {
lock (_setBitsLock) {
ApiGroup tmp = modFlags;
if( mask != ApiGroup.Off ){
modFlags ^= (bits ^ tmp) & mask;
}
return tmp;
}
}
private static object _setBitsLock = new object();
#if BID_USE_INSTANCE_TRACKING
//
// FAST COMMUNICATION WITH THE SUBSYSTEM
//
private
struct TouchCode
{
internal const uint
Reverse = 1,
Unicode = 2,
Extension = 0 * 4,
ObtainItemID = 1 * 4 + Unicode,
RecycleItemID = 1 * 4 + Reverse + Unicode,
UpdateItemID = 2 * 4 + Unicode
;
}
//
// INSTANCE TRACKING IDs
//
internal static void ObtainItemID(out int itemID, string textID, IntPtr invariant){
itemID = (modID != NoData)
? NativeMethods.Touch01(modID, textID, TouchCode.ObtainItemID, invariant, IntPtr.Zero)
: 0;
}
internal static void ObtainItemID(out int itemID, string textID, uint invariant){
itemID = (modID != NoData)
? NativeMethods.Touch01(modID, textID, TouchCode.ObtainItemID, (IntPtr)invariant, IntPtr.Zero)
: 0;
}
internal static void ObtainItemID(out int itemID, string textID, int invariant){
itemID = (modID != NoData)
? NativeMethods.Touch01(modID, textID, TouchCode.ObtainItemID, (IntPtr)invariant, IntPtr.Zero)
: 0;
}
internal static void RecycleItemID(ref int itemID, string textID){
if (modID != NoData && itemID != 0) {
NativeMethods.Touch01(modID, textID, TouchCode.RecycleItemID, (IntPtr)itemID, IntPtr.Zero);
itemID = 0;
}
}
internal static void UpdateItemID(ref int itemID, string textID, string associate){
if (modID != NoData)
NativeMethods.Touch02(modID, textID, TouchCode.UpdateItemID, ref itemID, associate);
}
internal static void UpdateItemID(ref int itemID, string textID, IntPtr associate){
if (modID != NoData)
NativeMethods.Touch03(modID, textID, TouchCode.UpdateItemID, ref itemID, associate);
}
internal static void UpdateItemID(ref int itemID, string textID, int associate){
if (modID != NoData)
NativeMethods.Touch03(modID, textID, TouchCode.UpdateItemID, ref itemID, (IntPtr)associate);
}
internal static void UpdateItemID(ref int itemID, string textID, uint associate){
if (modID != NoData)
NativeMethods.Touch03(modID, textID, TouchCode.UpdateItemID, ref itemID, (IntPtr)associate);
}
#endif
//
// BID-specific Text Metadata
//
internal static bool AddMetaText(string metaStr) {
if( modID != NoData ){
NativeMethods.AddMetaText(modID, DefaultCmdSpace, CtlCmd.AddMetaText, IntPtr.Zero, metaStr, IntPtr.Zero);
}
return true;
}
#if BID_USE_CONTROL
//
// Explicit shutdown of the diagnostic backend.
// Note that it's up to BID implementation how to handle this command; it can be just ignored.
//
internal static void Shutdown(int arg) {
if( modID != NoData ){
NativeMethods.DllBidCtlProc( modID, DefaultCmdSpace, CtlCmd.Shutdown,
(IntPtr)arg, IntPtr.Zero, IntPtr.Zero );
}
}
#endif
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// DEBUG-ONLY SERVICES
//
[System.Diagnostics.Conditional("DEBUG")]
internal static void DTRACE(string strConst) {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData) {
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)ModeFlags.SmartNewLine, strConst);
}
}
[System.Diagnostics.Conditional("DEBUG")]
internal static void DTRACE(string clrFormatString, params object[] args) {
if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData) {
NativeMethods.PutStr(modID, UIntPtr.Zero, (UIntPtr)ModeFlags.SmartNewLine,
String.Format(CultureInfo.CurrentCulture, clrFormatString, args));
}
}
[System.Diagnostics.Conditional("DEBUG")]
internal static void DASSERT(bool condition) {
if (!condition) {
#if false
if (0 == nativeAssert(sourceFileLineNumber)) {
if (!Debugger.IsAttached) {
Debugger.Launch();
}
Debugger.Break();
}
#else
System.Diagnostics.Trace.Assert(false);
#endif
}
}
//+//////////////////////////////////////////////////////////////////////////////////////////
// //
// IMPLEMENTATION DETAILS //
// //
//+//////////////////////////////////////////////////////////////////////////////////////////
//
// modID and modFlags must be unique for each loadable entity (.exe, .dll, .netmodule)
// modID should be unique within the process (generated by DllBidEntryPoint), however modID may be recycled and reused
//
private
static IntPtr modID = internalInitialize();
private
static ApiGroup modFlags;
private static string modIdentity;
private delegate ApiGroup CtrlCB( ApiGroup mask, ApiGroup bits );
private static CtrlCB ctrlCallback;
//
// Binding Cookie
//
[StructLayout(LayoutKind.Sequential)]
private class BindingCookie
{
internal IntPtr _data;
internal BindingCookie() { _data = (IntPtr)(-1); }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal void Invalidate() { _data = (IntPtr)(-1); }
};
private static BindingCookie cookieObject;
private static GCHandle hCookie;
private static void deterministicStaticInit()
{
__noData = (IntPtr)(-1);
__defaultCmdSpace = (IntPtr)(-1);
modFlags = ApiGroup.Off;
modIdentity = string.Empty;
ctrlCallback = new CtrlCB(SetApiGroupBits);
cookieObject = new BindingCookie();
hCookie = GCHandle.Alloc(cookieObject, GCHandleType.Pinned);
}
//
// CONTROL CENTRE
//
private static IntPtr __defaultCmdSpace;
internal static IntPtr DefaultCmdSpace {
get { return __defaultCmdSpace; }
}
private
enum CtlCmd : uint
{
//
// Standard modifiers for command codes.
//
Reverse = 1,
Unicode = 2,
//
// Predefined commands are in range [CtlCmd.DcsBase .. CtlCmd.DcsMax]
// 'Dcs' stands for 'Default Command Space'
//
DcsBase = 268435456 * 4, // 0x10000000 * 4
DcsMax = 402653183 * 4, // 0x17FFFFFF * 4
//
// Control Panel commands are in range [CtlCmd.CplBase .. CtlCmd.CplMax]
//
CplBase = 402653184 * 4, // 0x18000000 * 4
CplMax = 536870911 * 4, // 0x1FFFFFFF * 4
//
// Predefined commands (have wrapper functions)
//
CmdSpaceCount = 0 * 4 + DcsBase,
CmdSpaceEnum = 1 * 4 + DcsBase,
CmdSpaceQuery = 2 * 4 + DcsBase,
GetEventID = 5 * 4 + DcsBase + Unicode,
ParseString = 6 * 4 + DcsBase + Unicode,
AddExtension = 7 * 4 + DcsBase + Unicode,
AddMetaText = 8 * 4 + DcsBase + Unicode,
AddResHandle = 9 * 4 + DcsBase + Unicode,
Shutdown = 10 * 4 + DcsBase + Unicode,
LastItem
} // CtlCmd
#if BID_USE_CONTROL
internal static IntPtr GetCmdSpaceID (string textID) {
return (modID != NoData)
? NativeMethods.GetCmdSpaceID(modID, DefaultCmdSpace, CtlCmd.CmdSpaceQuery, 0, textID, IntPtr.Zero)
: IntPtr.Zero;
}
#endif
//-//////////////////////////////////////////////////////////////////////////////////////////
//
// EntryPoint
//
private const int BidVer = 9210;
[StructLayout(LayoutKind.Sequential)]
private struct BIDEXTINFO
{
IntPtr hModule;
[MarshalAs(UnmanagedType.LPWStr)]
string DomainName;
int Reserved2;
int Reserved;
[MarshalAs(UnmanagedType.LPWStr)]
string ModulePath;
IntPtr ModulePathA;
IntPtr pBindCookie;
internal BIDEXTINFO(IntPtr hMod, string modPath, string friendlyName, IntPtr cookiePtr)
{
hModule = hMod;
DomainName = friendlyName;
Reserved2 = 0;
Reserved = 0;
ModulePath = modPath;
ModulePathA = IntPtr.Zero;
pBindCookie = cookiePtr;
}
}; // BIDEXTINFO
private static string getIdentity(Module mod)
{
string idStr;
object[] attrColl = mod.GetCustomAttributes(typeof(BidIdentityAttribute), true);
if( attrColl.Length == 0 ){
idStr = mod.Name;
} else {
idStr = ((BidIdentityAttribute)attrColl[0]).IdentityString;
}
//Debug.Assert( attrColl.Length == 1 );
return idStr;
}
private static string getAppDomainFriendlyName()
{
string name = AppDomain.CurrentDomain.FriendlyName;
if( name == null || name.Length <= 0 ) {
name = "AppDomain.H" + AppDomain.CurrentDomain.GetHashCode();
}
return VersioningHelper.MakeVersionSafeName(name, ResourceScope.Machine, ResourceScope.AppDomain);
}
private const uint configFlags = 0xD0000000; // ACTIVE_BID|CTLCALLBACK|MASK_PAGE
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] // Module.FullyQualifiedName
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
private static string getModulePath(Module mod) {
return mod.FullyQualifiedName;
}
[ResourceExposure(ResourceScope.None)] // info contained within call to DllBidEntryPoint
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] // getModulePath
private static void initEntryPoint()
{
NativeMethods.DllBidInitialize();
//
// Multi-file assemblies are not supported by current model of the BID managed wrapper.
// The below Marshal.GetHINSTANCE(mod) will return HINSTANCE for the manifest module
// instead of actual module, which is Ok because it is the only module
// in the single-file assembly.
//
Module mod = Assembly.GetExecutingAssembly().ManifestModule;
modIdentity = getIdentity(mod);
modID = NoData;
string friendlyName = getAppDomainFriendlyName();
BIDEXTINFO extInfo = new BIDEXTINFO(Marshal.GetHINSTANCE(mod),
getModulePath(mod),
friendlyName,
hCookie.AddrOfPinnedObject());
NativeMethods.DllBidEntryPoint( ref modID, BidVer, modIdentity,
configFlags, ref modFlags, ctrlCallback,
ref extInfo, IntPtr.Zero, IntPtr.Zero );
if( modID != NoData )
{
object[] attrColl = mod.GetCustomAttributes(typeof(BidMetaTextAttribute), true);
foreach (object obj in attrColl) {
AddMetaText( ((BidMetaTextAttribute)obj).MetaText );
}
Bid.Trace("<ds.Bid|Info> VersionSafeName='%ls'\n", friendlyName);
}
} // initEntryPoint
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static void doneEntryPoint()
{
if (modID == NoData) {
modFlags = ApiGroup.Off;
return;
}
try {
NativeMethods.DllBidEntryPoint( ref modID, 0, IntPtr.Zero,
configFlags, ref modFlags,
IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero );
NativeMethods.DllBidFinalize();
}
catch {
//
// We do intentionally catch everything because no matter what happens
// we don't want any exception to escape when we're in context of a finalizer.
// Note that critical exceptions such as ThreadAbortException could be
// propagated anyway (CLR 2.0 and above).
//
modFlags = ApiGroup.Off; // This is 'NoOp', just to not have empty catch block.
}
finally {
cookieObject.Invalidate();
modID = NoData;
modFlags = ApiGroup.Off;
}
} // doneEntryPoint
//
// Automatic Initialization/Finalization.
//
private sealed class AutoInit : SafeHandle
{
internal AutoInit() : base(IntPtr.Zero, true) {
initEntryPoint();
_bInitialized = true;
}
override protected bool ReleaseHandle() {
_bInitialized = false;
doneEntryPoint();
return true;
}
public override bool IsInvalid {
get { return !_bInitialized; }
}
private bool _bInitialized;
}
private static AutoInit ai;
private static IntPtr internalInitialize()
{
deterministicStaticInit();
ai = new AutoInit();
return modID;
}
//=//////////////////////////////////////////////////////////////////////////////////////////
//
// Interop calls to pluggable hooks
//
[SuppressUnmanagedCodeSecurity, ComVisible(false)]
private static partial class NativeMethods
{
//
// Plain text
//
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall,
EntryPoint="DllBidPutStrW")] extern
internal static void PutStr(IntPtr hID, UIntPtr src, UIntPtr info, string str);
//
// Trace
//
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl,
EntryPoint="DllBidTraceCW")] extern
internal static void Trace(IntPtr hID, UIntPtr src, UIntPtr info, string strConst);
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl,
EntryPoint="DllBidTraceCW")] extern
internal static void Trace(IntPtr hID, UIntPtr src, UIntPtr info, string fmtPrintfW, string a1);
//
// Scope
//
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, EntryPoint="DllBidScopeLeave")] extern
internal static void ScopeLeave(IntPtr hID, UIntPtr src, UIntPtr info, ref IntPtr hScp);
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl,
EntryPoint="DllBidScopeEnterCW")] extern
internal static void ScopeEnter(IntPtr hID, UIntPtr src, UIntPtr info, out IntPtr hScp, string strConst);
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl,
EntryPoint="DllBidScopeEnterCW")] extern
internal static void ScopeEnter( IntPtr hID, UIntPtr src, UIntPtr info, out IntPtr hScp,
string fmtPrintfW, int a1);
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl,
EntryPoint="DllBidScopeEnterCW")] extern
internal static void ScopeEnter( IntPtr hID, UIntPtr src, UIntPtr info, out IntPtr hScp,
string fmtPrintfW, int a1, int a2);
//
// Output control
//
#if BID_USE_CONTROL
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidEnabledW")] extern
internal static bool Enabled(IntPtr hID, UIntPtr src, UIntPtr info, string tcs);
#endif
#if BID_USE_IDENT
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidIndent")] extern
internal static int Indent(IntPtr hID, int nIdx);
#endif
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl,
EntryPoint="DllBidTraceCW")] extern
internal static void TraceBin(IntPtr hID, UIntPtr src, UIntPtr info, string fmtPrintfW, byte[] buff, UInt32 len);
#if BID_USE_INSTANCE_TRACKING
//
// Fast Communication API
//
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidTouch")] extern
internal static int Touch01(IntPtr hID, string textID, uint code, IntPtr arg1, IntPtr arg2);
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidTouch")] extern
internal static void Touch02(IntPtr hID, string textID, uint code, ref int itemID, string associate);
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidTouch")] extern
internal static void Touch03(IntPtr hID, string textID, uint code, ref int itemID, IntPtr associate);
#endif
//
// Services
//
#if BID_USE_CONTROL
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidCtlProc")] extern
internal static void DllBidCtlProc( IntPtr hID, IntPtr cmdSpace, CtlCmd cmd,
IntPtr arg1, IntPtr arg2, IntPtr arg3 );
#endif
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidCtlProc")] extern
internal static void AddMetaText( IntPtr hID, IntPtr cmdSpace, CtlCmd cmd, IntPtr nop1,
string txtID, IntPtr nop2);
#if BID_USE_EXTENSIONS
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Unicode, EntryPoint="DllBidCtlProc")] extern
internal static void AddExtension( IntPtr hID, IntPtr cmdSpaceID, CtlCmd cmd,
IntPtr data, string txtID, ExtDelegate proc);
#endif
#if BID_USE_CONTROL
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName, CharSet=CharSet.Ansi, BestFitMapping=false, EntryPoint="DllBidCtlProc")] extern
internal static IntPtr GetCmdSpaceID( IntPtr hID, IntPtr cmdSpace, CtlCmd cmd, uint noOp,
string txtID, IntPtr NoOp2 );
#endif
//
// Initialization / finalization
//
[ResourceExposure(ResourceScope.Machine)]
[DllImport(dllName, CharSet=CharSet.Ansi, BestFitMapping=false)] extern
internal static void DllBidEntryPoint(ref IntPtr hID, int bInitAndVer, string sIdentity,
uint propBits, ref ApiGroup pGblFlags, CtrlCB fAddr,
ref BIDEXTINFO pExtInfo, IntPtr pHooks, IntPtr pHdr);
[ResourceExposure(ResourceScope.Machine)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport(dllName)] extern
internal static void DllBidEntryPoint(ref IntPtr hID, int bInitAndVer, IntPtr unused1,
uint propBits, ref ApiGroup pGblFlags, IntPtr unused2,
IntPtr unused3, IntPtr unused4, IntPtr unused5);
[ResourceExposure(ResourceScope.None)]
[DllImport(dllName)] extern
internal static void DllBidInitialize();
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport(dllName)] extern
internal static void DllBidFinalize();
} // NativeMethods
} // Bid{PrivateBase}
//+//////////////////////////////////////////////////////////////////////////////////////////////
// //
// Attributes //
// //
//-//////////////////////////////////////////////////////////////////////////////////////////////
//
// [module: BidIdentity("ModuleIdentityString")]
//
[AttributeUsage(AttributeTargets.Module, AllowMultiple=false)]
internal sealed class BidIdentityAttribute : Attribute
{
internal BidIdentityAttribute( string idStr ){
_identity = idStr;
}
internal string IdentityString {
get { return _identity; }
}
string _identity;
}
//
// [module: BidMetaText("<Alias> ...")]
// [module: BidMetaText("<ApiGroup> ...")]
// ...etc...
//
[AttributeUsage(AttributeTargets.Module, AllowMultiple=true)]
internal sealed class BidMetaTextAttribute : Attribute
{
internal BidMetaTextAttribute( string str ){
_metaText = str;
}
internal string MetaText {
get { return _metaText; }
}
string _metaText;
}
/// <summary>
/// This attribute is used by FxCopBid rule to mark methods that accept format string and list of arguments that match it
/// FxCopBid rule uses this attribute to check if the method needs to be included in checks and to read type mappings
/// between the argument type to printf Type spec.
///
/// If you need to rename/remove the attribute or change its properties, make sure to update the FxCopBid rule!
/// </summary>
[System.Diagnostics.ConditionalAttribute("CODE_ANALYSIS")]
[System.AttributeUsage(AttributeTargets.Method)]
internal sealed class BidMethodAttribute : Attribute
{
private bool m_enabled;
/// <summary>
/// enabled by default
/// </summary>
internal BidMethodAttribute()
{
m_enabled = true;
}
/// <summary>
/// if Enabled is true, FxCopBid rule will validate all calls to this method and require that it will have string argument;
/// otherwise, this method is ignored.
/// </summary>
public bool Enabled {
get
{
return m_enabled;
}
set
{
m_enabled = value;
}
}
}
/// <summary>
/// This attribute is used by FxCopBid rule to tell FXCOP the 'real' type sent to the native trace call for this argument. For
/// example, if Bid.Trace accepts enumeration value, but marshals it as string to the native trace method, set this attribute
/// on the argument and set ArgumentType = typeof(string)
///
/// It can be applied on a parameter, to let FxCopBid rule know the format spec type used for the argument, or it can be applied on a method,
/// to insert additional format spec arguments at specific location.
///
/// If you need to rename/remove the attribute or change its properties, make sure to update the FxCopBid rule!
/// </summary>
[System.Diagnostics.ConditionalAttribute("CODE_ANALYSIS")]
[System.AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple=true)]
internal sealed class BidArgumentTypeAttribute : Attribute
{
// this overload can be used on the argument itself
internal BidArgumentTypeAttribute(Type bidArgumentType)
{
this.ArgumentType = bidArgumentType;
this.Index = -1; // if this c-tor is used on methods, default index value is 'last'
}
// this overload can be used on the method to add hidden spec arguments
// set index to -1 to add an argument to the end
internal BidArgumentTypeAttribute(Type bidArgumentType, int index)
{
this.ArgumentType = bidArgumentType;
this.Index = index;
}
public readonly Type ArgumentType;
// should be used only if attribute is applied on the method
public readonly int Index;
}
#if BID_AUTOSIG
//+//////////////////////////////////////////////////////////////////////////////////////////////
// //
// SignatureGenerator //
// //
//-//////////////////////////////////////////////////////////////////////////////////////////////
//
// NOTE:
// SignatureGenerator is NOT part of product code. It can be only used in development
// cycle in order to help generate strongly typed overloads for Bid.Trace and Bid.ScopeEnter
//
internal sealed class SignatureGenerator
{
private sealed class FmtString
{
const string surrogateOutputMarker = "*****";
string _str;
bool _newLine;
internal FmtString(string fmt)
{
int len = fmt.Length;
if( len <= 0 ){
_newLine = false;
_str = string.Empty;
} else {
_newLine = (fmt[len-1] == '\n');
_str = surrogateOutputMarker + (_newLine ? fmt.Substring(0, len-1) : fmt);
}
}
internal bool WantsNewLine {
get { return _newLine; }
}
internal string Body {
get { return _str; }
}
} // FmtString
[Serializable]
private sealed class UniqueSignatures
{
const string invalidTypeSuffix = ".Edit_TypeName_Here";
StringCollection _sigPool;
ArrayList _numArgsPool;
StringBuilder _buf;
int _problemCount;
internal UniqueSignatures()
{
_sigPool = new StringCollection();
_numArgsPool = new ArrayList();
_buf = new StringBuilder(256);
_problemCount = 0;
}
internal int Consider(params object[] args)
{
string signature = argList2Sig(args);
int idx1 = _sigPool.IndexOf(signature);
if( idx1 < 0 ){
idx1 = _sigPool.Add(signature);
_numArgsPool.Add(args.Length);
}
Bid.DASSERT( NumOfArgs(idx1) == args.Length );
return idx1;
}
internal int Count {
get {
int cnt = _sigPool.Count;
Bid.DASSERT( cnt == _numArgsPool.Count );
return cnt;
}
}
internal string Signature(int idx) {
return _sigPool [idx];
}
internal int NumOfArgs(int idx) {
return (int)_numArgsPool [idx];
}
string argList2Sig(params object[] args)
{
Type argType;
int idx = 0;
_buf.Length = 0; // cleanup StringBuilder
foreach (object arg in args)
{
_buf.Append(", ");
if( arg != null )
{
argType = arg.GetType();
_buf.Append(argType.FullName);
if( !argType.IsPrimitive && argType != typeof(string) )
{
_buf.Append(invalidTypeSuffix);
_problemCount++;
}
}
else
{
_buf.Append("System" + invalidTypeSuffix);
_problemCount++;
}
_buf.Append(" a");
_buf.Append(++idx);
}
return _buf.ToString();
}
internal void writeSignatures(TextWriter stm, string[] pattern)
{
for (int i = 0; i < this.Count; i++) {
makeSignature(pattern, this.Signature(i), this.NumOfArgs(i), ref _buf);
stm.WriteLine(_buf);
}
_buf.Length = 0;
}
private static void makeSignature(string[] pattern, string argList, int numOfArgs,
ref StringBuilder buf)
{
buf.Length = 0;
foreach (string patternChunk in pattern)
{
switch (patternChunk)
{
case "ARGS":
buf.Append(argList);
break;
case "ARGUSE":
buf.Append(argListUse(numOfArgs));
break;
case "ARGNUM":
buf.Append(numOfArgs.ToString());
break;
default:
buf.Append(patternChunk);
break;
}
}
}
internal void PrepareForIntermediateStore()
{
_buf.Length = 0;
}
} // UniqueSignatures
//=//////////////////////////////////////////////////////////////////////////////////////////
//
// SignatureGenerator methods ...
//
private static string argListUse(int numOfArgs)
{
StringBuilder buf = new StringBuilder();
for (int idx = 1; idx <= numOfArgs; idx++) {
buf.Append(",a");
buf.Append(idx);
}
return buf.ToString();
}
private static string dumpArgList(params object[] args)
{
StringBuilder buf = new StringBuilder();
foreach( object obj in args ){
buf.Append(" ");
if( obj != null ){
buf.Append(obj.ToString());
} else {
buf.Append("(null)");
}
}
return " [" + buf.ToString().Substring(1) + "]";
}
static void writeHeader(TextWriter stm, string modName)
{
int idx = modName.LastIndexOfAny(new char[]{'\\', '/'});
if (idx > 0) {
modName = modName.Substring(idx+1);
}
string[] pattern = Templates.Headers.File.Split('^');
foreach (string patternChunk in pattern) {
switch (patternChunk) {
case "MODNAME":
stm.Write(modName);
break;
default:
stm.Write(patternChunk);
break;
}
}
}
//=//////////////////////////////////////////////////////////////////////////////////////////
private static void fakeOutput(uint flags, string fmt, params object[] args)
{
FmtString fmtStr = new FmtString(fmt);
string buf = fmtStr.Body + dumpArgList(args);
if( fmtStr.WantsNewLine || (flags & (Bid.ModeFlags.NewLine|Bid.ModeFlags.SmartNewLine)) != 0 ){
buf += Environment.NewLine;
}
Bid.PutStr(buf);
}
internal static void Trace(string fmtPrintfW, params object[] args)
{
fakeOutput(0, fmtPrintfW, args);
Buckets.Trace.Consider(args);
Buckets.Native.Trace.Consider(args);
}
internal static void TraceEx(uint flags, string fmtPrintfW, params object[] args)
{
fakeOutput(flags, fmtPrintfW, args);
Buckets.TraceEx.Consider(args);
Buckets.Native.Trace.Consider(args);
}
internal static void ScopeEnter(out IntPtr hScp, string fmt, params object[] args)
{
FmtString fmtStr = new FmtString(fmt);
string buf = fmtStr.Body + dumpArgList(args);
buf += Environment.NewLine;
Bid.ScopeEnter(out hScp, "%s", buf);
Buckets.ScopeEnter.Consider(args);
Buckets.Native.ScopeEnter.Consider(args);
}
#if BID_USE_EXTENSIONS
internal static void WriteEx(IntPtr hCtx, uint flags, string fmtPrintfW, params object[] args)
{
//
// WARNING:
// PutStr inside fakeOutput uses standard modID but should use hCtx in context of WriteEx.
// Shouldn't be a problem in case of generating signatures, because the default
// text-streaming BID implementation makes no difference between modID and hCtx.
// In fact, SignatureGenerator doesn't need pluggable implementation at all.
//
fakeOutput(flags, fmtPrintfW, args);
Buckets.WriteEx.Consider(args);
Buckets.Native.Trace.Consider(args);
}
#endif
//
// Automatic Initialization / Finalization
//
private static Buckets buckets = null;
static SignatureGenerator() {
buckets = new Buckets();
}
//=//////////////////////////////////////////////////////////////////////////////////////////
private sealed class Buckets
{
internal static UniqueSignatures Trace;
internal static UniqueSignatures TraceEx;
internal static UniqueSignatures ScopeEnter;
internal static UniqueSignatures WriteEx;
internal struct Native {
internal static UniqueSignatures Trace;
internal static UniqueSignatures ScopeEnter;
}
private Stream _tempStore;
private BinaryFormatter _formatter;
private string _moduleName;
internal Buckets()
{
_tempStore = null;
_moduleName = getModuleName();
initSignatures();
}
~Buckets()
{
writeFiles();
}
private void writeFiles()
{
saveSignatures();
TextWriter stm = null;
try {
stm = new StreamWriter(SignatureFileName);
writeSignatureFile(stm, SignatureFileName);
}
finally {
if( stm != null ){
stm.Close();
stm = null;
}
}
}
private string TempStoreFileName
{
get { return _moduleName + "_tempstore.tmp"; }
}
private string SignatureFileName
{
get { return _moduleName + "_BID.cs"; }
}
private string getModuleName()
{
string modName; // AppDomain.CurrentDomain.BaseDirectory;
modName = Assembly.GetExecutingAssembly().ManifestModule.Name;
int len = modName.LastIndexOf('.');
Bid.DASSERT( len > 0 );
if( len > 0 ){
modName = modName.Substring(0, len);
}
return modName;
}
Stream tryOpenTempStore(bool bWrite)
{
Stream store = null;
try {
store = bWrite ? File.OpenWrite( TempStoreFileName )
: File.OpenRead( TempStoreFileName );
}
catch(FileNotFoundException){
store = null;
}
return store;
}
private void initSignatures()
{
_tempStore = tryOpenTempStore(false);
try {
Trace = newUniqueSignatures();
TraceEx = newUniqueSignatures();
ScopeEnter = newUniqueSignatures();
WriteEx = newUniqueSignatures();
Native.Trace = newUniqueSignatures();
Native.ScopeEnter = newUniqueSignatures();
}
finally {
if( _tempStore != null ){
_tempStore.Close();
_tempStore = null;
}
}
}
private void saveSignatures()
{
_tempStore = tryOpenTempStore(true);
if( _tempStore != null ){
try {
storeIntermediate(Trace);
storeIntermediate(TraceEx);
storeIntermediate(ScopeEnter);
storeIntermediate(WriteEx);
storeIntermediate(Native.Trace);
storeIntermediate(Native.ScopeEnter);
}
finally {
_tempStore.Close();
_tempStore = null;
}
}
}
private UniqueSignatures newUniqueSignatures()
{
if( _tempStore == null || _tempStore.Length == 0 ){
return new UniqueSignatures();
}
if( _formatter == null ){
_formatter = new BinaryFormatter();
}
return (UniqueSignatures)_formatter.Deserialize(_tempStore);
}
private void storeIntermediate(UniqueSignatures usig)
{
if( _formatter == null ){
_formatter = new BinaryFormatter();
}
usig.PrepareForIntermediateStore();
_formatter.Serialize(_tempStore, usig);
}
private void writeSignatureFile(TextWriter stm, string moduleName)
{
writeHeader(stm, moduleName);
if( Trace.Count > 0 ) stm.Write(Templates.Headers.Trace);
Trace.writeSignatures(stm, Patterns.Trace);
if( TraceEx.Count > 0 ) stm.Write(Templates.Headers.TraceEx);
TraceEx.writeSignatures(stm, Patterns.TraceEx);
if( ScopeEnter.Count > 0 ) stm.Write(Templates.Headers.ScopeEnter);
ScopeEnter.writeSignatures(stm, Patterns.ScopeEnter);
if( WriteEx.Count > 0 ) stm.Write(Templates.Headers.WriteEx);
WriteEx.writeSignatures(stm, Patterns.WriteEx);
stm.Write(Templates.Headers.Native);
Native.Trace.writeSignatures(stm, Patterns.Native.Trace);
Native.ScopeEnter.writeSignatures(stm, Patterns.Native.ScopeEnter);
stm.WriteLine();
stm.WriteLine(" } // Native");
stm.WriteLine();
stm.WriteLine("} // Bid");
}
} // Buckets
//=//////////////////////////////////////////////////////////////////////////////////////////
struct Templates
{
internal struct Headers
{
internal const string File =
"//-----------------------------------------------------------------------------------\r\n" +
"// <copyright file=\"^MODNAME^\" company=\"Microsoft\">\r\n" +
"// Copyright (c) Microsoft Corporation. All rights reserved.\r\n" +
"// </copyright>\r\n" +
"//-----------------------------------------------------------------------------------\r\n" +
"\r\n" +
"using System;\r\n" +
"using System.Text;\r\n" +
"using System.Security;\r\n" +
"using System.Reflection;\r\n" +
"using System.Security.Permissions;\r\n" +
"using System.Runtime.InteropServices;\r\n" +
"\r\n" +
"internal static partial class Bid\r\n" +
"{\r\n" +
" //\r\n" +
" // Loader Stub DLL. Can be the assembly itself (mixed mode).\r\n" +
" //\r\n" +
" private const string dllName = \"BidLdr.dll\";\r\n" +
"\r\n" +
"\r\n";
internal const string Native =
" //\r\n" +
" // Interop calls to pluggable hooks [SuppressUnmanagedCodeSecurity] applied\r\n" +
" //\r\n" +
" private static partial class NativeMethods\r\n" +
" {\r\n" +
"\r\n";
internal const string Trace =
" //\r\n" +
" // Trace overloads\r\n" +
" //\r\n";
internal const string TraceEx =
" //\r\n" +
" // TraceEx overloads\r\n" +
" //\r\n";
internal const string ScopeEnter =
" //\r\n" +
" // ScopeEnter overloads\r\n" +
" //\r\n";
internal const string WriteEx =
" //\r\n" +
" // WriteEx overloads\r\n" +
" //\r\n";
} // Headers
internal const string Trace =
" internal static void Trace(string fmtPrintfW^ARGS^) {\r\n" +
" if ((modFlags & ApiGroup.Trace) != 0 && modID != NoData)\r\n" +
" NativeMethods.Trace (modID, UIntPtr.Zero, UIntPtr.Zero, fmtPrintfW^ARGUSE^);\r\n" +
" }\r\n";
internal const string TraceEx =
" internal static void TraceEx(uint flags, string fmtPrintfW^ARGS^) {\r\n" +
" if (modID != NoData)\r\n" +
" NativeMethods.Trace (modID, UIntPtr.Zero, (UIntPtr)flags, fmtPrintfW^ARGUSE^);\r\n" +
" }\r\n";
internal const string ScopeEnter =
" internal static void ScopeEnter(out IntPtr hScp, string fmtPrintfW^ARGS^) {\r\n" +
" if ((modFlags & ApiGroup.Scope) != 0 && modID != NoData) {\r\n" +
" NativeMethods.ScopeEnter (modID, UIntPtr.Zero, UIntPtr.Zero, out hScp, fmtPrintfW^ARGUSE^);\r\n" +
" } else {\r\n" +
" hScp = NoData;\r\n" +
" }\r\n" +
" }\r\n";
internal const string WriteEx =
" internal static void WriteEx(IntPtr hCtx, uint flags, string fmtPrintfW^ARGS^) {\r\n" +
" NativeMethods.Trace (hCtx, UIntPtr.Zero, (UIntPtr)flags, fmtPrintfW^ARGUSE^);\r\n" +
" }\r\n";
internal struct Native
{
internal const string Trace =
" [DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl, EntryPoint=\"DllBidTraceCW\")] extern\r\n" +
" internal static void Trace (IntPtr hID, UIntPtr src, UIntPtr info, string fmtPrintfW^ARGS^);\r\n";
internal const string ScopeEnter =
" [DllImport(dllName, CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl, EntryPoint=\"DllBidScopeEnterCW\")] extern\r\n" +
" internal static void ScopeEnter (IntPtr hID, UIntPtr src, UIntPtr info, out IntPtr hScp, string fmtPrintfW^ARGS^);\r\n";
} // Native
} // Templates
private sealed class Patterns
{
internal static string[] Trace;
internal static string[] TraceEx;
internal static string[] ScopeEnter;
internal static string[] WriteEx;
internal struct Native {
internal static string[] Trace;
internal static string[] ScopeEnter;
}
static Patterns()
{
init(ref Trace, Templates.Trace);
init(ref TraceEx, Templates.TraceEx);
init(ref ScopeEnter, Templates.ScopeEnter);
init(ref WriteEx, Templates.WriteEx);
init(ref Native.Trace, Templates.Native.Trace);
init(ref Native.ScopeEnter, Templates.Native.ScopeEnter);
}
private static void init(ref string[] pattern, string templateString) {
pattern = templateString.Split('^');
}
} // Patterns
} // SignatureGenerator
#endif // BID_AUTOSIG
|