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);
// 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);
// 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!
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
// ...and write new count of locals (cOrigLocals+1)
if (iNewSig + 4 > sizeof(rgbNewSig))
// CorSigCompressData will write up to 4 bytes but no room!
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!
memcpy(&rgbNewSig[iNewSig], &rgbOrigSig[iOrigSig], cbOrigSig-iOrigSig);
iNewSig += cbOrigSig-iOrigSig;
// Manually append final local
ULONG cbLocalType;
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).
// CorSigCompressToken will write up to 4 bytes but no room!
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.
// 0-based index of new local = 0-based index of original last local + 1
// = count of original locals
return cOrigLocals;