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)
13112정성태7/30/20221738.NET Framework: 2037. C# 11 - 목록 패턴(List patterns) [1]파일 다운로드1
13111정성태7/29/20221636.NET Framework: 2036. C# 11 - IntPtr/UIntPtr과 nint/nuint의 통합파일 다운로드1
13110정성태7/27/20221753.NET Framework: 2035. C# 11 - 새로운 연산자 ">>>" (Unsigned Right Shift)파일 다운로드1
13109정성태7/27/20221469VS.NET IDE: 177. 비주얼 스튜디오 2022를 이용한 (소스 코드가 없는) 닷넷 모듈 디버깅 - "외부 원본(External Sources)"
13108정성태7/26/20221232Linux: 53. container에 실행 중인 Golang 프로세스를 디버깅하는 방법
13107정성태7/25/20221494Linux: 52. Debian/Ubuntu 계열의 docker container에서 자주 설치하게 되는 명령어
13106정성태7/24/20221111오류 유형: 819. 닷넷 6 프로젝트의 "Conditional compilation symbols" 기본값 오류
13105정성태7/23/20221462.NET Framework: 2034. .NET Core/5+ 환경에서 (프로젝트가 아닌) C# 코드 파일을 입력으로 컴파일하는 방법 - 두 번째 이야기 [1]
13104정성태7/23/20221737Linux: 51. WSL - init에서 systemd로 전환하는 방법
13103정성태7/22/20221417오류 유형: 818. WSL - systemd-genie와 관련한 2가지(systemd-remount-fs.service, multipathd.socket) 에러
13102정성태7/19/20221168.NET Framework: 2033. .NET Core/5+에서는 구할 수 없는 HttpRuntime.AppDomainAppId
13101정성태7/15/20223116도서: 시작하세요! C# 10 프로그래밍
13100정성태7/15/20221583.NET Framework: 2032. C# 11 - shift 연산자 재정의에 대한 제약 완화 (Relaxing Shift Operator)
13099정성태7/14/20221848.NET Framework: 2031. C# 11 - 사용자 정의 checked 연산자파일 다운로드1
13098정성태7/13/20221194개발 환경 구성: 647. Azure - scale-out 상태의 App Service에서 특정 인스턴스에 요청을 보내는 방법 [1]
13097정성태7/12/2022854오류 유형: 817. Golang - binary.Read: invalid type int32
13096정성태7/8/20221683.NET Framework: 2030. C# 11 - UTF-8 문자열 리터럴
13095정성태7/7/20221222Windows: 208. AD 도메인에 참여하지 않은 컴퓨터에서 Kerberos 인증을 사용하는 방법
13094정성태7/6/20221091오류 유형: 816. Golang - "short write" 오류 원인
13093정성태7/5/20221384.NET Framework: 2029. C# - HttpWebRequest로 localhost 접속 시 2초 이상 지연
13092정성태7/3/20221495.NET Framework: 2028. C# - HttpWebRequest의 POST 동작 방식파일 다운로드1
13091정성태7/3/20221177.NET Framework: 2027. C# - IPv4, IPv6를 모두 지원하는 서버 소켓 생성 방법
13090정성태6/29/20221015오류 유형: 815. PyPI에 업로드한 패키지가 반영이 안 되는 경우
13089정성태6/28/20221186개발 환경 구성: 646. HOSTS 파일 변경 시 Edge 브라우저에 반영하는 방법
13088정성태6/27/2022827개발 환경 구성: 645. "Developer Command Prompt for VS 2022" 명령행 환경의 폰트를 바꾸는 방법
13087정성태6/23/20221885스크립트: 41. 파이썬 - FastAPI / uvicorn 호스팅 환경에서 asyncio 사용하는 방법 [1]
1  2  3  4  5  [6]  7  8  9  10  11  12  13  14  15  ...