본문 바로가기

개발 일지

[Windows] NSIS 를 이용해서 Forms Application 배포하기

Windows 에서 C# 을 이용해서 GUI 애플리케이션을 만들어야 할 때, 디자인이 무겁지 않다면, Windows Forms Application 은 굉장히 좋은 옵션이라고 생각한다. Visual Studio 를 이용해서 Forms Application 을 만들면서 패키징을 하기 위해 NSIS 를 이용했는데, 필자가 구성한 방식을 정리해 보았다.

Windows Forms Application 프로젝트 생성

먼저, Visual Studio 에서 프로젝트를 생성한다.

새 프로젝트 만들기

 

주어지는 옵션 중, Windows Forms Application 을 선택한다.

Windows Forms 앱

 

프로젝트 구성에서 프로젝트 이름은 편의상 WinFormAppForNSIS 라고 지었다.

모든 구성을 마치고, 프로젝트 생성이 완료되면, Forms designer 화면이 나오면서, 빈 Form 애플리케이션을 볼 수 있다. F5 버튼을 누르거나, 상단의 초록색 화살표를 클릭하면, 프로젝트를 빌드 후 실행할 수 있다.

초록색 화살표로 앱을 실행할 수 있다

 

성공적으로 실행되었다면, 그림과 같이 빈 창이 하나 실행될 것이다.

비어 있는 재미없는 Forms 애플리케이션

 

Post Build 이벤트 설정하기

NSIS 로 Release 빌드 된 결과물을 패키징할 때 편의성을 위해서, Visual Studio 에서 빌드가 완료되면, 프로젝트 최상단 디렉토리의 dist 폴더로 빌드 결과물을 복사하는 이벤트를 설정해 보자.

메뉴 바의 프로젝트 -> WinFormAppForNSIS 속성 을 클릭해서 프로젝트의 속성을 로드한다.

속성 편집

 

프로젝트의 현재 속성을 볼 수 있는데, 이 중 빌드 -> 이벤트 -> 빌드 후 이벤트 항목을 편집할 것이다. Batch 스크립트를 작성할 수 있는데, 다음과 같이 작성한다.

if $(ConfigurationName) == Release (
rmdir /s /q $(SolutionDir)\dist
mkdir $(SolutionDir)\dist

copy $(TargetDir)* $(SolutionDir)\dist\.
)

 

$(SolutionDir) 나 $(TargetDir) 는 Visual Studio 에서 사용할 수 있는 매크로로, MSBuild 매크로 에서 사용할 수 있는 매크로를 확인할 수 있다.

빌드가 완료되면, 기존의 dist 폴더를 비운 후, 빌드 결과물이 있는 $(TargetDir) 에서 결과물을 전부 복사해 오는 스크립트이다.

빌드 후 이벤트를 편집한다

 

사실 .csproj 파일을 통해서도 편집할 수 있다. Post Build 이벤트를 설정했으면, Release 빌드를 진행한다. 빌드 -> 일괄 빌드 를 선택해서 빌드 구성 관리 화면을 연 후, Release 구성을 활성화 한 후 빌드 를 실행하면 Visual Studio 에서 빌드를 실행한다.

일괄 빌드
Release 빌드

 

빌드가 완료되면, 다음과 같이 프로젝트의 최상단 디렉토리에 dist 폴더가 생성된 것을 확인할 수 있다. dist 폴더 안에는 빌드 결과물이 복사되어 있어야 한다.

dist 가 만들어졌다

 

NSIS 빌드 설정하기

NSIS 를 이용해서 패키징을 하는 부분은 이전 포스트 에서 다룬 적이 있다. dist 폴더가 있는 솔루션 디렉토리에 install.nsi 파일을 생성하고, 다음과 같이 작성한다.

 

[Windows] NSIS 를 이용해서 설치 파일 패키징하기

열심히 소프트웨어를 개발해도, 그 프로그램을 다른 사람이 사용할 수 있게 배포하지 않으면, 나 혼자 보고 만족하는 장식장 속의 진열물에 불과하다. 내가 개발한 소프트웨어를 배포할 때에,

dev-seb.tistory.com

; define const
!define PRODUCT_NAME "WinFormAppForNSIS"
!define PRODUCT_VERSION $%VERSION%
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${PRODUCT_NAME}.exe"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define INPUT_DIR "dist"

!include "MUI2.nsh"

; MUI Settings
!define MUI_ABORTWARNING

; Installer pages
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_RUN "$INSTDIR\${PRODUCT_NAME}.exe"
!insertmacro MUI_PAGE_FINISH

; Uninstaller pages
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

!insertmacro MUI_LANGUAGE "Korean"
; MUI end ------

Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "${PRODUCT_NAME}_${PRODUCT_VERSION}_Setup.exe"
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""

RequestExecutionLevel admin

; Copy Files to INSTDIR
Section "Application" SEC01
  SetOutPath "$INSTDIR"
  SetOverwrite ifnewer
  File "${INPUT_DIR}\*"

  CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
  CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.exe"
SectionEnd

; Write Registry Info
Section "-Uninstaller"
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\${PRODUCT_NAME}.exe"
  WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
  WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
  WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_NAME}.exe"
  WriteRegStr HKLM "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
SectionEnd

Section Uninstall
  RMDir /r "$INSTDIR\*"
  RMDir $INSTDIR

  DeleteRegKey HKLM "${PRODUCT_UNINST_KEY}"
  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"

  RMDir /r "$STARTMENU\${PRODUCT_NAME}"
  DELETE "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
SectionEnd

 

설치 시에 dist 폴더 안의 빌드 결과물을 설치하고, 시작 메뉴에 프로그램을 추가하는 스크립트이다. PRODUCT_VERSION 에 $%VERSION% 라는 심볼을 사용하는데, 이는 컴파일 타임의 환경변수를 받아오는 방법이다. 프로그램을 계속 개발하면서 버전이 올라갈 텐데, 그 때마다 nsi 스크립트를 편집하려면 귀찮기 때문에, 환경변수로 VERSION 을 넘겨주도록 설정했다. 따라서, 다음 커맨드를 실행해서 인스톨러를 생성한다.

cmd /C "set VERSION=0.1.0 && makensisw install.nsi"

 

인스톨러 컴파일이 완료되면, WinFormAppForNSIS_0.1.0_Setup.exe 라는 설치파일이 생성된다. 설치를 시작하면, 다음과 같이 설치가 시작된다.

네 설치를 시작하세요

 

설치가 완료되어, 실행하기 체크박스를 활성화 한 상태로 설치를 완료하면, Forms Application 이 실행되는 것을 확인할 수 있고, Windows 시작 메뉴에도 WinFormAppForNSIS 가 추가되는 것을 확인할 수 있다.

시작 메뉴에서 프로그램을 실행할 수 있다

 

결론

Post Build Event 를 설정하지 않거나, NSIS 스크립트를 작성하지 않아도, 수작업으로 설치 파일을 작성하는 방법이 있을 수 있다. 하지만, 이렇게 패키징 플로우를 정립해 놓으면, 이후에 Jenkins 나 Github Action 등을 이용하여 Continuous Deployment 를 구성하는 데에도 도움이 된다.

 

전체 프로젝트는 다음에서 확인할 수 있습니다.

 

GitHub - k2sebeom/windows-form-app-nsis: Packaging Windows Form Application using NSIS

Packaging Windows Form Application using NSIS. Contribute to k2sebeom/windows-form-app-nsis development by creating an account on GitHub.

github.com