Code Snippet: Ensuring a file is in a project
Every couple of weeks, I'll get a question about getting an arbitrary file on disk into a project in VS without asking VS to open in a document window directly. It seems to be pretty hard to find information for (when I needed to do it, it took a few email threads with various other teams to figure it out), so here's a code snippet I use for this. It works by adding the file to the miscellaneous files project (if it isn't already in another project) and then returning the hierarchy/itemid for the file, which can be used with other methods involving the shell, opening documents, locking documents, etc.
///
<summary>
///
If the given file isn't in a project, put it in the miscellaneous files project, and return
///
the project/itemid of the file.
///
</summary>
///
<returns>hresult (failure code)</returns>
static int
EnsureFileInAProject(string
fileName,
out
IVsUIHierarchy hierarchy, out uint itemId)
{
IVsUIShellOpenDocument shellOpenDocument = ServiceProvider.GlobalProvider.GetService(typeof(SVsUIShellOpenDocument))
as
IVsUIShellOpenDocument;
IOleServiceProvider unused;
int
pDocInAProject;
// Before we can take a lock, we need to make sure the given doc data is in a project.
// First, ask the shell if it already is
if
(ErrorHandler.Failed(shellOpenDocument.IsDocumentInAProject(fileName,
out
hierarchy,
out
itemId,
out
unused,
out
pDocInAProject)))
{
Debug.Fail("IsDocumentInAProject failed, which is unexpected.");
return
VSConstants.E_FAIL;
}
// We need to add it to the miscellaneous files project if it isn't in a project.
if
(pDocInAProject == (int)__VSDOCINPROJECT.DOCINPROJ_DocNotInProject)
{
var
externalFilesManager = Shell.Package.GetGlobalService(typeof(SVsExternalFilesManager))
as
IVsExternalFilesManager;
if
(externalFilesManager == null)
{
Debug.Fail("Can't find the miscellaneous files project to use.");
return
VSConstants.E_FAIL;
}
// Make sure the misc files project doesn't actually *open* the document
uint
createFlags = (uint)__VSCREATEDOCWIN.CDW_RDTFLAGS_MASK | (uint)_VSRDTFLAGS.RDT_PlaceHolderDoc;
Guid
emptyGuid = Guid.Empty;
int
unusedPos;
IVsWindowFrame unusedFrame;
if
(ErrorHandler.Failed(externalFilesManager.AddDocument(createFlags, fileName, IntPtr.Zero,
IntPtr.Zero,
ref
emptyGuid,
null, ref emptyGuid,
null, null, out unusedPos,
out
unusedFrame)))
{
Debug.Fail("Couldn't add the document to miscellaneous files project.");
return
VSConstants.E_FAIL;
}
IVsProject miscProject;
if
(ErrorHandler.Failed(externalFilesManager.GetExternalFilesProject(out
miscProject)) ||
(hierarchy = miscProject as IVsUIHierarchy) ==
null
||
ErrorHandler.Failed(hierarchy.ParseCanonicalName(fileName,
out
itemId)))
{
Debug.Fail("Couldn't get the misc files project or item we just added.");
return
VSConstants.E_FAIL;
}
}
return
VSConstants.S_OK;
}