천객만래 [千客萬來] (It has an interminable succession of visitors)

[VC] IE에 사용자 툴바를 설치후에 기본으로 보이게 하는 방법





IE에 새 툴바밴드를 설치하고 새 IE를 실행했을때 기본으로 툴바가 IE에 보여지도록 하는 방법에 대한 문서이다. 혹자는 이것이 왜 필요하냐고 물을수도 있는데, 한마디로 필요하다. 

왜냐하면 설치를 했다면 당연히 눈여보여서 동작하는 것이 사용자의 기대동작이기 때문이다. 만약 IE에서 툴바를 켜는 방법을 모르는 사용자가 있다면 어떨까? 설치를 한 의미가 없어진다. 사용을 촉진시키고, UI를 보여줌으로써 관심을 일으키는 것이 마케팅일것이다.

1 툴바 DLL의 기본 설정을 이용하는 방법 

이 방법을 알아낸다면 밑에 있는 방법은 다 없어도 된다. 이 방법은 웹 검색과 구글검색으로도 쉽게 알아내지 못했다. IE의 툴바 레이아웃은 
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Toolbar
There are 3 sub keys: Explorer, ShellBrowser, WebBrowser'
In each of these sub-keys is the entry for ITBarLayout 
For IE Toolbars: The WebBrowser Sub-key directly affects IE.
For Windows Explorer Toolbars: The Explorer Sub-key directly affects Explorer.
The ShellBrowser sub-key may affect IE as well. Its effect on IE and Windows Explorer is unknown at this time, so if the first option doesn't work, delete the ITBarLayout value here as well.
Choose the relavent sub-key and right click where it says ITBarLayout and select Delete. 
The deleted value will automatically be recreated for you.

이런식으로 저장이 된다. 문제는 ITBarLayout에 레이아웃 구조체가 저장되는데 이 키를 지우면 모든 레이아웃 정보가 사라지고 IE가 디폴트로 툴바 레이아웃을 생성하는데, 이때 특정 툴바는 기본으로 뜬다는 것이다. 설치하고 나서 기본으로 뜨고 사용자가 안 보이게 하면 그때 부터 안 보인다. 이런 설정은 어떻게 하는 것일까? 만들때 어떤 옵션을 주는것 같기도 하고. 만약 방법을 찾게 되면 이 페이지에서 가장 강조되는 블럭으로 말들어 놓겠다.

2 html을 이용하는 방법 

이 방법은 해당 툴바를 Object 태그로 HTML에 삽입하는 방법이다. 다시 말해서 해당 COM객체를 IE에서 실행하라고 알리는 것이다. 설치가 끝나고 나서 인스톨러가 설치가 완료되었다는 깜찍하고 작은 IE를 띄우는것은 애교로 봐 줄만하다. 그 IE가 띄우는 페이지에 저 Object에 툴바의 클래스 아이디를 넣는다는 얘기이다. HTML에서는 COM객체를 로드할 것이고, 그 객체는 툴바DLL이기 때문에 당연히 IE에 리바영역에 나타날 것이다. 

문제점이있다. 어떤 툴바는 로드되지 않는다. 내가 뜨기를 원하는 툴바에서는 안 뜨고 다른 툴바는 성공적으로 뜨는 바람에 바로 다른 방법을 강구하기 시작했는데, 자기가 배포하려는 툴바가 이 방법으로 잘 되는지 확인해 볼 필요가 있다. 

주의할 점은 winxp sp2에서는 기본 보안설정으로는 DLL이 로드되지 않는다는 점이다., IE의 보안레벨에 의존적이다.

3 IE 메뉴를 이용하는 방법 

새로운 IE를 실행하면서 그 IE의 IEFrame핸들을 얻을 수 있는데 그 윈도우 핸들에 WM_COMMAND를 보내는 방법이다. 이 경우, 예를들면 Ctrl+N과 같은 IE의 기본적인 값은 spy++로 확인해 보면 항상 같다는 점을 알 수 있다. 그래서 테스트 결과 WM_COMMAND로 wParam에 그 값을 넣어서 보내면 정확히 그 메뉴가 실행된다. 이 점을 응용하면 보기-툴바에서 우리 툴바의 메뉴아이템의 ID를 구하기만 하면 되는 것이다. 그 ID는 항상 동적이다. 설치된 툴바의 갯수나 설치된 순서에 따라 다르기 때문이다. 그래서 IE의 메인메뉴를 HMENU를 구하고 거기서 모든 메뉴 아이템을 얻어서 우리가 원하는 메뉴 캡션을 찾아내면 그 메뉴 아이템의 ID가 우리가 찾는 ID가 되는 것이다.

[치명적 문제점]
메인메뉴의 HMENU 값을 구할 수가 없다? 일단 GetMenu(HWND) 는 메뉴가 없다. 왜 그럴까? IE의 메인메뉴는 메뉴바라고 하는 툴바에 올라가 있고, 팝업메뉴로 나타나기 때문이다. HMENU만 알아낸다면 확실히 효율적이고 안정적인 좋은 방법이다.

4 IWebBrowser2를 이용하는 방법 




STDMETHODIMP CShowBarObj::SetSite(IUnknown *pUnkSite)

(

 if (NULL != pUnkSite)

 {

  IWebBrowser2 *pBrowser = NULL;

  // Ensure that our site is an browser window

  HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **) &pBrowser);

  if (SUCCEEDED(hr))

  {

   // Display the band object (the Search bar in this case)

   VARIANT vtBandGUID, vtShow;

   vtBandGUID.vt = VT_BSTR;

   vtBandGUID.bstrVal = SysAllocString(OLESTR("{30D02401-6A81-11D0-8274-00C04FD5AE38}"));

   vtShow.vt = VT_BOOL;

   vtShow.boolVal = true;

   VARIANT vret;

   pBrowser->ShowBrowserBar(&vtBandGUID, &vtShow, &vret);

   SysFreeString(vtBandGUID.bstrVal);

   pBrowser->Release();

  }

 }

 return S_OK;

}




이 코드인데 이 코드를 툴바(툴바는 문제가 있는데 툴바는 켜지 않으면 DLL을 로드하지 않기 때문이다.)나 BHO에 넣으면 잘 동작한다. 그러나 IE를 실행하고 그 실행한 IE의 IWebBrowser2의 ShowBrowserBar를 호출하면 절대로 동작하지 않는다. 그것이 문제이다. 일단 그 이유를 모르겠다. 한가지 생각나는 이유라고는 TopLevel의 IWebBrowser2가 아니기 때문이 아닐까 싶기도 한데, 사실상 그런 이유때문은 아닌것 같다. 

아래 코드는 Activex에서 탑 레베의 IWebBrowser2를 얻는 코드이다. 나중에 참조해 볼 것.





#include <SHLGUID.h>

#define COMRELEASE(ptr)

if (ptr != NULL) 

{

ptr->Release();

   ptr = NULL;

}

IWebBrowser2 *browser = NULL;

STDMETHODIMP SetClientSite(IOleClientSite *pClientSite) 

{

  HRESULT hr = S_OK;

   IServiceProvider *isp, *isp2 = NULL;

    if (!pClientSite)

{

 COMRELEASE(browser);


else

{

hr = pClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast<void **>(&isp));

if (FAILED(hr)) 

{

hr = S_OK;

goto cleanup;

}

hr = isp->QueryService(SID_STopLevelBrowser, IID_IServiceProvider, reinterpret_cast<void **>(&isp2));

if (FAILED(hr))

{

hr = S_OK;

goto cleanup;

}

hr = isp2->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, reinterpret_cast<void **>(&browser));

if (FAILED(hr)) 

{

hr = S_OK;

goto cleanup;

}

cleanup:

// Free resources.

COMRELEASE(isp);

COMRELEASE(isp2);

return hr;

}

}


5 BHO를 이용하는 방법 

이 방법이 그나마 안정적이고 좋은방법 같다. ShowBrowserBar를 BHO에서 동작하도록 하는 것이다. BHO의 SetSite에서 우리가 원하는 툴바를 보이게 만들고 DLL을 등록해제해서 (레지스트리 삭제) 다음 IE에서는 이 DLL을 다시 로드하지 않도록 하는 방법이다. 

bho등록
IE를 안 보이게 실행
로드된 bho에서 우리가 원하는 툴바를 보이게 함
IE를 종료함 WM_CLOSE를 보내거나 ->Quit를 호출함
bho등록해제
bho dll삭제

와 같은 순서로 동작한다.

6 레이아웃 레지스트리를 조작하는 방법

레지스트리는 바이네리 데이타이다. 상식적으로 생각했을때 그건 IE내부에서만 사용되는 어떤 구조체일 것이고, 그 내막은 파악하기는 소스가 없다면 리버스엔지니어링이라고 불리는 삽질을 하는 수 밖에 없는 법이다. 당행스럽게도 나에겐 win2k src가 있었는데 없었다면 감히 삽질하려고 시도조차 하지 않았을 것이다. 그런데 그런 시도를 이미 한 사람이 있었으니 내가 감탄하지 않을 수 없었다. 구조체는


typedef struct tagCOOLBARSAVE
{
  UINT cbVer;
   UINT uiMaxTBWidth;
    UINT uiMaxQLWidth;
#ifdef UNIX
    BITBOOL fUnUsed : 28; // unused
#endif
  BITBOOL fVertical : 1; // The bar is oriented vertically
   BITBOOL fNoText :1; // "NoText"
    BITBOOL fList : 1; 
// toolbar is TBSTYLE_LIST (text on right) + TBSTYLE_EX_MIXEDBUTTONS
BITBOOL fAutoHide : 1; // Auto hide toolbar in theater mode
    BITBOOL fStatusBar : 1; // Status bar in theater mode
BITBOOL fSaveInShellIntegrationMode : 1; 
// Did we save in shell integration mode?
UINT uiVisible; // "Visible bands"
UINT cyRebar;
BANDSAVE bsCBANDSMAX;
CLSID aclsidExternalBands[ MAXEXTERNALBANDS ]; // Check classid
CLSID clsidVerticalBar; //clsid of bar persisted within vertical band
CLSID clsidHorizontalBar;
} COOLBARSAVE, *LPCOOLBARSAVE;




이렇다. 소스 코드를 분석해 본 결과 상당히 복잡한 방법으로 bs 멤버와 aclsidExternalBands에 저장되는 순서가 어떤 함수로 관계지어지고 uiVisible에 교묘한 방법으로 계산한 bit를 OR시켜야 한다. 등등 상당히 복잡한 방법으로 저장이 되고 있다는 점이다. 내가 수십시간에 걸쳐 분석하고 완성한 소스가 있지만 그것조차 100% 완벽하다고 장담하지 못하겠다. 솔직히 MS얘네들 간단한 내용을 왜 이렇게 복잡하게 만들었는지 모르겠다. 그냥 최대 15개의 툴바를 지원하므로 15개의 툴바에 구조체를 할당하고 보임 안보임 BOOL 변수와, 스타일 변수, 위치변수 3개만 있으면 다 될것 같은데, 뭐가 그리 복잡하게 만드어 놨는지. 간단하고 읽기좋고 단순한 알고리즘으로 충분히 리팩토링이 필요한 소스가 아닌가 하는 개인적인 불만이 있다.

7 가장 확실한 방법 



#include <mshtml.h>
void CDeletmeDlg::OnButton1()
{
 CoInitialize(NULL);
 IWebBrowser2 *pIE;
 HRESULT hr =  CoCreateInstance(CLSID_InternetExplorer, NULL,
  CLSCTX_LOCAL_SERVER,
  IID_IWebBrowser2,(void**)&pIE);
 pIE->put_Visible(VARIANT_TRUE);
 VARIANT vtBandGUID;
 VARIANT vtShow;
 VARIANT vtRet;
 vtBandGUID.vt = VT_BSTR;
 vtBandGUID.bstrVal = ::SysAllocString( L"{5258771B-ACBE-4974-8ABC-AE4969A2A5CD}" );
 vtShow.vt = VT_BOOL; 
 vtShow.boolVal = VARIANT_TRUE; //** 주의 true가 아니라 VARIANT_TRUE이다.
 vtRet.vt = VT_INT;
 vtRet.intVal = 1;
 //**주의 vtRet는 리턴값이므로 반드시 읽어야 한다.
 //NULL을 넣으면 제대로 동작하지 않는다..
 hr = pIE->ShowBrowserBar(&vtBandGUID, &vtShow, &vtRet); 
 SysFreeString(vtBandGUID.bstrVal);
 //주소바가 보이도록 설정되 있으면
 VARIANT_BOOL b;
 pIE->get_AddressBar(&b);
 if(b == VARIANT_TRUE)
 {    
  HWND hWnd=0;
  pIE->get_HWND((long*)&hWnd);
  if(::IsWindow(hWnd))
  {
   //수동으로 안 보이게한다.
   //put_AddressBar는 현재창에서는 되지만 종료하고 닫으면 주소바가 다시 보이게 되어 있다.
   //따라서 사용자가 메뉴를 누른것처럼 동작하도록 한 다면 리바의 위치정보를 즉시 다시 기록하게 된다.
   ::PostMessage(hWnd, WM_COMMAND, 41477, 0);
  }
 }
 pIE->Release();
}



내가 미처 몰랐는데 이 방식이 있다. 주의라고 표시되지 않은 부분에서 내가 실수를 해서 안 되었던 것이고, 이제 하니 잘 된다. 툴바를 새 줄로 놓는다면 그건 DLL에서 GetHostInfo인가 하는 함수에서 _BREAK을 제거하면 된다.




Posted by SB패밀리





Borland Delphi 5로 개발된 암호화 DLL

문자열을 암호화 하고 해독하는 함수

Readme.txt : 지금 보고 있는 텍스트 파일
cccipher.dll : 암호화/해독 함수가 포함된 DLL

[델파이에서 선언]
Function Encrypt(Src: PChar; Key: Word): PChar; stdcall; External 'CCCIPHER.DLL';
Function Decrypt(Src: PChar; Key: Word): PChar; stdcall; External 'CCCIPHER.DLL';

[델파이에서 사용]
// encipher
Edit2.Text := StrPas(Encrypt(PChar(Edit1.Text), StrToInt(Edit5.Text)));
// decipher
Edit4.Text := StrPas( Decrypt( PChar(Edit3.Text), StrToInt(Edit5.Text) ) );

※ C++Builder 5 예제도 포함되어 있음.

Base64 인코딩/디코딩 된 결과물을 볼 수 있음.
사용에 버그가 있거나 문의사항이 있을 경우에 연락을 주시면 감사하겠습니다. 
homepage: http://sb.pe.kr 

암호화DLL테스트.ZIP


좋은 목적을 위해서라면 아무나 쓰셔도 상관 없습니다.

- 쌈꼬쪼려 소백촌닭 -




Posted by SB패밀리

[강좌] 리소스의 활용 II  

리소스의 활용 II

글: 하영재(vaio91@yahoo.com)
    델파이 코리아(www.delphikorea.com)

1편 강좌가 나간후 참 오랜만에 2편 강좌를 올리게 되는군여. 죄송합니다. 먹고살다
보니 이런일이.. 흑...

1편 강좌에서는 리소스를 어떻게 프로그램에 링크시키고 불러오고 하는지에 대해서
알아보았었죠... 이번엔 리소스 DLL을 만들고 사용하는 법에 대해 알아보겠습니다. 
이번 강좌에서는 AVI, Cur, Ico, Bmp, Jpeg, string을 Dll에 넣고 불러오는 방법에
대해 설명하겠습니다. 그리고 시간이 된다면 Resource의 활용법으로 실행파일을
리소스에 넣고 불러오는 방법에 대해서도 알아보도록 하겠습니다.
그럼 시작하죠...(지금 부터 존칭이 생략되는거... 다 아시죠? ^^)

1. 리소스 Dll 만들기

리소스 Dll이란 말 그대로 리소스를 포함하고 있는 Dll을 말한다. 만드는 순서를
먼저 알아보자. 

1. 리소스의 경로를 저장하고 있는 RC 파일을 만든다. 
2. RC 파일을 Brcc32등으로 컴파일 하여 Res 파일로 만든다. 
3. 만들어진 Res 파일을 Dll에 포함시킨다. (폼에 포함시키는것과 동일하다.)
4. Dll을 컴파일 한다. 

2번까지는 지난번 강좌의 내용과 같다. 3번 항목의 Res를 Dll에 포함 시키는 부분은
폼에 하는것과 동일하다고 했는데 아래의 예제를 보면 왜 동일하다는 건지 쉽게
이해가 될 것이다. 


library ResOnly;

{$R Resource.res}

begin
end.

아무런 함수등을 포함하지 않고 오직 리소스만 가지고 있는 Dll의 모습이다. 
Dll에 리소스를 포함시키기 위해서 폼에서 했던것과 마찬가지로 $R 지시자를
사용해서 Dll에 리소스를 포함 시키고 있다. 
일반 Dll과의 차이를 의심하는 분들이 계실지 모르지만... ^^ 동일한 Dll이다. 단지
리소스를 포함하고 있다는 것만이 다를뿐. 이 Dll에도 함수를 넣을 수 있다. 그리고
기존의 Dll에도 리소스를 포함시킬 수도 있다. 

그럼 실제로 예제로 사용할 Dll을 하나 만들어 보자. 


먼저 RC 파일을 만든다. 

[MyRes.RC]

MyBMP BITMAP Delphikorea.bmp
MyAVI AVI Cool.avi 
MyCur CURSOR HandPoint.cur
MyJPG JPEG Window.jpg

저장한 후 컴파일 한다. (리소스를 활용하자 1편 강좌 참고)
컴파일이 완료되면 MyRes.Res 란 리소스 파일이 생성되었을 것이다.
이 리소스 파일을 Dll에 포함시킨다.

[MyResource.dpr]

library MyResource;

{$R MyRes.res}

begin
end.

이 프로젝트 파일을 컴파일 하면 아무런 함수등이 포함되지 않은 순수 리소스 Dll이
완성된다. 물론 이 리소스 Dll엔 일반 Dll과 마찬가지고 함수를 가지고 있을 수도
있다. 단지 리소스 파일을 포함하고 있다는 것만 다를 뿐이다.
이제 남은일은 dll에 포함된 리소스를 하나 하나 꺼내 사용하는 일뿐이다.


2. Dll내의 리소스를 사용하자.

2-1) AVI 리소스의 사용

Dll 내의 AVI 리소스를 사용하기 위해서는 먼저 리소스 Dll을 로드하여야 한다. 
우리는 간단히 LoadLibrary API를 이용해서 Dll을 로드 할 수 있다. 

var
DllHandle: THandle;

...

DllHandle := LoadLibrary('MyResource.dll');

이렇게 해서 얻어진 Dll의 Instance Handle은 앞으로 두고 두고 사용할 것이므로 잘
챙겨 두도록 하자. ^^

로드된 Dll을 이용해서 AVI 리소스를 뽑아내는 것은 정말 정말 간단하다. TAnimate
객체를 사용하여 플레이 할것이기 때문이다. 
우리는 TAnimate 객체의 ResName과 ResHandle 프러퍼티만을 셋팅해 줌으로써 바로
플레이가 가능하다.

먼저 ResHandle을 채워준다.

Animate1.ResHandle := DllHandle;

다음으로 ResName을 준다.

Animate1.ResName := 'MyAVI'; //우리가 저장한 AVI의 이름이다.

마지막으로 플레이...

Animate1.Play(1, Animate1.FrameCount, 0);


2-2) JPEG 리소스의 사용
JPEG는 Resource Type으로 등록되지 않은 녀석이다. 별도로 등록되지 않은 리소스
형식은 RT_RCDATA 형식으로 봐도 무방하다. 바이너리로 저장되었으므로 JPEG
리소스를 로드하기 위해선 TResourceStream이란 메모리 스트림 계열의 스트림을
이용해서 리소스 Dll로 부터 메모리로 JPEG 데이터를 옮겨 올 수 있다.

var
ResStream: TResourceStream;
...

ResStream := TResourceStream.Create(DllHandle, 'MyJPEG', 'JPEG');

여기까지 작업하면 ResStream에 JPEG 파일이 들어온다. 
이것을 담을 JPEG 형식의 객체가 필요하므로 하나 생성하자.(JPEG Unit을
포함시켜야 한다.)

uses
JPEG;

var
JPEG: TJPEGImage;
...

JPEG := TJPEGImage.Create;

JPEG Image를 생성했으면 위에서 로드한 ResStream을 받아온다.

JPEG.LoadFromStream(ResStream);

마지막으로 Image에 JPEG를 넣어준다.

Image1.Picture.Bitmap.Assign(JPEG);

위에서 동적 생성한 객체들을 해제해 준다.

JPEG.Free;
ResStream.Free;



2-3) Cursor 리소스의 사용
Custom Cursor를 사용하기 위해선 먼저 Screen의 Cusors에 리소스를 로드해 줘야
한다. 단, 우리가 사용할 커서의 액세를 위해 유니크한 커서 상수를 하나 미리
선언해 주자.

const
crMyCursor = 10;

이 값은 0보다 큰 값이면 어느 값이나 사용해도 무방하다. 단... ^^ 미리 윈도우에
등록된 Cursor 상수값과는 달라야 한다.
커서를 로드하는데는 LoadCursor란 API를 이용한다.

Screen.Cursors[crMyCursor] := LoadCursor(DllHandle, 'MyCur');

로드가 되었으므로 사용하고저 할 때 이 커서를 불러주면 된다.

Screen.Cursor := crMyCursor;


2-4) Bitmap 리소스의 사용

Bitmap 리소스는 리소스 중에서 사용하기가 가장 쉽다. ^^ 이미 델파이에선
TBitmap에 리소스를 사용하기 위한 모든 준비를 마쳐 놨기 때문이다. 그렇지
않았다면 우리는 일일이 많은 작업을 손수 했어야 할 것이다. 
우리는 리소스의 비트맵을 로드하기 위해 단지 LoadFromResourceName이란 메소드만
호출해 주면 된다.

Image2.Picture.Bitmap.LoadFromResourceName(DllHandle, 'MyBMP');

내부적으로 어떻게 처리되는지 알고 싶은 사람은 Graphics.pas에 정의된
LoadFromResourceName 메소드를 분석해 보자...



이것으로 할 얘긴 거의 다 한것 같다. 한 가지 빠진것이 있다면 Icon 파일에 대한
것인데 이것또한 별로 설명할 것이 없으므로 직접 한 번 해 보시길... ^^
마지막 단계로 로드한 Dll을 해제 할 차례이다.

FreeLibrary(DllHandle);

폼의 종료에 넣어 두면 될 것이다.


자... 이제 보너스를 드릴 차례이다. ^^

앞에서도 얘기 했듯이 Exe 파일도 리소스에 포함시켜서 사용할 수 있다. 눈치채신
분도 있으시겠지만 별 특별한건 없다. 그저 TResourceStream을 이용하는 것이다. 
그 외에 MIDI 파일도 넣어보고 String 데이터도 한 번 넣어 보자. 

[MyExeRc.rc]

MyNotePad EXEFILE c:\windows\NotePad.exe
MyMIDI MIDI xi_shui_chang_liu.mid

STRINGTABLE 
{
1, "하영재 바보! 윽... 앞으론 이런 예문은 만들지 않으렵니다."
2, "델파이 코리아 만세!!! (www.delphikorea.com)"
}

위 에서 설명한대로 컴파일 후 Dll에 포함시켜서 다시 컴파일 한다.
그럼 Dll이 만들어 질 것이다. 여기서 Dll이름은 MyExeDll.dll로 했다. 

먼저 dll을 로드 한다.

var
DllHandle: THandle;
...

DllHandle := LoadLibrary('MyExeDll.dll');
...

[Exe 파일 저장하고 실행하기]

var
ExeRes: TResourceStream;
begin
if DllHandle = 0 then Exit;

ExeRes := TResourceStream.Create(DllHandle, 'MyNotePad', 'EXEFILE');
ExeRes.SaveToFile('Note.exe');
WinExec(PChar('Note.exe'), SW_SHOW);
ExeRes.Free;
end;

설명은 생략한다. 위에서 모두 했으므로... ^^

[MIDI 파일 저장하고 연주하기]

var
MidiRes: TResourceStream;
begin
if DllHandle = 0 then Exit;

MidiRes := TResourceStream.Create(DllHandle, 'MyMIDI', 'MIDI');
MidiRes.SaveToFile('MyMIDI.Mid');

MediaPlayer1.FileName := 'MyMidi.mid';
MediaPlayer1.Open;
MediaPlayer1.Play;
MidiRes.Free;
end;

여기서 MIDI의 연주는 MediaPlayer를 이용했다. 역쉬 설명 생략... ^^

[String Resource 사용하기]

리소스내의 String을 읽어오기 위해 LoadString 함수를 이용한다.

var
FText : pchar;
begin
if DllHandle = 0 then Exit;

GetMem(FText, 1025);

LoadString(DllHandle, 1, FText, 1024);
ShowMessage(string(FText));
FreeMem(FText);
end;

마찬가지로 사용한 Library를 해제해 준다.

FreeLibrary(DllHandle);


보너스 끝... ^^



3. 마치며...

언제나 그렇듯이 좀 좋은 강좌를 쓸수 없을까 늘 고민을 하게 된다. 이번에도
아쉽지만 이쯤에서 마무리를 지을까 한다. 다음번에 여유가 된다면 Icon
Library에서 Icon을 읽고 또 원하는 Icon만 모아서 Icon Libarary를 만드는 방법에
대해 강좌를 해 볼까 한다. (물론 원하시는 분들이 계시다면...^^)
다음에 더 좋은 강좌로 찾아 뵐 것을 약속드리며 이만 줄이겠다. 



 
Posted by SB패밀리


ANSI 또는 유니코드 컨트롤 버전

컨트롤을 ANSI 버전으로 제공할지 유니코드 버전으로 제공할지 또는 두 버전을 모두 제공할지 여부를 결정해야 합니다. 이러한 사항은 ANSI 및 유니코드 문자 집합 고유의 이식성과 관련된 요소에 따라 결정됩니다.

모든 Win32 운영 체제에서 작동하는 ANSI 컨트롤을 사용하면 다양한 Win32 운영 체제 간의 이식성을 최대화할 수 있습니다. 반면, 유니코드 컨트롤은 Windows NT(버전 3.51 이상)에서만 작동하고 Windows 95나 Windows 98에서는 작동하지 않습니다. 따라서 이식성 문제가 주요 관심사인 경우에는 ANSI 컨트롤을 제공해야 합니다. Windows NT에서만 컨트롤을 실행할 계획인 경우에는 유니코드 컨트롤을 제공할 수 있습니다. 또한 두 가지 버전을 모두 제공하여 해당 응용 프로그램에서 사용자의 운영 체제에 따라 가장 적절한 버전을 설치하도록 할 수도 있습니다.

ActiveX 컨트롤 및 재배포 가능한 DLL 설치

ActiveX 컨트롤과 함께 제공되는 설치 프로그램을 통해 Windows 디렉터리에 별도의 하위 디렉터리를 만들고 이 하위 디렉터리에 해당 컨트롤의 .OCX 파일이 설치되도록 해야 합니다.

참고   설치 프로그램에 Windows GetWindowsDirectory API를 사용하면 Windows 디렉터리의 이름을 가져올 수 있습니다. 또한 사용자의 회사 또는 제품 이름을 사용하여 하위 디렉터리 이름을 만들 수도 있습니다.
설치 프로그램을 통해 Windows 시스템 디렉터리에 재배포 가능한 필수 DLL 파일이 설치되어야 합니다. 또한 사용자의 시스템에 필수 DLL 중 하나라도 이미 설치되어 있는 경우, 설치 프로그램에서 해당 DLL의 버전과 설치하려는 DLL의 버전을 비교한 후 이미 설치된 파일보다 설치하려는 파일의 버전 번호가 더 높은 경우에만 해당 파일을 다시 설치하도록 해야 합니다.

ActiveX 컨트롤은 OLE 컨테이너 응용 프로그램 내에서만 사용할 수 있으므로 모든 OLE DLL을 컨트롤과 함께 배포하지 않아도 됩니다. 이것이 가능한 이유는 포함하는 응용 프로그램이나 운영 체제 자체에 표준 OLE DLL이 설치되어 있기 때문입니다.

컨트롤 등록

컨트롤을 사용하려면 먼저 Windows 등록 데이터베이스에 해당 컨트롤에 대한 적절한 엔트리를 만들어야 합니다. 일부 ActiveX 컨트롤 컨테이너는 사용자가 새 컨트롤을 등록할 수 있도록 메뉴 항목을 제공하지만 모든 컨테이너에서 이 기능을 사용할 수 있는 것은 아닙니다. 따라서 컨트롤 설치 시 설치 프로그램에서 해당 컨트롤을 등록하도록 만들 수 있습니다. 이 경우, Visual C++에는 컨트롤을 등록하는 데 사용할 수 있는 RegSvr32.exe라는 재배포 가능한 프로그램이 포함되어 있으므로, 이 RegSvr32에 해당 컨트롤에 대한 .OCX 파일의 전체 경로 및 파일 이름을 인수로 전달하기만 하면 됩니다. MFC ActiveX 컨트롤 REGSVR 샘플에는 RegSvr32.EXE에 대한 소스 코드가 포함되어 있습니다. 이 샘플은 등록 작업을 수행하는 데 사용할 수 있는 방법에 대한 한 가지 예로, 사용자가 직접 등록 루틴을 만들 때 지침으로 사용할 수 있습니다.

원하는 경우에는 사용자 대신 설치 프로그램에서 컨트롤을 직접 등록하도록 만들 수도 있습니다.

LoadLibrary Windows API를 사용하여 해당 컨트롤의 DLL을 로드합니다. 그런 다음, GetProcAddress를 사용하여 "DllRegisterServer" 함수의 주소를 가져옵니다. 마지막으로, DllRegisterServer 함수를 호출합니다. 다음 코드 샘플에서는 이 경우에 사용할 수 있는 한 가지 방법을 보여 줍니다. 여기에서 hLib에는 컨트롤 라이브러리의 핸들이 저장되고 lpDllEntryPoint에는 "DllRegisterServer" 함수의 주소가 저장됩니다.

 

 

HINSTANCE hLib = LoadLibrary(pszDllName);

if (hLib < (HINSTANCE)HINSTANCE_ERROR)
{
   DisplayMessage(IDS_LOADLIBFAILED, pszDllName); //unable to load DLL
   iReturn = FAIL_LOAD;                           //unable to load DLL
}

// Find the entry point.
(FARPROC&)lpDllEntryPoint = GetProcAddress(hLib,
   _T("DllRegisterServer"));
if (lpDllEntryPoint != NULL)
   (*lpDllEntryPoint)();
else
   // Unable to locate entry point

 


컨트롤을 직접 등록하면 별도의 프로세스(즉, REGSVR32)를 호출하거나 로드할 필요가 없으므로 설치 시간이 줄어든다는 장점이 있습니다. 또한 이 경우 등록 작업은 내부 프로세스이기 때문에 외부 프로세스보다는 설치 프로그램에서 오류 및 예측할 수 없는 상황을 좀 더 적절하게 처리할 수 있습니다.

참고   설치 프로그램에서 ActiveX 컨트롤을 설치하기 전에 OleInitialize를 호출해야 합니다. 또한 설치 프로그램을 종료할 때에는 OleUnitialize를 호출해야 합니다. 그래야만 OLE 시스템 DLL이 ActiveX 컨트롤을 올바르게 등록할 수 있습니다.
MFCx0.DLL은 사용자가 등록해야 합니다.


출처: http://msdn.microsoft.com/ko-kr/library/cc451427(VS.71).aspx

Posted by SB패밀리

DLL이나 OCX를 레지스트리에 등록하거나 제거..
regsvr32를 이용한다..

예)
regsvr32 "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /u  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /s  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /s /u  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"
regsvr32 /s /c  "C:ProjectNeoTest 2.60_Output_Debugeoweboardax.ocx"

/u : Unregister
/s : Silent
/c : Console output

regsvr32는 DLL이나 OCX를 호출하고, DLL내부의 DllRegisterServer()과 DllUnregisterServer()을 호출하는 역할을 한다.
만약 regsvr32를 사용하지 않고 직접 등록하려면 다음과 같이 할 수 있다..(Devpia 참고..)

// Usage
AfxMessageBox( RegFunc("MsComm.ocx") );  

CString RegFunc(LPCTSTR lpOCXName) 
{

CString systemDir = _T("");
CString FindFileName = _T("");

::GetSystemDirectory(  systemDir.GetBuffer(255), 255);

FindFileName.Format("%s\%s", systemDir, lpOCXName);

HINSTANCE h = ::LoadLibrary(FindFileName);

if (h != NULL) {
FARPROC pFunc = ::GetProcAddress(h,"DllRegisterServer");
if (pFunc != NULL)
{
(*pFunc)();
} else {
FindFileName.Format("%s 등록 실패 되었읍니다.", lpDiscript);
return FindFileName; 
}
::FreeLibrary(h);

FindFileName.Format("%s 등록 되었읍니다.", lpDiscript);
return FindFileName;
} else {
FindFileName.Format("%s 등록 실패 되었읍니다.", lpDiscript);
return FindFileName;

}


출처: http://ninvu.egloos.com/1936098
Posted by SB패밀리