웹, HTML

Web에서 APP로 메세지 전달과 자바스크립트(javascript) 호출

디버그정 2008. 9. 11. 12:14
Web에서 APP로 메세지 전달과 자바스크립트(javascript) 호출
작성자 : 박영목  (gsbsoft) 읽음 : 2417    2006-06-09 오후 3:10:05
427KB
WEB에서 APP로 메세지 전달과 자바스크립트 호출

어느 회사의 요청으로 익스프로에 주소창에 웹브라우즈를 넣는 것을 만들게 되었습니다. 실시간 예측검색으로 불리우더군요... nova의 토마토, dreamwiz의 스마트검색... 처음에 노바를 요여 주더군요.... 이것을 만들 수 있니?  처음에 아주 간단해 보였다. 이스프로 주소창에 작은 버튼이 하나 있고 그것을 누르거나 키를 입력하면 작은 브라우즈가 주소창 밑에 열리면서... 영문으로 입력하면 한글로 보여 주고... 사용자가 검색하고자 하는 문자열을 DB에서 가져와서 보여 주고... 기능은 너무 단순했다. 물론 이 날은 제가 결근한 날.... 다음날 분석해 보라고 해서.... 이것 또 모르는 기술이다. 우리 팀장이 BHO는 아니라고 했다. 그래서 늙은 나에게 이 프로젝터가 넘어왔다.  그래서 분석을 했다. 3일을 해도 헷갈렸다. 사용된 함수들을 보고 헥사코드를 보고 구성된 파일들.... 관찰했지만 어떻게 했는지 볼 때마다 생각이 달라졌다.   그러다 드림위즈의 스마트검색을 보게 되었다. 호호... 보자마자 어떤 원리인지 알겠더군요... 그래서 이런 형태로 만들면 1달 정도 하면 되겠다. 그래서 열심히 만들었습니다. nova는 2달도 더 걸맀게다(기술을 몰라서...) 그래서 어플을 하나 만들어 익스프로에의 주소창 밑에 WebBrowser를 SetParent로 집어넣었다. 그런데... 주소창 안에 버튼도 넣기를 바란다. 그런데 이게 쉽지가 않다. 남의 프로그램에 넣었다. 그곳의 크고 작 함에 따라 위치가 바뀌고... 익스프로를 너려개 띄우면 더 골치 아프고... 속도도 웬지 느렸다... 이렇게 해서는 되지 않겠다.  노바처럼  익스프로 Process에 DLL을 심어야 한다.  2000 이상에서는 리치의 책을 참고해서 집어 넣은 본 적이 있다. 나의 프로그램을 절대 죽지 않게 할 때.... 물론 2000 전용함수를 사용해서... 쓰레드 형식으로 들어간다. 그렇기 때문에 인터페이스가 있는 것은 넣어면 동작을 하지 않습니다. 그래서 알아낸 것이 98과 2000 모두 에서 다 집어 넣을 수 있는 CBT HOOK을 걸어서 그 프로세스 영역에 삽입하는 것으로 집어 넣었습니다. 이제 이 안에서 모든 것을 통제할 수 있다. 그런데... 약간의 통제에 어려움이 있더군요... ㅋㅋㅋ 다른 프로세스로 주입되는 DLL은 크기가 작아야 한다. 델파이나 빌더로 만들면 700k 가까이 나옵니다. 집어넣으면 그 익스프로는 잘 죽습니다... ㅋㅋㅋ 크기가 작아야 하거나... 그래서 VC로 만들었습니다. 그런더니 저희회사 PC 반은 돌아가고 반은 그냥 죽습니다. ㅋㅋㅋ 물론 웹과 어플 사이의 통신 기술이 없어 작은 브라우즈 속에 ActiveX를 만들어 넣었습니다. 처음에 델파이로(ActiveX를 직접 만들어 보지 못해서.. 우리 팀장이 만들어 주었음) 그래도 계속 묻고 하기가 번거로워 제가 어느 강의를 보고 하루만에 빌더로 만들었습니다. 그런데 이 ActiveX 용량도 700k 가까이... 작은 브라우즈 창만 열리면 잘 죽습니다. 그래서 이것도 VC로 만들자... 그래서 VC로 만드니... 200K 정도 그래도 잘 안되는 PC가 있어서 VC에 있는 ATL로 만들었습니다. 44K 이제 잘 돌아가더군요....  그런데 또 죽는 컴이 있었습니다. 그래서 도저히 안되겠다. 작은 브라우즈만 열리면 죽으니까? 아예 OBJECT를 빼자 그러면 통신을 어떻게 하지... WebBrowser를 DLL로 만들면 동작되지 않는 것이 아주 많습니다. 경험을 해보아야 압니다.... 그래서 꼭 웹과 연동이 필요한데.... 웹쪽 기술 경험이 없어서.... 또 goole 찾기 시작했습니다. 자바 스크립트는 쉽게 호출 가능하더군요. 처음에 Navigate 함수를 사용해서 했습니다. 되더군요... 그런데 사용될 때마다 커서가 아주 바쁘게 바뀝니다. 보기 싫더군요. 그래서 execScript 함수를 사용했습니다. VC에서는 자료가 많았습니다. 그래서 그럭저럭 호출을 했습니다. 그런데 웹에서 어플로 어떻게 보내는 방법을 몰라 또 찾았습니다. BeforeNavigate2함수를 이용하는 것이었습니다. 이것도 VC에서는 쉽게 찾을 수 있고 Builder에도 쉽게 적용이 되었습니다. 자바스크립트 호출에 관한 것이 Delphi는 있던데,,, 빌더용이 없더군요... 물론 비슷한데... 이쪽에 익숙하지 않고.... 하나라도 값이 잘못되면 동작되지 않는 것을 것 우리가 다 알기에 또 찾았습니다. 히브리어 글자 같은 웹 사이트에서 찾아습니다... 빌더를 사용하는 곳이 이렇게 적은가???? 조금 짜증이 나더군요.... 이렇게 해서 다 해결했습니다. 그런데 다 만들고 나서 그날 저녁 다른 사무실 디자이너 익스프로에 네이버 검색창 같은 것이 붙어 있더라구요... 이것은 툴바 같은데... 그런데 제가 만든 기능이랑 또 같은 것이 있더군요.... 그러면 이런이 이미 많이 보급... 다른 사람의 말을 빌리면 나온지 얼마 안되었다고 하는데....... 아... 허무,,,,  저는 이곳을 파라 하면 그냥 이마빽이로 밀고들어가는 것만 있어서,... 인터넷도 게임도 노는 것도 전혀 모릅니다... 그냥 찾고 연구만 하는데....  누가 이걸 만들라고 한거야~~~~....

힘들게 얻은 것 볼랜드포름에 없는 것 같아 올립니다.   너무 쓸데없는 이야기 봐주셔서 감사합니다.  몇 주 프로그램 한다고 말을 안해서.... 까깝해서.... 수다를 떨었습니다.  ㅋㅋㅋㅋ

//------------ 

//---------------------------------------------------------------------------

#include <vcl.h>
#include <mshtml.h>         //요놈을 꼭 포함하세요

#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "SHDocVw_OCX"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  //현재 이 실행파일의 경로를 가지고 온다.
  char cPath[_MAX_PATH];     //현재 프로그램의 실행경로를 저장하기 위한 것이다.  GetCurrentDir();을 사용하니 바로가기 같은 것에서 쉽게 변질 될 수 있음을 알고 이것을 선호하게 됨
  DWORD dwLen;
  dwLen = ::GetModuleFileName( NULL, cPath, _MAX_PATH-1 );

  char *p;
  p = strrchr( cPath, '\\' );                                                   //C:\nnnn\nnnn\owner.exe -> C:\nnnn\nnnn\만 얻게 된다.
  *(p+1) = 0x00;

  AnsiString asUrl = cPath;
  asUrl = asUrl + "index_direct.html";  //로컬에서 불러오기, 웹에서 하려면 "http://XXXXXXX.com/index_direct.html" 이렇게 입력하면 되겠지요
  wbEnterMobile->Navigate( WideString(asUrl).c_bstr(), EmptyParam, EmptyParam, EmptyParam, EmptyParam );
}
//---------------------------------------------------------------------------

//Web에서 locate로 보내는 것(주소창으로 보내는 것) 여기서 가로채 버린다.  이것은 응용 안이니까? 여러분이 마음대로 할 수 있게지요...  그냥 파싱만 잘 하시면 됩니다. ㅋㅋㅋㅋ 
void __fastcall TForm1::wbEnterMobileBeforeNavigate2(TObject *Sender,
      LPDISPATCH pDisp, Variant *URL, Variant *Flags,
      Variant *TargetFrameName, Variant *PostData, Variant *Headers,
      VARIANT_BOOL *Cancel)
{
  AnsiString APP, as;

  APP = "app:";
  as = (AnsiString)*URL;
  as = as.SubString(1,4);

  if( as.AnsiCompare( APP )==0 )   //app가 붙어 있으면 여기서 가로채 버립니다. 웹에서 이리로 보낸다.
  {
    ShowMessage( (AnsiString)(*URL) );
    *Cancel = true;
  }
  else
  {
    *Cancel = false;
  }

}
//---------------------------------------------------------------------------


void __fastcall TForm1::Button3Click(TObject *Sender)  //Navigate를 이용한 자보 호출
{
  wbEnterMobile->Navigate( WideString( "javascript:ReceiveMsgFromMsg( \"GSBSOFT\" )" ) );
}
//---------------------------------------------------------------------------

/*          http://www.wischik.com/lu/programmer/webform.html에서 얻은 소스파일
IHTMLDocument2  *doc = WebformGetDoc(hwebf);
IHTMLWindow2 *win;
HRESULT hr = doc->get_parentWindow(&win);
if (SUCCEEDED(hr))
{ BSTR cmd = L"MyJavascriptFunc(\"argument\")";
  VARIANT v; VariantInit(&v);
  win->execScript(cmd,NULL,&v);
  VariantClear(&v);
  win->Release();
}
doc->Release();
*/

//execScript을 이용한 자바호출
void _fastcall ExecuteScript( IHTMLDocument2 *doc, AnsiString script, AnsiString language )
{
  IHTMLWindow2 *win;
  HRESULT hr;
  VARIANT v;

  if( doc )
  {
    hr = doc->get_parentWindow(&win);
    if( SUCCEEDED(hr) )
    {
      try
      {
        VariantInit(&v);
        win->execScript( WideString(script), WideString(language), &v );
        VariantClear(&v);
        win->Release();
      }
      __finally
      {
        win = NULL;
      }
    }
  }
}

/*           http://forum.sources.ru/index.php?showtopic=85381 에서 얻은 소스파일
IHTMLDocument2 *HTMLDocument = NULL;
IPersistFile *PersistFile = NULL;
LONG ilFramesCount = 0;
AnsiString slTmpFileExtension = ".html";
// Falls eine Seite geladen:
if(!CppWebBrowser->Busy && CppWebBrowser->Document &&
AnsiString(CppWebBrowser->LocationURL) != "about:blank" &&
SUCCEEDED(CppWebBrowser->Document->QueryInterface(
IID_IHTMLDocument2, (LPVOID*)&HTMLDocument)))
..
.
*/

void __fastcall TForm1::Button4Click(TObject *Sender)
{
  IHTMLDocument2 *HTMLDocument = NULL;

  if( SUCCEEDED( wbEnterMobile->Document->QueryInterface(IID_IHTMLDocument2, (LPVOID*)&HTMLDocument) ) )
  {
    ExecuteScript( HTMLDocument, "ReceiveMsgFromMsg( \"GSBSOFT\" )", "javascript" );
    HTMLDocument->Release();
  }
}
//---------------------------------------------------------------------------