ActiveX에서 IE제어하기

From YYpBD's MediaWiki

Jump to: navigation, search

[강좌] 웹브라우져에 삽입된 ActiveX 콘트롤에서 웹브라우져 제어하기..  
자! 간만에 강좌를 하겠심다..

내용은 제목 대로 웹브라우져에 삽입된 액티브엑스에서 웹브라우져 제어하기..

혹은,

두개이상의 ActiveX콘틀롤들끼리 대화하기...

물론 이 두개는 한 창안에 두개가 다 있을수도 있고 서로 다른 창일수도 있고 ^^;;

이하 반말 ^^;;

시작..

1.액티브폼부터 만들자..

액티브폼이란.. 일반 액티브에스 콘트롤하고 똑같은건데 단지 그 콘트롤을 델파이의 폼디자이너로 디자인 할수 있도록 만들어놓은 것이 액티브폼이다..

그러므로 반드시 액티브폼이어야하는 건 아니고 웹브라우져에 삽입되는 액티브엑스 콘트롤이면 다 된다..

자.. 액티브폼을 만들자.

델파이를 시작하고…

파일->뉴->액티브엑스->액티브폼 을 클릭하면 일반 프로젝트 처럼 빈폼이 떨렁 생기는게 아니라…

몇가지를 써넣어야하는 대화상자가 뜬다..

알아서 채워넣자..

오케이하면 그제서야 빈폼이 떨렁 반갑게 뜬다.

저장부터하고..

컴파일해보면 작업 경로에 확장자가 OCX인 파일이 만들어진다..

메뉴에서 프로젝트 -> 웹디플로이먼트옵션 을 클릭하자

그러면 에디트가 세개가 뜨는데 위,아래 두개는 작업 경로를 써넣자

가운데는 만들어질 ocx파일명을 써넣자. 이거는 http://www.어쩌구/저쩌구.ocx 와같이 실제 ocx가 있는 경로를 써넣는건데..

걍 HTML에 써지는거니깐 나중에 고치면 된다.

다음 역시 메뉴에서 프로젝트 -> 웹디플로이먼트를 클릭하면 컴파일을 하고 머라고 머라고 뜬다..

다 닫고 작업경로를 탐색기로 열어보면 좀전에 맹근 액티브액스 콘트롤을 삽입하는 HTML파일이 만들어진다.

그걸 델파이 에디터로 열어보면 <OBJECT 태그가 삽입되어져 있는 것을 알수있을것이다.

그 HTML을 실행하기 전에 OCX를 레지스트리에 등록부터 해야한다 RegSvr32.exe를 이용해서 등록해도 좋고 프로젝트 매니져에서 xxxx_TLB.pas파일을 열어서 F12를 누르면 타입라이브러리 에디터가 뜨는데 거기에서 레지스트리편집기 아이콘 같은 버튼을 눌러도 등록해준다.

그 다음에 HTML을 실행해 보면 액티브폼이 삽입되어져 있을것이다.

자 여기까지는 걍 액티브폼을 만들어 본거구…

이제부터는 그 액티브폼에서 웹브라우져를 콘트롤해보자…

젤 쉬운 딱 한가지 예제만 만들어 보겠다…

우선 아까 그 타입 라이브러리 에디터를 연다…

타입라이브러리 에디터의 왼쪽 트리뷰에 이 프로젝트의 XXX_TLB.pas에 들어있는 OLE인터페이스 목록이 나오는데 젤위에꺼를 펼쳐본다.

아마도 프로퍼티가 왕창 많들어져 있을텐데….. 나의 경우는 그 프로퍼티들을 일단 다 제거하고 쓴다…

왜냐면 필요도 없는 것이 소스만 지저분하게 차지하고 있어서리….

거기서 프로퍼티를 지우면 그 인터페이스를 다중상속하는 클래스(폼클래스)에서(____imp.pas) 그 프로퍼티핸들러로 사용되는 메소드들도 제거해주는 것이 좋다.  

예컨데 타입라이브러리 에디터의 맨위에 인터페이스에 Visible이라는 프로퍼티가 두개가 있을것이다.하나는 get이고 하나는 set인데(read, write) 두개를 모두 지우자(물론 하나만 지워도 되는데…위에것이 get이다)

그리고 ___imp.pas파일을 열어서 (폼이 있는 유닛) 폼클래스에서 Get_Visible, Set_Visible을 찾아서 지우면 된다.

자.. 이제 인터페이스에 window객체를 추가해보자.

Window객체는 웹브라우져의 window다 자바스크립트 상에서는 주로 이렇게 쓴다…

<script>
window.close();
</script>

자 우리가 말하는 window란 바로 저 window를 말한다.

저 window를 우리의 폼에서 다룰수 있으면 되겠다.

우선 타입라이브러리 에디터에서 맨위에 인터페이스를 선택하고 오른쪽 버튼을 클릭한다. New를 클릭하고 Property를 클릭한다. 물론 메소드를 만들거라면 메소드를 클릭한다.

그러면 새 프로퍼티가 두개(get, set)가 생기고 밑에꺼의 캡션을 수정할수 있는 상태가 되는데 ‘window’라고 써넣자. 그러면 위에껏두 똑같이 바뀐다.

다음으로 이 프로퍼티의 자료형을 정해줘야하는데 오른쪽 화면에서 Type이라는 항목이 그거다 콤보박스에서 IUnknown * 이라고 되있는걸로 선택한다. * 표가 있다.

그리고 저장..

다음으로 ___imp.pas파일을 연다. 폼이 있는 유닛이다.

폼의 클래스에 메소드가 두 개가 추가되어져 있을것이다.

Get_window Set_window 이렇게 두개..

물론 구현부는 걍 begin end로 비워져 있다.

Uses에 MSHTML 을 추가한다.

다음으로 private에다가 다음을 추가한다.

FWindow: IHTMLWindow2;

요렇게 추가한다.

다음으로 Get_window 메소드의 구현부를 다음과 같이 써넣는다.

function TActiveFormX.Get_window: IUnknown;
begin
Result := FWindow;
end;

글구 Set_window 메소드에는 다음과 같이..

procedure TActiveFormX.Set_window(const Value: IUnknown);
begin
FWindow :=  Value as IHTMLWindow2;
end;

자.. 이걸로 기본 준비는 다 됐고..

이제 테스트 해볼 것을 만들자..

버튼을 하나 올려놓고…

온클릭에 이렇게 코딩하자꾸나..

procedure TActiveFormX.Button1Click(Sender: TObject);
begin
FWindow.close;
end;

내용은 보면 알겠지만 액티브콘트롤이 들어가 있는 웹브라우져를 닫으라는것이다.

아까 자바스크립트로 썼던거하고 똑같은 내용니다.

이제..

바로 HTML을 실행해서 버튼을 클릭하면 곧장 액쎄쓰바이오뢔이션에러가 뜬다.

왜냐하면

window프로퍼티를 만들어만 놨지.. 프로퍼티에 값을 할당하지 않았기때문이다..

물론 if FWindow <> nil then  이렇게 확인하면 에러는 면하겠지....

HTML을 연다…(지금 여는 사람은 아까 열라고 했을 때 안열어 본사람이겠지..)

<OBJECT 태그가 있을텐데..

<OBJECT 에는 아직 id가 부여되어있지 않다..

id를 부여하자…

<OBJECT
id="Form1"
  classid="clsid:B51C2035-8E2F-46C0-B4B8-AFBE5D7FB567"
  codebase="ActiveFormProj1.ocx/ActiveFormProj1.ocx#version=1,0,0,0"
  width=864

델파이답게 Form1이라고 써넣었다

<PARAM 태그를 이용해서 이 오브젝트의 window프로퍼티를 세팅해주면 좋으련만..

그렇게는 안된다… 생각같아서는 ..

<PARAM Name="window" Value="javascript:window">

요렇게 하면 될것두 같은데… 암튼 안된다..

그래서 천상 <SCRIPT 태그를 써서 동적으로 세팅해줘야한다.

<SCRIPT>
Form1.window = window;
<SCRIPT>

요렇게..

자.. 다 됐다.

이제 HTML을 실행하고 버튼을 클릭하면 뭐라고 나오나…

현재 창이 메인 창이므로 걍 닫히지는 않고 머라고 머라고 궁시렁 거리면서 닫을거냐고 물을거다..

암튼..

액티브엑스 콘트롤에서 웹브라우져는 이렇게 제어하면된다.

만약 HTML상에 플레시가 있고 이것을 액티브엑스에서 제어하려면..

IHTMLWindow2대신에 플레시 인터페이스를 사용하고

스크립트에서 Form1.window = window; 하는 대신에 플레시 콘트롤의 ID로 세팅하면 될것이다.

이후로는

해당 인터페이스(IHTMLWindow2)를 얼마다 잘 다루느냐가 중요할것이다.

한 가지 더…

HTML이 두개 있고 (하나는 팝업창이라 치자..)

Main HTML의 콘트롤에서 Popup HTML의 콘트롤을 제어를 할때도 이와 같이 하면 된다..

다시 말해..

두 개의 창에 모두 각각의 액티브엑스 콘트롤이 들어가 있고(물론 똑같은거 일수도 있고 다른 콘트롤일수도 있고..)

이쪽 콘트롤에서 저쪽 콘트롤을 제어하려면

이쪽 콘트롤의 인터페이스에 저쪽 콘트롤을 제어하기 위한 프로퍼티를 하나 만든다..

두개가 같은 콘트롤이라면 걍 자신의 인터페이스형 * 을 추가하면 되겠고 서로 다른 형이라면 Iunknown * 을 추가하면된다.

두개가 다른 OCX일때는 서로의 ___TLB.pas파일을 uses해준다.

그리고..

한쪽에서 다른 한쪽을 열 때..

var
SubWindow: IHTMLWindow2;
var
SubWindow := FWindow.Open( “Sub.htm”, ‘Sub” “width=200 height=300”, False );
SubWindow.opener = Self;

요렇게 해준다.

즉, FWindows.Open 메소드의 리턴값이 새로 열리는 창의 window인데(IHTMLWindow2)

그 window의 opener프로퍼티에 자기 자신을 세팅해 놓는것이다.

자.. 그리고 열리는 Sub.htm의 콘트롤에서는 Set_window와 같이 초기화로 사용하기 적당한 메소드에서

var
FMain: IMain;
begin
FMain := Iunknown( Fwindow.opener ) as IMain;

요렇게 하면 저쪽에서 이쪽을 다룰수 있게된다.


물~~론....

두 개의 콘트롤이 같은 창에 있으나 다른 창에 있으나....

자…

대충 그림 한 장 없이 주저리 주저리 떠들었는데..

일단 함 해보고..잘 안되면…한번 더 해보자..그래도 안되면 될때까지 해보자..

델/파/이/만/세






[답변]veX폼에서 Explorer제어..  
손병찬 wrote:
> 익스플로에서 ActiveX폼을 올린다음 익스플로를 ActiveX폼이제어할려면 어떻게 해야합니까?? 예를들어 익스플로에서 F5(새로고침)을 누르면 ActiveX폼이 먼저 액션을 취하게 하고싶어요..

간단하게 예제로 설명 드리겠습니다.

IOleInPlaceActiveObject 를 상속받습니다.

TOCXControl = class(TActiveForm, IOCXControl, IOleInPlaceActiveObject);

이런식으로요.

   function PreTranslateMessage(var Msg: TMsg): BOOL;
   function TranslateAccelerator(var Msg: TMsg): HRESULT; stdcall;
   function OnFrameWindowActivate(fActivate: BOOL): HResult; stdcall;
   function OnDocWindowActivate(fActivate: BOOL): HResult; stdcall;
   function ResizeBorder(const rcBorder: TRect; const uiWindow:
     IOleInPlaceUIWindow; fFrameWindow: BOOL): HResult; stdcall;
   function EnableModeless(fEnable: BOOL): HResult; stdcall;
   function GetWindow(out wnd: HWnd): HResult; stdcall;
   function ContextSensitiveHelp(fEnterMode: BOOL): HResult; stdcall;

를 public 안에 추가하고 구현해 줍니다. 인터페이스 구현부입니다.

function TOCXControl.PreTranslateMessage(var Msg: TMsg): BOOL;
begin
result := false;
case Msg.message of
   WM_KEYDOWN,
   WM_KEYUP:
   begin
  
     case Msg.wParam of // F3, F11, TAB, 방향키는 제외
       // place as many as you want such as VK_F4, VK_F12, etc.
       VK_F3,
       VK_F5:
       begin
         // 콘트롤에게 메세지를 직접 보내세요. 아니면 바로 여기서 처리하세요.
         result := true; // Tell IE we've handled these, otherwise return false!
       end;
              
     end;

   end;

end; //end case
end;


function TOCXControl.TranslateAccelerator(var msg: TMsg): HResult;
var
Used: boolean;
begin
// 이 키를 핸들링하고 있습니까? 또는 IE 는 그것들을 핸들링하고 있습니까?
Used := PreTranslateMessage(Msg);
if (Used) then
   result := S_OK // 키를 핸들링
else
   result := S_FALSE; //Le IE handling the key!
   // Beep;
end;

function TOCXControl.GetWindow(out wnd: HWnd): HResult;
begin
// FWincontrol 은 당신의 콘트롤입니다. 이름은 당신이 정한대로...
if self.HandleAllocated then
begin
   wnd := FWincontrol .Handle;
   Result := S_OK;
end
else
   Result := E_FAIL;
end;

나머진 전부 Result := S_OK; 해주신 후 PreTranslateMessage 에서 입력받기를 원하는 키를 잡아서 처리하심 됩니다..

그럼 즐푸하세요~



맞춤검색