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

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13397정성태7/23/20233639닷넷: 2134. C# - 문자열 연결 시 string.Create를 이용한 GC 할당 최소화
13396정성태7/22/20233336스크립트: 54. 파이썬 pystack 소개 - 메모리 덤프로부터 콜 스택 열거
13395정성태7/20/20233307개발 환경 구성: 685. 로컬에서 개발 중인 ASP.NET Core/5+ 웹 사이트에 대해 localhost 이외의 호스트 이름으로 접근하는 방법
13394정성태7/16/20233253오류 유형: 873. Oracle.ManagedDataAccess.Client - 쿼리 수행 시 System.InvalidOperationException
13393정성태7/16/20233417닷넷: 2133. C# - Oracle 데이터베이스의 Sleep 쿼리 실행하는 방법
13392정성태7/16/20233284오류 유형: 872. Oracle - ORA-01031: insufficient privileges
13391정성태7/14/20233367닷넷: 2132. C# - sealed 클래스의 메서드를 callback 호출했을 때 인라인 처리가 될까요?
13390정성태7/12/20233338스크립트: 53. 파이썬 - localhost 호출 시의 hang 현상
13389정성태7/5/20233322개발 환경 구성: 684. IIS Express로 호스팅하는 웹을 WSL 환경에서 접근하는 방법
13388정성태7/3/20233511오류 유형: 871. 윈도우 탐색기에서 열리지 않는 zip 파일 - The Compressed (zipped) Folder '[...].zip' is invalid. [1]파일 다운로드1
13387정성태6/28/20233531오류 유형: 870. _mysql - Commands out of sync; you can't run this command now
13386정성태6/27/20233601Linux: 61. docker - 원격 제어를 위한 TCP 바인딩 추가
13385정성태6/27/20233807Linux: 60. Linux - 외부에서의 접속을 허용하기 위한 TCP 포트 여는 방법
13384정성태6/26/20233563.NET Framework: 2131. C# - Source Generator로 해결하는 enum 박싱 문제파일 다운로드1
13383정성태6/26/20233312개발 환경 구성: 683. GPU 런타임을 사용하는 Colab 노트북 설정
13382정성태6/25/20233355.NET Framework: 2130. C# - Win32 API를 이용한 윈도우 계정 정보 (예: 마지막 로그온 시간)파일 다운로드1
13381정성태6/25/20233740오류 유형: 869. Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
13380정성태6/24/20233195스크립트: 52. 파이썬 3.x에서의 동적 함수 추가
13379정성태6/23/20233206스크립트: 51. 파이썬 2.x에서의 동적 함수 추가
13378정성태6/22/20233093오류 유형: 868. docker - build 시 "CANCELED ..." 뜨는 문제
13377정성태6/22/20236871오류 유형: 867. 파이썬 mysqlclient 2.2.x 설치 시 "Specify MYSQLCLIENT_CFLAGS and MYSQLCLIENT_LDFLAGS env vars manually" 오류
13376정성태6/21/20233282.NET Framework: 2129. C# - Polly를 이용한 클라이언트 측의 요청 재시도파일 다운로드1
13375정성태6/20/20232980스크립트: 50. Transformers (신경망 언어모델 라이브러리) 강좌 - 2장 코드 실행 결과
13374정성태6/20/20233107오류 유형: 866. 파이썬 - <class 'AttributeError'> module 'flask.json' has no attribute 'JSONEncoder'
13373정성태6/19/20234398오류 유형: 865. 파이썬 - pymssql 설치 관련 오류 정리
13372정성태6/15/20233108개발 환경 구성: 682. SQL Server TLS 통신을 위해 사용되는 키 길이 확인 방법
1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...