Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 6개 있습니다.)

.NET SmartClient 컨트롤을 윈도우 8/2012에서 활성화하는 방법

최근의 질문도 있고,

안녕하십니까 SmartClient 에 관한 질문이 있습니다.
; https://www.sysnet.pe.kr/3/0/1283

아무래도 언젠가 한번은 정리해야겠다 싶어서 이렇게 기록으로 남깁니다. ^^




테스트를 위해 .NET 3.5 대상으로 Web Application과 WindowsFormsControlLibrary 프로젝트를 2개 추가합니다.

net_usercontrol_in_ie_1.png

그리고, 중간 중간 파일 복사하는 것이 귀찮으므로 WindowsFormsControlLibrary1 프로젝트 속성의 Build Events에서 "Post-build event command line" 설정을 다음과 같이 복사 명령어로 입력해 둡니다.

copy $(TargetDir)$(TargetFileName) $(SolutionDir)WebApplication1

그럼, 빌드가 될 때마다 WindowsFormsControlLibrary1.dll은 웹 프로젝트로 복사가 될 것입니다.

그 결과를 아래의 제 홈페이지 경로에 올려두었습니다.

https://www.sysnet.pe.kr/program/netuserctl.aspx

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1">
        <div style="background-color: green">
            User Control  
        <object id="myuc" classid="WindowsFormsControlLibrary1.dll#WindowsFormsControlLibrary1.UserControl1" />
        </div>
    </form>
</body>
</html>

자, 이제부터 이 Smart Client를 새로 설치한 윈도우 서버 2012에서 로드해 보겠습니다. (즉, .NET 4.5만 설치되어 있고 3.5는 없습니다.) 또한 테스트가 확실히 되는 것을 위해 브라우저의 임시 파일 정책을 "Automatically"에서 "Every time I visit the webpage"로 바꿉니다.

시험삼아 지금 상태의 netuserctl.aspx를 방문하면, 당연히 아무것도 나오지 않습니다.

net_usercontrol_in_ie_2.png

이제 ^^ 조정을 해볼까요?

우선, www.sysnet.pe.kr 주소를 "Local Intranet" 영역에 추가합니다.

net_usercontrol_in_ie_3.png

다시 한번 방문하면,

net_usercontrol_in_ie_4.png

역시 안 나오는 것은 마찬가지래도, 활성화에 실패했다는 듯이 사각형 박스가 나오는 변화가 있습니다.

그다음 regedit.exe를 실행시키고 다음의 레지스트리 설정을 합니다.

이름: EnableIEHosting
타입: REG_DWORD
값: 1

키 경로:
HKLM\SOFTWARE\MICROSOFT\.NETFramework 
HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework

둘다 할 필요는 없지만, 그냥 기왕 할 수 있으면 둘다 하는 것이 좋습니다. (고객의 IE가 x86/x64중에 어떤 걸로 뜰지 알 수 있다면 적절히 조절하시면 됩니다.)

다시 한번 방문해 봅니다. 음... 이번에는 아무런 변화가 없이 활성화는 계속 실패하고 있습니다. 아쉽게도 .NET Framework 4.x만 있으면 스마트 클라이언트가 활성화가 안됩니다. 그러하니, 이제 운영체제에 .NET 3.5를 활성화 시켜 줍니다.

그런 후에 다시 방문하면,

net_usercontrol_in_ie_5.png

이제 잘 되는군요. 그렇습니다. IE에 내장되는 닷넷 스마트 클라이언트는 여전히 윈도우 2012에서도 잘 동작하고 있습니다. 단지! 설정이 복잡할 뿐.

여기서 약간의 변화를 한번 줘볼까요?

.NET 3.5로 맞춰져 있는 WindowsFormsControlLibrary 프로젝트를 .NET 4.0 대상으로 다시 컴파일하고 웹 사이트에 올린 후 방문해 보면 어떻게 될까요? 아쉽게도 활성화가 안됩니다.

따라서 앞으로도 닷넷 스마트 클라이언트를 사용하고 싶다면 다음의 2가지 규칙을 지켜야 합니다.

  • 닷넷 스마트 클라이언트는 .NET 3.5 이하로 작성
  • 고객 컴퓨터에 .NET 3.5 설치




기본 스마트 클라이언트의 활성화는 성공했으니, 이제 기능을 붙여나가야 할 차례입니다. 먼저, 스마트 클라이언트의 공용 함수를 제작해서 스크립트에서 호출해 보도록 하겠습니다.

using System.Windows.Forms;

namespace WindowsFormsControlLibrary1
{
    public partial class UserControl1: UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public void DoMyControl(string txt)
        {
            MessageBox.Show(txt);
        }
    }
}

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>

    <script>
        function myuc_call() {
            form1.myuc.DoMyControl("test is good");
        }
    </script>

</head>
<body>
    <form id="form1">
        <div style="background-color: green">
            User Control  
        <object id="myuc" classid="WindowsFormsControlLibrary1.dll#WindowsFormsControlLibrary1.UserControl1" />
        </div>

        <button onclick="myuc_call()">Call DoMyControl()</button>
    </form>
</body>
</html>

이 상태에서 테스트 해보시면 "Call DoMyControl" 버튼을 눌러도 아무런 동작을 하지 않습니다. F12 개발자 도구를 통해 보면 해당 프로퍼티나 메서드가 없다는 스크립트 오류를 확인할 수 있는데요.

SCRIPT438: Object doesn't support property or method 'DoMyControl'

이 문제를 해결하기 위해 AssemblyInfo.cs 파일에 ComVisible 특성을 추가해야 합니다.

[assembly: ComVisible(true)]

다시 빌드하고 배포하면 이번에는 다음과 같이 잘 동작하는 것을 확인할 수 있습니다.

net_usercontrol_in_ie_6.png

내친 김에 그럼 이벤트도 만들어 볼까요? ^^ 스마트 클라이언트에 있는 "button1"이 눌린 경우 자바 스크립트에서 이벤트를 받도록 만들어 보겠습니다.

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>

    <script>
        function myuc_call() {
            alert(form1.myuc);
            form1.myuc.DoMyControl("test is good");
        }
    </script>

    <script event="ButtonClicked()" for="myuc">
        alert('button clicked');
    </script>


</head>
<body>
    <form id="form1">
        <div style="background-color: green">
            User Control  
        <object id="myuc" classid="WindowsFormsControlLibrary1.dll#WindowsFormsControlLibrary1.UserControl1" />
        </div>

        <button onclick="myuc_call()">Call DoMyControl()</button>
    </form>
</body>
</html>

[Guid("B59B958D-B363-454b-88AA-BE8626A131FA")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyUserEvent
{
    [DispId(0x60020000)]
    void ButtonClicked();
}

using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsControlLibrary1
{
    [ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(IMyUserEvent))]
    [Guid("F08C3529-A6FF-42b4-912A-4C4754DC0272")]
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public delegate void ButtonClickedHandler();
        public event ButtonClickedHandler ButtonClicked;

        public void DoMyControl(string txt)
        {
            MessageBox.Show(txt);
        }

        protected void OnNodeClicked()
        {
            if (ButtonClicked != null)
            {
                Invoke(ButtonClicked, null);
            }
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            OnNodeClicked();
        }
    }
}

이렇게 변경하고 다시 웹 브라우저에서 반영하면 이번에는 버튼이 눌릴 때 다음과 같은 예외 창이 뜹니다.

net_usercontrol_in_ie_7.png

상황이 더욱 안 좋게 되는 것이 있는데, 이벤트를 추가하기 전에는 잘 동작하던 "Call DoMyControl" 버튼마저 이제는 안된다는 점입니다. 우선 다시 "Call DoMyControl" 버튼이 동작하도록 해보겠습니다. 이 문제를 해결하려면 기존의 DoMyControl 메서드를 인터페이스에 연결해서 보내야 합니다.

[Guid("108C3529-A6FF-42b4-912A-4C4754DC12F2")]
public interface IMyUserControl
{
    void DoMyControl(string txt);
}

using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsControlLibrary1
{
    [ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(IMyUserEvent))]
    [Guid("F08C3529-A6FF-42b4-912A-4C4754DC0272")]
    public partial class UserControl1 : UserControl, IMyUserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public delegate void ButtonClickedHandler();
        public event ButtonClickedHandler ButtonClicked;

        public void DoMyControl(string txt)
        {
            MessageBox.Show(txt);
        }

        protected void OnNodeClicked()
        {
            if (ButtonClicked != null)
            {
                Invoke(ButtonClicked, null);
            }
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            OnNodeClicked();
        }
    }
}

일단, 이렇게 빌드하고 배포하면 정상적으로 "Call DoMyControl" 버튼의 자바 스크립트 호출은 됩니다. 물론, 이벤트 전달은 안됩니다.

이벤트 전달은 아래의 문서에서 설명했던 것처럼 복잡한 이유로 인해 보안이 필요합니다.

[마소 연재 기사: 2004-02] 실전!강의실 - IE에서 닷넷 스마트 클라이언트 개발 1
; https://www.sysnet.pe.kr/2/2/50

따라서 www.sysnet.pe.kr을 Full Trust 권한을 부여해야 하는데 이 과정에서 caspol.exe가 사용됩니다. 또한 실행해야 할 caspol.exe 위치도 해당 스마트 클라이언트가 IE의 32비트/64비트 모드냐에 따라 달라집니다.

32비트인 경우: C:\Windows\Microsoft.NET\Framework\v2.0.50727\caspol.exe
64비트인 경우: C:\Windows\Microsoft.NET\Framework64\v2.0.50727\caspol.exe

판단이 안되면 그냥 두군데 모두 해주는 것이 좋습니다. (아래는 32비트 IE에서 스마트 클라이언트라고 가정하고 진행합니다.)

우선, 현재의 보안 사항을 한번 확인해 볼까요?

C:\Windows\Microsoft.NET\Framework\v2.0.50727>caspol -l
Microsoft (R) .NET Framework CasPol 2.0.50727.7905
Copyright (c) Microsoft Corporation.  All rights reserved.

Security is ON
Execution checking is ON
Policy change prompt is ON

Level = Machine

Code Groups:

1.  All code: Nothing
   1.1.  Zone - MyComputer: FullTrust
      1.1.1.  StrongName - 00240000048000009400000006020000002400005253413100040
0000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE
79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E82
1C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8
A12436518206DC093344D5AD293: FullTrust
      1.1.2.  StrongName - 00000000000000000400000000000000: FullTrust
   1.2.  Zone - Intranet: LocalIntranet
      1.2.1.  All code: Same site Web
      1.2.2.  All code: Same directory FileIO - 'Read, PathDiscovery'
   1.3.  Zone - Internet: Internet
      1.3.1.  All code: Same site Web
   1.4.  Zone - Untrusted: Nothing
   1.5.  Zone - Trusted: Internet
      1.5.1.  All code: Same site Web


Named Permission Sets:

...[이하 생략]...

우리가 해야 하는 것은 LocalIntranet 존에 www.sysnet.pe.kr 사이트를 FullTrust로 등록하는 것입니다. 이를 위해 caspol.exe를 다음과 같은 옵션으로 실행해 줍니다.

C:\Windows\Microsoft.NET\Framework\v2.0.50727>caspol -addgroup 1.2. -site www.sysnet.pe.kr FullTrust -name "MyIntranet_CG"
Microsoft (R) .NET Framework CasPol 2.0.50727.7905
Copyright (c) Microsoft Corporation.  All rights reserved.

The operation you are performing will alter security policy.
Are you sure you want to perform this operation? (yes/no)
y
Added union code group with "-site" membership condition to the Machine level.
Success

다시 -l 옵션으로 확인하면,

C:\Windows\Microsoft.NET\Framework\v2.0.50727>caspol -l
Microsoft (R) .NET Framework CasPol 2.0.50727.7905
Copyright (c) Microsoft Corporation.  All rights reserved.

Security is ON
Execution checking is ON
Policy change prompt is ON

Level = Machine

Code Groups:

1.  All code: Nothing
   1.1.  Zone - MyComputer: FullTrust
      1.1.1.  StrongName - 00240000048000009400000006020000002400005253413100040
0000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE
79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E82
1C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8
A12436518206DC093344D5AD293: FullTrust
      1.1.2.  StrongName - 00000000000000000400000000000000: FullTrust
   1.2.  Zone - Intranet: LocalIntranet
      1.2.1.  All code: Same site Web
      1.2.2.  All code: Same directory FileIO - 'Read, PathDiscovery'
      1.2.3.  Site - www.sysnet.pe.kr: FullTrust
   1.3.  Zone - Internet: Internet
      1.3.1.  All code: Same site Web
   1.4.  Zone - Untrusted: Nothing
   1.5.  Zone - Trusted: Internet
      1.5.1.  All code: Same site Web

Named Permission Sets:

보시는 바와 같이 www.sysnet.pe.kr 사이트가 FullTrust로 LocalIntranet Zone 하위에 등록되었고, 마지막으로 이제 IE에서 버튼을 누르면 이벤트가 전달되어 자바스크립트가 실행되는 것을 확인할 수 있습니다.

net_usercontrol_in_ie_8.png

현재 "https://www.sysnet.pe.kr/program/netuserctl.aspx" 경로를 방문하면 위에 테스트한 최종 컨트롤이 동작하고 있기 때문에 원하는 클라이언트 PC에 설정만 잘 해주시면 자바스크립트에서 DoMyControl 메서드 호출 및 ButtonClicked 이벤트 발생이 잘 될 것입니다.

이 정도 검증이면 IE SmartClient가 여전히 잘 동작하고 있음을 보여주는 것으로 충분하겠죠? ^^

(사용된 프로젝트 예제도 첨부했으니 참고하세요.)




마지막으로, 테스트하다 보면 간혹 이전 컨트롤이 캐시되어 있을 수도 있기 때문에 테스트 하시는 동안 미심쩍으면 (HKCU\Software\Microsoft\Fusion\DownloadCacheLocation 레지스트리에 명시된) 다음의 경로에 있는 컨트롤을 수시로(?) 지워주시면 됩니다.

C:\Users\[사용자 계정]\AppData\Local\assembly

* 명령행에서 "gacutil.exe /cdl"라고 치면 삭제됩니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/5/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 16  17  18  19  20  21  22  [23]  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
13060정성태5/15/20229441.NET Framework: 2012. C# - async/await 그리고 스레드 (3) Task.Delay 재현파일 다운로드1
13059정성태5/14/20227839.NET Framework: 2011. C# - CLR ThreadPool의 I/O 스레드에 작업을 맡기는 방법 [1]파일 다운로드1
13058정성태5/13/20227738.NET Framework: 2010. C# - ThreadPool.SetMaxThreads 사용법
13057정성태5/12/20229419오류 유형: 812. 파이썬 - ImportError: cannot import name ...
13056정성태5/12/20226530.NET Framework: 2009. C# - async/await 그리고 스레드 (2) MyTask의 호출 흐름 [2]파일 다운로드1
13055정성태5/11/20229508.NET Framework: 2008. C# - async/await 그리고 스레드 (1) MyTask로 재현 [11]파일 다운로드1
13054정성태5/11/20226924.NET Framework: 2007. C# - 10진수 숫자를 담은 문자열을 숫자로 변환하는 방법 [11]파일 다운로드1
13053정성태5/10/20226580.NET Framework: 2006. C# - GC.KeepAlive 메서드의 역할
13052정성태5/9/20226634.NET Framework: 2005. C# - 생성한 참조 개체가 언제 GC의 정리 대상이 될까요?
13051정성태5/8/20226565.NET Framework: 2004. C# XingAPI - ACF 검색 결과로 구한 CSV 파일을 통해 퀀트 종목 찾기파일 다운로드1
13050정성태5/6/20226597.NET Framework: 2003. C# - COM 개체의 이벤트 핸들러에서 발생하는 예외에 대한 CLR의 특별 대우파일 다운로드1
13049정성태5/6/20225587오류 유형: 811. GoLand - Error: Cannot find package
13048정성태5/6/20226751오류 유형: 810. "ASUS TUF GAMING B550M-PLUS (WI-FI)" 모델에서 블루투스 장치가 인식이 안 되는 문제
13047정성태5/6/20226748오류 유형: 809. Speech Recognition could not start
13046정성태5/5/20227021.NET Framework: 2002. C# XingAPI - ACF 파일을 이용한 퀀트 종목 찾기(t1857)
13045정성태5/5/20227050.NET Framework: 2001. C# XingAPI - 주식 종목에 따른 PBR, PER, ROE 구하는 방법(t3341 예제)
13044정성태5/4/20226505오류 유형: 808. error : clang++ exited with code 127
13043정성태5/3/20226176오류 유형: 807. C# - 닷넷 응용 프로그램에서 Informix DB 사용 시 오류 메시지 정리
13042정성태5/3/20226581.NET Framework: 2000. C# - 닷넷 응용 프로그램에서 Informix DB 사용 방법파일 다운로드1
13041정성태4/28/20226851개발 환경 구성: 642. Informix 데이터베이스 docker 환경 구성
13040정성태4/27/20227339VC++: 156. 비주얼 스튜디오 - Linux C/C++ 프로젝트에서 openssl 링크하는 방법
13039정성태4/27/20228146.NET Framework: 1999. C# - Playwright를 이용한 간단한 브라우저 제어 실습
13038정성태4/26/20225974오류 유형: 806. twine 실행 시 ConfigParser.ParsingError: File contains parsing errors: /root/.pypirc
13037정성태4/25/20226332.NET Framework: 1998. Azure Functions를 사용한 간단한 실습
13036정성태4/24/20227083.NET Framework: 1997. C# - nano 시간을 가져오는 방법 [2]
13035정성태4/22/20227678Windows: 204. Windows 10부터 바뀐 QueryPerformanceFrequency, QueryPerformanceCounter
... 16  17  18  19  20  21  22  [23]  24  25  26  27  28  29  30  ...