Add local to LocalVarSig

All source code is provided as is, with no warranties intended or implied. Use at your own risk.

// Parse
the local variables signature for the method we're rewriting, create a new

//
localvar signature containing one new local, and return the 0-based ordinal for

// that
new local.

UINT AddNewLocal()

{

   
// Get the metadata interfaces on the module
containing the method being rewritten.

    HRESULT hr =
m_pICorProfilerInfo->GetModuleMetaData(

            m_moduleId,
ofRead | ofWrite, IID_IMetaDataImport, (IUnknown**)&m_pMetaDataImport);

   
if (FAILED(hr))

    {

       
return 0;

    }

 

    hr =
m_pMetaDataImport->QueryInterface(IID_IMetaDataEmit, (void**)&m_pMetaDataEmit);

   
if (FAILED(hr))

    {

       
return 0;

    }

 

   
// Here's a buffer into which we will write out the
modified signature. This sample

   
// code just bails out if it hits signatures that are
too big. Just one of many reasons

   
// why you use this code AT YOUR OWN RISK!

    COR_SIGNATURE
rgbNewSig[4096];

 

   
// Use the signature token to look up the actual
signature

    PCCOR_SIGNATURE
rgbOrigSig = NULL;

    ULONG cbOrigSig;

    hr =
m_pMetaDataImport->GetSigFromToken(m_tkLocalVarSig, &rgbOrigSig, &cbOrigSig);

   
if (FAILED(hr))

    {

       
return 0;

    }

 

   
// These are our running indices in the original and
new signature, respectively

    UINT iOrigSig = 0;

    UINT iNewSig = 0;

 

   
// First byte of signature must identify that it's a
locals signature!

   
assert(rgbOrigSig[iOrigSig] == SIG_LOCAL_SIG);

 

    //
Copy SIG_LOCAL_SIG

   
if (iNewSig + 1 >
sizeof(rgbNewSig))

    {

       
// We'll write one byte below but no room!

       
return 0;

    }

    rgbNewSig[iNewSig++]
= rgbOrigSig[iOrigSig++];

 

   
// Get original count of locals...

    ULONG cOrigLocals;

    ULONG cbOrigLocals;

    ULONG cbNewLocals;

    hr =
CorSigUncompressData(&rgbOrigSig[iOrigSig],

4, //
[IN] length of the signature

&cOrigLocals, //
[OUT] the expanded data

&cbOrigLocals); //
[OUT] length of the expanded data   

   
if (FAILED(hr))

    {

       
return 0;

    }

 

   
// ...and write new count of locals (cOrigLocals+1)

   
if (iNewSig + 4 >
sizeof(rgbNewSig))

    {

       
// CorSigCompressData will write up to 4 bytes but no
room!

       
return 0;

    }

    cbNewLocals =
CorSigCompressData(cOrigLocals+1, // [IN]
given uncompressed data

&rgbNewSig[iNewSig]);
// [OUT] buffer where data will be compressed and
stored.  

    iOrigSig +=
cbOrigLocals;

    iNewSig +=
cbNewLocals;

 

   
// Copy the rest

   
if (iNewSig + cbOrigSig - iOrigSig >
sizeof(rgbNewSig))

    {

       
// We'll copy cbOrigSig - iOrigSig bytes, but no room!

       
return 0;

    }

    memcpy(&rgbNewSig[iNewSig],
&rgbOrigSig[iOrigSig], cbOrigSig-iOrigSig);

    iNewSig +=
cbOrigSig-iOrigSig;

 

   
// Manually append final local

 

    ULONG cbLocalType;

   
if (iNewSig + 1 >
sizeof(rgbNewSig))

    {

       
// We'll write one byte below but no room!

       
return 0;

    }

   
rgbNewSig[iNewSig++] = ELEMENT_TYPE_VALUETYPE;

 

   
// You'll need to replace 0x01000002 with the
appropriate token that describes

   
// the type of this local (which, in turn, is the type
of the return value

   
// you're copying into that local). This can be
either a TypeDef or TypeRef,

   
// and it must be encoded (compressed).

   
if (iNewSig + 4 >
sizeof(rgbNewSig))

    {

       
// CorSigCompressToken will write up to 4 bytes but no
room!

       
return 0;

    }

    cbLocalType =
CorSigCompressToken(0x01000002,

&rgbNewSig[iNewSig]);

 

    iNewSig +=
cbLocalType;

 

   
// We're done building up the new signature blob. We
now need to add it to

   
// the metadata for this module, so we can get a token
back for it.

    assert(iNewSig <=
sizeof(rgbNewSig));

    hr =
m_pMetaDataEmit->GetTokenFromSig(&rgbNewSig[0],
// [IN] Signature to define.    

iNewSig,
// [IN] Size of signature data.

&m_tkLocalVarSig);
// [OUT] returned signature token. 

   
if (FAILED(hr))

    {

       
return 0;

    }

 

   
// 0-based index of new local = 0-based index of
original last local + 1

   
// = count of original
locals

   
return cOrigLocals;

}