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)
13533정성태1/18/20242288닷넷: 2206. C# - TCP KeepAlive의 서버 측 구현파일 다운로드1
13532정성태1/17/20242189닷넷: 2205. C# - SuperSimpleTcp 사용 시 주의할 점파일 다운로드1
13531정성태1/16/20242234닷넷: 2204. C# - TCP KeepAlive에 새로 추가된 Retry 옵션파일 다운로드1
13530정성태1/15/20242189닷넷: 2203. C# - Python과의 AES 암호화 연동파일 다운로드1
13529정성태1/15/20242049닷넷: 2202. C# - PublishAot의 glibc에 대한 정적 링킹하는 방법
13528정성태1/14/20242177Linux: 68. busybox 컨테이너에서 실행 가능한 C++, Go 프로그램 빌드
13527정성태1/14/20242106오류 유형: 892. Visual Studio - Failed to launch debug adapter. Additional information may be available in the output window.
13526정성태1/14/20242203닷넷: 2201. C# - Facebook 연동 / 사용자 탈퇴 처리 방법
13525정성태1/13/20242157오류 유형: 891. Visual Studio - Web Application을 실행하지 못하는 IISExpress
13524정성태1/12/20242219오류 유형: 890. 한국투자증권 KIS Developers OpenAPI - GW라우팅 중 오류가 발생했습니다.
13523정성태1/12/20242027오류 유형: 889. Visual Studio - error : A project with that name is already opened in the solution.
13522정성태1/11/20242188닷넷: 2200. C# - HttpClient.PostAsJsonAsync 호출 시 "Transfer-Encoding: chunked" 대신 "Content-Length" 헤더 처리
13521정성태1/11/20242254닷넷: 2199. C# - 한국투자증권 KIS Developers OpenAPI의 WebSocket Ping, Pong 처리
13520정성태1/10/20242000오류 유형: 888. C# - Unable to resolve service for type 'Microsoft.Extensions.ObjectPool.ObjectPool`....'
13519정성태1/10/20242092닷넷: 2198. C# - Reflection을 이용한 ClientWebSocket의 Ping 호출파일 다운로드1
13518정성태1/9/20242351닷넷: 2197. C# - ClientWebSocket의 Ping, Pong 처리
13517정성태1/8/20242197스크립트: 63. Python - 공개 패키지를 이용한 위성 이미지 생성 (pystac_client, odc.stac)
13516정성태1/7/20242301닷넷: 2196. IIS - AppPool의 "Disable Overlapped Recycle" 옵션의 부작용
13515정성태1/6/20242581닷넷: 2195. async 메서드 내에서 C# 7의 discard 구문 활용 사례 [1]
13514정성태1/5/20242254개발 환경 구성: 702. IIS - AppPool의 "Disable Overlapped Recycle" 옵션
13513정성태1/5/20242175닷넷: 2194. C# - WebActivatorEx / System.Web의 PreApplicationStartMethod 특성
13512정성태1/4/20242142개발 환경 구성: 701. IIS - w3wp.exe 프로세스의 ASP.NET 런타임을 항상 Warmup 모드로 유지하는 preload Enabled 설정
13511정성태1/4/20242161닷넷: 2193. C# - ASP.NET Web Application + OpenAPI(Swashbuckle) 스펙 제공
13510정성태1/3/20242097닷넷: 2192. C# - 특정 실행 파일이 있는지 확인하는 방법 (Linux)
13509정성태1/3/20242121오류 유형: 887. .NET Core 2 이하의 프로젝트에서 System.Runtime.CompilerServices.Unsafe doesn't support netcoreapp2.0.
13508정성태1/3/20242140오류 유형: 886. ORA-28000: the account is locked
1  2  3  [4]  5  6  7  8  9  10  11  12  13  14  15  ...