ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 비주얼 스튜디오 확장 vsix, 간단 활용 정리
    프로그래밍 2017. 12. 27. 11:28
    반응형

    회사 업무를 하다보면 패킷을 만들 일이 있는데 이 일은 전혀 재밌지 않다보니, 좀 더 편하고 재밌게 하고 싶었다.
    비주얼 스튜디오에 있는 확장 기능 같은 것이 떠올랐으며 해당 기능을 개발하기 위해선 뭐를 해야하는지 간단히 알아봤다.
    (vs2017 기준)

    새 프로젝트 -> Visual C# -> Extensibility -> VSIX Project
    로 VSIX 프로젝트를 만들 수 있다.
    난 프로젝트 이름을 vermouse로 지었다. 어감이 좋아서.


    위에서 만든 프로젝트에서
    새 항목 -> Visual C# 항목 -> Extensibility -> Custom Command
    이 중 눈여겨 볼 곳은 위에서 만든 Custom Command 파일과 .vsct 확장자 파일이다.


    Custom Command 파일에서 MenuItemCallback 을 찾는다.

    private void MenuItemCallback(object sender, EventArgs e)
    {
    string message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.GetType().FullName);
    string title = "Command";

    // Show a message box to prove we were here
    VsShellUtilities.ShowMessageBox(
    this.ServiceProvider,
    message,
    title,
    OLEMSGICON.OLEMSGICON_INFO,
    OLEMSGBUTTON.OLEMSGBUTTON_OK,
    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
    }

    이 MenuItemCallback에서 커맨드를 실행했을 때의 동작을 정의할 수 있다.


    나 같은 경우는 MenuItemCallback이 실행될 때 유저가 선택(드래그)한 텍스트를 바탕으로 패킷을 생성하는 것이 목적이었으므로,
    현재 유저가 선택한 텍스트, 프로젝트 경로, 등을 얻어올 필요가 있었다.다음은 해당 프로젝트에 사용한 몇 가지 vsix관련 코드들이다.


    /* 유저가 선택한 텍스트 가져오는 코드 */
    public string GetSelectedText()
    {
    EnvDTE80.DTE2 applicationObject = ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
    if (applicationObject == null)
    return null;

    EnvDTE.TextDocument textDocument = (EnvDTE.TextDocument)applicationObject.ActiveDocument.Object("");
    EnvDTE.TextSelection selectedText = textDocument.Selection;

    return selectedText.Text;
    }

    [유저가 선택한 텍스트 가져오기]

    /* 솔루션의 하위 프로젝트를 가져오는 코드 */
    EnvDTE80.DTE2 applicationObject = ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
    if (applicationObject == null)
    return null;

    EnvDTE.Projects projects = applicationObject.Solution.Projects; // 솔루션의 모든 하위 프로젝트들

    [솔루션 하위 프로젝트 가져오기]


    /* 프로젝트 하위 아이템 가져오기 */
    public EnvDTE.ProjectItem GetProjectItem(EnvDTE.Project project, string itemName)
    {
    foreach (EnvDTE.ProjectItem item in project.ProjectItems)
    {
    if(item.Name == itemName)
    {
    return item;
    }
    }
    return null;
    }

    [프로젝트 하위 아이템 가져오기]
    [프로젝트 하위 아이템 가져오기]에서 주의해야 할 건, 프로젝트 아래 필터 안에 넣어두었다면, 일단 필터까지만 가져와진다는 것이다.
    예를 들어 sources 필터 안에 있는 foo.h라는 소스 코드를 찾고자 한다. 그러면 sources 필터를 찾아 가져오고, 그 sources 필터의 ProjectItems에서 foo.h를 찾아야 한다는 것이다.


    /* 아이템의 경로 얻어오기 */
    EnvDTE.ProjectItem enumFileItem = GetProjectItem(project, "NPPacketDefine.h");
    string enumPath = enumFileItem.FileNames[0];

    [(프로젝트)아이템의 경로 얻어오기]
    유저마다 솔루션의 위치가 다를 수 있다. 때문에 유저 로컬에서의 경로를 알아야 새로운 파일들을 올바른 경로에 생성하게 할 수 있다.


    /* 프로젝트에 파일 추가하기 */
    EnvDTE.Project project = GetSolutionProject("NPublic");

    project.ProjectItems.AddFromFile("NewPacketFileHere.h");

    [프로젝트에 파일 추가하기]
    패킷 파일을 만들면 프로젝트에 포함시켜야 했다. 그래야 프로젝트에서 검색을 할 수 있으니까.


    EnvDTE80.DTE2 applicationObject = ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
    if (applicationObject == null)
    return null;

    EnvDTE.TextDocument textDocument = (EnvDTE.TextDocument)applicationObject.ActiveDocument.Object("");
    EnvDTE.TextSelection selectedText = textDocument.Selection;

    EnvDTE.TextPoint ep = textDocument.EndPoint; // 파일의 처음 부분 줄
    EnvDTE.TextPoint sp = textDocument.StartPoint; // 파일의 마지막 부분 줄
    int currentLine = textDocument.Selection.CurrentLine; // 현재 라인

    [현재 활성화 된 라인 가져오기]


    /* 현재 프로젝트에 아이템 삽입하기 */
    EnvDTE.Project project = GetSolutionProject("NPublic");

    project.ProjectItems.AddFromFile("NewFileHere.h");

    [현재 프로젝트에 아이템(파일 등) 삽입하기]


    ++ 추가

    그리고 .vsct 확장자의 파일로 간다.

    <!--The Commands section is where commands, menus, and menu groups are defined.
    This section uses a Guid to identify the package that provides the command defined inside it. -->
    <Commands package="guidCommandPackage">
    <!-- Inside this section we have different sub-sections: one for the menus, another
    for the menu groups, one for the buttons (the actual commands), one for the combos
    and the last one for the bitmaps used. Each element is identified by a command id that
    is a unique pair of guid and numeric identifier; the guid part of the identifier is usually
    called "command set" and is used to group different command inside a logically related
    group; your package should define its own command set in order to avoid collisions
    with command ids defined by other packages. -->
    <!-- In this section you can define new menu groups. A menu group is a container for
    other menus or buttons (commands); from a visual point of view you can see the
    group as the part of a menu contained between two lines. The parent of a group
    must be a menu. -->
    <!--<Groups>
    <Group guid="guidCommandPackageCmdSet" id="MyMenuGroup" priority="0x0600">
    <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
    </Group>
    </Groups>-->
    <Groups>
    <Group guid="guidCommandPackageCmdSet" id="MyMenuGroup" priority="0x0600">
    <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>
    </Group>
    </Groups>

    Groups의 id로 해당 커맨드가 뜨는 위치를 설정할 수 있다 나는 마우스 오른쪽 버튼을 누르면 뜨는 것을 원했다.
    그래서 id를 IDM_VS_CTXT_CODEWIN으로 변경했다.

    이제 텍스트를 설정하자 Command 하위 노드의 Buttons 노드를 보면 <ButtonText>라고 된 노드가 있다.

    <Buttons>
    <!--To define a menu group you have to specify its ID, the parent menu and its display priority.
    The command is visible and enabled by default. If you need to change the visibility, status, etc, you can use
    the CommandFlag node.
    You can add more than one CommandFlag node e.g.:
    <CommandFlag>DefaultInvisible</CommandFlag>
    <CommandFlag>DynamicVisibility</CommandFlag>
    If you do not want an image next to your command, remove the Icon node /> -->
    <Button guid="guidCommandPackageCmdSet" id="CommandId" priority="0x0100" type="Button">
    <Parent guid="guidCommandPackageCmdSet" id="MyMenuGroup" />
    <Icon guid="guidImages" id="bmpPic1" />
    <Strings>
    <ButtonText>vermouse, make it!</ButtonText>
    </Strings>
    </Button>
    </Buttons>

    그 노드에 보여지고 싶은 텍스트를 적는다. 위 작업까지 하면 이런식으로 보여질 수 있다.

    이 개발로 더이상 패킷을 일일히 수작업으로 만드는 재미 없는 노가다는 앞으로 없었으면 좋겠다.

    반응형
Designed by Tistory.