유돌이

calendar

1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

Notice

2011. 7. 9. 10:55 핫이슈

COM은?
-.컴포넌트 객체 모델 (Component Object Model)의 약자이다. COM은 컴파일과 링크가 되어 있는 바이너리코드로 객체지향 프로그래밍이 가능하게 해주는 윈도우의 기능 중에 하나이다.
-."인터페이스라는 미리 정의된 루틴들을 통해 객체들 사이의 상호작용을 가능하게 해주는 객체기반의 바이너리 표준"라고 MS에서 정의 해 놓았다. 이 말은 객체(Application도 포함)들 사이에 인터페이스가 있는데, 이 인터페이스를 통해 객체간의 공유가 가능하다. 분산환경(Corba, COM) 프로그래밍에는 각각 인터페이스를 정의 하는 표준적인 룰과 그를 응용한 룰(타입 라이브러리 등)이 있다.
-.인터페이스가 상속과 다형성 등의 할 수 있으므로 바이너리 코드기반으로 객체지향 프로그래밍이 가능하다.
-.COM 객체는 위에서 말했듯이 바이너리코드 이다. 이것을 프로세스 단위로 실행 시켜 주어야 한다. 그 프로세스 단위 안에 COM 객체는 1개 이상 있을 수 있다. 또 그 프로세스는 DLL (in-process), EXE (out-of-process) 형태로 만들어질 수 있다.
-.이상 위의 내용을 정리하면 "COM은 인터페이스라는 약속을 정해놓고 특정 프로세스단위 내에 존재하는 클래스를 지금 개발자가 만들고 있는 Application의 인스턴스로 갖다 쓰자." 라고 이해 하자. 추가로 "그 인터페이스를 상속 받아서 다른 COM Class도 만들 수 있다." 라고 이해 하자.
-. 위의 내용을 그림으로 그린 것이 [그림1] 이다.

[그림1] COM의 기본구조.

[그림1] 같이 COM객체는 COM 서버 내에 존재해야 하고, 각각의 COM 객체는 1개 이상의 인터페이스를 통해 Client Application 에게 COM객체 자신의 기능을 노출시킨다. Client Application은 노출된 인터페이스의 GUID (= IID)를 가지고 해당 COM 객체에 접근할 수 있는 것이다. COM 객체 자체가 어떤 일을 하고 그에 따른 함수를 노출하기만 하면(인터페이스를 통해서 ) Client Application 에서는 COM 객체가 어떻게 구현되어있는지 알지 않아도 COM 객체의 기능을 사용할 수 있다. 그렇다면 인터페이스를 이해할 필요가 있을 것이다. 아래에 인터페이스의 기본원리와 어떤 규칙을 따르는지 알아보자.

Interface는?
-.인터페이스는 COM 객체를 외부에서 사용할 수 있도록 하는 매개체 역활을 한다.
-.인터페이스는 함수들의 선언으로만 구성되어있고 COM 객체에서 인터페이스의 함수를 구현해 준다.
-.인터페이스를 서로를 식별하기 위해 GUID 타입의 128bit의 유일한 값을 가진다.
-.인터페이스는 언어 독립적으로 제작가능하고 인터페이스 내의 함수들은 포인터를 통해서 접근할 수 있다.

COM 서버의 형태는?
-. 위에서 COM객체는 COM 서버 내에 존재해야 한다고 설명했는데, COM 서버의 형태에 따란 Client Application에 바인딩이 달리 된다. [그림2]는 이것을 설명하는 그림이다.


[그림2-1 ] In-Process 의 형태


-. [그림2-1]의 In-Process는 COM 서버가 *.DLL로 제작되어있을 경우 이다. DLL로 되어있는 COM 객체에 Client Application이 접근하면 Client Application의 프로세스내에 COM 서버의 인스턴스가 바인딩 된다. 주로 ActiveX 컨트롤이 이런 형태이다. 익스플로어에서 COM서버내의 COM 객체를 호출할 때 익스플로어 프로세스내에 바인딩 되는 것이다. 참고로 ActiveX 컨트롤의 OCX 파일은 구조적으로 DLL과 동일하다.



[그림2-2] Out-Of-Process 의 형태


-. [그림2-2]의 Out-of-process는 COM 서버가 *.EXE로 제작되어있을 경우 이다. EXE로 되어있는 COM 객체에 Client Application이 접근하면 COM 서버는 자체적으로 프로세스를 생성된다. 내부적으로 Client Application에서는 Proxy로 COM서버의 Stub으로 연결된 구조로 In-process 보다 복잡하지만 개발자는 별다른 신경을 쓰지않아도 In-Process와 동일하게 작성하면 된다. 단지 Client Application내에 COM 서버가 인스턴스화 되는지 아니면 다른 프로세스로 생성 되는지 가 중요하다. 그래서 여러 Client Application에서 하나의 COM 객체를 호출할 때 Out-of-Process의 경우에는 호출한 Client Application의 수 만큼 COM 서버 프로세스가 생성되고, In-Process의 경우에는 호출한 Client Application의 수 만큼 COM 서버 인스턴스가 생성되는 것이다.

-. 그 외로 다른 컴퓨터의 COM서버의 COM객체를 호출하는 구조의 Remote COM 이 있다. 하지만 이 문서에는 따로 언급을 하지 않겠다.

COM의 확장이란?
-.MS나 그 외 여러 문서를 살펴보면 OLE, ActiveX, COM 등의 정의를 분명하게 하지않아서 혼동의 여지가 있다. 어떤 곳에서는 COM에서 OLE한 면이 없으면 ActiveX 이라고도 하고 OLE3.0에서 부터 COM를 ActiveX라고 부르기도 하지만 모두 틀린 말은 아니다.
-.그래도 계속 혼동스럽 다면 기본 COM에 추가된 기능, 확장된 기능 이라고 생각하자. (단어에 연연하지 말자는 뜻 이다.)
•.Automation Server (독립실행 가능한 Application(EXE)이나 DLL이 프로그래밍을 할수 있도록 객체(COM객체)를 다른 애플리케이션에 제공하는것)
•.Automation Control (위에서 설명한 Automation Sever에서 제공된 COM 객체를 이용하는 Client Application)
•.ActiveX Control(프로그래밍의 언어에 상관 없이 일반 컴포넌트처럼 사용할 수 있고 웹에서도 사용 가능한 객체)
•.Type Library (COM 서버내의 COM객체에 대한 정보를 Client Application에서 사용 가능하도록 하는 바이너리 코드. 표준적인 방식으로 저장되므로, 프로그래밍의 언어와 상관없이 읽을 수 있다. 또 COM 서버파일(DLL)등에 함께 저장될 수 있고 따로 저장해서 링크해서 사용할 수 있다. )
-.그 외 ActiveX Documemt , DCOM, MTS 등은 COM를 기초로 확장된 모습이다.

실습 (간단한 COM서버(DLL=In-Process)와 Client Application 만들기. Delphi5 Ent 기준)

-. COM 서버와 COM 객체 만들기.
1. 모든 프로젝트를 종료하고 File|New 해서 New Items 대화상자에서 --> ActiveX 탭 --> ActiveX Library 를 선택하고 [ OK ]버튼을 클릭한다. 여기서 추가한 ActiveX Library는 일반 DLL과 같은 파일을 생성하지만 COM객체를 레지스트리에 등록하고 해제하고 COM 서버 내의 특정 COM객체를 얻을 수 있는 함수를 Export 한다.

2.File|Save 해서 프로젝트명을 COMSrv.dpr로 저장한다. 다시 File|New --> ActiveX 탭 --> COM Object 를 선택하고 [ OK ]버튼을 클릭한다. CoClassName 을 COMObject로 하고 나머지 옵션은 기본사항으로 하고 [ OK ]버튼을 클릭한다.

옵션 설명
•.Instancing
-. Internal = COM객체를 COM 서버 내부적으로만 사용 가능하게 생성한다.
-. Single Instance = Application 마다 하나의 COM 인터페이스 만을 허용. 다른 인스턴스를 요구하면 COM 서버자체를 또 생성한다.
-. Multiple Instance = 여러 Application에서 서버객체를 연결 하면 인스턴스를 계속 새로 성성 한다. In-Process는 이것만 적용 가능하다.
•. Thread Model
-. Single = COM 서버전체가 하나의 쓰레드에서 생성한다. 쓰레드 사용이 불가능 하다.
-. Apartment = COM 객체는 각각의 쓰레드에서 생성된다. STA 라고 부르고  [그림 3-1]의 모습이다.
-. Free = Client Application은 어떤 시점이나, 어떤 쓰레드 상에서도 COM 객체의 메소드를 호출할 수 있다. MTA 라고 부르고 [그림 3-2]의 모습이다.
-. Both = STA와 MTA 둘 다 사용 가능하다.

[그림 3-1] Single Thread Apartment 모델 [그림 3-2] Mutipul Thread Apartment 모델

그림3-1처럼 STA의 경우에는 COM 객체를 생성한 Thread 만이 해당 COM 객체를 접근할 수 있다. 다른 Thread에서 생성한 COM객체는 접근할 수 없다. 그림3-2 처럼 MTA의 경우에는 COM 객체를 생성한 Thread 말고도 다른 쓰레드 에서도 COM객체에 접근할 수 있다. 개발자가 프로젝트가 쓰레드를 사용하지 않는 다면, STA로 만들고 별로 신경 쓰지 않아도 된다.

3. 타입 라이브러리에서 ICOMObject (COM 객체의 인터페이스)에 팝업메뉴을 띄워서 method를 새로 추가한다.

4. Method 이름을 "callDialog" 로 변경하고 오른쪽 파라메타 탭에서 파라메타를 1개 추가 한다. Name = uName , Type = BSTR

5. Method 를 한 개 더 추가해 이름을 "getNowTime" 로 변경하고 오른쪽 파라메타를 1개 추가한다. Name = nowtime, Type = BSTR* , Modifier = [out, retval] nowTime 파라메타는 호출한 Application으로 리턴할 수 있다.

6. Refresh 버튼을 눌러서 현재 상태를 적용한다.
-. 참고로 기본 리턴값인 HResult 는 COM서버의 내장된 객체의 메소드를 호출이 성공, 실패의 리턴값을 돌려준다.

7. File|SaveAll 해서 Unit1.pas를 ComSrvImpl.pas 로 저장한다. 그리고 다음과 같이 소스코드를 작성한다.

 unit ComSrvImpl;
 interface
 uses
   Windows, ActiveX, Classes, ComObj, COMServer_inpro_TLB, StdVcl;
 type
   TMyCOMObject = class(TTypedComObject, IMyCOMObject)
   protected
     function callDialog(const uName: WideString): HResult; stdcall;
     function getNowTime(out nowTime: WideString): HResult; stdcall;
   end;
 implementation
 uses ComServ, Dialogs, SysUtils;
 function TMyCOMObject.callDialog(const uName: WideString): HResult;
 begin
    ShowMessage('이름: ' + uName  +#13#10 + 'COM 서버에서실행된 대화상자');
 end;
 function TMyCOMObject.getNowTime(out nowTime: WideString): HResult;
 begin
    nowTime := TimeToStr(Now);
 end;
 initialization
   TTypedComObjectFactory.Create(ComServer, TMyCOMObject, Class_MyCOMObject,
     ciMultiInstance, tmApartment); //COM Object Factory 에 인스턴스 등록 
 end.

-. Client Application 만들기


[그림 4] Client Application 폼

1. 그림4 처럼 폼을 디자인 한다. 그리고 아래와 같이 소스코드를 작성한다.

  uses COMSrv_TLB, COMObj;
  {$R *.DFM}
  procedure TForm1.Button1Click(Sender: TObject);
  var
    COMObj: ICOMObject;
    strTime: wideString;
  begin
   COMObj := CoCOMObject.Create;
   oleCheck(COMObj.callDialog(Edit1.Text));
   oleCheck(COMObj.getNowTime(strTime));
   Label2.Caption := '호출된 시간: ' + strTime
  end;
 

2. 테스트.
-. 일반적인 DLL 파일은 실행파일과 같은 디렉토리나 Windows\System\ 디렉토리에 위치하면 되지만 COM 서버 DLL은 위치에 상관없도록 레지스트리에 등록해서 사용한다.
-. 레지스트리에 등록되는 내용은 ClassID (CLASS_), Type Libray ID (LibID_), InterfaceID(IID_) 등에 DLL 파일의 위치와 ProID 등이 저장된다.
-. 등록하는 방법은 COMSrv.dpr프로젝트를 Open 하고 RUN 메뉴에 Register ActiveX Server를 선택하면 된다. Out-Of-Process 경우 RUN만 한다.
-. Client Application을 실행하고 [COM 객체의 함수 호출] 버튼을 클릭한다. 그러면 메시지 창과 함께 현재시간이 Label1에 출력되면 COM 서버를 레지스트리 에서 위치를 얻고 난 후에 해당 인터펭이스를 통해 COM서버를 Client Application 내에 바인딩 한다.

Automation 서버 / Client 만들기

- Automation 서버 만들기 ( Out-Of-Process )

-.델파이에서는 자동화 컨트롤러가 자동화 서버를 호출하는 3가지방법을 제공한다.
1.Virtual Method Table (Vtable) 을 이용하는 방식 - Interface를 이용( 초기 바인딩 )
2.Dispatch Interface 를 이용하는 방식 - Idispatch.invoke()를 이용 ( 후기 바인딩 )
3.Variant를 이용하는 방식( 후기 바인딩 )
참고로 성능 Vtable이 가장 좋고, Dispath Interface가 그 다음이고, Variant는 가장 느리다. 델파이에서는 Vtable을 생성하는 Interface방식으로 Client Application을 만들면 되고, COM 객체는 Dual Interface(Vtable, Dispateh Interface) 형식으로 호환성을 생각해서 작성한다.


[그림 5 ] Automation 서버의 폼

1. 그림5 처럼 File|New Application 해서 폼안에 TShape 컴포넌트를 한 개 추가해서 폼을 디자인한다. File|SaveAll해서 프로젝트이름 AutoSrv.dpr 로 Unit1.pas --> SrvFrm.pas 로 한다.

2. File|New 해서 ActiveX 탭 --> Automation Object 를 선택하고 [ OK ]버튼을 클릭한다. CoClassName을 AutoTest 로 하고 나머지는 기본값으로하고 [ OK ] 버튼을 클릭한다.

3. Type Library 에서 IAutoTest 인터페이스를 클릭하고, setShapeType 메소드를 추가한다. 파라메타 탭에서 paramater name = sType , Type = int 로 파라메타 한개를 추가한다.

5. File Save All 해서 COM 객체 유닛을 AutoImpl.pas로 저장한다.

6. AutoImpl.pas 파일에 선언되어있는 setShapeType 메소드를 구현한다.

  uses ComServ,SrvFrm, extCtrls ;
  procedure TAutoTest.setShapeType(sType: SYSINT);
  begin
    Form1.Shape1.Shape := TShapeType(sType);
  end; 

7. 전체를 다시 저장하고, COM 서버를 레지스트리에 등록한다. Out-Of-Process(.Exe)는 실행만 해도 레지스트리에 자동 등록 된다.

- Automation Control 만들기


[그림6 ] Automation Control의 폼

1. 그림6 처럼 File | New Application 해서 폼안에 TEdit 한개와 TUpDown 1개 Associcate 속성을 Edit1 으로 한다. 그리고 TButton 컴포넌트 4개를 추가하고 위에서부터 vTable호출 (Button1) ~ 연결해제 (Button4) 로 캡션을 입력한다.

2. 소스코드를 아래와 같이 작성한다.

  uses AutoServer_TLB, COMObj;
  {$R *.DFM}
  var
    AutoTest: IAutoTest;  // interface 이용
    AutoTestDisp: IAutoTestDisp; //dispinterface 이용
    vAutoTest: Variant; // variant 이용

  procedure TForm1.Button1Click(Sender: TObject); // Interface(Vtable)을 이용해서 COM 객체 생성
  begin  
     AutoTest := CoAutoTest.Create;
    AutoTest.setShapeType(UpDown1.Position);
  end;

  procedure TForm1.Button2Click(Sender: TObject); // Dispatch Interface를 이용해서 COM 객체 생성
  begin
    AutoTestDisp := CreateComObject(Class_AutoTest) as IAutoTestDisp;
    AutoTestDisp.setShapeType(UpDown1.Position);
  end;
 
  procedure TForm1.Button3Click(Sender: TObject); // Variant 변수에 Program ID 값을 넣고 COM 객체 생성
  begin
    vAutoTest := CreateOleObject('AutoServer.AutoTest');
    vAutoTest.setShapeType(UpDown1.Position);
  end;

  procedure TForm1.Button4Click(Sender: TObject);
  begin
    AutoTest := nil; // Pointer 변수 해제
    AutoTestDisp := nil; 
    vAutoTest := Unassigned; //Variant 변수 해제 
  end;

3. 모두 저장하고 Automation Control (Client Application ) 을 실행한다. UpDown 컴포넌트의 값을 0 ~5 사이에서 변경하면서 테스트 해보자.

Excel 97, 2000 을 Control 하는 Automation Controler 만들기

-. MS사에서 만든 많은 제품들이 COM 객체로써 외부에서 Control 할 수 있도록 만들어져 있다. 이번 실습은 Excel 97, 2000 을 간단히 Control 할 수 있도록 COM Controler 를 만들어 본다.


[그림7 ] Excel Controler 폼

- . 델파이 5 에서 Server 탭에 MS의 Office 제품군을 Control 할 수 있도록 컴포넌트를 만들어 놓았는데, 기본적으로 Interface (VTable) 방식으로 접근할수 있다. 물론 다른 방식도 가능하지만 위에서 설명했듯이 Automation 서버를 Control하는 Client Application 을 델파이에서 만들때에는 Interface 방식의 성능이 가장 우수하다.

1. File|New Application 해서 그림7과 같이 TMemo 컴포넌트 1개와 TButton 3개, Server탭에서 TExcelApplication, TExcelWorkSheet, TExcelWorkBook 1개를 폼안에 추가한다.

2. 아래와 같이 소스코드를 작성한다.

  var
    vExcel: Variant;
 implementation
  uses COMObj;

  procedure TForm1.Button1Click(Sender: TObject);
  Var 
    i: Integer;
  begin
    varExcel := CreateOleObject('Excel.Application');
    varExcel.workbooks.Add;
    for i := 0 to Memo1.Lines.Count-1 do
      varExcel.workbooks[1].worksheets[1].Cells[i+1, 1] := Memo1.Lines[i];
    varExcel.Visible := true;
  end;

  procedure TForm1.Button2Click(Sender: TObject);
  var
    i: Integer;
  begin
    ExcelApplication1.Connect;
    ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Item[1]);
    ExcelWorkSheet1.ConnectTo(ExcelWorkBook1.Sheets[1] as _WorkSheet);
    with ExcelWorkSheet1 do
      for i := 0 to Memo1.Lines.Count-1 do
        Cells.Item[i+1, 1] := Memo1.Lines[i];
    ExcelApplication1.Visible[0] := True;
  end;

  procedure TForm1.Button4Click(Sender: TObject);
  begin
    if not varIsEmpty(varExcel) then
      varExcel.quit;
    if not varIsEmpty(ExcelApplication1.Application) then
    begin
      ExcelApplication1.Disconnect;
      ExcelApplication1.Quit;
    end;
  end;
 

3. 실행 하고 버튼을 눌러본다. 위의 예제는 PC에 Excel 프로그램이 설치되어 있는 경우에만 제대로 동작 한다.

-이외에도 Delphi에서는Excel의 차트등 거의 모든 객체를 Control 할수 있다. Excel .vbs 파일을 생성해서 실행할수도 있다
아래 소스코드는 Excel 내에 특정 매크로를 생성해서 실행시키는 예제 이다.

  procedure TForm1.Button1Click(Sender: TObject);
  var
    str: String;
    vModule: OleVariant;
  begin
    str := 'Sub Macro()' + #13#10 +
         'Dim X, Y' + #13#10 +
         'Dim X_END, Y_END' + #13#10 +
         'Dim Min, Max' + #13#10 +
         'If Cells(1, 2) = "N" Then'+ #13#10 +
         'X_END = 21'+ #13#10 +
         'Else'+ #13#10 +
         'X_END = 25'+ #13#10 +
         'End If'+ #13#10#13#10+
         'Y_END = Cells(1, 3) + 4'+ #13#10#13#10+
         'For Y = 5 To Y_END'+ #13#10 +
         ' For X = 2 To X_END'+ #13#10 +
         '   Min = Cells(3, X)'+ #13#10 +
         '   Max = Cells(4, X)'+ #13#10 +
         '   Cur = Cells(Y, X)'+ #13#10#13#10+
         '   Cells(Y, X).Font.ColorIndex = 2'+ #13#10 +
         '   Cells(Y, X).Font.FontStyle = "굵게"'+ #13#10#13#10+
         '   If (Min <= Cur) And (Cur <= Max) Then'+ #13#10 +
         '     Cells(Y, X).Interior.ColorIndex = 5'+ #13#10 +
         '   Else'+ #13#10 +
         '     Cells(Y, X).Interior.ColorIndex = 3'+ #13#10 +
         '   End If'+ #13#10 +
         '  Next X' + #13#10 +
         '  Next Y' + #13#10 +
         'End Sub';

    vModule :=  ExcelWorkBook1.VBProject.VBComponents.Add(1);
    vModule.CodeModule.AddFromString(str);
    ExcelApplication1.Run('Macro');
  end; 

'핫이슈' 카테고리의 다른 글

★냉동인간★ 부활시킬 단초 발견!!!  (0) 2011.07.09
고지전 예고편!!  (0) 2011.07.09
나도가수다!! 도플겡어들..ㅋ  (0) 2011.07.08
연금복권 인터넷구매 방법!!!!  (0) 2011.07.08
옵티머스3d 상세스펙  (0) 2011.07.08
posted by 유돌이
2011. 7. 5. 13:10 델파이

Creating a Dynamic Link Library

The following few lines will demonstrate how to create a simple DLL using Delphi.

For the beginning start Delphi and select File | New ... DLL. This will create a new DLL template in the editor window. Select the default text and replace it with the next piece of code.

 library TestLibrary;
 
 uses SysUtils, Classes, Dialogs;
 
 procedure DllMessage; export;
 begin
   ShowMessage('Hello world from a Delphi DLL') ;
 end;
 
 exports DllMessage;
 
 begin
 end. 
If you look at the project file of any Delphi application, you’ll see that it starts with the reserved word Program. By contrast, DLLs always begin with the reserved word Library. This is then followed by a uses clause for any needed units. In this simple example, there then follows a procedure called DllMessage which does nothing except showing a simple message.

At the end of the source code we find an exports statement. This lists the routines that are actually exported from the DLL in a way that they can be called by another application. What this means is that we can have, let's say, 5 procedures in a DLL and only 2 of them (listed in the exports section) can be called from an external program (the remaining 3 are "sub procedures" in a DLL).

In order to use this simple DLL, we have to compile it by pressing Ctrl+F9. This should create a DLL called SimpleMessageDLL.DLL in your projects folder.

Finally, let's see how to call the DllMessage procedure from a (statically loaded) DLL.

To import a procedure contained in a DLL, we use the keyword external in the procedure declaration. For example, given the DllMessage procedure shown earlier, the declaration in the calling application would look like :

 procedure DllMessage; external 'SimpleMessageDLL.dll' 
the actual call to a procedure will be nothing more than
 DllMessage; 
The entire code for a Delphi form (name: Form1) with a TButton on it (name: Button1) that's calls the DLLMessage function could be:
 unit Unit1;
 
 interface
 
 uses
    Windows, Messages, SysUtils, Variants, Classes,
    Graphics, Controls, Forms, Dialogs, StdCtrls;
 
 type
    TForm1 = class(TForm)
      Button1: TButton;
      procedure Button1Click(Sender: TObject) ;
    private
      { Private declarations }
    public
      { Public declarations }
    end;
 
 var
    Form1: TForm1;
 
   procedure DllMessage; external 'SimpleMessageDLL.dll'
 
 implementation
 
 {$R *.dfm}
 
 procedure TForm1.Button1Click(Sender: TObject) ;
 begin
    DllMessage;
 end;
 
 end. 

posted by 유돌이
2009. 6. 26. 13:57 델파이

uses
 
ActiveX, Shdocvw_tlb, MSHTML_TLB;

type
 
TObjectFromLResult = function(LRESULT: lResult; const IID: TIID; wParam: wParam;
    out pObject): HRESULT;
  stdcall;

function GetIEFromHWND(WHandle: HWND; var IE: IWebbrowser2): HRESULT;
var
 
hInst: HWND;
  lRes: Cardinal;
  Msg: Integer;
  pDoc: IHTMLDocument2;
  ObjectFromLresult: TObjectFromLresult;
begin
 
hInst := LoadLibrary('Oleacc.dll'); @ObjectFromLresult :=
    GetProcAddress(hInst, 'ObjectFromLresult');
  if @ObjectFromLresult <> nil then
  begin
    try
     
Msg := RegisterWindowMessage('WM_HTML_GETOBJECT');
      SendMessageTimeOut(WHandle, Msg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes);
      Result := ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc);
      if Result = S_OK then
       
(pDoc.parentWindow as IServiceprovider).QueryService(IWebbrowserApp,
          IWebbrowser2, IE);
    finally
     
FreeLibrary(hInst);
    end;
  end;
end;

 

 

[※ 참고]

: 프레임의 경우엔 프레임의 인터페이스를 얻는 방법과 Shell Embedding 이란 클래스 핸들을 얻어서 다시 Shell DocObject View 클래스 핸들을 얻고, 다시 Internet Explorer_Server 핸들을 얻으면 됩니다. 그러니까 프레임은 Shell Embedding 클래스 안에 Shell DocObject View가 여러개 있는게 되죠...^^;

 

 

 

 

출처 : http://skyrack.tistory.com/45#recentTrackback 

사진찍는 나귀

posted by 유돌이
2009. 5. 26. 20:24 델파이

uses
 
ActiveX, Shdocvw_tlb, MSHTML_TLB;

type
 
TObjectFromLResult = function(LRESULT: lResult; const IID: TIID; wParam: wParam;
    out pObject): HRESULT;
  stdcall;

function GetIEFromHWND(WHandle: HWND; var IE: IWebbrowser2): HRESULT;
var
 
hInst: HWND;
  lRes: Cardinal;
  Msg: Integer;
  pDoc: IHTMLDocument2;
  ObjectFromLresult: TObjectFromLresult;
begin
 
hInst := LoadLibrary('Oleacc.dll'); @ObjectFromLresult :=
    GetProcAddress(hInst, 'ObjectFromLresult');
  if @ObjectFromLresult <> nil then
  begin
    try
     
Msg := RegisterWindowMessage('WM_HTML_GETOBJECT');
      SendMessageTimeOut(WHandle, Msg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes);
      Result := ObjectFromLresult(lRes, IHTMLDocument2, 0, pDoc);
      if Result = S_OK then
       
(pDoc.parentWindow as IServiceprovider).QueryService(IWebbrowserApp,
          IWebbrowser2, IE);
    finally
     
FreeLibrary(hInst);
    end;
  end;
end;

 

 

[※ 참고]

: 프레임의 경우엔 프레임의 인터페이스를 얻는 방법과 Shell Embedding 이란 클래스 핸들을 얻어서 다시 Shell DocObject View 클래스 핸들을 얻고, 다시 Internet Explorer_Server 핸들을 얻으면 됩니다. 그러니까 프레임은 Shell Embedding 클래스 안에 Shell DocObject View가 여러개 있는게 되죠...^^;

 

 

 

 

출처 : http://skyrack.tistory.com/45#recentTrackback 

사진찍는 나귀

posted by 유돌이
2008. 12. 30. 23:10 C/C++/MFC

[BHO - Browser Helper Object]

 

인터넷 익스플로러를 손쉽게 제어할 수 있는 DLL 파일.

 

인터넷 익스플로러를 시작할 때마다 생겨나 메모리를 공유하고

브라우저 창과 모듈에 어떠한 지시라도 할 수 있는 객체이다.

 

이벤트를 감지하여 띄워진 페이지에 추가 정보를 보여주기 위해 브라우저 창을 만들고,

메시지와 작업을 감시할 수도 있다. 또한 다른 브라우저 침투에 의한 배너 광고 변경,

페이지 감시 및 보고, 홈 페이지 변경 등 스파이 기능도 있다.

'C/C++/MFC' 카테고리의 다른 글

MFC (디바이스 컨텍스트와 관련 클래스)  (0) 2008.12.30
윈도우즈와 메시지  (0) 2008.12.30
API 기초??  (0) 2008.12.30
const 사용법  (0) 2008.12.30
C프로그래밍 별모양~  (0) 2008.12.30
posted by 유돌이
2008. 12. 20. 12:03 ATL / WTL

Browser Helper Object라고 하는 놈은 Internet Explorer의 인스턴스에 연결되어 Explorer의 액션을 제어하고 발생되는 이벤트들을 알아내는 역할을 해줍니다.

 

BHO이 구동되는 원리는

 

Explorer이 구동될때 특정 레지스트리에 등록에 CLSID에 값을 읽어서 Load하게끔 되어 있는데...

 

HKLM

{

    SOFTWARE

    {

        Microsoft

        {   

            Windows

            {

                CurrentVersion

                {

                    Explorer

                    {

                        'Browser Helper Objects'

                        {

 

이 위치가 됩니다.

 

물론 여기에 등록만 되어 있다고 해서...등록된 Dll들이 Load되서 이벤트를 감시하고 제어가 되는건 아닙니다.

일정 규약에 맞게끔 인터페이스가 지원되야 하고 규정된 메써드를 밖으로 노출시켜야 합니다.

 

그 규정된 인터페이스가 IObjectWithSite라는 놈이고...IObjectWithSite인터페이스에 있는 SetSite메써드를 Explorer에서 호출하게끔 되어 있는겁니다.

 

HRESULT Cbhotest::SetSite(IUnknown *pUnkSite)

{

    m_spWebBrowser2 = pUnkSite;

 

    if (m_spWebBrowser2 == NULL)

        return E_INVALIDARG;

    

    m_spCPC = m_spWebBrowser2;

 

    if (m_spCPC == NULL)

        return E_POINTER;

    RetrieveBrowserWindow();

 

    return Connect();

}

 

질문하셨듯이.. Connect()함수는 Explorer에서 SetSite는 자동으로 불려져서 호출됩니다.

 

그 다음부터는 Invoke함수에서.... Explorer에서 발새오디는 이벤트를 감지/제어가 가능해 지는거죠.

아니면 Explorer에 윈도우 메세지를 후킹해서...샘플에서 종료를 막는다거나.,.. 하는 일들을 하게되는거죠...

 

ExDisPID.h

이 파일을 한번 열어 보셨으면 금방 아실텐데요...아쉽....

이건 Explorer의 이벤트 ID가 정의되어 있는 헤더파일입니다.

 

다른 궁금하신 사항들 검색을 해보시거나... 아님 관련 서적을 찾으시면 금방 아실 수 있는 내용이구요.

 

되도록이면 com관련 서적을 한번 보시는 것을 추천합니다...


posted by 유돌이
2008. 12. 20. 12:02 ATL / WTL
출처 AmesianX 님의 블로그 | 아메시안
원문 http://blog.naver.com/amesianx/50002572812

BHO 란 Browser Helper Object 의 약자로 우리가 많이 사용하는 인터넷 익스플로어를 띄우면

BHO 와 같이 작동이 된다. 즉, 인터넷 익스플로어에 DLL 형태로 같이 낑겨들어가는데 하는 행동은

인터넷 브라우저를 제어할 수 있다. 흔히 생각하면 스파이웨어나 인터넷 돌아당기다가 악성코드가

걸려서 시작페이지가 성인사이트로 바뀌어서 뜬다거나 하는 놈이 이 BHO 의 능력을 악용한 거다.

BHO 는 레지스트리에 기록되며 인터넷 익스플로어가 작동될때는 이 레지스트리에 있는 값을 이용

해서 BHO 프로그램을 로딩하고 같이 올라가는데 일단 BHO 가 뜬 상태에서는 BHO 가 전적으로

브라우져를 통제하게 되므로 사용자 개인정보를 훔친다던지 아니면 성인사이트 광고를 한다던지

온갖 잡짓(?)을 다 할 수 있다. 그렇기 때문에 레지스트리에서 시작페이지를 고쳤는데 계속 시작

페이지가 안바뀐다고 울지말자. BHO 를 레지스트리에서 삭제하면 되니까.. ㅎㅎ

이런 BHO 는 ATL 로 개발될수도 있고 MFC 로 개발될 수도 있다. ATL 이 퍼포먼스 면이나 용량면

에서 MFC 보다 좀 낫다고 한다. 그리고 국내에서는 대부분 MFC 로 개발하는 것보다는 ATL 로

COM 을 제작하는 것이 압도적으로 많은 것 같고 일반화된 것 같다. MFC 로 개발하면 상대적으로

쉬운데 국내 분위기는 인정을 안하는 건지 굳이 어려운 ATL 이 더 정보가 많다. 외국은 1:1 인것

같다. 이번에 BHO 를 ATL 로 만들면서 참고한 사이트와 개발하면서 겪은 고난의 역사를 올려본다.

참고로 나는 ATL 의 A 자도 모르고 시작해서 약 3 일 정도 걸려 개념을 잡기위한 참고자료들을

모았다. 그리고 대략 5일정도 되서 개념을 잡고 코드들을 주무를 수 있었다.

페이지의 크기가 제한되어 있는지라 ATL 개발의 완벽한 지식을 주었던 개발백서는 다른 사이트에

올리고 링크를 달려고 한다. 여기에 있는 참고 사이트는 그 개발백서를 제외한 나머지이다.

다음에 올리는 글에 개발백서를 올리려고 한다.. 그 개발백서만 있으면 아마도 ATL 프로그래밍을

처음 시작하는 사람도 2~3일만에 개념을 다 잡을 수 있지 않을까 생각된다..

 

[BHO 를 만들기 위한 설명]
상대적으로 BHO 를 만들기 위한 내용을 잘 설명해 놓았다. 외국 사이트라서
영어인 점을 제외하면 BHO 를 만들기 위해서 어떻게 인터넷 브라우져가 작동하기 때문에
어떻게 해서 작동을 시켜야 한다는 내용이 잘 정리되어 있고 처음 접하는 사람이 읽어볼만 하다.
물론 ATL 로 만드는 것을 설명하고 있다.
http://newssearch.looksmart.com/p/articles/mi_zdpcm/is_200009/ai_ziff7872/pg_2

[팝업 블록커]
팝업 방지기능이 있는 BHO 를 만들 수 있는 법을 설명한다.
그런데 중상급자용 강좌인것고 너무 어렵다. 알아듣기도 힘들고.. 소스 자체만 가치가 있는것 같다.
http://www.codeproject.com/atl/PopupBlocker.asp

[ThumbNailer Visual C++ Image Processing plug-in Tutorial]
그럭저럭 ATL 에 대한 튜토리얼이나 초보자가 참고하기는 좀 그렇다.
http://www.smalleranimals.com/thumbnailer/thumbimgtut.htm

[Example of Handling HTML Element Events in Microsoft Internet Explorer]
MFC 용 코드 이기 때문에 ATL 사용자가 쓰기는 좀 그렇다.. 초보자에게 그다지 도움이 많이 되지 않는다.
http://lists.w3.org/Archives/Public/w3c-wai-ua/2000JanMar/att-0287/htmlevent.htm

[Objvw is a sample that illustrates using Internet Explorer's Automation model and scripting interfaces from within a contained ATL control.]
잘 모르지만 브라우저를 다루는 소스이다. ATL 로 되어있고 참고소스이다.
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/samples/internet/components/objvw/default.asp


[DEVPIA 질답 모음]

- 이벤트 사용법 -
http://www.devpia.com/Forum/BoardView.aspx?no=518183&ref=518183&page=3&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- BHO 와 MSHTML 의 차이 -
http://www.devpia.com/Forum/BoardView.aspx?no=497131&ref=497131&page=4&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- BHO 사용방법 (접근방법) -
http://www.devpia.com/Forum/BoardView.aspx?no=486404&ref=486292&page=4&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- 브라우져를 여러개 띄워도 한개의 BHO 만 실행시킬 수 있나? -
http://www.devpia.com/Forum/BoardView.aspx?no=466840&ref=466840&page=5&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- BHO 로 프레임의 주소와 소스 뽑아오기(불완전) -
http://www.devpia.com/Forum/BoardView.aspx?no=457244&ref=457244&page=5&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- BHO 로 Document 의 HTML 소스 뽑아오기 -
http://www.devpia.com/Forum/BoardView.aspx?no=334979&ref=334969&page=10&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- 브라우저 닫힐때 BHO 가 알수있는 방법 -
http://www.devpia.com/Forum/BoardView.aspx?no=466020&ref=447181&page=5&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- 인터넷 익스플로어의 기본 경로 저장 레지스트리 키 -
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\IEXPLORE.EXE

- BHO에서.. SetSite와 Translate.. 사용시 문제점 -
http://www.devpia.com/Forum/BoardView.aspx?no=456390&ref=456390&page=6&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- [BHO초보]Atladvise,invoke 를 구현하니까, 기존에 작성한 함수가 동작을 안합니다.(참고할만한 소스존재) -
http://www.devpia.com/Forum/BoardView.aspx?no=422640&ref=422640&page=7&forumname=VC_QA&stype=&KeyW=bho&KeyR=title

- BHO 에서 Invoke 재구현으로 이벤트 처리법
http://www.devpia.com/Forum/BoardView.aspx?no=522323&ref=522323&forumname=VC_QA&stype=VCF&KeyW=bho+%c0%cc%ba%a5%c6%ae&KeyR=title

- DISPID_DOCUMENTCOMPLETE가 여러번 불리는 이유 -
http://www.devpia.com/Forum/BoardView.aspx?no=422044&ref=422044&page=1&forumname=VC_QA&stype=&KeyW=dispid&KeyR=title

[블로그 검색]

- ActiveX 에서 이벤트 싱크하기 -
http://blog.naver.com/zzoouc?Redirect=Log&logNo=20312485

- BHO 로 브라우저 요리할 수 있는 완벽한 참고서 -
http://blog.naver.com/jeonghj66?Redirect=Log&logNo=140021348390


[디버깅 참고]
http://www.debuglab.com/knowledge/filetrace.html

 

>> 암복호화 OpenSSL 관련 <<

[암복호화 에 관련된 CryptoAPI 에 관한 글 및 HTML 을 MSHTML 의 도움으로 파싱하는 Moniker 방법]
http://haje.kaist.ac.kr/~oedalpha/tips/WindowsProgramming/

[Subversion 구축과 사용버 OpenSSL 사용법이 존재]
http://www.devpia.com/forum/BoardView.aspx?no=7273&ref=7273&page=1&forumname=vc_lec&stype=

>> 정규 표현식 라이브러리 참고 사이트 <<

[Boost regex 사용법]
http://blog.naver.com/redsusia?Redirect=Log&logNo=60002340337

[참고:누군가 댓글에 Boost 보다 GRETA 가 성능이 더 좋다고 적어놓았음]
http://madchick.egloos.com/302213

[MS 의 GRETA 엔진 사이트]
MS 의 연구원이 개발한 것으로 사용법이 편하고 속도가 빠르다고 함
http://research.microsoft.com/projects/greta/

[가지 각색의 쓸만한 정규표현식 라이브러리를 소개하는 곳]
http://www.oobdoo.com/directory/Computers/Programming/Languages/RegularExpressions/CandC++/

----------------------------------------------------------------------------------------------------------------------------

[개발 히스토리: 문제점 봉착에 관한 고찰]

[문제점1]

Invoke 함수를 사용하는 방법을 쓰려고 하였으나 dispid 값이 자꾸 -525 가 나오는데 그 이유는 제대로
커넥션 포인터를 얻어내지 못하는 것이 아닌가 생각된다. 다음의 정보에서 dispid 값이 -525 이면
DISPID_READYSTATE 값이라는 것을 알 수 있고 브라우져가 아닌 컴포넌트(객체)의 상태값이며 브라우져의
아이디 값이 아닌 것을 추측할 수 있다. 그렇다면 이벤트가 연결이 되지 않은 것이라고 판단되었다.

(dispid 참고 링크)
http://hyons.hp.infoseek.co.jp/ref/dispid.shtml
http://www.4programmers.net/bin/SHDocVw_TLB.pas

문제점을 알기 위해서 SetSite 에 디버깅을 걸었으나 함수에 들어가지지 조차 않는 문제점이 발견되었다.
이와 같은 문제점을 다른 사람도 겪고 있는 것을 데브피아에서 발견하였다.

(데브피아 글)
http://www.devpia.com/Forum/BoardView.aspx?no=543797&ref=491741&page=1&forumname=VC_QA&stype=&KeyW=SetSite&KeyR=titlecontent

SetSite 함수에 들어가지지 않으면 윈도우의 핸들을 얻어올수 없기 때문에 커넥션이 제대로 맺어지지 않아
자기 자체의 객체 dispid 값을 얻어와서 -525 가 들어오는 것으로 판단되었다. 내가 원하는 값은 100 이므로
이 값이 들어와야 문서의 다운로드 완료 시점을 알 수있다.

(해결책 추측제시 1)
레지스트리에 BHO 관련 설정 값을 셋팅하지 않아서 SetSite 함수 안으로 안들어가는 것이 아닌가?
테스트 중...
http://www.devpia.com/Forum/BoardView.aspx?no=520529&ref=520484&page=2&forumname=VC_QA&stype=&KeyW=SetSite&KeyR=titlecontent
다음의 글에서 어떤 사람이 레지스트리에 BHO 를 등록했냐고 물어온다.. ㅡ.ㅡ; 나는 등록 안했는데 등록을 얼렁 해야 겠다...
http://www.devpia.com/Forum/BoardView.aspx?no=486404&ref=486292&page=3&forumname=VC_QA&stype=&KeyW=SetSite&KeyR=titlecontent
나와 똑같이 SetSite 가 콜이 되지 않아서 몸살을 알고 있는 사람이 또 있다니...
http://www.devpia.com/Forum/BoardView.aspx?no=319724&ref=319689&page=5&forumname=VC_QA&stype=&KeyW=SetSite&KeyR=titlecontent


(해결책)
염병헐... 드디어 해결책 발견.. rgs 파일에 레지스트리를 추가해줘야 하는데 하질 않아서 문제가 발생한 거였다..
역시 언제나 나의 육감은 항상 적중한다.. ㅋㅋㅋ ㅡ.ㅡ;

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects

클래스 CLSID 를 기록만 해주면 끝난다..

http://www.devpia.com/Forum/BoardView.aspx?no=455356&ref=454567&page=2&forumname=VC_QA&stype=&KeyW=BHO+%b5%ee%b7%cf&KeyR=titlecontent


(제일 참고에 많이 도움이 된 사이트.. 역시 MSDN)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ietechcol/dnwebgen/bho.asp

마지막 문제점 다이얼로그를 만들어서 트레이에 심어야 하는데 다이얼로그 만들었더니 초기화 에러가 나네.. 썅..

느긋히 서치를 때려보니 야후 뮤직 플레이어를 다이얼로그로 만들어서 플러그인화 시키는 몬가가 있었다..

http://mep.music.yahoo.com/plugins/docs/helloworldplugin_page.html

ㅎㅎㅎ... 위의 ATL 개발백서에서는 듬성듬성 건너뛰고 넘어간 다이얼로그 생성 추가에 관련된 ATL 프로그래밍이
상세히 적혀있다. 이것으로 다이얼로그도 해결이 됐다..


[문제점2]

이미 한번 만들어서 잘 작동되는 프로그램을 다시 만들고 나니 Invoke 함수로 들어가지지 않는다.

(해결책 추측제시 1)
아마도 이벤트를 연결해주는 connect(개인함수) 함수를 임의적으로 제거해서 그런것이 아닌가...

(해결책)
connect(개인함수)를 사용하여 DWebBrowserEvents2 이벤트를 커넥션 시키지 않아서 Invoke 가 호출되지 않았었다.
이벤트를 연결하여 Invoke 를 호출 시키는 것을 해결하였다.

[문제점3]

ActiveX 와 BHO 를 분리 시키는 것으로 확정하고 다시 프로그래밍을 하여 구조를 잡았는데 이런 빌어먹을 정규표현식
라이브러리 GRETA 가 VC 6.0 에서밖에 컴파일이 안되는 거지같은 경우가 생겨버렸다. 이잡듯이 구굴을 뒤져서 엄청나게
많은 글을 뒤져봤지만 VC 7.0 이나 8.0 에서 typename 을 쓰라고 써놨다.. 하지만 VC 7.0 에서는 될지 몰라도 나는
VC8.0 으로 개발하고 있었기 때문에 어쩔수 없었다. 더 골때리는 것은 VC 7.0 에서 조차도 컴파일이 제대로 되지 않는지
컴파일 안된다는 사람이 나말고도 한둘이 아니다.. 왠만하면 수정해서 사용할려고 했지만 대부분이 MS 의 VC++ 이 표준
컴파일러를 지키지 않기 때문에 나타나는 현상이라며 차라리 VC 6.0 을 사용하라고 회의적인 반응이었다.
어쩔수 없이 프로젝트를 VS 2005 (VC 8.0) 에서 VC 6.0 으로 옮겨야 된다.. 젠장.. VC 6.0 으로 시작한 것이 VC 7.0 으로
다시 VC 8.0 에서 처음 시작인 VC 6.0 환경까지 오게 되었다.. 이 어찌 기가 막히고 코가 막히는 시츄에이션인가..
매번 개발툴을 발표할때마다 컴파일러를 개같이 만드는 MS 에 혐오감이 생긴다.. 차라리 델파이로 가는게 낫겠다는 생각이..

GRETA 정규표현식 라이브러리를 BHO 에 합치기 위해서 GRETA 컴파일을 시도하닌 다음처럼 무수한 경고가 뿌려지며 컴파일이
완료되었다. 난생 처음보는거라 기가 막혀서 찾아보니 또 버그란다..
VC++ 에서 템플릿 명을 이빠이 길게 늘여쓰면 다음과 같이 경고가 무지막지 하게 튀어나온다...
그 이유는 255자가 넘어가면 네임 맹글링이 될수 없다는 것이다. 네임 맹글링은 VC 에서만 사용하는 특이한 명명자를 만드는
방법인데 템플릿으로 클래스를 길게 늘여쓰니깐 네임 맹글링때도 255자가 넘어가서 짤린다는 경고인 것이다.
그래서 다음처럼 해결하려고 하였다.
#pragma warning( disable : 4786)
이렇게 하면 경고가 안나올것이라고 생각했으나 역시나 경고가 쏟아져 나온다.. 찾아 봤더니 아예 MS 에서 이 경고를 무시하려고
pragra 를 썼을때 조차도 경고가 나오는건 자기네들의 버그라고 한다..
어이가 없다.. 정말로.. 돌아가실 지경이다.. 어쩔 수 없이 그냥 경고를 볼 수밖에... 대부분의 사이트의 그루(GURU)들이 말하길
코드 자체에는 이상이 없으니 무시하란다.. 쩝.. ㅡ.ㅡ; 디버깅할때만 좀 안될거란다.. 다음처럼 써있었다...

Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section.

This problem was corrected in Microsoft Visual C++ .NET.
 Back to the top

MORE INFORMATION
This warning can be ignored. However, the identifier may not be accessible or viewable in the debugger.

위에서 MS 가 하는 말로 골때리는 부분이 있다.. "Visual C++ .NET 에서 이 문제가 해결되었다." 개새끼들이다.. 정말로..
패치가 있을 줄 알았더니 닷넷버젼에서 버그가 해결되었으니 닷넷쓰라 이런 똥배짱을 부린다.. 내가 닷넷 쓰다가 지금 VC 6.0 으로
돌아왔는데 장난하냐 새끼들아.. 라고 한 소리 해주고 싶다.

warning C4786:
'std::rb_tree<CAiSpanningTree<State,std::less<State>>::TransClosureNode, CAiSpanningTree<State,std::less<State>>::
TransClosureNode,std::ident<Cai SpanningTree<State,std::less<State>>::TransClosureNode,CAiSpanningTree<S tate,std::
less<State>>::TransClosureNode>,std::less<CAiSpanningTree<Stat e,std::less<State>>::TransClosureNode>>' :
identifier was truncated to '255' characters in the debug information


[MS 사이트: BUG: You still receive a "warning C4768" message even if you use the warning pragma to disable
            the warning in Visual C++ ]
http://support.microsoft.com/?id=167355


posted by 유돌이
prev 1 next