I was able to write the function below that clones an existing attachment. The code requires the plugin to be running in full-trust mode. I hope the FogCreek guys don't mind that I'm looking up their skirt a little bit.
CAttachment CloneAttachment(CAttachment attachment)
{
// find the type for the internal CAttachment class
// (this is different from FogCreek.FogBugz.Plugins.Entity.CAttachment)
var ass = Assembly.Load("FogBugz");
var tCAttachment = ass.GetType("FogCreek.FogBugz.CAttachment");
if (tCAttachment == null)
throw new Exception("Couldn't load 'FogCreek.FogBugz.CAttachment' type.");
// find the constructor and create an instance
var ctor = tCAttachment.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[] {},
null);
if (ctor == null)
throw new Exception("Couldn't find default CAttachment constructor.");
var entity = ctor.Invoke(null);
// create a new attachment record in the DB
var storeAttachmentMethod = tCAttachment.GetMethod("StoreAttachmentInDB", BindingFlags.Instance | BindingFlags.NonPublic);
if (storeAttachmentMethod == null)
throw new Exception("Couldn't find StoreAttachmentInDB method.");
var ixAttachment = (int)storeAttachmentMethod.Invoke(entity, new object[] {attachment.rgbData, attachment.sFileName});
if (ixAttachment == 0)
throw new Exception("Unable to clone attachment.");
return api.Attachment.GetAttachment(ixAttachment);
}