반응형




유저모드 동기화에는 CRITICAL_SECTION , interlock 의 방법이 있고

 

크리티컬 섹션은 범위를 설정 할 수 있다

 

인터락은 증가에 관한 변수에 대해 간략한 동기화 기능

 

커널모드 동기화 에는 세마포어, 뮤텍스 등등이 있다

 

 

세마포어와, 뮤텍스의 의 차이는 키의 개수의 차이다

 

뮤텍스는 허용 하는 키의 개수가 하나, 세마포어는 여러개

 

 

그래서 세마포어의 키의 개수르 1 개를 두면 뮤텍스처럼 이용할 수 있다

 

유저모드나 커널모드나 한 프로세스 내에서 사용 할 수 있는건 마찬가지 이지만

 

커널모드동기화는 동기화 관리를 커널이 해주기 대문에 프로세스와 프로세스 간의 동기화도 지원해준다

 

그렇기 대문에 유저보드 보단 커널 모드의 기능들이 더 많아진다는 것을 유추해 볼 수 있으며

 

속도는 일반적으로 유저모드가 더 빠름을 짐작 할 수 있다 

 

Tip1 : 크리티컬 섹션 즉 유저모드에서는 임계영역에 대한 변수를 선언 하지만, 커널모드에서는 각 프로세스 내에서 유효한 핸들을

선언해 동기화를 관리한다

 

Tip2: 핸들은 한 프로세스 내에서만 유효한 것임으로 서로 다른 프로세스 끼리의 동기화를 하기 위한 커널모드에서의 기법은

동기화 함수 생성시 동기화할 프로세스들간의 이름으로 동기화를 꾀할 수 있다

 


http://blog.naver.com/kimgudtjr/140107512792

[ 유저 모드에서의 동기화(Synchronization in User Mode) ]

 

윈도우즈에서 쓰레드를 동기화 시키는 방법은 크게 유저 모드를 기반으로 하는 동기화 기법과

커널 모드를 기반으로 하는 동기화 기법 두가지로 나누어 진다.  각각의 장,단점이 존재한다고 한다.

유저 모드 동기화 기법으로는 CRITICAL_SECTION 오브젝트(Object)를 사용하는 방법이 있다.

사용 방법은 잠시 뒤로하고 유저 모드에서의 동기화 기법이 지니는 장점과 단점부터 이야기 해보자.

유저 모드에서 동기화를 하는 경우에 동기화 작업을 위해서 프로세스의 연산 모드를 변경할 필요가 없다.

응용 프로그램이 유저 모드로 돌아오는 작업을 할 필요가 없다. 사실 연산 모드의 변환 자체가

많은 연산 과정을 거쳐서 이루어진다. 즉 CPU가 해야 하는 일이 많다는 것이다. 결과적으로

유저 모드에서의 동기화 기법은 커널 모드 동기화 기법에 비해 빠르다. 따라서 유저모드에서의

동기화 기법만으로도 충분할 경우에는 이 방법을 적용하는 것이 좋을 것이다.

물론 사용하는 방법도 빅적 쉬운 편이다. 그러나 이러한 장점을 지니는 대신에 커널 모드에서의

동기화 기법에 비해서 제한된 기능만을 지닌다는 단점이 있다.

※ CRITICAL_SECTION 오브젝트를 사용하는 동기화 방법을 자칫 "임계 영역을 이용하는 동기화 방법인가 보다"

라는 오해를 하기 쉽다. (CRITICAL_SECTION 을 한글로 번역하면 임계영역이 된다.) 그러나

임계 영역은 동기화를 해야 하는 영역을 가리키는 것이지 그 자체가 동기화 방법이 될 수는 없다. 그냥

동기화를 하기 위해 사용하는 객체를 가리켜 CRITICAL_SECTION 이라는 이름을 붙여 준 것이다.


=============================================================================

 

 

 

[ 커널 모드에서의 동기화(Synchronization in Kernel Mode) ]

 

유저모드에서의 동기화 기법이 지는 제한 사항 중에 하나는 단일 프로세스 내에서만 사용 가능

하다는 것이다. 경우에 따라서는 서로 다른 프로세스 안에 존재하는 쓰레드들 간의 동기화가 필요한

경우도 존재한다. 이러한 경우에 반드시 커널 모드 동기화 기법을 적용해야만 한다. 커널 모드

동기화에서는 다른 프로세스 안에 존재하는 쓰레드들간의 동기화도 가능하다.

또한 유저 모드 동기화 기법은, 잘못 구현했을 경우 Deadlock 에 빠지기 쉽다는 문제도 지니고 있다.

그러나 커널 모드 동기화 기법엣는 Deadlock 에 빠지지 않도록 타임-아웃을 설정해 줄 수 있다.

 

--------------- < Deadlock 설명 생략 ... >  ---------------

대략 스레드가 무한 대기상태에 빠지는 경우인데...

이것의 완벽한 해결책은 없다고 한다. 프로그래머가 신경 써야 한다고 함..

그외 설명 생략...

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

커널 모드 동기화 기법으로는 Event, Semaphore, Mutex 오브젝트를 사용하는 방법이 있다.

이들은 모두 커널 오브젝트(Kernel Object)이다.

커널 오브젝트는 다른 프로세스 안에 존재 하는 쓰레드들간의 동기화도 가능하다.

왜냐하면 커널 오브젝트는 하나의 프로세스에 의해 소유되는 것이 아니라, 커널의 의해 공유되기

때문이다. 성능상에 있어서는 유저모드 동기화보다 느리지만(유저모드와 커널모드 사이에 발생하는

전환과정 때문에), 보다 유연성 있는 방법을 제공한다.


반응형
반응형

임계영역 : 동시에 접근될 수 있는 영역

 

동기화 : 동시접근에 순서를 배치하는 기법

 

 

접근동기화 : 메모리적 영역의 동기화 방법, 순서는 상관 없고 한순간에 하나의 쓰래드가 메모리에 접근하게 하는 방법

 

순서 동기화 : 프로그램 흐름 순서의 동기화 방법

 

 


 

 

커널에서 제공하는 임계영역의 범위를 설정할때

 

최소한의 범위로 임계영역 범위를 설정할 것, 범위가 넓은 수록 다른 쓰레드의 대기 시간이 길어져 성능이 느려질 수 있다

 

 

 

 

Atomic Access (원자적 접근) : 한순간에 하나의 쓰래드에 의해서만 접근이 가능한 접근

 

그러한 동기화 함수가 InterlockedIncrement 이고

 

이함수는 해당 변수에 대한 증가를 실행시키는 함수이다, 이 함수의 장점은 CRITICAL_SECTION 을 사용하기 위한 5,6 개의 함수들을 쓰지 않아도

 

된다는 것

반응형
반응형

쓰래드생성 ,_ beeginthreadex, _endthreadex 를 사용 CreateThread, ExitThread 사용 하지말기!

 

 

ansi 표준의 CreateThread, ExitThread   쓰래드 생성 함수들은 함수 내부에서 데이터를 저장하고 있을 경우

 

다른 쓰래드로 즉 CreateThread, ExitThread  로 생성해서 동일한 함수 내부에 데이터를 저장하고 있는 함수를 호출 할경우

 

메모리 공유가 발생해 의도치 않은 결과가 나오는데

 

쓰래드를 고려한 함수인 ,_ beeginthreadex, _endthreadex  은 각 함수마다 독립된 메모리 공간을 갖게 해줌으로써

 

이러한 문제점을 피할 수 있다

 

 



  

http://blog.naver.com/kki2406?Redirect=Log&logNo=80041209326

의 내용을 살짝 변경하여 올림

 

#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <tchar.h>
#include <iostream>

unsigned counter;

unsigned __stdcall SecondThreadFunc( void *pArg )
{
 _tprintf(_T(" * In second thread... \n") );
 while(1)
 {
  std::cout<<"쓰래드 실행중"<<std::endl;
  _endthreadex(0);    //쓰래드를 도중에 종료하는 구문으로 주석처리하면 루프가 무한히 돈다
 }
 
 return 0;
}

int main()
{
 HANDLE hThread;
 unsigned threadID;

 _tprintf( _T(" * Creating second thread... \n ") );
 hThread = (HANDLE) _beginthreadex(NULL, 0, SecondThreadFunc, NULL, 0, &threadID );

 WaitForSingleObject( hThread, INFINITE );
 _tprintf( _T(" * Counter should be 1000000; it is -> %d\n"), counter );
 CloseHandle( hThread );   //_endthreadex 안에서 CloseHandle 이 불려지지 않음으로 직접 명시해야한다

 return 0;
}

 

 

 

이 _beginthreadex 함수는 내부적으로 CreateThread 함수를 호출하고 있다.

 

이를 보고 싶다면 MS사에서 제공하는 코드를 직접 보면 될 것이다.

 

이 코드 파일은 첨부토록 하겠다. _beginthreadex 함수를 찾아보면 알 것이다.

 

또한, thread 생성과 파괴시 다음과 같은 함수들이 존재한다.

 

학습 : CreateThread(), ExitThread()
C Library + API : _beginthreadex(), _endthreadex();
MFC : AfxBeginThread(), AfxEndThread();


 


C++ 멤버함수 beginthreadex  C/C++ / Programming 

2010/06/26 16:36

복사http://blog.naver.com/haruka7879/140109537378

C++에서 멤버함수를 스레드로 이용시

 

#pragma comment (lib, "ws2_32.lib")

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>   // _beginthreadex 함수 참조
#include <windows.h>

 

class a{
public:
    static UINT WINAPI aaa(void *arg);
};

 

UINT WINAPI a::aaa(void *arg)

{
    printf("[%s:%d]\n", __FILE__, __LINE__);

    return 0;
}

 

int main()
{
    HANDLE hThread;
    hThread = (HANDLE)_beginthreadex(NULL, 0, a::aaa, NULL, 0, NULL);
    WaitForSingleObject(hThread, 100);

    return 0;
}

반응형
반응형


주의해야 하는 것은 부모 프로세스에 등록된 핸들 테이블이나, 자식 프로세스에 등록된 핸들 테이블은 가짜라는 것

직접적으로 연결된 핸들 값이 아니다






http://sosal.tistory.com/98

/*
 http://sosal.tistory.com/
 * made by so_Sal
 */


환경변수 :: 시스템의 속성을 기록하고 있는 변수.
                변수의 이름과 의미가 대부분 미리 정해져 있고,
                사용자가 의도적으로 변경, 생성 가능하다.

유닉스, 리눅스 운영체제에서는 환경변수를 설정하면
모든 프로세스가 동시에 접근 가능합니다.
따라서 '상속' 과정에 상관 없이, 환경변수라는 공유 메모리 영역을 통해
서로 정보를 주고 받을 수 있습니다.
(사실 환경변수로 정보를 주고받게 끔 프로그래밍 하는건 흔하지 않음)

윈도우에서는 시스템 환경변수를 제외한 
(Path, OS,TMP 등 컴퓨터 환경설정 고급탭에서 설정가능한 환경변수)
환경변수는 각 프로세스마다 테이블이 따로 주어져
공유하지 않게끔 되어있습니다.

환경변수로 정보를 주고받는 과정에서
다른 프로세스의 접근에 의한 정보 손실, 레이스컨디션 취약점 등
취약한 부분이 존재하지만, 실제 정보를 숨기는 차원에서 (특히 웹에서)
환경변수를 통해 변수를 변환하는 경우도 많습니다.

====== 함수 분석 ======

환경변수 설정하기
BOOL SetEnvironmentVariable(
    LPCWSTR lpName,
    LPCWSTR lpValue)

lpName :: 환경변수로 등록할 변수 이름
lpValue  :: 환경변수가 가지는 정보 (보통 Message buffer)

환경변수 반환하기
DWORD GetEnvironmentVariable(
    LPCWSTR lpName,
    LPWSTR lpBuffer,
    DWORD nSize);

lpName ::  환경변수 이름 // 이름을 알아야 반환이 가능z
lpBuffer ::  환경변수가 가지고 있는 정보를 반환하여 저장되어질 버퍼
nSize    ::  버퍼에 들어갈 수 있는 최대 크기

SetEnvironmentVariable( _T("나는"), _T("sosal"));
이렇게 선언시, "나는" 이라는 환경변수가 등록되며
GetEnvironmentVariable( _T("나는"), buffer, sizeof(buffer));
buffer에다가 "나는" 이라는 환경변수의 값을 반환하여 저장합니다.


앞에서 환경변수를 통해서 통신한다는 말을 언급했는데,
윈도우에서 부모프로세스와 자식프로세스처럼
직접적인 관계가 있는 프로세스들만이 통신이 가능합니다.
(리눅스에서는 모든 프로세스가 함께 공유)

자식프로세스 생성시에 < CreateProcess > 매개변수중
LPVOID lpEnvironment 이란 변수가 있는데,
NULL을 넣어주면 환경변수를 상속처리하게 됩니다.


Set/GetEnvironmentVariable, CreateProcess,
그리고 상속 모두를 사용한 예제를 보겠습니다.


========= 환경변수 상속 부모 프로세스 =========

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<tchar.h>

int _tmain( int argc, TCHAR* argv[]){

 SetEnvironmentVariable(_T("sosal"), _T("winner"));
 SetEnvironmentVariable(_T("limsy"), _T("lo-ser"));
 //sosal, limsy라는 환경변수 2개를 지정합니다.
 //각각의 값은 차례대로 winner, lo-ser


 _tprintf( _T("Set EnvironmentVariables \n"));
 _tprintf( _T("sosal -> winner \n"));
 _tprintf( _T("limsy -> lo-ser \n"));

 STARTUPINFO si = {0,};
 PROCESS_INFORMATION pi = {0,};
 
 si.cb = sizeof(si);
 TCHAR Command[] = _T("EnvChild.exe");
  //Command는 자식프로세스 실행파일의 이름인데,
  //자식프로세스의 프로젝트 이름을 넣어주시면 됩니다.

 
  CreateProcess(
  NULL, Command, NULL, NULL, FALSE,
  CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
  NULL//NULL일 경우 프로세스의 환경변수를 상속합니다.
  NULL,&si,&pi);

 Sleep(330000);
 return 0;
 
}

========= 환경변수 상속 자식 프로세스 =========

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<tchar.h>


#define BUFSIZE 1024

int _tmain(int argc, TCHAR *argv[]){

 TCHAR value[BUFSIZE];

 if(GetEnvironmentVariable( _T("sosal"), value, BUFSIZE) > 0)
  _tprintf( _T("%s = %s \n"), _T("sosal"), value);
 //부모프로세스가 지정한 환경변수를 가져와서 출력합니다.

 if(GetEnvironmentVariable( _T("limsy"), value, BUFSIZE) > 0)
  _tprintf( _T("%s = %s \n"), _T("limsy"), value);
 //부모프로세스가 지정한 환경변수를 가져와서 출력합니다.

 Sleep(90000);

 return 0;
}

 

반응형
반응형

메일슬롯 방식의 IPC  WindowsSystem 

2011/08/03 13:45

복사http://blog.naver.com/kater102/134225491

첨부파일 (2)

IPC(Inter-Process Communication) 란 프로세스간 통신을 의미 합니다.

 

프로세스 간의 통신을 하려면 어떻게 해야될까요??

 

 

 

 

 

 

 

 

(출처:뇌를자극하는윈도우즈시스템프로그래밍)

 

 프로세스 A 와 프로세스 B 가 같은 공간의 메모리를 공유하고 있다면 통신을 하기에 어려운 점이 없을겁니다. 그냥 만나서 주면 되는 것이죠.

 

 하지만 Windows 에서는 프로세스 간의 메모리 공간을 침범할 수 없게 되어있습니다. 시스템의 안정성을 위해서인데요.

 

 MS word 작업시 미디어플레이어 때문에 MS word 가 에러가 나고 IE 때문에 미디어플레이어가 에러가 나는 등의 오류가 생길 수 있는 것이죠.

 

 실제로 이런 일이 있다면 시스템의 안정성에 상당히 영향을 미치기 때문에 Windows에서는 프로세스의 메모리가 독립적으로 생성되어 서로의 공간을 침범할 수 없게 되어있습니다. 아주 프라이버시가 강한 녀석들이죠?

 

 "프로세스들은 자신에게 할당된 메모리 공간 이외에는 접근이 불가능"

 

 메일슬롯 방식의 IPC

 

 그럼 이들 프로세스간에 통신을 하기 위해서는 방법이 필요한데 (편지를 보낸다든지, 소포를 보낸다든지.) 이때 IPC 의 방법중에 총 세 가지의 방법이 있습니다.

 

 그 중 한가지가 이번 포스팅에서 알아볼 메일슬롯(Mail Slot) 입니다.


(출처: 뇌를자극하는윈도우즈시스템프로그래밍)

 

 메일슬롯은 우체통이라고 생각하시면 됩니다.

 

 "데이터를 주고 받기 위해서 프로세스가 우체통을 마련하는 것"

 

 Receiver(수신인) 이 우체통을(메일슬롯) 만들어두고 Sender(발신인) 가 통로(일종의 스트림?)를 통해 메시지를 보내면 되는 것이죠.

 

 직접 만날수없으니 중간 매개체로 메일슬롯(Mail Slot) 을 이용하는 것입니다.

 

 1. Receiver 가 준비해야 할 것

 => 우체통을 만들면 된다.

 HANDLE CreateMailSlot(

       LPCTSTR lpName,----------------------(1)

       DWORD nMaxMessageSize,-------------(2)

       DWORD lReadTimeout,-----------------(3)

       LPSECURITY_ATTRIBUTE lpSecurityAttributes--(4)

);

 If the function fails, the return value is INVALID_HANDLE_VALUE

 

(1) lpName : 생성하는 메일슬롯의 이름을 결정하는 데 사용

  ex) \\computer\mailslot\[path]name

(2) nMaxMessageSize : 메일슬롯의 크기 결정하는 인자. 0이 전달될 경우 시스템이 허용하는 최대 크기

(3) lReadTimeout : 메일슬롯의 데이터를 읽을 때 파일 입,출력 함수인 ReadFile 함수 사용. But 메일슬롯이 비어 있다면 데이터가 채워질때까지 ReadFile 함수는 반환하지 않고 블로킹(Blocking) 상태에 놓인다. 이때

 lReadTimeout 은 최대 블로킹 시간을 밀리세컨드 단위로 지정. 0을 전달하면 메일슬롯에 읽어 들일 데이터가 있든지, 없든지 간에 블로킹 상태 없이 빠져 나와서 다음 단계로 실행.

 MAILSLOT_WAIT_FOREVER 인자 전달할 경우 ReadFile 함수는 읽어 들일 데이터가 존재하게 될 때까지 블로킹 상태 유지

(4) lpSecurityAttributes : 핸들 상속 용도

 

 2. Sender 가 준비해야할 것

 => 데이터를 Receiver 에게 보내는  역할

 통로를 만들때 쓰는 함수인 CreateFile 함수와 보내는 함수 WriteFile 함수 사용.

 

 

 

 첨부한 예제 파일의 프로그램 구성도입니다.

 

명심해야할 점은 메일슬롯은 단방향 통신입니다. 즉, 우체통을 만들어놓고 메시지를 받는다고해서 그 우체통으로 Receiver 가 메시지를 보내봤자 전달이 안된다는 말이죠. 물론 양쪽에다가 우체통을 (메일슬롯을) 만들어놓으면 가능하겠죠?

 

 파일 입출력 함수 세 가지가 나오는데 메일슬롯 관점에서 중요한 부분만 살펴보고 이번 포스팅은 마무리를 하겠습니다.

 

 CreateFile 함수 간략한 예제 및 설명

 

 

ReadFile

 BOOL ReadFile(

     HANDLE hFile, ----------------------(1)

     LPVOID lpBuffer,--------------------(2)

     DWORD nNumverOfBytesToRead,-----(3)

     LPDWORD lpNumberOfByteRead,------(4)

     LPOVERLAPPED lpOverlapped---------(5)

); 

 ReadFile 함수는 메일슬롯에 존재하는 데이터를 읽어 들인다.

(1) hFile : 메일슬롯의 핸들을 인자로 전달

(2) lpBuffer : 읽어 들인 데이터를 저장할 버퍼를 지정하는 용도로 사용

(3) nNumberOfBytesToread : 읽어 들일 데이터의 최대 크기를 지정

(4) lpNumberOFBytesRead : 함수 호출 완료 된 후, 읽어 들인 데이터 크기를 바이트 단위로 얻기 위한 변수를 지정

(5) lpOverlapped : NULL

 

WriteFile

  BOOL WriteFile(

     HANDLE hFile,---------------------(1)

     LPVOID lpBuffer,--------------------(2)

     DWORD nNumverOfBytesToRead,-----(3)

     LPDWORD lpNumberOfByteRead,------(4)

     LPOVERLAPPED lpOverlapped---------(5)

); 

 WriteFile 함수는 메일슬롯으로 데이터를 전송

(1) hFile : 데이터를 읽어들일 파일을 지정

(2) lpBuffer : 전송할 데이터가 저장되어 있는 버퍼 지정

(3) nNumberOfBytesToWrite : 전송할 데이터 크기 지정

(4) lpNumberOfBytesWritten : 함수 호출 완료된 후, 전송된 실제 데이터의 크기를 바이트 단위로 얻기 위한 변수의 주소를 지정

(5) lpOverlapped : NULL

 

 

 이하 파일 입출력 함수는 나중에 파일 IO 부분에서 더 자세하게 다룰것이나 더 궁금하신 분들은 구글링이나 MSDN 검색을 활용해주시길 바랍니다.

 

 감사합니다.

 

 --By Flow


/*
 
http://sosal.tistory.com/
 * made by so_Sal
 */



Windows 08. IPC 프로세스간 통신
예제소스 입니다.
잘 이해가 안되는 부분이 있다면
아래 링크를 참조하세요.
LINK_

======================= Receiver =======================

#include<stdio.h>
#include<tchar.h>
#include<windows.h>

#define SLOT_NAME _T("\\\\.\\mailslot\\Mail")

int _tmain(int argc,TCHAR *argv[]){

 HANDLE hMailSlot;
 TCHAR messageBox[BUFSIZ];
 DWORD bytesRead;

 hMailSlot = CreateMailslot(     //우체통 생성!!
  SLOT_NAME, 0,
  MAILSLOT_WAIT_FOREVER,
  NULL );

 if(hMailSlot == INVALID_HANDLE_VALUE){
  _fputts( _T("Unable to create MailSlot ! \n"), stdout);
  return 1;
 }

 _fputts( _T("=========== Message =========== \n"),stdout);

 while(1){
  if(!ReadFile(hMailSlot, messageBox, BUFSIZ, &bytesRead,NULL)){
   _fputts( _T("Unable to read 1 \n"), stdout);    // 글이 들어올때까지 기다리고
   CloseHandle(hMailSlot);                              // 들어오면 읽어버림
   return 1;
  }

  if(!_tcsncmp(messageBox, _T("EXIT"), 4)){
   _fputts(_T("Good bye ! \n"), stdout);
   break;
  }

  messageBox[bytesRead/sizeof(TCHAR)] = NULL;
  _fputts(_T("Sender :: "),stdout);
  _fputts(messageBox,stdout);            // 읽어버린거 출력!
 }

 CloseHandle(hMailSlot);
 return 0;
}

======================= Sender =======================

#include<stdio.h>
#include<tchar.h>
#include<windows.h>

#define SLOT_NAME _T("\\\\.\\mailslot\\Mail")

int _tmain(int argc,TCHAR *argv[]){

 HANDLE hMailSlot;
 TCHAR message[BUFSIZ];
 DWORD bytesWritten;

 hMailSlot = CreateFile(       // 우체통에 글쓰려구 파일처럼 취급
  SLOT_NAME,GENERIC_WRITE,
  FILE_SHARE_READ,
  NULL,
  OPEN_EXISTING,
  FILE_ATTRIBUTE_NORMAL,
  NULL
 );

 if(hMailSlot == INVALID_HANDLE_VALUE){
  _fputts( _T("Unable to create mailslot ! \n"), stdout);
  return 1;
 }

 while(1){
  _fputts(_T("shell) "), stdout);
  _fgetts(message,sizeof(message)/sizeof(TCHAR), stdin);

  if(!WriteFile(hMailSlot,message,          //우체통에 글을 써버림.
   _tcslen(message)*sizeof(TCHAR), &bytesWritten, NULL)){
    _fputts( _T("Unable to write ! "), stdout);
    CloseHandle(hMailSlot);
    return 1;
  }

  if(!_tcscmp(message, _T("EXIT"))){    //입력문자열이 EXIT 면 끝!
   _fputts(_T("Good Bye!"), stdout);
   break;
  }
 }
 CloseHandle(hMailSlot);
 return 0;
}


 

반응형
반응형

설명은 하단에...


 

 

 

 

 

 

 

커널 : 운영체제의 핵심적인 부분

 

커널 오브젝트 : "커널 리소스의 정보를 담고 있는 데이터 블록"

                      -1. 해당 리소스(ex 프로세스) 의 상태 정보를 알려주기 위한 오브젝트

                      - 2. 프로세스  or 파일 등을 생성하면 생성과 동시에 이것들을 구분 짖는 어떤 정보들이 생성되는데 이러한 정보들을 말한다

 


 

핸들은 단지 핸들 테이블에 등록되어 있는 번호일뿐 실질적으로 프로세스의 커널 오브젝트에 직접 접근 할 수 없고 핸들 테이블 에서

 

해당 프로세스에 등록되어 있는 핸들과 매치가 되는 대상과 연결되게 되도록 되어 있다


 

 

각 프로세스는 각 프로세스 내에서의 고유 핸들이 있다 ( A ,B 프로세스에서는 A 에도 같은 번호의 프로세스 값은 있을 수 있지만 서로 같은

커널 오브젝트를 가르키고 있진 않을 수 있다 )

 

 

또한 각 프로세스는 자식 프로세스를 생성할때마다 자신의 핸들테이블에 생성된 자식 프로세스로 접근 할 수 있는 핸들 값을 리턴 받아

 

자신의 핸들 테이블에 저장해 놓고 자식 프로세스의 커널오브젝트 정보에 접근 할 수 있는 연결자를 가지고 있는데

 

연결된 개수만큼 해당 커널 오브젝트에는 usage count 가 올라가 있음으로 부모에서 자식 프로세스를 생성한다면 UC 는 2 가 되며

 

부모에서 자식을 닫으면 UC 는 1 이 되어 아직 살아 있게 된다, 즉 이것은 자식과 부모 관계를 끊는 결과를 가져오며 프로세스 종료는

 

UC=0 이 되야 종료 됨으로 자식 프로세스에서 UC 를 0 으로 낮춰야 (죽어야 최종적으로 죽어야 ) 자식 프로세스가 종료 된다

 

 

반응형
반응형

vs 는 파일 실행파일 경로를 순차적으로 아래 순서대로 검색해나간다

 

반응형
반응형

http://cs.knou.ac.kr/~khkim/faq/file.asp?code=aa027&num=1&snum=15


▣ LNK1104 : cannot open file "Debug/MiniMFC.exe"
▣ Mini MFC 단원에서 

[질문] =========================== 

Linking...
LINK : fatal error LNK1104 : cannot open file "Debug/MiniMFC.exe"
Error executing link.exe.
MiniMFC.exe - 1 error(s), 0 warning(s)

해결하는 방법은?

[답변] ===============================

해결방안 1 : 대부분의 경우 한번 실행한 후 실행된 윈도우를 닫지 않고 다시 실행하면 이런 에러가
발생합니다. 

해결방안 2 : 다운 받은 모든 파일의 속성을 열어서 읽기 속성을 쓰기로 바꿉니다. 

해결방안 3 : Visual C++을 닫고 프로젝트 폴더 내의 디버그 폴더를 삭제한 후 
Visual C++을 열고 나서 F5키를 눌어 실행시켜 줍니다.

또는

디버그 폴더를 삭제한 후 Build 메뉴에서 Rebuild All을 클릭하여 재컴파일 및 링크를 합니다.

-> 위와 같은 방법으로 해결이 안되는 경우는 다른 부분에 문제가 있는 것입니다. 
프로그램 문제는 아닙니다.

반응형
반응형

 

lib 파일 만든후 lib 링크 하고

lib파일과, 헤더파일 해당 프로젝트에 복사 한 후

헤더파일을 include 하면 함수를 사용 할 수 있다.

 

 

우선 해당 lib파일을 project에 include 시켜주어야 합니다.

그방식은 project->Setting->Link탭에서 library modules에 포함시키시거나

 

아래와 같이 Header파일에 포함하는 방식이 있습니다.

#pragma comment(lib, "C:\\abc\abc.lib")

 

다음으로 PcmtoWave()함수가 선언된 Header파일을 님이 사용하시려는 곳에서 include 시켜주시고

 

PcmtoWave()를 호출하시면 됩니다.

 

첫번째 Parameter는 PCM파일의 Path를 집어넣으시면 되고, 두번째 Parameter에서는 변환되서 저장될

 

Wav파일의 Path를 넘겨주시면 될듯 하네요






 http://pmguda.com/52


 라이브러리란?

특정한 코드(함수 혹은 클래스)를 포함하고 있는 컴파일된 파일이다. 

라이브러리를 만드는 이유?
 자주 사용되는 특정한 기능을 main 함수에서 분리시켜 놓음으로써, 프로그램을 유지, 디버깅을 쉽게하고 컴파일 시간을 좀더 빠르게 할수 있기 때문이다.

라이브러리에도 그 쓰임새에 따라서 여러가지 종류가 있다(크게 3가지). 가장 흔하게 쓰일수 있는 "정적라이브러리"와 "공유라이브러리", "동적라이브러리" 가 있다.

이들 라이브러리가 서로 구분되어지는 특징은 적재 시간이 될것이다.

정적라이브러리

정적라이브러리는 object file(.o로 끝나는) 의 단순한 모음이다. 정적라이브러린느 보통 .a 의 확장자를 가진다. 간단히 사용할수 있다. 컴파일시 적재되므로 유연성이 떨어진다. 최근에는 정적라이브러리는 지양되고 있는 추세이다. 컴파일시 적재되므로 아무래도 바이너리크기가 약간 커지는 문제가 있을것이다.

공유라이브러리

공유라이브러리는 프로그램이 시작될때 적재된다. 만약 하나의 프로그램이 실행되어서 공유라이브러리를 사용했다면, 그뒤에 공유라이브러리를 사용하는 모든 프로그램은 자동적으로 만들어져 있는 공유라이브러리를 사용하게 된다. 그럼으로써 우리는 좀더 유연한 프로그램을 만들수 잇게 된다.

정적라이브러리와 달리 라이브러리가 컴파일시 적재되지 않으므로 프로그램의 사이즈 자체는 작아지지만 이론상으로 봤을때, 라이브러리를 적재하는 시간이 필요할것이므로 정적라이브러리를 사용한 프로그램보다는 1-5% 정도 느려질수 있다. 하지만 보통은 이러한 느림을 느낄수는 없을것이다.

동적라이브러리

공유라이브러리가 프로그램이 시작될때 적재되는 반면 이것은 프로그램시작중 특정한때에 적재되는 라이브러리이다. 플러그인 모듈등을 구현할때 적합하다. 설정파일등에 읽어들인 라이브러리를 등록시키고 원하는 라이브러리를 실행시키게 하는등의 매우 유연하게 작동하는 프로그램을 만들고자 할때 유용하다.

– MS VC++  라이브러리 만들기


사용자 삽입 이미지
1.project name란에 라이브러리 이름 작성
사용자 삽입 이미지
사용자 삽입 이미지












2.test.c 파일을 생성한다.(함수 정의(구현)부분에 대한 내용)

3.test.h 파일을 생성한다.(함수의 선언부분이 있는곳)

사용자 삽입 이미지

 
//나만의 덧셈 라이브러리 만들기
#include <stdio.h>
#include "test.h"
//덧셈 함수 구현부분
int Add(int a,int b)
{
   return a+b;
}




3.test.h 에 함수에 대한 선언
   ex> int Add(int a, int b);
4.컴파일 하면 Debug 디렉토리 안에 프로젝트명.lib 이 생성

그 다음은 헤더파일을 해당 프로젝트에 넣고 라이브러리 링크
시키면 사용됨.

C로 만든 라이브러리를 C++ 프로젝트에 사용할때는 주의를 하자.
컴파일 과정에서 만들어진 라이브러리의 함수명이 차이가 있다.
C 로 만든 라이브러리는 C프로젝트에서..
C++로 만든 라이브러리는 C++프로젝트에서.. 
다른 방법으로는 위에 글에 설명..

반응형
반응형

http://blog.naver.com/guriis/40002401420




첨부파일 (1)

여기에 사용되는 설명은 DLLs for Beginners.Doc 문서에서 발췌 했다.

내가 설명하는 것 보단 훨씬 좋기 때문이다. 물론 난 글을 잘 못쓴다.

DLLs for Beginners.Doc 문서는 첨부 했다.

 

Static Linking(정적 링크)

C, Pascal, FORTRAN와 같은 고 수준의 프로그래밍 언어들에서는, 실행가능한 파일을 생성하기 위해서 응용프로그램의 소스 코드를 컴파일하고 다양한 라이브러리에 링크한다. 이러한 라이브러리들은 메모리를 할당하거나 숫자의 제곱근을 계산하는 것과 같은 일반적인 작업을 수행하기 위해서 호출되는 미리 컴파일된(precompiled) 함수들의 개체(object) 파일을 포함한다. 이러한 라이브러리 함수들이 응용프로그램에 링크될 때, 그것들은 응용프로그램 실행파일에 영구적으로 속하는(permanent) 부분이 된다. 그 라이브러리 함수에 대한 모든 호출은 링크 시간에 결정된다(resolved) - 즉 그 이름은 정적 링크(static linking)이다.

Dynamic Linking(동적 링크)

동적 링크는 실행시간에 응용프로그램이 라이브러리를 링크하는 메커니즘을 제공한다. 그 라이브러리들은 자체의 실행 파일에 존재하며, 응용프로그램의 실행 파일에 정적 링크처럼 복사되지 않는다. 이들 라이브러리들은 동적 링크 라이브러리(DLL)라고 불리우는데, 그것들이 로드되고 실행될 때가 그것이 링크되었을 때가 아니라 응용프로그램에 링크되었을 때임을 강조한 것이다. 응용프로그램이 DLL을 사용할 때, 운영 체제는 DLL을 메모리로 로드하고, DLL 안의 함수들에 대한 참조를 결정한다. 그래서 그것들은 응용프로그램에 의해 호출될 수 있으며, 더 이상 필요하지 않을 때 DLL은 언로드될 수 있는 것이다. 이 동적 링크 메커니즘은 응용프로그램이나 운영체제에 의해서 명시적으로 수행될 수 있다.


1.    File에서 New를 선택해서 Project 탭을 선택한다.

2.    프로젝트 타입 목록에서 Win32 Dynamic-Link Library를 선택한다 .

 

 

 

3.    적절한 프로젝트명을 기입하고, Finish.

 

 

 

이제 DLL을 위한 기본적인 프로젝트 파일이 만들어진 것이다

 

4.    cpp 및 헤더 파일 생성은 알아서 해라.

5.    def 파일은 File-New-C/C++HeaderFile 을 선택하고 파일명 기입시 확장자를 입력하면 된다.

 

MyDLL.cpp

#include <windows.h>

 

BOOL WINAPI DllEntryPoint(HINSTANCE hDllDWORD dwReasonLPVOIDReserved)

{

             switch(dwReason)

             {

                           case DLL_PROCESS_ATTACH:

                                        break;

                                       

                           case DLL_PROCESS_DETACH:

                                        break;   

             }

 

             return TRUE;

}

 

이것은 이 DLL을 사용하는 프로그램들이 이 DLL을 로드하면 DllEntryPoint()가 자동으로 호출이 되는 것이다. 그리고 위의 코드는 switch ~ case 문으로 구성이 되어있다. DLL_PROCESS_ATTACH는 DLL이 EXE에 로딩될 때, 실행된다. 그러므로 초기화에 관련된 코드는 이 곳에 넣어주면 된다. 또한 DLL_PROCESS_DETACH는 DLL이 EXE 파일에서 해제될 때 실행된다. 그러므로 이 부분엔 DLL을 사용하는 EXE 파일이 종료되기 직전에 실행될 부분을 넣어주면 된다.

 

 

int MyFunc(int aint b)

{

    return a*b;

}

int CdeclFunc(int  a)

{

    return  2*a;

}

 

MyDLL.h

int MyFunc(int aint b);

int CdeclFunc(int a);

 

MyDLL.def

EXPORTS

             MyFunc

             CdeclFunc

 

 

 

 

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

EXE 프로그램 작성


1.       File에서 New를 선택해서 Project 탭을 선택한다.

2.       프로젝트 타입 목록에서 Win32 Console Application 를 선택한다 .

 

 

 


 

 

 

3.       적절한 프로젝트명을 기입하고, Finish

 

 

 


 

 

APP.cpp

 

#include <windows.h>

#include <stdio.h>

 

void main()

{

             typedef int(*lbFunc1)(int);

             typedef int(*lbFunc2)(intint); // 포인터 함수 사용

 

    int x = 3;

             int a = 3;

 

             lbFunc2 Func2;

 

             HINSTANCE  hLibrary;

             hLibrary = LoadLibrary("MyCPP.dll"); //Load DLL in main

 

             ifhLibrary == 0 ){ //HINSTANCE handle 얻음

        printfNULL, " Load rfm Library failed.", 0 );

exit(0);

    }

 

             Func2 = (lbFunc2)GetProcAddress(hLibrary, "MyFunc"); // 함수 얻음.

             if(Func2 == NULL){

        printfNULL, " Load CMyFunc failed.", 0 );

        exit(0);

    }

            

             a = ((Func2)(x,a));

 

             printf("%d", a);

 

             FreeLibrary(hLibrary); //Free Library in main

}

dll 파일은 Exe 실행파일이 있는곳에 복사 해야 된다. /Debug 밑이나 /Release밑에 복사 하면 된다.

 

 이상 태클 걸지 마라나도 찾아서 알아  거다.

반응형
반응형

윈도우 운영체제 환경에서 특정한 프로세스가 장악하고 있는 핸들이나 DLL 파일에 대한 중요한 정보를 자세하게 살펴 볼 수 있는 Process Explorer의 v14.01 버전이 출시되었습니다.


프로그램은 아래 링크에서 다운로드할 수 있습니다.


 

 

반응형

'유틸리티 > 자료 & 사이트' 카테고리의 다른 글

한국 과학기술 연합 사이트  (0) 2012.11.02
Directx sdk summer 2004  (0) 2012.11.02
ECS P67H2-A3(B3) 오버클럭 후 클럭 고정 방법  (1) 2012.10.31
마이크로 소프트 고객센터  (0) 2012.10.31
딩컴  (0) 2012.10.31
반응형

http://www.winapi.co.kr/

 

 

1.소개

스파이는 비주얼 C++과 함께 배포되는 개발 보조툴로 주로 윈도우에 대한 정보를 조사하고자 할 때 사용된다. 윈도우의 클래스 이름이나 스타일 또는 포함 관계를 조사하거나 윈도우로 전달되는 메시지를 감시하는 것이 주된 용도이며 이 툴을 사용하면 다른 프로그램의 구성이나 동작 방식에 대해 많은 것을 배울 수 있다. 이름 그대로 이미 만들어져 있는 윈도우의 정보를  몰래 살짝 들여다 보는 도구이다. 그다지 실용적이지는 않지만 스레드나 프로세스에 대한 감시 기능도 제공한다.

스파이가 제공하는 정보는 Win32 API의 표기법을 그대로 사용하므로 이 정보를 제대로 해석하려면 Win32 API에 대한 기본적인 이해가 필요하다. 예를 들어 윈도우 스타일은 WS_CHILD나 WS_VSCROLL 등으로 표기되는데 이 상수들이 어떤 의미를 가지는가를 알고 있어야 하며 윈도우 클래스의 각 멤버에 대한 이해도 필요하다. 클래스 바이트(cbClsExtra)나 인스턴스 핸들, 윈도우 프로시저같은 용어에도 거부감이 없어야 한다. 이 강좌를 읽고 있는 사람이라면 이런 기본적인 용어에 대해서는 잘 알고 있을 것이다.

비주얼 스튜디오의 모든 버전에 포함되어 있기 때문에 별도로 설치할 필요가 없으며 각 버전별로 기능상의 차이점도 거의 없으므로 한가지 버전에 대해서만 사용법을 익혀두면 된다. 이 강좌는 비주얼 스튜디오 .Net의 Spy++로 작성되었다. 비주얼 C++ 6.0에도 스파이가 있고 더 최신의 닷넷 2003에도 포함되어 있는데 사용 방법은 비슷하다.

시작 버튼을 눌러 프로그램 메뉴를 열고 비주얼 스튜디오 폴더의 Visual Studio .Net Tools를 선택하면 이 안에 Spy++이 등록되어 있으며 이 항목을 선택하면 스파이가 실행된다. 한번만 실행되는 프로그램이므로 이미 실행중이라면 실행중인 스파이로 포커스만 넘어간다. 자주 사용한다면 단축 아이콘을 만들어 놓는 것이 좋을 것이다. 스파이는 다음과 같이 생겼다.

MDI 형태로 되어 있으므로 여러 개의 뷰를 동시에 열어 놓을 수 있으나 실제 중요한 정보는 개별적인 대화상자를 통해 확인하기 때문에 MDI의 이점은 별로 없는 셈이다. 대체로 관심있는 뷰 하나만 열고 최대화해 놓고 많이 쓰는 편이다.

비주얼 C++ 6.0까지는 영문으로 되어 있었으나 7.0부터는 스파이도 한글화되어 메뉴나 대화상자의 캡션이 한글로 바뀌었다. 그러나 개발자들은 실제로 영문으로 된 전문 용어에 익숙해져 있기 때문에 번역된 캡션이 더 어색하게 느껴지기도 한다. 번역이 그다지 매끄럽지는 않지만 번역된 캡션을 보면 어떤 대상을 가리키는지 직관적으로 알 수 있는 정도이다. 예를 들어 "창 바이트"라는 말은 윈도우의 여분 바이트(cbWndExtra)라는 뜻이고 "창 프로시저"라는 말은 윈도우 프로시저의 번지라는 뜻이다. 개인적으로 이런 전문적인 프로그램은 한글화 하지 않는 것이 더 좋다고 생각한다.

타이틀 바 아래에 메뉴가 있고 그 아래에 툴바가 있으며 작업영역 아래에는 상태란이 배치되어 있어 전체적인 모양은 지극히 평범하다. 메뉴에는 스파이의 모든 명령들이 정리되어 있겠지만 대부분의 명령들이 툴바에 있으므로 이 버튼들에 대해서만 알아 두면 스파이의 모든 기능을 다 활용할 수 있다.

메뉴에 있는 명령 중 유일하게 실용성이 있는 명령은 메인 윈도우의 글꼴을 변경할 수 있는 보기/글꼴 명령밖에 없다. 디폴트 글꼴은 9포인트의 Sans Serif인데 굴림이나 바탕으로 변경할 수 있으며 글꼴의 크기도 크게 만들 수 있다. 다음은 툴 버튼에 대한 간략한 설명이다.

 

버튼

설명

 뷰를 보여준다.

프로세스 뷰를 보여준다.

스레드 뷰를 보여준다.

메시지 옵션 대화상자를 보여준다.

 찾기 대화상자를 띄운다.

메시지 기록을 시작하거나 잠시 중지한다.

메시지 옵션 대화상자를 보여준다.

지금까지 조사된 메시지 기록을 삭제한다.

조건에 맞는 프로세스스레드메시지를 검색한다.

다음 찾기

이전 찾기

 속성 대화상자를 보여준다.

새로 고침.

 

상태란은 선택된 메뉴나 툴바에 대한 간단한 도움말을 보여주는 정도의 기능밖에 없다. 겉으로 보이는 이런 것들 외에 화면 각 부분을 누르면 나타나는 팝업 메뉴가 있는데 이에 대해서는 관련 부분에서 따로 설명하기로 한다.

 


 

6.메시지 뷰

메시지 뷰는 윈도우로 전달되는 모든 메시지를 감시하여 어떤 메시지가 어떤 인수와 함께 전달되었는지를 보여준다. 프로세스나 스레드로 전달되는 메시지를 감시할 수도 있지만 주로 윈도우의 메시지를 감시하는 경우가 많다. 전달되는 모든 메시지를 순서대로 살펴볼 수 있기 때문에 디버깅과 분석시에 아주 큰 도움이 된다.

메시지 뷰를 열 때는 각 뷰의 팝업 메뉴에서 메시지 항목을 선택하면 된다. 예를 들어 메모장의 에디트 컨트롤로 전달되는 메시지를 보고 싶다면 창 뷰에서 에디트 컨트롤을 선택하고 팝업 메뉴에서 메시지 항목을 선택하면 된다. 또는 창 찾기 대화상자에서 찾기 도구를 메모장의 에디트에 떨어뜨린 후 대화상자 아래의 표시 항목을 메시지로 선택해도 된다.

 

메시지 기록이 시작되면 메시지 뷰가 열리며 여기에 해당 윈도우로 전달되는 메시지들이 순서대로 출력된다. 스파이는 메시지 감시를 위해 후킹을 사용하기 때문에 메시지를 감시하는동안에는 시스템의 전반적인 속도가 눈에 띄게 느려지는데 속도만 느려질 뿐 기능상의 문제는 없다. 윈도우로 전달되는 메시지를 일일이 감시하고 문자열로 바꾸어 출력하고 있으니 느려질 수밖에 없다. 다음은 메모장으로 전달되는 메시지들이다.

제일 왼쪽의 번호는 메시지의 일련 번호이며 두번째 칸의 16진수는 메시지를 받은 윈도우의 핸들이다. 세번째 P,R,S,s는 메시지가 전달된 방식을 나타내는 메시지 코드가 출력된다. 메시지 코드는 다음과 같다.

 

코드

설명

P

PostMessage 함수로 메시지 큐에 붙여진 메시지이다.

S

SendMessage 함수에 의해 윈도우 프로시저로 직접 전달된 메시지이다.

R

S 보내진 메시지를 처리한 결과이다메시지 처리 중에 다른 메시지를  보낼  있기 때문에 S R 중첩될  있다.

s

S 유사하되 보안상의 이유로  메시지의 처리 결과를 조사할  없다.

 

메시지 코드 다음에는 실제 전달된 메시지와 메시지의 인수들이 표시되는데 각 메시지별로 의미가 해석되어 있다. 예를 들어 WM_KEYDOWN이면 어떤 키가 눌러졌고 반복 회수는 얼마이며 스캔코드와 확장키의 상태 등이 표시되며 WM_CHAR이면 입력된 문자를 보여준다. wParam, lParam을 보여주는 것이 아니라 인수로 전달된 메시지의 논리적인 실제값을 보여주기 때문에 메시지의 의미를 파악하기가 쉽도록 되어 있다.

윈도우로 아주 많은 메시지가 전달될 뿐만 아니라 전달되는 속도가 대단히 빠르기 때문에 순식간에 수백개의 메시지가 전달된다. 그러다 보니 정작 관심있는 메시지가 너무 빨리 위로 스크롤되어 버리는 불편함이 있는데 스파이는 원하는 메시지를 자세히 살펴 볼 수 있도록 몇가지 장치를 제공한다.

우선 툴바의  버튼을 누르면 기록을 잠시 중지/재개할 수 있다. 살펴보고 싶은 메시지가 전달되었으면 메시지 기록을 일단 중지하고 목록을 살펴볼 수 있다.  버튼은 지금까지 작성한 모든 기록을 삭제하고 다시 기록을 시작하도록 한다.  버튼은 메시지 기록에 대한 몇가지 옵션을 지정하는 다음 대화상자를 보여 준다.

세 개의 페이지로 구성되어 있는데 이 대화상자에도 찾기 도구가 있으므로 대상 윈도우를 직접 변경할 수 있다. 뿐만 아니라 추가 창을 선택하면 관련있는 주변 윈도우로 전달되는 메시지도 같이 감시할 수 있다. 메시지 페이지에서는 기록 대상 메시지를 선택한다.

디폴트로 모든 메시지를 다 기록하도록 되어 있는데 여기서 관심있는 메시지만 선택하거나 불필요한 메시지는 선택 취소할 수 있다. 예를 들어 다른 메시지는 관심이 없고 키보드 관련 메시지만 보고 싶다면 Keyboard만 선택하면 된다. 또한 WM_MOUSEMOVE, WM_NCHITTEST 같은 메시지는 너무 자주 발생하므로 제외시킬 수도 있다. 출력 페이지는 메시지의 출력 형식을 지정한다.

파일에도 로그 옵션을 선택하고 파일명을 주면 메시지 기록을 텍스트 파일에도 작성해 주므로 조사가 끝난 후 파일을 열어서 볼 수 있다. 메시지 전달 속도가 너무 빠르기 때문에 화면으로 확인하기 힘든 메시지는 파일에서 정밀 검색하면 된다.

메시지 뷰가 보여 주는 정보는 아주 다양하게 활용된다. 우선 디버깅에 활용되는데 메시지가 전달되는 순서와 처리되는 과정을 자세하게 살펴 볼 수 있어 프로그램의 동작을 세밀하게 감시할 수 있다. 프로그램이 이상 동작을 한다면 그 시점이 언제인지를 스파이로 조사할 수 있으며 일단 시점이 파악되면 디버거로 해당 메시지를 집중 디버깅해 보면 된다. 또한 원치않은 메시지가 발생한다면 어떤 메시지에 의해 추가로 발생한 메시지인지, 그 순서는 어떻게 되는지를 알 수 있으며 SendMessage로 보낸 메시지를 확실히 수신했는지 확인할 수도 있다.

Win32 API를 처음 공부하는 사람에게 스파이는 또한 학습용으로도 아주 가치가 있는데 예를 들어 IME같이 메시지의 순서나 파생 관계가 복잡할 때 스파이를 활용하면 메시지의 발생 시기와 순서을 정확하게 알 수 있다.

 

반응형
반응형

http://sol9501.blog.me/70102942944


|DLL 분석 ①|DLL파일 생성과 설명

 

* 이번 포스팅은 실제 DLL파일이란 무엇인지 알아보고 직접 생성하는 방법을 알아보겠습니다.

 

 

 1. DLL(Dynamic Link Library)이란?

   1)정의

     - 어플리케이션에서 동적으로 링크하여 사용할 수 있는 라이브러리를 말하며 확장자로는 .dll, .fon, .drv, .exe 등이 사용된다.

구조는 간단히 코드부분과 데이터로 구성되어있으며, 스택이 없다는 것이 특징이다. 스택은 어플이케이션의 것을 사용한다. 스택이 없으므로 독립적인 프로세스가 될 수 없으며 운영체제로 부터의 메세지를 받을 수 없다. 내부에 Exported Function Table을 가지고 있으며 서수 + 기호이름 + 실제함수를 가리키는 포인터로 구성되어 있다.

 

   2) 종류

    - Regular DLL (Statically linked MFC DLL) : 배포시 자신의 DLL만 제공가능

    - Regular DLL (using Shared MFC DLL) : 배포시 자신의 DLL과 MFC공유DLL을 같이 제공

      -> 어플리케이션이 MFC이외의 경우에도 사용가능

      C언어 기반의 인터페이스제공 필요.

     - MFC Extension DLL (using Shared MFC DLL) : MFC로 작성된 어플리케이션에서만 사용가능

 

    3) 로딩방법

     ㄱ) Implicit Loading (암시적 로딩)

        - DLL + Lib + header file 필요. 

- 어플리케이션 로딩때 같이 로딩.

     ㄴ) Explicit Loading (명시적 로딩)

         - 로딩타임 마음대로 결정가능

- 주요함수

- LoadLibrary : DLL모듈 로딩

- GetProcAddress : 함수의 포인터를 얻어옴

- FreeLibrary : DLL 종료 (reference counter를 1감소시킨다)

 

* 이번 포스팅은 DLL 파일 생성 방법만 알아보고 로딩방법이나 기타 자세한 상항은 PE파일 (DLL 로딩과 임포트 섹션편)을 참고해 주시길 바랍니다.

DLL 로딩과 임포트 섹션 - 포스팅중..^^

 

 

  2. DLL 생성

    - DLL을 만드는 방법에는 크게 두 가지가 있다. 하나는 고전적인 DLL정의 방법인 모듈 정의 파일을 이용하는 것이고 다른 하나는 내장 Visulal c++ 지시자인 __declspec(dllexport)를 이용하는 것이다. 우선은 고전적인 방법인 모듈정의 파일을 이용해 먼저 DLL 파일을 생성해 보겠습니다. 소스는 아래와 같습니다. VS2010기준으로 DLL 파일을 생성하는 방법은 아래의 그림 1-1부터 1-3과 같습니다.

 

그림 1-1) win32 project

 

그림 1-2) Application Setting

 

- 그림 1-2에서처럼 어플리케이션 타입은 DLL을 클릭해 줍니다. 프로젝트가 생성되었으면 빈 cpp소스파일을 하나 생성하고 아래의 예제소스를 복사해 붙여 넣고 빌드합니다. 빌드가 성공하면 그림 1-3과 같이 dll 파일이 생성됩니다.

 

Ex1) 예제소스 1

#include <Windows.h>

 

void WINAPI DrawTextPos04(HDC hDC, LPTSTR pszText, POINT ptPos)

{

TextOut(hDC, ptPos.x, ptPos.y, pszText, lstrlen(pszText));

}

 

int IntSum06(int a, int b)

{

    return a+b;

}

 

BOOL WINAPI IsPointInRect11(RECT rcRgn, POINT ptPos)

{

    return PtInRect(&rcRgn, ptPos);

}

 

 

그림 1-3) Application Setting

 

- 여기서 잠깐 우리는 저 DLL을 왜 만드는지 짚고 넘어가야 한다. DLL을 사용하는 근본적인 이유는 반복해서 사용하는 코드를(위의 경우 3가지 함수들) 매번 작성할 것이 아니라 따로 바이너리 모듈로 만들어두고 필요할 때마다 링크해서 사용하고자 하는 목적이다. 여기서 확장자가 .lib라는 파일인 정적 라이브러리와 .DLL인 동적 라이브러리로 나뉘는데 이 둘의 차이는 정적 라이브러리는 코드나 데이터가 링크 시에 pe파일 내에 병합되어 그만큼 PE파일의 사이즈가 커지지만 동적 라이브러리의 경우(.DLL) 라이브러리의 코드나 데이터는 해당 PE가 로드 될 때 그 PE의 가상 주소 공간에 병합된다는 것입니다. 즉 링크된 EXE의 PE 파일에는 단지 해당 라이브러이에서 사용할 함수에 대한 간단한 정보만 기록됩니다.(이 부분의 확인은 위에서 링크한 PE파일 익스포트 섹션분석편을 참고하세요.)

모듈 자체가 정적 라이브러리처럼 EXE의 PE이미지 내에 병합되는 것이 아니기 때문에 DLL의 경우 이렇게 실행 이미지에 병합하고자 하는 함수나 변수는 미이 병합될 함수라는 것을 컴파일러나 링커에게 알려주어야 합니다. 이렇게 알려주는 것을 "익스포트"한다라고 하는데 익스포트시키지 않으면 해당 DLL 내의 어떤 함수나 변수를 사용할 수 있는 지 판단한 수 없습니다.

위의 과정은 단지 함수만 정의했을 뿐 그 외 어떠한 것도 지정하지 않았습니다. 즉 익스포트시키지 않은 것입니다. 그 결과 그림 2와 같이 dumbin 으로 익스포트 정보를 요구해도 아무런 정보가 나타나지 않는 것입니다.

이러한 익스포트 하는 방법으로 위에서 언급한 모듈 정의 파일을 정의하거나 __declspec(dllexport) 지시어를 사용하는 방법이 있습니다. 우리는 우선 고전적이고 지금은 사용빈도가 적지만 기본이 되는 모듈 정의 파일을 이용하는 방법을 알아보겠습니다. 제가 항상 말씀드리지만 고수와 하수의 차이는 기본기에 있습니다. ^^ 기초가 튼튼해야죵..^^

 

그림 2) 익스포트 되지 않은 dll파일

 

 

1) 모듈정의 파일 사용

- 모듈 정의 파일의 장점은 서수를 지정할 수 있다는 것이다. 서수를 지정할 수 있다는 이야기는 서수가 익스포트 함수들에 대한 인덱스 역할을 하게 되기 때문에 문자열 비교 없이 빠른 속도로 해당 함수를 링크할 수 있다는 장점이 있다. 또한 DLL에 익스포트 함수를 새로 추가할 때 이 함수에 해당하는 서수를 그 DLL내에서 익스포트된 다른 모든 함수의 서수 값들보다 더 높은 값으로 할달 할 수 있다. 이렇게 되면 암시적 링크를 사용하는 응용 프로그램에서 새로운 함수가 추가된 DLL에 해당하는 LIB파일을 다시 링크할 필요가 없어진다. 이 경우 기존의 DLL에 새로운 기능을 추가하여 계속 업그레이드시키면서도 기존 응용 프로그램이 업그레이드된 DLL과 올바르게 작동하도록 할 수 있다. 또한 만약 익스포트시킬 함수가 많을 경우 모듈 정의 파일을 통해 "NONAME"의 속성을 지정하게 되면 함수 이름을 저장하지 않고 서수만 저장하기 때문에 DLL의 사이즈를 최적화할 수 있다.

아래 그림 3은 모듈정의 파일을 정의하는 방법을 보여주고 있다. 모듈정의 파일은 노트패드나 문서화 도구를 이용해서 아래 그림 3과 같이 만들어 주면 된다.

 

그림 3)모듈 정의 파일(.DEF)

 

- 모듈 정의 파일은 말 그대로 모듈을 정의한다는 의미이다. 이 말은 곧 굳이 작성하는 PE가 DLL이 아니라 exe이더라도 링크 시에 모듈정의 파일에 정의된 지시어들이 유효함을 말하며 링커는 모듈 정의 파일이 존재한다면 이 파일에 지정된 지시어들을 링크 스위치로 해석하게 된다. 일반적으로 모듈 정의문 대신에 사용할 수 있는 링커 옵션이 있기 때문에 일반적으로는 모듈 정의 파일이 필요하지 않다. 하지만 함수 익스포트의 경우 위의 그림 3처럼 EXPORTS 키워드 아래에 익스포트 함수들을 한 번에 정의할 수 있기 때문에 DLL 작성시 모듈 정의 파일을 사용하는 것이다. 각 키워드는 표 1을 참고하세요.

 

[표 1] – 모듈정의 파일

키워드

의미

LIBRARY

형식

LIBRARY [library][BASE=address]

library

* library 옵션은 DLL의 이름을 지정한다. 링커 옵션 /OUT을 사 용하여 DLL의 출력 이름을 지정 할 수도 있다.

BASE=address

* BASE= ADDRESS 옵션은 운영체제가 해당 DLL을 로드하는데 사용하는 기본 주소를 설정한다. 정의되지 않았다면 DLL 매핑의 디폴트 주소인 0x10000000으로 설정한다.

EXPORTS

형식

EXPORTS

definition

definition = entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

entryname

* entryname은 익스포트하고자 하는 함수 또는 변수의 이름으로서 반드시 지정되어야 하는 요소이다. internalname의 경우는 익스포트하고자 하는 이름이 DLL에 있는 이름과 다른 경우에 이 요소를 통해 실제 이름을 지정하기 위해 사용된다.

@ordinal

* @ordinal을 사용하면 함수 이름이 아닌 서수가 DLL의 익스포트 테이블에 들어가도록 지정된다. 이렇게 서수를 지정하게 하면 후에 DLL을 링크하는 응용 프로그램에서는 이름 대신 서수를 통해 해당 함수를 링크하게 된다.

NONAME

* 선택적 키워드인 NONAME을 사용하면 함수를 서수로만 익스포트시키기 때문에 해당 DLL이 많은 익스포트 함수를 정의할 경우에 익스포트 테이블의 크기를 줄일 수 있다. 하지만 링크하고자 할 때 이름이 유효하지 않게 되므로 반드시 서수를 알아야 한다.

PRIVATE

* 선택적 키워드인 PRIVATE는 LINK로 생성된 LIB파일에 ENTRYNAME이 포함되지 않도록 한다.

DATA

* 선택적 키워드인 DATA는 익스포트 대상이 코드가 아니라 데이터임을 알려준다.

EXPORTS

DllExam @1 PRIVATE, DATA

DllName = ValName DATA

DllObject @4 NONAME, PRIVATE

DllRegi

 

 

- 위의 그림 3과 같이 모듈정의 파일을 정의했으면 이젠 다음 그림4와 같이 정의 파일을 프로젝트에 포함시켜주자.

 

그림 4) 모듈정의 파일 추가

 

 

- 위의 그림 4와 같이 모듈정의 파일을 추가했으면 다시 한 번 빌드해줍니다. 그러면 이번에는 lib파일과 exp파일이 생성되었음을 알 수 있습니다. 아래의 그림은 dumpbin으로 다시 한 번 DLL의 익스포트 정보를 확인해 보겠습니다.

 

그림 5) DLL 익스포트 정보

 

 

- 그림 2와 비교하여 이 번에는 예제소스의 함수들이 제대로 익스포트되어 출력됨을 알 수 있습니다. 실행방법은 생성된 lib파일을 실행할 프로젝트에 포함시키고 컴파일 시키시면 됩니다. 아래 그림 6은 실행화면 설명입니다. 소스는 실행파일 소스입니다.

 

 

Ex2) 실행파일 소스 1

#include <windows.h>

 

#define DLL_NAME "DllExam_01.dll"

 

void ChkPrint(LPCTSTR str);

int IntSum06(int a, int b);

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpCmdLine,intnShowCmd)

{

    HMODULE hModule;

    TCHAR buf[512];

 

    hModule = LoadLibrary(DLL_NAME);

 

    

    wsprintf(buf,"hModule = 0x%8x\n",hModule);

    ChkPrint(buf);

    

 

    wsprintf(buf,"hModule = %d\n",IntSum06(5,6));

    ChkPrint(buf);

 

 

    return 0;

}

 

    void ChkPrint(LPCTSTR str)

{

    MessageBox(HWND_DESKTOP,str,"OK",MB_OK);

}

 

 

그림 6) 모듈정의 파일 방법실행

 

 

2) __dlclspec(dllexport) 지시자 사용

- MS에서는 컴파일러에서 익스포트할 함수나 변수의 이름을 자동으로 생성한 다음에 ,LIB 파일에 포함시킬 수 있도록 하였는데 그 때 쓰이는 지시자가 __declspec이다. dexlspec(dllexport) 지시자를 사용하여 dll에서 데이터, 함수, 클래스 또는 클래스 멤버 함수를 내보낼 수 있도록 변경할 수 있다. 그리고 __declspec(dllexport)와 쌍으로 사용되는 키워드가 __declspec(dllimport)이다. __declspec(dllexport)은 컴파일러로 하여금 해당 함수가 익스포트될 것임을 알려준다. 반대로 __declspec(dllimport)는 컴파일러로 하여금 해당 함수가 임포트되는 함수임을 미리 알려주는 역할을 한다. 소스파일과 헤더파일의 소스는 아래와 같습니다.

 

 

Ex3) 소스 1

#include "Windows.h"

 

#ifdef __cplusplus

#define DLLBASIC_API extern "C" __declspec(dllexport)

#else

#define DLLBASIC_API __declspec(dllexport)

#endif

#include "Dll_declspec.h"

 

void WINAPI DrawTextPos04(HDC hDC, LPTSTR pszText, POINT ptPos)

{

    TextOut(hDC, ptPos.x, ptPos.y, pszText, lstrlen(pszText));

}

 

int WINAPI IntSum06(int a, int b)

{

    return a+b;

}

 

BOOL WINAPI IsPointInRect11(RECT rcRgn, POINT ptPos)

{

    return PtInRect(&rcRgn, ptPos);

}

 

 

Ex4) 헤더 1

#ifndef __DLLBASIC_H__

#define __DLLBASIC_H__

 

#ifndef DLLBASIC_API

#ifdef __cplusplus

#define DLLBASIC_API extern "C" __declspec(dllimport)

#else

#define DLLBASIC_API __declspec(dllimport)

#endif

#endif

 

DLLBASIC_API void WINAPI DrawTextPos04(HDC hDC, LPTSTR pszText, POINT ptPos);

DLLBASIC_API int WINAPI IntSum06(int a, int b);

DLLBASIC_API BOOL WINAPI IsPointInRect11(RECT rcRgn, POINT ptPos);

 

#endif    //__DLLBASIC_H__

 

- 위의 소스가 정의문들이 많아 약간 어려워 하실 분들도 있을 수 있겠지만 실상은 상당히 간단한 문장입니다..

__cplusplus와 extrn "C"는 함수 호출 방법에 따른 스택정리와 이름 데코레이션의 관계때문에 정의해 준 부분입니다. 이 부분을 설명하자면 이번 포스팅의 범위를 넘어가니 이 부분은 따로 관계된 문서를 찾아 보시길 바랍니다.

아래 그림과 같이 소스 파일과 헤더파일을 추가 시키고 빌드 하면 위이 파일정의 모듈방식과 동일하게 LIB파일이 생성됨을 알 수 있습니다. 이 파일을 dumpbin으로 출력해보면 위의 그림 5와 같이 익스포트 정보들이 출력됨을 알 수 있습니다.

 

그림 9) declspec 빌드

 

그림 10) dumpbin 출력화면

 

반응형
반응형

http://cs.knou.ac.kr/~khkim/faq/slist.asp?code=aa027&num=1

 

 

▣ LIB, DLL 관련 문제 해결 방법(error C3861, LNK2019, LNK1136)
▣ LIB, DLL 관련 문제 해결 방법(error C3861, LNK2019, LNK1136)

[답변] ===============================
1. error C3861:'FUNCTION_NAME()':인수 종족성을 조회해도 식별자를 찾을 수 없습니다.

-> 프로토타입 선언을 하지 않았다.
헤더나 cpp의 상단에 라이브러리 내에 존재하는 함수의 선언을 해주어야 한다.
(ex. int FUNCTION_NAME(char* str); )

2. error LNK2019: unresolved external symbol 
(또는 "외부기호를 찾을 수 없습니다.." 어쩌구.. 저쩌구..)

-> 프로젝트에 lib 파일을 링크시키지 않았다. 
메인메뉴- Project- Link(링커)- object/library modules 에다 lib파일을 추가시키자.

3. LNK1136: invalid or corrupt file Error executing link.exe.
( 또는 "파일이 잘못되었거나 손상되었습니다." )
-> object/library modules에다가 'lib'파일이 아니라 'dll'파일을 적어두지 않았는지?
굳이 dll이 아니라도 lib가 아닌 걸 쓰면 이런 에러도 뜬다. 

※ DLL을 Implicit binding으로 쓰고 싶다면 "파일명.dll"과 "파일명.lib" 둘 모두 
있어야 한다.

 

반응형
반응형

방법은 간단하다

 

프로젝트 A, 프로젝트 B 가 있고 B 가 lib 로 생성된다고 하고 A 가 시작프로젝트이며

 

빌드 순서는 B->A 의 종속성이라고 가정하면

 

프로젝트B의 출력디렉토리를 프로젝트A의 'VC++라이브러리' 경로에 추가해준다

 

대부분 B프로젝트의 경우는 출력디렉토리가 $(SolutionDir)$(Configuration)\ 로 지정되어 있음으로 이것을 복사해

 

A프로젝트의 라이브러리 경로에 추가하면 된다


반응형
반응형

static link 이든 dynamic link 이든 둘다 라이브러리이다

 

그런데 사용 방법에 있어 좀 차이가 있다

 

상황에 따라 적절한 것을 사용 하면 되겠다

 

 

static link  실행 파일에 라이브러리를 포함하여 배포 : 일반적으로 사용자는 해당 dll 을 가지고 있지 않기 때문에 이 방식으로

배포를 한다

 

static link(debug) 싱행파일에 라이브러리를 포함하는데 debug 할 수 있는 정보까지 같이 배포한다

 

dynamic link 라이브러리를 독립적으로 분리한다, 이점은 하나의 파일만 만들어 짐으로 메모리 점유율이 static link 보단 적다

 

그리고 개발 시 dll 부분에 오류가 있으면 해당 dll 만 수정하여 해당 dll 만 배포하면 된다

 

또한 여러곳에서 동일한 파일로 툴, 엔진 등의 라이브러리 관리를 static link 처럼 종속되지 않고 독립적으로

 

관리 할 수 있어 관리의 용이성이 더해진다

 

 

dynamic link (debug) dynamic link 에 debug 정보를 포함하여 해당 dll 에서의 debug도 가능하게 해준다

 

 

 

반응형
반응형

라이브러리란 특정한 코드(함수 혹은 클래스)를 포함하고 있는 컴파일된 파일이

 

 

 

 

라이브러리를 만드는 이유는 자주 사용되는 특정한 기능을 main 함수에서 분리시켜 놓음으로써, 프로그램을 유지, 디버깅을 쉽게하고 컴파일 시간을 좀더 빠르게 할수 있기 때문이다.

 

 

 

 

라이브러리에도 그 쓰임새에 따라서 여러가지 종류가 있다(크게 3가지). 가장 흔하게 쓰일수 있는 "정적라이브러리"와 "공유라이브러리", "동적라이브러리" 가 있다. 이들 라이브러리가 서로 구분되어지는 특징은 (로드) 시간이 될것이다.

 

http://cafe.naver.com/whatvoip.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=202&

 

 

C로 만든 라이브러리를 C++ 프로젝트에 사용할때는 주의 하자. 컴파일 과정에서 만들어진 라이브러리의 함수명이 차이가 있다. C 로 만든 라이브러리는 C프로젝트에서, C++로 만든 라이브러리는 C++프로젝트에서

 

 

 

 

 


정적라이브러리 

 

정적라이브러리는 object file(.o로 끝나는) 의 단순한 모음이다. 정적라이브러린느 보통 .a 의 확장자를 가진다. 간단히 사용할수 있다. 컴파일시 적재(로드)되므로 유연성이 떨어진다. 최근에는 정적라이브러리는 지양되고 있는 추세이다. 컴파일시

적재(로드)되므로 아무래도 바이너리크기가 약간 커지는 문제가 있을것이다.

 

 

공유라이브러리


공유라이브러리는 프로그램이 시작될때 적재(로드)된다. 만약 하나의 프로그램이 실행되어서 공유라이브러리를 사용했다면, 그뒤에 공유라이브러리를 사용하는 모든 프로그램은 자동적으로 만들어져 있는 공유라이브러리를 사용하게 된다. 그럼으로써 우리는 좀더 유연한 프로그램을 만들수 잇게 된다.

 

정적라이브러리와 달리 라이브러리가 컴파일시 적재되지 않으므로 프로그램의 사이즈 자체는 작아지지만 이론상으로 봤을때, 라이브러리를 적재하는 시간이 필요할것이므로 정적라이브러리를 사용한 프로그램보다는 1-5% 정도 느려질수 있다. 하지만 보통은 이러한 느림을 느낄수는 없을것이다.

 

 

동적라이브러리


공유라이브러리가 프로그램이 시작될때 적재(로드)되는 반면 이것은 프로그램시작중 특정한때에 적재(로드)되는 라이브러리이다. 플러그인 모듈등을 구현할때 적합하다. 설정파일등에 읽어들인 라이브러리를 등록시키고 원하는 라이브러리를 실행시키게 하는등의 매우 유연하게 작동하는 프로그램을 만들고자 할때 유용하다.

 

 


 

 


정적 라이브러리와 동적 라이브러리 차이  C++ /API/MFC 

2011/10/13 15:15

복사http://blog.naver.com/hacker1420/120142196000

정적 라이브러리(lib) : 컴파일할 때 같이 링크 

동적 라이브러리(dll) : 컴파일 할 떄가 아닌, 실제로 프로그램이 실행될 때 동적으로 링크

 

둘 다 실행 모듈이지만 언제 링크가 되느냐의 차이!

메모리를 효율적으로 쓰기 위해서는 lib 보다 dll 방식이 좋음.(필요할 때만 링크해서 쓰고 필요 없으면 바로 해제)

lib 방식은 프로그램이 실행되면 바로 메모리를 차지하고 프로그램이 종료될 때까지 메모리에 남아있음.

반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..








Dll 예제 파일, 소스안에 설명

 

 

실행 환경 vs2008




p.s 예전에 만들었던것..

3dmp

반응형

'운영체제 & 병렬처리 > DLL_LIB' 카테고리의 다른 글

dll과 lib 배포하기  (0) 2012.11.01
Dll과 Lib 차이와 설명  (0) 2012.11.01
확장 DLL 전역변수 선언 및 사용  (0) 2012.11.01
dllimport과 dllexport  (0) 2012.11.01
__declspec(dllimport)의 호출 원리  (0) 2012.11.01
반응형

퍼온글임..

 

 

확장 DLL 전역변수 선언 및 사용

1. 전역변수 사용에 대한 고찰..
: 전역 변수는 파일 내부의 전역변수와 파일 외부의 전역변수로 나뉩니다.

: 파일 내부의 전역변수는.. 그 파일 내에서 유효한 범위를 가지는 변수로
함수의 외부에서 선언하며 그 선언된 아래쪽에서 유효합니다.

: 파일 외부의 전역변수는.. 그 프로젝트에 포함된 다른 소스 파일의 전역변수 중
공통으로 가져다 쓰고자 할 때 사용되며, 포함하고자 하는 소스파일에서는
extern 변수형 변수명..형태로 포함한 후.. 자신의 전역변수처럼 사용할 수 있습니다.

: 아래에 내부 전역 변수와 외부 전역 변수를 구분합니다.

ex) A.cpp ----

#include "stdafx.h"
#include "A.h"

...

int g_nSum = 0; <== 전역변수..일반적으로 Global이라는 뜻의 g_사용(이츠 미)

CA::MyFunc()
{

int nValue = 10; <== 지역변수..함수 내부에서만..유효

m_nKuk = 100; <== 멤버 변수 형태..

g_nSum += (nValue + m_nKuk); <== 전역변수 사용

....

}

CA::PrintSum()
{

printf( "%d", g_nSum );

}

사실.. 클래스 개념으로 오면서.. 전역변수와 멤버 변수는 차이가 없어졌습니다..

도스형 코딩에 익숙한..깨고르..같은 사람은.. 부분적으로 쓰고는 있지만..
멤버 변수와 컨트롤 변수, 전역변수.. 비슷하면서도..조금은 다르더군여..

그렇지만..멤버 변수와 전역변수는 거의 같은거 가타영..!--

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

B.cpp ---

#include "stdafx.h"
#include "B.h"

...

int g_nSum; <== 이로케..하면.. 내부의 전역 변수가..되어서. A.cpp의
g_nSum 과는 전혀 다른값을 가지게..됩니다.

위의 부분을 외부 전역변수 형태로 만든다면..

int g_nSum ==> extern int g_nSum; 처럼..해주면..됩니다.

즉.. 자신의 파일이 아닌..외부(extern)의 파일에 전역변수 선언되어 있는 g_nSum을 
이용하겠다고 컴파일러에게 알리는 것입니다.

그리고선.. 그냥..자신의 전역변수처럼..쓸 수 있져..!--

2. DLL 내부에서 전역변수 선언하기(외부 전역변수 선언으로..)
: 전역변수의 원형 선언 : __declspec(dllexport) 변수 타입, 변수~명..

ex) __declspec(dllexport) int g_nSum;

: DLL 전체에서 사용하기 위해..extern 선언.. : extern __declspec(dllexport) 변수 타입, 변수~명..

ex) extern __declspec(dllexport) int g_nSum;

+++> 위의 전역변수 선언을 보면.. __declspec(dllexport)외에는 별루 다른게 없어 보입니다.

: 클래스를 확장 DLL로 선언하기..위하여..

클래스의 헤더 선언부에.. class CA::public CWnd
{
요런식으루..선언되어 있는데..
이걸.. 다음과 같이.. 앞쪽에.. AFX_EXT_CLASS 를 붙여서.. 외부로 인터페이스 가능한 클래스라구
컴파일러에 통보합니다.

class AFX_EXT_CLASS CA::public CWnd
{

처럼여..


3. 확장 DLL을 이용하는 프로그램에서..

: DLL에 선언된 전역 변수를 포함해야져.. 
: DLL 전체에서 사용하기 위해.. extern 선언했던 것과 유사합니다.
: extern __declspec(dllimport) int g_nSum;

자세히..보면.. __declspec(dllexport) 가.. __declspec(dllimport)로 바뀐것을
알 수 있습니다.

export는..밖으루.. 오픈될 수 있는..
import는..밖에 선언되어 있는걸..가져올 수 있는.. 이라는..의미를 가진듯 합니다. --;;;


반응형
반응형

Microsoft Specific

dllimport, dllexport

DLL에서(로) 함수, 데이터, 개체를 내보내는(가져오는) 속성. 함수를 dllexport로 선언하면, 적어도 export된 함수 스펙과 관련된 .DEF (모듈 정의) 파일이 필요없다. 또한 dllexport는 __export 키워드 (16비트 버전의 VC++에서 사용) 를 대체한다.

declspec(dllexport) 클래스의 클래스 템플릿 특수화(specialization)는 암묵적으로 declspec(dllexport)가 된다. 즉 템플릿은 명시적으로 인스턴스화(==구체화)되고, 그 멤버들은 반드시 정의되어야 한다.

dllexport C++ 함수는 이름장식을 가진 함수를 노출시킨다. C++ 이름장식이 필요없다면, .def 파일 (EXPORTS(MSDN) 키워드)를 사용하거나 함수를 extern "C"로 선언한다.

dllexport와 dllimport는 반드시 declspec과 확장된 속성 구문을 사용해야 한다.

__declspecdllimport int i;

__declspecdllexport void func();

좀 더 보기좋게 다음과 같이 매크로를 쓸 수도 있겠다.

#define DllImport __declspecdllimport )

#define DllExport __declspecdllexport )

정의와 선언

DLL 인터페이스는 일부 프로그램이 export한 모든 항목 (함수와 데이터) 을 참조한다; 즉 모든 항목은 dllimport나 dllexport로 선언되며, DLL에 선언된 것들은 반드시 둘 중 하나를 가져야 한다. 하지만, 그 정의는 반드시 dllexport여야한다. 즉 다음과 같은 코드는 컴파일 에러란 말이다:

DllImport int func() { return 1; } // 둘 다 정의

DllImport int i = 10;

dllexport는 정의를 dllimport는 선언을 의미한다. dllexport와 extern 키워드를 같이 사용하면 강제로 선언할 수 있다; 그렇지 않으면 정의를 의미한다. 다음 코드들을 보자:

extern DllImport int k; // 둘 다 선언을 의미하며 정확하다

DllImport int j;

static DllImport int l; // 에러; extern으로 선언되지 않음

void func() {

static DllImport int s; // 에러. extern으로 선언되지 않음

DllImport int m; // OK. 이것은 선언

DllExport int n; // 에러. 로컬 범위에서 외부정의를 포함

extern DllImport int i; // OK. 이것은 선언

extern DllExport int k; // OK. extern은 선언을 의미한다

DllExport int x = 5; // 에러. 로컬 범위에서 외부정의를 포함

}

dllexport/ dllimport로 선언된 인라인 C++ 함수 정의

dllexport 함수를 인라인으로 선언하면, 어떤 모듈이 그 함수를 참조하던말던 항상 인스턴스화되고 export되며, 다른 프로그램에서 import한다고 가정된다.

dllimport 함수를 인라인으로 선언하면, 그 함수는 확장될 수 있지만 (/Ob(VS6.0) 설정에 따라) 절대 인스턴스화되지는 않는다. 특히 인라인 import 함수의 주소가 있다면, DLL 안에 존재하는 그 함수의 주소가 리턴된다. 이는 인라인이 아닌 import 함수의 주소를 얻는 것과 같은 방식이다.

위 규칙들은 클래스 안에 정의된 인라인 함수에 적용된다. 게다가, 인라인 함수 안의 정적 로컬 데이터와 스트링은 마치 하나의 프로그램 (즉 DLL 인터페이스가 없는 실행 파일) 안에 있는 것처럼 DLL과 클라이언트 사이에서 동일성을 유지한다.

DLL을 업데이트할 때, 클라이언트가 바뀐 DLL을 사용할 거라고 가정하지 않는다. 올바른 버전의 DLL을 로딩하려면, 해당 클라이언트 또한 재빌드한다.

일반적인 규칙과 제한사항

─ dllimport나 dllexport 없이 선언된 함수나 개체는 DLL 인터페이스로 간주되지 않으며, DLL 인터페이스로 만들려면 dllexport로 정의한다. 이런 경우든 dllexport로 선언된 경우든, 같은 프로그램 안에 정의되어야 한다. 아니면, 링커 에러가 발생한다.

─ 하나의 모듈 안에 동일한 함수나 개체가 dllimport와 dllexport 2가지로 선언되면 dllexport 속성이 우선하지만, 이는 파일러 경고를 일으킨다:

__declspecdllimport ) int i;

__declspecdllexport ) int i; // 경고; 불일치; dllexport가 우선한다

─ C++에서는 글로벌/ 정적 로컬 데이터 포인터를 dllimort로 선언된 데이터 개체의 주소로 초기화할 수 있다. 하지만 이는 C에서 에러다. 또한, 정적 로컬 함수 포인터를 dllimport로 선언된 함수의 주소로 초기화할 수 있다. 이 포인터는 C에서 DLL import thunk (함수로 제어를 넘기는 코드 토막) 의 주소, C++에서는 함수의 주소가 할당된다:

__declspecdllimport ) void func1( void );

__declspecdllimport ) int i;

int *pi = &i; // C에서는 에러

static void ( *pf )( void ) = &func1; // C에서는 thunk 주소, C++에선 함수 주소

void func2() {

static int *pi = &i; // C에서는 에러

static void ( *pf )( void ) = &func1; // C에서는 thunk 주소, C++에선 함수 주소

}

하지만 dllexport 개체 선언을 포함하는 프로그램은 반드시 정의도 가져야하므로, 글로벌/ 로컬 정적 함수 포인터를 dllexport 함수의 주소로 초기화할 수 있다. 또한 글로벌/ 로컬 정적 데이터 포인터를 dllexport 데이터 개체의 주소로 초기화할 수 있다. 가령 다음 코드는 C/ C++에서 모두 에러가 아니다:

__declspecdllexport ) void func1( void );

__declspecdllexport ) int i;

int *pi = &i;

static void ( *pf )( void ) = &func1;

void func2() {

static int *pi = &i;

static void ( *pf )( void ) = &func1;

}

─ VC++ .NET에서는 regular 클래스와 클래스 템플릿의 특수화 사이에서 dllexport를 가진 애플리케이션이 보다 일관되도록 하기위해, dllexport가 아닌 기본 클래스를 가진 regular 클래스에 dllexport를 적용하면 C4275(한글) 컴파일러 경고가 발생한다.

이 경고는 기본 클래스가 클래스 템플릿의 특수화일 경우도 발생하는데, 이 때는 dllexport를 표시해주면 된다. 즉 클래스 템플릿에 __declspec(dllexport)을 쓸 수 없다. 대신 다음처럼, 명시적으로 클래스 템플릿을 인스턴스화하고 여기에 dllexport를 사용한다:

template class __declspecdllexport ) B<int>);

class __declspecdllexport ) D : public B<int> {}

이 방법은 다음처럼 템플릿 인자가 부모 클래스인 경우 에러가 발생한다:

class __declspecdllexport ) D : public B<D> {}

이는 템플릿에서 흔한 패턴이기 때문에, VC++ .NET 컴파일러는 하나 이상의 기본 클래스를 가지는 클래스에 적용될 때와 하나 이상의 기본 클래스가 클래스 템플릿의 특수화일 경우 dllexport 구문을 바꿨다. 이 경우 컴파일러는 암묵적으로 클래스 템플릿의 특수화에 dllexport를 사용하며, 위 문장은 문제없이 컴파일된다.

dllexport/ dllimport를 C++ 클래스에서 사용하기

dllimportdllexport로 클래스를 선언하면, 그 클래스 전체가 import/ export되며, 이렇게 export된 클래스를 exportable 클래스라 한다.

#define DllExport __declspecdllexport )

class DllExport C {

int i;

virtual int func( void ){ return 1; }

};

참고 exportable 클래스의 멤버는 dllimport와 dllexport를 명시적으로 쓸 수 없다.

─ dllexport 클래스는 모든 멤버함수와 정적 데이터멤버가 export되므로, 동일 프로그램 안에서 모든 멤버를 정의해야 한다. 그렇지않으면 링커에러가 발생한다. 단 순수 가상함수의 경우 예외이며, 가상 클래스의 소멸자는 항상 기본클래스의 소멸자에서 호출되므로, 순수 가상 소멸자는 반드시 정의해야 한다. 이 규칙들은 exportable 클래스가 아니더라도 적용된다.

클래스타입의 데이터나 클래스를 리턴하는 함수를 export하려면, 클래스를 export해야만 한다.

─ dllimport 클래스는 모든 멤버함수와 정적 데이터멤버가 import된다. 비클래스 타입에서의 dllimportdllexport와는 달리, 정적 데이터멤버는 dllimport 클래스가 정의된 프로그램에서 정의할 수 없다.

─ exportable 클래스의 모든 기본 클래스는 exportable이어야 한다. 아니면, 컴파일러 경고가 발생한다. 게다가, 클래스이기도 한 모든 accessible 멤버는 exportable이어야 한다. 이로써 dllexport 클래스는 dllimport 클래스로부터 상속받을 수 있고, dllimport 클래스는 dllexport 클래스에서 상속받을 수 있다 (후자는 권장되지 않는다). 대개, (C++ 접근 규칙에 따라) DLL 클라이언트에서 accessible한 모든 것들은 exportable 인터페이스의 일부여야 한다(should). 이는 인라인 함수에서 참조되는 private 데이터멤버에도 해당된다.

End Microsoft Specific

출처 : http://redsky84.tistory.com/entry/declspec-%ED%99%95%EC%9E%A5%EB%90%9C-%EC%86%8D%EC%84%B1-%EA%B5%AC%EB%AC%B8-III

원문: C++ Language Reference, __declspec, dllexport/ dllimport(CE3.0)

참고: VC++ 개념, 가져오기 및 내보내기

반응형
반응형


DLLIMPORT / DLLEXPORT  MFC 

2008/01/25 14:41

복사http://blog.naver.com/niceyjb1024/46810517

dllimport와 dllexport는 DLL에서 function, variable, ***(class..)
를 import하거나 export하기 위해 사용합니다.

자세히 말하자면 DLL을 사용하는 프로그램이 DLL로 부터 function등을
가져다 쓰게 하기 위해 외부로 노출(?)시킬 필요가 있는데(.. 이런
함수, 데이터, 개체등을 DLL의 인터페이스라고 하죠..)
이런 목적으로 DLL내의 함수등을 정의할때 dllexport지시자를 붙여 줍니다.
그리고 dllexport를 사용한 함수등에 대해 일반적으로 DLL의 인터페이스를
정의해 두는 DEF파일(Module definition file)에 포함시킬 필요가 없습니다.

반대로 DLL을 가져다 쓰는 프로그램(or 다른 DLL)쪽에선 DLL의 인터페이스
를 사용하기 전에 당연히 미리 선언해 주어야 할 필요가 있습니다. 이때
선언문에서 dllimport 지시자를 함께 사용해 주는 것이죠..

__declspec( dllexport ) int func()
{
return 1;
}

....

__declspec(dllimport) int func() ;

이런 식으로 말이져..

함수의 경우에는 반드시 dllimport를 쓸 필요는 없지만
컴파일러가 좀더 효율적으로 코드를 만들어 주기때문에
함께 써주는 게 좋습니다. 그러나 변수등의 경우에는
꼭 dllimport를 붙여 줘야 함다.

[출처] DLLIMPORT / DLLEXPORT|작성자 완전초짜


 

 


 

 


 

__declspec(dllimport)의 호출 원리  Windows / Programming 

2009/01/28 09:12

복사http://blog.naver.com/iwillhackyou/110041460983

DLL을 통해서 함수를 제공하려면 DLL상의 Export Address Table(PE 포멧)에 함수의 위치를 나타내도록 __declspec(dllexport)지시자를 사용해서 함수를 노출시킨다. 반면에 함수를 호출하는 쪽에서는 특별한 코드 없이 헤더파일(.h)에 포함된 함수 이름을 직접 사용하면 링커가 해당 함수를 호출할 수 있도록 컴파일 시점에 연결시켜준다. 함수를 호출하는 쪽에서 사용한 헤더파일(.h)에 함수 원형이 __declspec(dllimport)으로 정의되지 않았도 정상적으로 DLL에서 제공된 함수를 사용 할 수 있다.

 

즉 다른 모듈에서 제공되는 함수를 호출하는데 있어서 함수 원형에 __declspec(dllimport)이 선언 유무와는 상관없이 항상 호출할 수 있다. 하지만 결론 부터 말하면 DLL에서 제공되는 함수를 사용할 때에는 항상 함수 선언 앞에 __declspec(dllimport) 지시자를 사용하는 것이 좋다.


대부분 DLL에서 제공되는 API는 헤더 파일에 다음과 같이 선언해서 제공한다.

 

// API Export/Import Header

#ifdef CALLEE_EXPORTS
#define CALLEE_API __declspec(dllexport)
#else
#define CALLEE_API __declspec(dllimport)
#endif

CALLEE_API DWORD __stdcall no_no_stdcall(DWORD);  // WINAPI
CALLEE_API DWORD __cdecl no_no_cdecl(DWORD);   // CDECL
CALLEE_API DWORD __fastcall no_no_fastcall(DWORD);

 

위 헤더 파일의 핵심은 모듈을 제공하는 쪽과 사용하는 쪽에서 동일한 하나의 헤더 파일을 공유해서 사용하도록 하는 것이다. (소스 관리 차원에서도 하나의 파일을 유지하는 것이 좋다. 특히 ThirdParty 벤더에서 제공되는 API모듈이라면 더욱더 그렇게 해야한다.)

즉, 프로젝트의 Preprocessor definitions에 특별히 CALLEE_EXPORTS를 선언하지 않은 사용자의 프로젝트에서는 함수를 __declspec(dllimport)형식으로 정의해서 링크하게 된다. 위의 예는 가장 확실하게 __declspec(dllimport)를 선언해서 사용할 수 있는 경우이고 헤더가 중복해서 관리해야하는 어려움도 필요없는 최적의 상태이다.



하지만 내부 프로젝트 모듈이건 다른 벤더의 모듈이던 위와 같이 정의해서 사용하지 않고 다음과 같이 API의 Import용으로 헤더 파일을 별도로 정의해서 제공하는 경우가 종종 있다.

 

 

// API Import Header

DWORD __stdcall no_no_stdcall(DWORD);  // WINAPI
DWORD __cdecl no_no_cdecl(DWORD);   // CDECL
DWORD __fastcall no_no_fastcall(DWORD);


이 경우는 소스 코드상의 헤더 관리의 어려움을 떠나서 성의가 없는 경우이다 -_-.

DWORD __stdcall no_no_stdcall(DWORD);
__declspec(dllimport) DWORD __stdcall no_no_stdcall(DWORD);  


일단 DLL을 static link 할 경우에 링커는 위의 두가지 경우를 구분없이 모두 정상적으로 처리해서 함수를 호출할 수 있도록 한다. 그렇다면 차이점이 무엇일까?
DWORD __stdcall no_no_stdcall(DWORD) 와 같이 선언된 상태에서 링커는 DLL과 함께 생성된 Lib 파일에서 가르키고 있는 Stub을 직접 호출하도록 한다. 컴파일러는 no_no_stdcall() 이라는 함수가 현재 프로젝트 내부에 다른 Obj에 선언된 함수인지 아니면 아예 다른 외부 모듈(DLL)에 선언된 함수인지 현 빌드 시점에는 알 수 없기 때문이다.

 

이렇게 static link용 Lib의 stub에 연결된 경우에도 실행시 실제 DLL의 함수는 정상적으로 호출된다. 그 이유는 DLL 생성시점에 함께 생성되는 Lib 파일의 Stub내부에는 실제 모듈(DLL)의 함수로 점프할 수 있는 코드가 이미 DLL 파일의 컴파일 타임에 이미 생성되어 Stub안에 존재하기 때문에 가능한 것이다. 즉 해당 Stub을 내부 함수처럼 호출하면 그곳에서 실제 모듈(DLL)의 함수를 가르키는 IAT(Import Address Table)를 참조해서 실제 API로 이동하는 코드가 수행되는 것이다. 


즉, DLL에서 제공되는 함수를 호출하는 쪽에서 사용한 함수의 선언 형태에 따라서 아래와 같은 두가지 형태의 코드 형식으로 호출할 수 있게 된다.

 

// 1. 함수원형 앞에 __declspec(dllimport) 지시자를 사용해서 호출할 경우
0x01002000 : CALL DWORD PTR [0x56780000]; // CALL DWORD PTR[_imp__MyFunc];


// 2. __declspec(dllimport) 지시자 없이 호출할 경우
0x01002000 : CALL 0x12340000;
0x12340000 : JMP DWORD PTR[0x56780000];



// (0x5678000 : 실제함수주소를 가르키고있는 IAT의 주소)

...

 

상기 코드 중에서 당연히 1번의 경우가 훨씬 효과적인 것을 알 수 있다. 2번의 경우에는 JMP를 위한 추가적인 5Byte의 Stub 코드를 더 수행하게 되므로 비효율적이다.

__declspec(dllimport)지시자를 사용함으로서 1번의 형태로 DLL에 제공되는 함수를 호출하는 것을 알 수 있다. 상기 코드에서 컴파일러는 __declspec(dllimport) 지시자를 보았을 경우에 실제 함수인 "MyFunc"을 참조하지 않고 "__imp__MyFunc"을 참조하는 코드를 만들어 놓는다. 그후에 링커는 함수 이름에 붙어있는 "__imp__" 라는 Prefix를 보고 외부 DLL에 존재하는 함수를 직접 호출하는 것을 알게 된다. (컴파일리가 링커에게 DLL에 존재하는 함수를 호출한다는 것을 알려주기 위해 "__imp__" Prefix를 함수앞에 추가한다.) DLL과 제공되는 Lib파일에는 "__imp__" prefix를 가지는 함수명이 함께 선언되어 있다.)

 

다음과 같은 링크 에러를 보면 실제 함수 이름 앞에 "__imp__" Prefix가 존재하는 것을 알 수 있다.

 

: error LNK2001: unresolved external symbol __imp__MyFunc

: fatal error LNK1120: 1 unresolved externals

 

위의 경우에는 링크 에러가 발생했는데 링크 에러가 발생하지 않으려면 빈 Lib안에 __imp__MyFunc에 대한 Stub이 존재하고 있어야 한다. DLL과 함께 생성된 Lib에는 "MyFunc", "__imp__MyFunc"에 대한 두가지 Stub이 모두 존재하고 있다. 컴파일러는 두 함수 이름을 Lib에 미리 생성해 놓고 있다.

 

반응형
반응형


GetProcAddress() - dll 함수 사용  API 

2008/03/12 10:54

복사http://blog.naver.com/silver6688/60048943503

FARPROC WINAPI GetProcAddress(
  HMODULE hModule
,
  LPCSTR lpProcName
);

솔직히 위에 명령어는 딱히 설명이 필요 없을 정도로 많이 사용하는 핵심 명령어임에 틀림없다.

 

그럼에도 불구하고 흥미로운 부분도 꽤나 숨어있는 녀석이다.

 

    HMODULE pTestDXLib;
    FARPROC pFunctionality;

    pTestDXLib=LoadLibrary("DSOUND");

    pFunctionality = GetProcAddress(pTestDXLib, (char*) 7);

 

 

위와 같이 Ordinary Number를 이용해서 원하는 함수를 호출할수도 있다.

 

typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);

HINSTANCE hDLL;               // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1;    // Function pointer


hDLL = LoadLibrary("MyDLL");
if (hDLL != NULL)
{
   lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "DLLFunc1");

      FreeLibrary(hDLL);
      return SOME_ERROR_CODE;
   }
   else
   {
      // call the function
      uReturnVal = lpfnDllFunc1(dwParam1, uParam2);
   }
}

일반적으로는 위에서 처럼 함수 이름으로 호출할 것이다.

 

 

또한 함수 이름뿐만 아니라 변수 이름을 적어서 익스포트된 변수 이름도 쉽게 구할수가 있다.

 

 

extern "C" _declspec(dllexport)
int k=50;//DLL이나 exe와 같은 실행 모듈에서 이렇게 해준다.

 

 

HINSTANCE hInst=GetModuleHandle(NULL);
int* p;
p=(int*)GetProcAddress(hInst,"k");

 

위에 경우는 바로 변수에서 읽어드리는 과정이다. 흥미롭지 않는가?

반응형
반응형

http://blog.naver.com/ysoftman?Redirect=Log&logNo=20095032204

 

 

C:\Program Files\Microsoft Visual Studio 9.0\VC

 

의 경로까지 가서 cmd 창에서 해당 경로에서 실행 해야 한다

반응형
반응형

프로젝트의 속성에서 출력형태를  클래스 라이브러리로 변경하여 빌드하면됨

반응형
반응형

#ifdef EXPORTRULE 
#define MYDLL __declspec(dllexport) 
#else 
#define MYDLL __declspec(dllimport) 
#endif 

이 같은 매크로를 이용해서 DLL 클래스를 작성하였고 

코드:
//--- "myclass.h" ---
class MYDLL CMyClass
{
private:
   CMyClass() {}
   ~CMyClass() {}
 
public:
   static const int SEVEN = 7;
   static const float PI;
};
 
//--- "myclass.cpp" ---
#include "myclass.h"
const float CMyClass::PI = 3.14f;
 
//--- "main.cpp" ---
#include "myclass.h"
int main()
{
   printf("%d", CMyClass::SEVEN); // OK
   printf("%f", CMyClass::PI); // LNK2001
}


위와 같이 컴파일 할 경우 CMyClass::PI에 대해서 LNK2001 에러가 발생합니다. 
static const int 같은 경우는 헤더에서 초기화 및 링크가 잘 되는데 
static const float의 경우 LNK2001 에러가 발생합니다. 

이런 경우 함수를 사용하거나 define 혹은 전역 변수를 쓸 수 밖에 없는지 
고수님들의 의견을 듣고 싶습니다. 
감사합니다.

 

 

 

static const int는 컴파일 단에서 인라인으로 처리 가능한데요 

int 이외의 것들은 그렇지 못하기 때문에 static 변수를 dll로 노출 시키지 못하는 환경 때문에 링크 에러에 거릴겁니다

 

 

반응형
반응형

 
 _declspec(dllexport) 또는 _declspec(dllimport) 정적 변수 정의가 여러 개 있는 클래스를 사용하여 첫 번째 변수를 제외한 모든 생성될 C2487 오류가 발생할 수 있습니다. 예를 들어, 이 클래스 선언을 참조하십시오:
 
class _declspec(dllexport) MyClass
{
public:
static int i,j,k;
};
  
 
이 클래스 선언은 이러한 오류가 발생하는 경우를 보여 줍니다. 
오류 C2487: 'j': DLL 인터페이스 클래스 멤버는 DLL 인터페이스를 사용하여 선언할 수 없습니다
오류 C2487: 'k': DLL 인터페이스 클래스 멤버는 DLL 인터페이스를 사용하여 선언할 수 없습니다
각 정적 변수 선언을 자체 줄로 이동하십시오. 위의 클래스 완전히 컴파일할 수 있도록 문제를 해결하려면 이 사용합니다: 
 
class _declspec(dllexport) MyClass
{
public:
  static int i;
  static int j;
  static int k;
};

반응형
반응형

http://blog.naver.com/kimgudtjr?Redirect=Log&logNo=140096145411 에서 인용한글


[두번째 방법 : __declspec(dllexport) 지시자 사용방법 ]

위에서는.def 파일을 이용했는데 이 방식은 예전 16비트 시절부터 쓰던 옛발 방식이라고 한다..

여기서는 다은방법을 보자면. 해당 수출하려는 함수에 export 하려는 함수 앞에

__declspec(dllexport) 라는 키워드를 쓰면 된다고 한다. -_-ㅋ

근데 여기 책에서 설명하는 방법은 좀 복잡하고 요상하게 쓰는데 -_-ㅋ 일단 아래를 따라가보자..


여기서는 __declspec(dllexport) 를 쓸대  

1. __declspec(dllexport) 용 test.h 라는 헤더파일을 만든다.


2. __declspec(dllexport) 용 test.cpp 라는 함수 구현 파일을 만든다.


------------------ test.h ---------------------------

#ifndef __DLLBASIC_H__
#define __DLLBASIC_H__

#define DLLBASIC_API
#define DLLBASIC_API extern "C" __declspec(dllimport)

DLLBASIC_API int Sum(int a, int b);

#endif
  
------------------------------------------------------

위의 Sum 함수는 실제로 책에는 다른 함수로  되어있지만  책의 함수가 조금 복잡해서

독자가 이해하기 휩게 하기 위해 단순하게 바껏다.


----------- test.cpp --------------------
#define DLLBASIC_API extern "C" __declspec(dllexport)

#include "test.h"

int SumIint a, intb)
{
 return a+b;
}

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

책에서는 이렇게 사용한ㄷ고 되어있다..

사실 test.cpp위에 부분에 보면 DLLBASIC_API 를 먼저 정의하고 test.h 파일을 포함하기 때문에

test.h 파일에 있는 dllimport 는 아무 의미없이 되고 전부다 dllexport로 대체 될것이다.

근데 굳이 이렇게 해더 파일에는 dllimport 를 쓰고 cpp에는 dllexport를 써서 복잡하기 하는 이유가

독자는 너무 긍금했다.. 하지만 책에 잘 설명이 되어있었다.... 하지만 ..-_-ㅋ 보고도 이해를 잘 하지 못했따.. -=_-ㅋㅋ

일단 책에 나와있는 설명을 그대로 옮겨보겠지만.. 혹시라도  아시는분 있으면 알려주길 바란다....

--- 책의 설명.. --------

하지만 왜 이렇게 따로 전처리기 까지 사용해서 복잡하게 dllimport까지 지정하는 것일까???

후에 해당 DLL 사용 시 test.h를 인클루드하게 되면 별도의 DLLBASIC_API라는 매크로를 정의하지 않기 때문에

해당 DLL을 사용하는 입장에서의 DLLBASIC_API는 __declspec(dllimport)로 정의 된다. 그렇게 되면 자연스럽게 헤더에 선언된 함수가

임포트 할 함수임을 미리 컴파일러에게 알리는 역할을 한다. 물론 굳이 알리지 않아도 사용하는 데에는 전혀 문제가 없다.

하지만 이렇게 임포트 함수임을 미리 알리느냐 알리지 않느냐의 미묘한 차이는 실제 PE이미지가 생성될 때 조그만한 차이를 불러온다.

그 차이는 5장 DLL 로딩과 임포트 섹션에서 논의하도록 한다.

------------------------------------------------------------------------
라고 되어있다 -_-ㅋ 먼말인지 몰것다. 그냥 재꼈다 -_-ㅋ

그러면 해당 dll파일을 dumpbin /export test.dll 이라고 해서 확인해보자

글엄 export 된 함수들을 볼수 있다.. 다만 이경우에는

서수를 사용자 임의대로 붙일수 없다고 한다. ..

그래서 서수를 지정해서 사용하는 방법은 포기해야 한다고 한다 -_-ㅋ






[익스포트 함수명의 문제 함수 호출 방식 - 파스칼 방식 C선언 방식 ]


1. 예전엔 아래와 같이 함수 호출 방식이 2가지였다고 함.
   - 하나 : 파스칼방식 
   - 둘    : C선언 방식

2. VC++ 에서 이 두가지 방식의 스택 이용방식을 통일했다고 함.. 둘다 왼쪽에서 오른쪽으로.. ..
   스택이용방식에 있어선 파스칼 방식으로 채택....  
   스택제거 시점은 아직 구분했다고 했다고함.. 아래와 같이 ...


 -------------- C언선방식 -----------------

함수매개변수 : 매개변수를 오른쪽에서 왼쪽으로 스택에 push 한다.

스택제거      : 함수를 호출한 쪽에서 스택을 제거 한다

키워드 :    : __cdecl

아무것도 정의 안하면 디폴트로 C선언 방식으로 된다.
------------------------------------


 -------------- 파스칼방식 -----------------
 
함수매개변수 : 매개변수를 왼쪽에서 오른쪽으로 스택에 push한다.

스택제거     : 함수가 호출된 쪽에서 스택을 제거

키워드         :  __stdcall

_stdcall  또는 WINAPI 를 함수 앞에 쓰면 파스칼 방식으로 된다.
------------------------------------


그리고 자세히보면 위 코드에

#define DLLBASIC_API extern "C" __declspec(dllexport)

라고 되어 잇는데 extern "C" 를 유심히 보자..

이 부분을 제거하고 컴파일 한후  dumpbin /EXPORTS test.dll 한번해보고

이 부분을 제거 하지 말고  컴파일 한후 dumpbin /EXPORTS test.dll 해보라..

그러면 export 되는 함수 이름이 다를 것이다.

extern "C" 라는 키워드는 C언어 형식으로 함수 이름을 짓고

extern "C" 를 제거하면 C++ 규칙대로 함수 이름을 짓는다..

extern "C" 방식은 모든 컴파일러에서 알아볼수 있는 형식이므로

extern "C" 방식으로 함수를 작성하면 다른 컴퓨터에서 무리 없이 돌아가지만

extern "C"를 제거한 C++ 방식으로 함수를 작성하면

함수이름이 이상하게 변하는데 그 이상하게 변환하는 규칙이 각각 컴파일러 마다

제각각이여서 다른 컴퓨터와 호환이 되지 않는다..

그래서 함수를 export 하고자 할때는 위의 extern "C" 키워드를 꼭 붙인다고 한다.

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

이렇게 함수이름을 어떤 형식으로 짓냐는 방법을

이름 데콜이션 이라고 한다.. 그 규칙이 버전별로 조금씩 다른데....................

독자는 귀찮아서.. 그냥 이 부분은 넘기려고 한다. -_-ㅋ

반응형
반응형





정적 라이브러리는 #include<stdio.h> 와 같이 인클루드 시키는 printf,scanf 와 같은 함수들이 있는 라이브러리

=> 컴파일시에 해당 라이브러리 코드가 실행 파일과 합쳐진다.

printf문을 쓰는 5개의 프로그램이 있다면


| 프로그램 1  (printf코드) |
| 프로그램 2  (printf코드) |
| 프로그램 3  (printf코드) |
| 프로그램 4  (printf코드) |
| 프로그램 5  (printf코드) |

와 같이 각각의 프로그램마다 printf 코드가 들어간다.. 왜냐 하면 컴파일시에

정적으로 해당 라이브러리 가 합체되어 컴파일 되기 때문이다.

그래서 똑같은 코드가 프로그램마다 합쳐저서 용량이 늘어나는 단점이 있다..



DLL = 동적 링크 라이브러리 Dynamic link Library

하지만  동적링크라이브러리는 다르다...

해당 라이브러리는 일단 메모리에 한번 올리고..

프로그램들이 그 라이브러리를 필요할때 메모리에 올라와 있는걸 가져다 쓰기만 하면된다.

만약 printf 코드를 동적라이브러리로 만들었다고 가정하고

그 동적라이브러리를 쓰는 5개의 프로그램이 있다면


-----------  메모리 ---------------
|  메모리에 printf 라이브러리 코드 딱 한번 로드 (주소 0x10001050) |
-----------  메모리 ---------------


| 프로그램 1 (0x10001050) 호출) |
| 프로그램 2 (0x10001050) 호출) |
| 프로그램 3 (0x10001050) 호출) |
| 프로그램 4 (0x10001050) 호출) |
| 프로그램 5 (0x10001050) 호출) |


해당 프로그램들은 덩치큰 라이브러리 코드들은 포함하고 있는게 아니고

그냥 해당 코드가 있는 메모리 주소를 불러오는 간단한 하고 조그만한 코드가 있으므로

프로그램 용량이 줄어들것이다..

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





글엄 간단한 DLL파일을 만들어 보자..

비주얼 c++ 6.0 에서 프로젝트 만들때  Win32 Dynamic-Link Library  라는 옵션을 주어서

만들면 된다. 아래에서 아주 간단한 함수 하나를 만들어보고  이 함수를 export 시켜서

일반 실행파일에서 쓰는 예제를 만들어 보자

------------------- test.cpp ----------------------

int Sum(int a, int b)

{

 return a+b;

}

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

다.. 만들었다... 죠낸 간다하다 -_-ㅋ 그렇다.

그냥 두 수를 인자로 받고 더 해서 결과를 리턴해주는 아주 죠낸 초 간단 함수이다.

이 함수를 dll파일로 만들었으니.. 이 함수는 동적링크 라이브러리 되시겠다... 

WinMain 필요없다.. main 도 필요없다.

그냥 우리가 필요한 함수만 딱 써놨다.. 그래도 된다.. -_-ㅋ


컴파일하면 test.dll 파일이 생성될것이다.



그렇다면 이 dll파일을 사용하는 일반 실행파일을 만들어보자..

일단 이 dll파일을  실행하려는 실행파일에 같은 폴더에 넣는다..

그리고 해당 실행파일이 이 dll을 불러오고.. 그리고 또  dll 않에 있는 함수를

사용하는 예제는 아래와 같다.




------------------ usedll.cpp ------------------

#include <windows.h>

#define DLL_NAME "test.dll" // 불러 오려는 dll 이름이다.
#define DLL_FUNC "Sum" // 불러 오려는 함수 이름이다.


void Error(LPCTSTR str);
void Printf(LPCTSTR str);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
 HMODULE hModule;
 LPVOID lpFunc = NULL;
 TCHAR buf[512];

 hModule = LoadLibrary(DLL_NAME);

 if(!hModule)
 {
  Error("LoadLibrary Error");
 }
 else
 {
  wsprintf(buf,"hModule = 0x%8x\n",hModule);
  Printf(buf);
 }

 lpFunc = GetProcAddress(hModule,DLL_FUNC);

 if(!lpFunc)
 {
  Error("GetProceAddress Error");
 }
 else
 {
  wsprintf(buf,"lpFunc = 0x%8x\n",lpFunc);
  Printf(buf);
 }

 return 0;
}

void Error(LPCTSTR str)
{
 MessageBox(HWND_DESKTOP,str,"ERROR",MB_OK);
 ExitProcess(1);
}

void Printf(LPCTSTR str)
{
 MessageBox(HWND_DESKTOP,str,"OK",MB_OK);
}

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




우의 코드는 실제로 함수를 사용하지 않고 그냥 dll을 로드하고 그 함수 주소를 얻어오는 코드인데

일단 함수 주소만 알면 언제든지 불러올수 있으므로 함수 주소를 얻는 코드까지만 작성했다.

이상이 없다면 모듈주소와 함수주소가 출력될것이다.

하지만 안타깝게도 위의 실행파일을 실행하면 DLL 파일은 찾을수 있지만

함수 주소는 찾을 수 없다는 에러를 발생시킨다......

그 이유는 .... 그 이유는... 그 이유는.....

dll 않에서 만든 함수는 외부로 수출???(export) 되야 하는 것이다.. 이것들은 특별하기 때문에

컴파일시에 이 함수는 외부로 링크될 함수야!!!!!! 라고 알려줘야 한ㄷ고 한다.......... 우리는 그 작업을 안한 것이다. -_-;;;


콘솔창으로 들어가서 해당 dll 파일이 있는 위치로 이동후

dumpbin /EXPORTS test.dll      <-- 라고 쳐보자... 이 명령어는 해당 dll 파일에서 export (수출하는 함수?) 리스트를 보여달라고 하는것이다.

결과 화면을 보면 수출하는 함수가 없다고 뜰 것이다...


그러면 export를 수출 하는 두가지 방법이 있다고 하는데.. 그 방법을 살펴보자

첫번째 방법 : 모듈 정의 파일 사용 (.def 파일사용)

두번째 방법 : __declspec(dllexport) 지시자 사용




[첫번째 방법 : 모듈 정의 파일 사용 (.def 파일사용)]


비주얼 컴파일에 프로젝트에서 소스파일 추가 하여 확장자를 .def 라고 하고 cpp 파일과 동일한 파일명으로 하나 만든다.

그리고 그 .def 파일에 다음과 같이 써보자


----------------------- dll.def --------------------------------------------

LIBRARY  
EXPORTS
 Sum   @1

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

LIBRARY  DLL      <-- 라이브러리 이름이다..

EXPORTS                                   <-- export (수출) 할 함수들 리스트 들

 Sum <-- 함수명  @1    <-- 서수지정..

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


대략 설명은 이렇다... 이렇게 def 파일을 정의하고 다시 컴파일 한 후!!!

생성되는 dll 파일을 다시 dll을 이용하는 실행파일에 넣고 하면!!

아무런 에러 없이 함수 주소를 가져올 것이다.

그리고.. dumpbin /exports test.dll 이라고 하면 전에 없던 export 라는 부분에서 수출하려는 함수 목록으로 Sum이라는 함수가 나타날 것이다...

 

 




반응형
반응형

http://idnch715.tistory.com/125

 

 

"도스창(명령 프롬프트)"에서 직접 또는, 배치 파일 속에서 디렉토리를 복사하는 방법입니다.

도스의 일반적인 COPY 명령에는 디렉토리 복사 기능이 없습니다. 파일만 복사할 수 있습니다. 그 외에도, 파일 속성을 복사할 수 없는 등의 제약이 아주 많습니다.

XCOPY 라는 외부 명령어로 디렉토리를 복사할 수 있습니다.

 

하위 디렉토리까지 포함, 모든 파일 복사 예제


 

xcopy d:\z\*.* d:\x\ /e /h /k

 

 

D드라이브의 Z디렉토리의 트리 구조를,
D드라이브의 X디렉토리로 전부 복사하는 예제입니다.


/e : 비어 있는 하위 디렉토리까지 복사
/h : 히든 파일과 시스템 속성의 파일까지 복사
/k : 파일 속성 복사. (이 옵션이 없으면, 읽기전용 등의 속성이 없어져 버림)

더 자세한 도움말은 xcopy /? 라고 하면 화면에 출력됩니다.

 
 
반응형

'프로그래밍(Programming) > 기타' 카테고리의 다른 글

xcopy 파일복사  (0) 2012.12.26
vs2008 에 OpenCV2.0 설치  (0) 2012.10.31
반응형

http://openarisu.tistory.com/191


다음 순서로 진행이 된다. 
알아두자.

1. WM_CLOSE (OnClose) 발생
2. DestoryWindow (DestoryWindow )  호출 
3. WM_DESTORY ( OnDestory) 발생

각 함수를 수정할려면
WM_CLOSE 메시지 선택시 OnClose()
DestoryWindow 재정의할 때 DestoryWindow()
WM_DESTROY 메시지 선택시 OnDestory() 함수를 작성할 수 있다.

소스 내용 보기.
void CTestDlg::OnClose()
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
    >> 이 부분에서 종료되는 윈도우를 제어할 수 있습니다.
    CDialog::OnClose();
}

BOOL CTestDlg::DestroyWindow()
{
    return CDialog::DestoryWindow();
}

void CTestDlg::OnDestory()
{
    CDialog::OnDestory();
}


참조 : http://yunhyeon.tistory.com/tag/DestroyWindow

반응형

+ Recent posts