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)
12885정성태12/20/20217825오류 유형: 776. uwsgi-plugin-python3 환경에서 MySQLdb 사용 환경
12884정성태12/20/20216871개발 환경 구성: 620. Windows 10+에서 WMI root/Microsoft/Windows/WindowsUpdate 네임스페이스 제거
12883정성태12/19/20217735오류 유형: 775. uwsgi-plugin-python3 환경에서 "ModuleNotFoundError: No module named 'django'" 오류 발생
12882정성태12/18/20216840개발 환경 구성: 619. Windows Server에서 WSL을 위한 리눅스 배포본을 설치하는 방법
12881정성태12/17/20217338개발 환경 구성: 618. WSL Ubuntu 20.04에서 파이썬을 위한 uwsgi 설치 방법 (2)
12880정성태12/16/20217153VS.NET IDE: 170. Visual Studio에서 .NET Core/5+ 역어셈블 소스코드 확인하는 방법
12879정성태12/16/202113401오류 유형: 774. Windows Server 2022 + docker desktop 설치 시 WSL 2로 선택한 경우 "Failed to deploy distro docker-desktop to ..." 오류 발생
12878정성태12/15/20218474개발 환경 구성: 617. 윈도우 WSL 환경에서 같은 종류의 리눅스를 다중으로 설치하는 방법
12877정성태12/15/20217114스크립트: 36. 파이썬 - pymysql 기본 예제 코드
12876정성태12/14/20216963개발 환경 구성: 616. Custom Sources를 이용한 Azure Monitor Metric 만들기
12875정성태12/13/20216628스크립트: 35. python - time.sleep(...) 호출 시 hang이 걸리는 듯한 문제
12874정성태12/13/20216617오류 유형: 773. shell script 실행 시 "$'\r': command not found" 오류
12873정성태12/12/20217772오류 유형: 772. 리눅스 - PATH에 등록했는데도 "command not found"가 나온다면?
12872정성태12/12/20217590개발 환경 구성: 615. GoLang과 Python 빌드가 모두 가능한 docker 이미지 만들기
12871정성태12/12/20217665오류 유형: 771. docker: Error response from daemon: OCI runtime create failed
12870정성태12/9/20216224개발 환경 구성: 614. 파이썬 - PyPI 패키지 만들기 (4) package_data 옵션
12869정성태12/8/20218516개발 환경 구성: 613. git clone 실행 시 fingerprint 묻는 단계를 생략하는 방법
12868정성태12/7/20217090오류 유형: 770. twine 업로드 시 "HTTPError: 400 Bad Request ..." 오류 [1]
12867정성태12/7/20216757개발 환경 구성: 612. 파이썬 - PyPI 패키지 만들기 (3) entry_points 옵션
12866정성태12/7/202114144오류 유형: 769. "docker build ..." 시 "failed to solve with frontend dockerfile.v0: failed to read dockerfile ..." 오류
12865정성태12/6/20216846개발 환경 구성: 611. 파이썬 - PyPI 패키지 만들기 (2) long_description, cmdclass 옵션
12864정성태12/6/20215288Linux: 46. WSL 환경에서 find 명령을 사용해 파일을 찾는 방법
12863정성태12/4/20217221개발 환경 구성: 610. 파이썬 - PyPI 패키지 만들기
12862정성태12/3/20215940오류 유형: 768. Golang - 빌드 시 "cmd/go: unsupported GOOS/GOARCH pair linux /amd64" 오류
12861정성태12/3/20218159개발 환경 구성: 609. 파이썬 - "Windows embeddable package"로 개발 환경 구성하는 방법
12860정성태12/1/20216277오류 유형: 767. SQL Server - 127.0.0.1로 접속하는 경우 "Access is denied"가 발생한다면?
... 16  17  18  19  20  21  22  23  24  25  26  27  28  29  [30]  ...