Microsoft MVP성태의 닷넷 이야기
C#으로 만든 DLL 배포하기 [링크 복사], [링크+제목 복사]
조회: 2290
글쓴 사람
홈페이지
첨부 파일
 
안녕하세요?

질문이 있어 글 남깁니다.

목적 :
 C#을 이용해 만든 dll 을
 EXCEL 에서 사용할려고 합니다.

수작업으로 아래와 같이 실행해 주면 사용이 가능해 집니다.
  1. 해당 dll 파일을 사용자의 컴퓨터에 저장
  2. RegAsm.exe 파일이 있는 경로에서 명령프롬프트 실행(관리자 권한으로)
  3. 아래 명령문 실행
     C:\Program Files (x86)\...path...\Tools>RegAsm /codebase C:\DLL\ExcelTest.dll

수작업으로 배포하는 부분을 자동화하고 싶습니다.
즉 C#으로 프로젝트를 만들어서 사용자의 컴퓨터에서 setup.exe를 실행하면 dll 을 사용할 수 있게 하고 싶습니다.

감사합니다

-----------------------------------------------------------------------------------
ExcelTest.dll 은 Resources 폴더에 추가한 상태고 빌드 작업을 [포함 리소스]로 설정한 상태입니다.

ExcelTest.dll 소스코드
namespace ExcelTest
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class CSharpTools
    {
        [ComVisible(true)]
        public string AddBrackets(string value)
        {
            return "[" + value + "]";
        }

    }
}

DLL 배포하기 위해 작업한 소스 코드
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Principal;
using System.Windows.Forms;

namespace RegisterTest
{
    static class Program
    {
        /// <summary>
        /// 해당 응용 프로그램의 주 진입점입니다.
        /// </summary>
        [STAThread]
        static void Main()
        {
            //ClickOnce - 관리자 권한 상승하는 방법
            //출처 : https://www.sysnet.pe.kr/2/0/950
            if (IsAdministrator() == false)
            {
                try
                {
                    ProcessStartInfo procInfo = new ProcessStartInfo();
                    procInfo.UseShellExecute = true;
                    procInfo.FileName = Application.ExecutablePath;
                    procInfo.WorkingDirectory = Environment.CurrentDirectory;
                    procInfo.Verb = "runas";
                    Process.Start(procInfo);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message.ToString());
                }

                return;
            }

            // 컴파일 배포시 단이 exe 로 배포하고 , 참조하는 dll은 리소스 파일에 추가하여 (참조리소스)
            // 단일 실행파일로 만들어 배포함.
            // 프로그램은 실행시 참조 dll 파일을 생성하고 리소스 파일에 있는 원 파일을 읽어서 대체함.
            string strDllPath = "";
            string strFullFileName = "";
            try
            {
                strDllPath = Application.ExecutablePath.Replace("/", "\\");
                int intPos = strDllPath.LastIndexOf("\\");
                if (intPos >= 1)
                    strDllPath = strDllPath.Substring(0, intPos).Trim('\\');

                strFullFileName = strDllPath + "\\ExcelTest.dll";
                FileInfo fileinfo = new FileInfo(strFullFileName);
                if (fileinfo.Exists == false)
                {
                    byte[] aryData = Resource1.ExcelTest; //리소드 디자인에 저장한 이름
                    FileStream fileStream = new FileStream(fileinfo.FullName, FileMode.CreateNew);
                    fileStream.Write(aryData, 0, aryData.Length);
                    fileStream.Close();
                }
                // 출처: https://lovelypang.tistory.com/73 [코코몽과 토토몽]
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }

            // dll 파일 레지스트리에 등록하기
            // 출처: https://developer-joe.tistory.com/148
            try
            {
                Console.WriteLine("This program is registering .TLB to Windows registry.");

                var proc = new ProcessStartInfo();

                // .dll을 이용해서 .tlb생성 및 레지스트리 등록 명령어
                // regasm의 사용법은 DOS창(커맨더 창)에서 regasm /?을 하면
                // regasm을 아래와같이 이 파일의 경로를 표시하지 않으면 현재의 프로그램의 실행 파일과 같은 위치에
                // regasm.exe가 있어야 된다.
                //string mCmd = "regasm ExcelTest.dll /tlb:ExcelTest.tlb";
                string mCmd = "regasm ExcelTest.dll /tlb:ExcelTest.tlb";
                proc.UseShellExecute = true;

                //아래 경로에 .DLL가 있어야하고 .tlb가 이 위치에 생성이 되고 regasm.exe도 이 위치에서
                //작업을 하게된다.
                proc.WorkingDirectory = @strDllPath;

                //위의 regasm EthernetClientLib.dll /tlb:EthernetClientLib.tlb를 실행시킬 명령어
                proc.FileName = "cmd.exe";

                //아래 속성의 runas 자체가 관리자 권한으로 실행시키겠다는 설정값이다.
                proc.Verb = "runas";
                proc.Arguments = "/C " + mCmd;
                proc.WindowStyle = ProcessWindowStyle.Hidden;
                Process rt = Process.Start(proc);

                Debug.WriteLine("##### .tlb 생성 및 레지스트리 등록을 마쳤습니다.");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
        }

        public static bool IsAdministrator()
        {
            WindowsIdentity identity = WindowsIdentity.GetCurrent();

            if (null != identity)
            {
                WindowsPrincipal principal = new WindowsPrincipal(identity);
                return principal.IsInRole(WindowsBuiltInRole.Administrator);
            }

            return false;
        }

    }
}

-----------------------------------------------------------------------------------
참고한 사이트
C# 코드상에서 .tlb 생성 및 레지스트리 등록하는 법
https://developer-joe.tistory.com/148

regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (1) - .NET 2.0 + x86/x64/AnyCPU
; https://www.sysnet.pe.kr/2/0/1286
 
regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (2) - .NET 4.0 + .NET 2.0
; https://www.sysnet.pe.kr/2/0/1287

regasm.exe로 어셈블리 등록 시 시스템 변경 사항 (3) - Type Library
; https://www.sysnet.pe.kr/2/0/1288






[최초 등록일: ]
[최종 수정일: 4/9/2019 ]


비밀번호

댓글 쓴 사람
 



2019-04-09 07시38분
수작업 1~3단계를 잘 구현하신 것 같은데... 어떤 문제가 있는 건가요?
정성태
2019-04-10 10시41분
[cab2da] 수작업으로 하면 사용자 컴퓨터에서 dll을 정상적으로 사용을 할 수 있는데
setup.exe를 이용해 실행하면 오류는 발생하지 않는데
dll 을 인식하지 못해 사용할 수 없습니다.
엑셀 VBA 편집기에서 참조를 눌러보면
수작업으로 배포한 컴퓨터에선 ExcelTest가 보이고
자동 배포한 컴퓨터에선 보이지 않습니다.

[손님]
2019-04-11 11시37분
이런 경우에는 원칙을 생각하시면 됩니다. 딱히 수작업이나 코드로 하는 거나 다를 바가 없기 때문에 안 된다는 것은 어딘가 오류가 있다는 것입니다. 따라서, 1) 파일이 로컬에 있는지 확인하고 2) regasm으로 인한 등록이 레지스트리에 잘 되었는지 확인하면 됩니다. 그냥 보면 regasm 과정 중에 오류가 있을 듯한데, 어쨌든 중요한 것은 코드로 했다고 달라질 만한 작업은 아닙니다.
정성태
2019-04-11 12시10분
[cab2da] 안녕하세요?

setup 파일을 실행하면 dll 파일도 포함되는지 궁금하여
strDllPath 에 있는 경로로 가보니 해당 파일이 있었습니다.
(숨긴 항목도 보이게 하니 AppData 폴더의 하위 폴더에 있더군요)

레지스트로에 잘 되었는지는 확인하는 방법을 찾아셔 확인해 보겠습니다.

아무래도 regasm.exe를 찾아서 해당 경로에서 실행하는 것으로 해야 할 듯 합니다.
(오류가 발생하지 않고 등록을 마쳤다고 하니...)

감사합니다

[손님]
2019-04-11 01시33분
그런데... 설마 "Debug.WriteLine("##### .tlb 생성 및 레지스트리 등록을 마쳤습니다.");" 코드가 수행되었다고 해서 regasm이 성공했다고 생각하는 건 아니죠?
정성태
2019-04-15 02시39분
[cab2da] 코드 중 일부를 아래처럼 수정하고
레지스트리 편집기에서
[EXCELTEST]를 찾기했는데...
찾지를 못하는군요.
무엇인가를 놓치고 있는 듯 합니다

string mCmd = @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe /codebase " + strFullFileName;


[손님]
2019-04-15 02시54분
FileName부터 cmd.exe를 주었는데 왜 그런 식으로 한 거죠?

이런 경우, FileName = "regasm.exe"로 하고 Arguments에 "/codebase …[dll_path]…"로 설정해야 합니다.

그리고 정상적으로 명령어가 실행되었는지 proc.StandardOutput을 이용해 확인하세요.
정성태
2019-04-16 10시47분
[cab2da] 안녕하세요?

아래의 코드로 테스트 해 보니
proc.StandardOutputEncoding 이 null로 나오는군요.

검토해 주셔서 감사합니다.

try
{
    ProcessStartInfo proc = new ProcessStartInfo();
    proc.UseShellExecute = true;
    proc.FileName = "RegAsm.exe";
    proc.WorkingDirectory = @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\";
    proc.Verb = "runas";
    proc.Arguments = "/codebase " + strFullFileName;
    proc.WindowStyle = ProcessWindowStyle.Hidden;
    Process.Start(proc);

    string result = "";
    if (proc.StandardOutputEncoding != null)
        result = proc.StandardOutputEncoding.ToString();
    else
        result = "null";
    MessageBox.Show(result);
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message.ToString());
}
[손님]
2019-04-16 04시22분
아래의 글을 참고하세요.

Process.Start로 실행한 콘솔 프로그램의 출력 결과를 얻는 방법
; http://www.sysnet.pe.kr/2/0/11870

정성태
2019-04-18 03시51분
[cab2da] 아래처럼 구문을 수정하고 실행하니 catch 부분에서 메세지박스가 출력되네요.
오류 : 지정된 파일을 찾을 수 없다

아마도
Process proc = Process.Start(psi);
이 구문에서 오류가 발생하는 듯 합니다.

소중한 시간 할애하여 검토해 주셔서 감사합니다.


----------------------------------------------------------
try
{
    ProcessStartInfo psi = new ProcessStartInfo();
    psi.FileName = "RegAsm.exe";
    psi.WorkingDirectory = @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\";
    psi.Verb = "runas";
    psi.Arguments = "/codebase " + strFullFileName;
    psi.WindowStyle = ProcessWindowStyle.Hidden;
    psi.RedirectStandardOutput = true;
    psi.UseShellExecute = false;

    MessageBox.Show("시작" + strFullFileName);

    Process proc = Process.Start(psi);
    string txt = proc.StandardOutput.ReadToEnd();

    MessageBox.Show(txt);
}
catch (Exception ex)
{
    MessageBox.Show("오류 : " + ex.Message.ToString());
}

----------------------------------------------------------

[손님]

1  2  3  4  5  [6]  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
5152세퉁5/3/20191001인터넷 시간을 불러와 pc에 적용 시키고 싶습니다. [3]파일 다운로드1
5151이대희5/3/2019852C# 7.3으로 개정판 출간 계획이 있으신가요? [1]
5150김이현5/2/2019781C# 딕셔너리 생성에 대해 질문드립니다. [1]
5149민성5/1/2019699ftp 이미지 업로드중 [1]
5148wpf질문4/30/2019699특정 사이트를 wpf에서 popup을 항상 허용하게 할려면 어떻게 해야할까요? [5]
5147민성4/30/2019724wpf에서 작업관리자를 띠울려면 어떻게 해야 하나요? [1]
5146불파겐4/25/2019736하나의 필드를 여러 스레드에서 읽어갈 때 스레드 동기화를 하지 않으면 문제가 생길까요? [2]
5145e구름4/17/20191301Properties.Setting.Default값에 대해 질문드립니다. [2]
5144성태님 사랑하는사람4/17/2019806질문하시기 전에 10000 페이지 오류 납니다. [1]
5143헌이4/16/2019854윈도우 작업표시줄에 프로그램 띄우기 [2]파일 다운로드1
5142cab2da4/9/20192290C#으로 만든 DLL 배포하기 [10]
5141하늘사랑4/8/20191039Axinterop 래퍼에 관해서 질문드립니다. [7]
5140게스트4/1/2019818안녕하세요. 초보 개발자입니다. SD리더기에서 SD카드를 꽂으면 발생하는 이벤트 문의 [2]
5139김이현3/28/20191497C#에서 CRON 같은 스케줄러를 사용하려면 어떻게 해야 하나요? [3]
5138김지원3/22/2019892유니티 쉐이더에서 오로지 포워드 애드 패스로만 만들 수 있을까요? [1]
5137세퉁3/22/2019995wpf 쓰레드에 대해 질문 있습니다. [4]
5136KGY3/13/2019879안녕하세요 닷넷코어 콘솔 프로그램 관련 질문입니다. [1]
5135러쎌3/13/2019874ASP.NET 공부 관련해서 문의를 드립니다. [1]
5134이정호3/12/2019821SampleProfiler 예제를 이용한 Class 객체의 접근 문의 [1]파일 다운로드1
5133ㅇㅇ3/12/2019876멀티코어사용 방법에 궁금한것이 있습니다. [3]
5132존기미3/3/2019870Physical Disk Access문의 [1]
5131강용규2/25/20191073c# 개발자입니다. 타이머 질문드립니다. [1]
5130노인코래방2/25/20192515C#에서 가장 좋은 성능을 보이는 파일 읽고 쓰는 방법이 무엇인가요? [2]
5129진우2/23/20191171닷넷 32비트 기반에서 메모리 부족으로 프로그램이 죽는경우 문의 [2]
5128게스트2/23/20191133안녕하세요. 초보개발자입니다. [3]파일 다운로드1
5127c#2/20/20191003책에 예제 문의드립니다. [2]
1  2  3  4  5  [6]  7  8  9  10  11  12  13  14  15  ...