한글2014 에서 HwpObjectLib 지원

안녕하세요.

현재 C# (.NET Framework 4.7.2) 환경에서 문서와 포럼을 참고하여 프로그램을 개발하고 있습니다.

개발 중 한글 버전별 동작 차이가 발생하여 문의드립니다.

개발 환경

  • Language : C#
  • Framework : .NET Framework 4.7.2

발생 현상

1. ReplaceAction 동작 차이

아래 코드에서:

bool isReplaceActionForFileSaveAs_S =
    _hwp.ReplaceAction("FileSaveAs_S", "HwpCustomSaveAs");
  • 한글 2024 : true
  • 한글 2018 : true
  • 한글 2014 : false

한글 2014에서만 ReplaceAction()이 실패하며 다른 포럼 게시글에 FileSaveAs_S_EX 로도 시도 해보았으나 동일 합니다. (매크로 정의 참고로 재 확인)

2. 이벤트 등록 오류

아래와 같이 이벤트를 등록하고 있습니다.

_hwp.DocumentBeforeSave += OnBeforeSave;
_hwp.DocumentAfterSave += OnAfterSave;
_hwp.DocumentAfterClose += OnAfterClose;
  • 한글 2024 : 정상 동작
  • 한글 2018 : 정상 동작
  • 한글 2014 : “해당 인터페이스를 지원하지 않습니다.” 예외 발생

문의사항

  1. ReplaceAction("FileSaveAs_S", "HwpCustomSaveAs")가 한글 2014에서 false를 반환하는 것이 정상 동작인지 궁금합니다.
  2. DocumentBeforeSave, DocumentAfterSave, DocumentAfterClose 이벤트는 한글 2014에서 지원되지 않는 인터페이스인지 궁금합니다.
  3. 만약 한글 2014에서 지원되지 않는 기능이라면, 해당 기능들이 어떤 버전부터 지원되는지 확인할 수 있는 자료가 있을까요?

감사합니다.

추가로 한글 2014 VP 버전은 9.1 에서 테스트 결과

HwpObject hwpobj; = new HwpObject(); 로 사용 할 경우
“널 참조 포인터를 스텁에 전달했습니다” 가 발생 하여

dynamic hwpObject;

Type hwpType = Type.GetTypeFromProgID(“HWPFrame.HwpObject.2”);
hwpObject = Activator.CreateInstance(hwpType);

로 변경 하였고, 이 경우에는 정상적으로 실행이 되며
hwpObject.ReplaceAction() 은 TRUE로 정상 동작 합니다.

다만 dynamic 으로 되어 DocumentBeforSave와 같은 이벤트를 추가 할 수 없어
HwpObject _hwpobj;
_hwpobj = (HwpObject)hwpObject;
로 캐스팅을 하여

_hwpobj.NewDocument += HwpObject_NewDocument;
_hwpobj.DocumentAfterClose += HwpObject_DocumentAfterClose;
이벤트 생성 시 동일하게
“해당 인터페이스를 지원하지 않습니다” 예외가 발생 합니다.

안녕하세요

dynamic 으로 되어 DocumentBeforSave와 같은 이벤트를 추가 하려면
dynamic 객체를 IConnectionPointContainer로 캐스팅 → FindConnectionPoint(IID {F04A09A0-F319-40D5-88CA-CA439CC6820C}) → Advise(sink)로 싱크를 직접 연결하면 됩니다.

감사합니다.

using System;
using System.Runtime.InteropServices;
using ComTypes = System.Runtime.InteropServices.ComTypes;

// 1) 이벤트 소스 dispinterface 정의 (Interop 어셈블리 대용)
//    GUID = 한글이 등록한 _DIHwpObjectEvents IID, 메서드는 DISPID로 매핑
[ComVisible(true)]
[Guid("F04A09A0-F319-40D5-88CA-CA439CC6820C")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IHwpObjectEvents
{
    [DispId(4)]  void NewDocument(int newVal);
    [DispId(8)]  void DocumentBeforeSave(int newVal);
    [DispId(9)]  void DocumentAfterSave(int newVal);
    [DispId(10)] void DocumentAfterClose(int newVal);
    // 필요한 이벤트만 선언해도 됨(나머지 DISPID는 서버가 무시). 전체 목록은 아래 표 참고.
}

// 2) 싱크 구현 — 서버가 Invoke(dispid)로 호출하면 해당 메서드가 실행됨
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class HwpObjectEventSink : IHwpObjectEvents
{
    public void NewDocument(int v)        { /* ... */ }
    public void DocumentBeforeSave(int v) { /* 저장 직전 처리 */ }
    public void DocumentAfterSave(int v)  { /* 저장 직후 처리 */ }
    public void DocumentAfterClose(int v) { /* 닫힘 후 처리 */ }
}

// 3) 연결 (Interop 어셈블리 없이 객체 생성 + Advise)
public class HwpAutomation
{
    private static readonly Guid DIID_HwpObjectEvents =
        new Guid("F04A09A0-F319-40D5-88CA-CA439CC6820C");

    private dynamic _hwp;
    private ComTypes.IConnectionPoint _cp;   // GC 방지 위해 필드로 보관
    private HwpObjectEventSink _sink;        // GC 방지 위해 필드로 보관
    private int _cookie;

    public void Start()
    {
        Type t = Type.GetTypeFromProgID("HWPFrame.HwpObject.2");
        _hwp = Activator.CreateInstance(t);

        // 메서드 호출은 그대로 dynamic 사용
        bool ok = _hwp.ReplaceAction("FileSaveAs_S", "HwpCustomSaveAs"); // true

        // 이벤트 연결: 서버의 연결점을 직접 조회 → Advise
        var cpc = (ComTypes.IConnectionPointContainer)_hwp;
        Guid iid = DIID_HwpObjectEvents;
        cpc.FindConnectionPoint(ref iid, out _cp);

        _sink = new HwpObjectEventSink();
        _cp.Advise(_sink, out _cookie);
    }

    public void Stop()
    {
        if (_cp != null && _cookie != 0)
        {
            _cp.Unadvise(_cookie);
            _cookie = 0;
        }
    }
}