Microsoft MVP성태의 닷넷 이야기
C#으로 만든 DLL 배포하기 [링크 복사], [링크+제목 복사],
조회: 13275
글쓴 사람
cab2da (cab2da at naver.com)
홈페이지
첨부 파일
 

안녕하세요?

질문이 있어 글 남깁니다.

목적 :
 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가 보이고
자동 배포한 컴퓨터에선 보이지 않습니다.

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

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

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

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

감사합니다

[guest]
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;


[guest]
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());
}
[guest]
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());
}

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

[guest]

... 31  32  33  34  35  36  37  38  39  40  [41]  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
4829윤현수4/26/201714710System.Text.Encoding 질문 [1]
4828jaem...4/20/201710999시스템 종료시 block 함수 xp 지원가능한 방법 질문 [2]
4827ds4/13/201712839매서드 정의로 이동시 [메타데이터에서]에서 라고 나오는 것은 뭔가요? [1]
4826김솔지4/11/201710137CxImage 문자 출력 [1]
4825플메4/10/201710539덱스트 업로드 하는데 구성요소 서비스에 엑셀이 안뜨네요..ㅜㅜ [1]파일 다운로드1
4824김상경4/9/20179891win7에서 vb6.0을 이용해서 프로그램을 만들었습니다.(제가 만든건 아니고 옆 동료가 만들었습니다.) [1]파일 다운로드1
4823조상현3/28/201710901windows event log 에 대한 정보는 어디서 얻을 수 있을까요? [1]
4822부우3/24/201712572글수정이 안되어 다시올려드립니다ㅠ [12]파일 다운로드2
4821부우3/22/201726208파일이나 어셈블리 중 하나를 로드에러 좀 봐주세요 [9]파일 다운로드1
4820듀이3/20/201711020오차 없이 동시에 명령을 보내게 가능한가요? [2]파일 다운로드1
4819popo3/20/201712328C# sslstream 사용시 Cipher List 설정 [3]
4818부우3/16/201721200DllImport 사용시 진입점을 찾을수 없습니다 [2]
4817yun3/15/201710533서피스프로4의 HYPER-V로 윈도우7을 깔았는데... [1]
4816부우3/15/201713271C++ DLL함수 사용 질문드립니다 [10]
4815김지용3/14/20179335.net core linux 오류 [2]
4814김솔지3/13/201710393인쇄 시 , 출력화면을 이미지 파일로 저장하고 싶습니다. [1]파일 다운로드1
4813spow...3/8/201711959멀티 스레드 환경에서 처리하여야 할 목록을 효율적으로 사용하는 기법 질문 드립니다 [2]
4812popo2/23/201712033.NET Window ClassName 변경 질문 드립니다. [1]
4809힘찬도약2/15/201715093C# 가상 시리얼 [4]
4808이길용2/9/201713809WCF 외부 접속 관련해서 질문드립니다ㅠ [1]
4807헬조선식...2/8/201720402WPF의 속도에 대해서 궁금합니다. [3]
4803헬조선식...2/7/201713829WPF로 메신져 메세지 박스 구현 문의 [2]
4802spow...2/6/201710854특정 범위의 값을 다른 값으로 치환하는 메소드를 만들어야 할 때 가장 빠른 방법은? [7]
4804spow...2/7/201710730    답변글 [답변]: 특정 범위의 값을 다른 값으로 치환하는 메소드를 만들어야 할 때 가장 빠른 방법은?
4805spow...2/7/201710409    답변글 [답변]: 특정 범위의 값을 다른 값으로 치환하는 메소드를 만들어야 할 때 가장 빠른 방법은? (글삭제가 안돼 재첨부합니다)파일 다운로드1
4801spow...2/3/201710298C#의 참조 동작관련하여 아이디어 문의 드립니다 [4]
... 31  32  33  34  35  36  37  38  39  40  [41]  42  43  44  45  ...