태그 보관물: c#

[Inno Setup] cmd 실행 뒤에 프로세스가 종료 안 되는 이슈

Inno Setup 툴은 윈도 애플리케이션을 패키징하는 툴이고, 스크립트 언어로 파스칼(Pascal)을 사용한다. 이 툴을 사용해서 애플리케이션을 패키징 하는 스크립트에서 애플리케이션 파일들을 복사하기 전/후에 외부 애플리케이션을 실행할 수 있다.
간단하게 스크립트 파일의 일부를 살펴보자.

[Files]
 Source: {#DefaultAssetFolderName}\NLog.dll; DestDir: {app}; Flags: ignoreversion
 .
 .
 .
[Run]
 Filename: "{cmd}"; Parameters: "/c taskkill /f /im explorer.exe"; Flags:runhidden;
 Filename: "{cmd}"; Parameters: "/c explorer.exe & exit"; Flags:runhidden;
[UninstallRun]
 Filename: "{cmd}"; Parameters: "/c taskkill /f /im explorer.exe"; Flags:runhidden;
 Filename: "{cmd}"; Parameters: "/c explorer.exe & exit"; Flags:runhidden;
[UninstallDelete]
 Type: filesandordirs; Name: {app}
 .
 .

위 소스는 다음의 과정을 거치게 된다.
1. 설치
1.1 [Files] 부분에 있는 파일들을 복사한다.
1.2 [Run] 부분을 차례로 실행한다.

2. 삭제
2.1 [UninstallRun] 부분을 차례로 실행한다.
2.2 [UninstallDelete] 부분에 있는 폴더/파일을 삭제한다.

위의 1.2와 2.1에서는 외부 애플리케이션으로 cmd를 사용하고 있다. 이 과정을 거치다 보면 설치는 되는데 cmd 프로세스가 종료되지 않는 문제와 삭제 시에 [UninstallDelete]의 과정으로 진행하지 못하는 문제가 있다.

그래서 이 경우를 해결하기 위해서 C#으로 애플리케이션을 만들어서 위의 과정을 실행시켜야 한다.

// 5초뒤에 프로세스를 종료시키는 스레드 시작 
Thread newThread = new Thread(new ThreadStart(Program.Run));
newThread.Start();

// cmd 실행 
ProcessStartInfo cmd = new ProcessStartInfo();
Process process = new Process();
cmd.FileName = @"cmd";
cmd.WindowStyle = ProcessWindowStyle.Hidden;             // cmd창이 숨겨지도록 하기
cmd.CreateNoWindow = true;                               // cmd창을 띄우지 안도록 하기

cmd.UseShellExecute = false;
cmd.RedirectStandardOutput = true;         // cmd창에서 데이터를 가져오기
cmd.RedirectStandardInput = true;          // cmd창으로 데이터 보내기
cmd.RedirectStandardError = true;          // cmd창에서 오류 내용 가져오기

process.EnableRaisingEvents = false;
process.StartInfo = cmd;
process.Start();

process.StandardInput.Write(@"taskkill /f /im explorer.exe" + Environment.NewLine);
process.StandardInput.Write(@"explorer.exe & exit" + Environment.NewLine);

process.StandardInput.Close();

string result = process.StandardOutput.ReadToEnd();
sb = new StringBuilder();
sb.Append("[Result Info]" + DateTime.Now + "\r\n");
sb.Append(result);
sb.Append("\r\n");

// 10초 대기
process.WaitForExit(10 * 1000);

public static void Run()
{
    Thread.Sleep(5 *1000);
    Application.ExitThread();
    Environment.Exit(0);
}

위 소스로 간단하게 cmd_exec.exe 애플리케이션을 만들었다고 가정하고, 패키징 스크립트를 수정하고 실행하면 정상으로 실행된다. 위 패키징 스크립트를 아래와 같이 변경해서 {cmd}로 수행하는 과정을 애플리케이션으로 래핑해서 실행시키면 된다.

[Files]
 Source: {#DefaultAssetFolderName}\NLog.dll; DestDir: {app}; Flags: ignoreversion
 .
 .
 .
[Run]
 Filename: "{app}\cmd_exec.exe"; Flags: runhidden waituntilterminated
[UninstallRun]
 Filename: "{app}\cmd_exec.exe"; Flags: runhidden waituntilterminated
[UninstallDelete]
 Type: filesandordirs; Name: {app}
 .
 .

C# 프로젝트에서 외부 dll 사인하기

마이크로소프트(Microsoft) 플랫폼 중의 하나인 .NET에서 C#으로 개발을 하다 보면 COM과 같은 모델로 등록하는 경우가 있고, 이 경우에 dll 파일의 사인이 필요하다. 프로젝트가 만들어 내는 바이너리는 문제가 없지만, 외부 dll을 사용하는 경우에는 COM으로 등록하는 데 문제가 될 수 있다.

이 경우에 외부 dll을 사인해야 하고 아래는 그 방법이다.

1. dll 다시 사인하기
이 방법은 C# dll을 decompile하고, 자신의 키로 다시 사인한다.
http://erjjones.github.io/blog/How-to-sign-third-party-assemblies/

2. strong name 사인하기
위 1.번의 사인이 문제가 있다. 그래서 아래의 툴을 사용해서 사인한다.
https://brutaldev.com/post/NET-Assembly-Strong-Name-Signer

이 툴을 사용하면서 VS에서 만들어놓은 .pfx 파일을 사용해서 사인한다.
이 과정으로 COM으로 사용할 수 있는 dll을 만들 수 있다.

자바 C/C++, C# 메서드 호출 지원 라이브러리

자바에서 C/C++, 그리고 C#의 메서드를  호출(Interop)할 수 있게 지원하는 라이브러리들이다.

1. C/C++ 메서드 호출

기본으로 자바에서 제공하는 JNI를 사용해서 C/C++의 메서드를 호출한다. 그리고, 아래는 JNI를 쉽게 사용하도록 래퍼(Wrapper)를 제공하는 라이브러리들이다.
– HawtJNI(https://github.com/fusesource/hawtjni)
– JNIWrapper(http://www.teamdev.com/jniwrapper/)
– JNIEasy(http://www.innowhere.com/jnieasy/?st=jnieasy_products#!st=jnieasy_products)

2. C# 메서드 호출

j-interop(Pure Java – Com Bridge) : http://j-interop.dimentrix.com/, 라이센스 : LGPL 3.0[1]

3. 자바 C# 양뱡 호출

– Jni4net : http://jni4net.sourceforge.net/, bridge between Java and .NET (interprocess, fast, object oriented, open-source), 라이선스: opensource, GPL tools and LGPL runtime

using net.sf.jni4net;

public class Program
{
	private static void Main()
	{
		Bridge.CreateJVM(new BridgeSetup());
		java.lang.System.@out.println("Greetings from C# to Java world!");
	}
}

C# 예제

import net.sf.jni4net.Bridge;
import java.io.IOException;
import java.lang.String;

public class Program {
	public static void main(String[] args) throws IOException {
		Bridge.init();
		system.Console.WriteLine("Greetings from Java to .NET world!");
	}
}

자바 예제

– ikvm.net : http://www.ikvm.net/, jar -> .dll, .dll -> .jar