How to duplicate a document on Visual Studio 2022?

Lilo 40 Reputation points
2025-07-10T06:53:23.4333333+00:00

I'm working on a Visual Studio 2022 C# extension, and I'm trying to "programmatically" duplicate an open document and move it into a different group.

By "duplicate" I mean like when you click on the option "Window > New Window" and it creates a "file.ext:2" copy of the original file.

For example, suppose I have two document groups opened side by side on the IDE:

First: file.cpp, main.cpp

Second: file.cpp:2 (this is a dupe/clone of file.cpp)

How I could programmatically make a "main.cpp:2" dupe/clone and also move it to the second "group"?

// ...
IVsWindowFrame secondGroupFrame; // A random IVsWindowFrame that is on the second group
// ...

DTE2 dte = (DTE2)Package.GetGlobalService(typeof(DTE));
try
{
    foreach (Document doc in dte.Documents)
    {
        if (doc.FullName != searchedDoc)
            continue;
			
		Window newWindow = doc.NewWindow();
		 
		// Find the newWindow frame
		IVsWindowFrame[] frame = new IVsWindowFrame[1];
		uint fetched;
		while (enumFrames.Next(1, frame, out fetched) == VSConstants.S_OK && fetched == 1)
		{
			frame[0].GetProperty((int)__VSFPROPID.VSFPROPID_ExtWindowObject, out object pvar);
			if (pvar is Window fframe && fframe == newWindow)
			{
				windowFrame = frame[0];
				break;
			}
		}


{
    foreach (Document doc in dte.Documents)
    {
        if (doc.FullName != searchedDoc)
            continue;
			
		 Window newWindow = doc.NewWindow();

I figured how to "duplicate" the document and also how to find the new document IVSWindowFrame and also the frame of a document in the "second group", but I'm not finding a way to move it to the second group.

Developer technologies | Visual Studio | Extensions
0 comments No comments
{count} votes

Accepted answer
  1. Mammon Z Baloch 80 Reputation points
    2025-07-10T15:40:36.7066667+00:00

    Visual Studio exposes exactly the same “Window → New Window” feature you use by hand through the VS SDK:

    step API what it does
    IVsUIShellOpenDocument.OpenCopyOfStandardEditor creates the “file:2” clone of an existing IVsWindowFrame (that is the programmatic equivalent of New Window)
    IVsUIShellOpenDocument.OpenCopyOfStandardEditor creates the “file:2” clone of an existing IVsWindowFrame (that is the programmatic equivalent of New Window)
    Window.Activate / DTE.ExecuteCommand("Window.MoveToNextTabGroup")(or …PreviousTabGroup, …MainDocumentGroup) moves the active document tab into any other document-group, exactly the way the built-in menu items Window → Move to Next Tab Group / Previous Tab Group do
    // async package suggested – avoids blocking the UI thread
    public async Task DuplicateIntoOtherGroupAsync(IVsWindowFrame sourceFrame)
    {
        // 1. clone the document (New Window)
        var openDoc = await AsyncServiceProvider.GlobalProvider
                           .GetServiceAsync(typeof(SVsUIShellOpenDocument))
                           as IVsUIShellOpenDocument;
    
        Guid logicalView = VSConstants.LOGVIEWID_Primary;      // normal text view
        IVsWindowFrame cloneFrame;
        ErrorHandler.ThrowOnFailure(
            openDoc.OpenCopyOfStandardEditor(sourceFrame, ref logicalView, out cloneFrame));
    
        // 2. show the new frame and obtain the EnvDTE.Window wrapper
        cloneFrame.Show();
        cloneFrame.GetProperty((int)__VSFPROPID.VSFPROPID_ExtWindowObject, out object winObj);
        var dteWin = (EnvDTE.Window)winObj;
    
        // 3. move it to the other document group
        dteWin.Activate();                                     // becomes the active tab
        var dte = (EnvDTE80.DTE2)Package.GetGlobalService(typeof(SDTE));
        dte.ExecuteCommand("Window.MoveToNextTabGroup");
    }
    
    

    Duplicate – OpenCopyOfStandardEditor gives you the brand-new IVsWindowFrame (main.cpp:2, etc.).

    Relocate – activating that frame and firing the built-in command moves it to the neighbour group; if you want the group on the left instead of the right, use Window.MoveToPreviousTabGroup, or send the command twice to hop across several groups.

    Because you are executing the same IDE commands the UI uses, you don’t have to worry about low-level frame layout APIs, persistence, or edge-cases—Visual Studio handles all of that for you.

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.