x86에서 CFILE::GetStatus 를 못받아오는 경우가 있따.

Windows/API&MFC 2014.06.19 13:31

ㅜㅜ 시바 이거때문에 한시간고생

신고

'Windows > API&MFC' 카테고리의 다른 글

x86에서 CFILE::GetStatus 를 못받아오는 경우가 있따.  (0) 2014.06.19
유니코드에서 char * 로 할당  (0) 2009.09.29
리치 에디트  (0) 2009.09.28
1. API 기본소스  (0) 2009.07.12

ASP.NET + MSSQL > XML

Windows/.NET 2011.11.21 21:38

현재 DB 의 상태

Table - babysign.dbo.test
no name subject
1 1 fdin hi
2 2 Epik High Love Love


xmlTest.aspx
->
< %@ Page Language="C#" AutoEventWireup="true" CodeBehind="xmlTest.aspx.cs" Inherits="WebApplication2.xmlTest" %>




xmlTest.aspx.cs
->
try
{
XmlTextWriter writer =
new XmlTextWriter(this.Response.OutputStream, System.Text.Encoding.UTF8);
SqlConnection con = new SqlConnection("Data Source=FDIN-PC;Initial Catalog=DB명;Integrated Security=True;");
string strSQL = "select * from test";
SqlCommand cmd = new SqlCommand(strSQL, con);

con.Open();
SqlDataReader rd = cmd.ExecuteReader();

writer.Formatting = System.Xml.Formatting.Indented;
writer.WriteStartDocument();
//루트 설정
writer.WriteStartElement("root");
int i = 0;

while (rd.Read())
{
for (int j = 0; j < rd.FieldCount; j++)
{
//노드와 값 설정
writer.WriteStartElement(rd.GetName(j));
writer.WriteString(rd[j].ToString());
writer.WriteEndElement();
}
i++;
}

writer.WriteEndDocument();

Response.ContentEncoding = System.Text.Encoding.UTF8;
Response.ContentType = "text/xml";
writer.Flush();
writer.Close();

rd.Close();
con.Close();
}
catch (Exception ex)
{
Response.Output.WriteLine("Exception : {0}", ex.Message);
}

출처 : http://fdin.tistory.com/8

으아으앜.. 음.... 갠적으론 php보다 훨씬 편한 느낌...

신고

'Windows > .NET' 카테고리의 다른 글

ASP.NET + MSSQL > XML  (0) 2011.11.21
[ERROR] <%@ Page EnableEventValidation="true" %>  (0) 2011.11.14
ASP 무료 게시판 에디터  (1) 2011.11.14
ODBC 오류  (1) 2011.06.20
ERROR : Server Error in '/' Application.  (0) 2011.06.20

[ERROR] <%@ Page EnableEventValidation="true" %>

Windows/.NET 2011.11.14 21:28
잘못된 다시 게시 또는 콜백 인수입니다. 이벤트 유효성 검사는 구성의 <pages enableEventValidation="true"/> 또는 페이지의 <%@ Page EnableEventValidation="true" %>를 사용하여 활성화됩니다. 이 기능은 다시 게시 또는 콜백 이벤트에 대한 인수가 원래 이들을 렌더링한 서버 컨트롤에서 발생하는지 확인하여 보안을 유지합니다. 데이터가 올바르면 유효성 검사에 대한 다시 게시 또는 콜백 데이터를 등록하는 데 ClientScriptManager.RegisterForEventValidation 메서드를 사용합니다.

아오 ㅡ ㅡ

      protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack)
            {
                return;
            }
  }

혹은

<%@ Page EnableEventValidation="false' %>

에이 쉬바 한시간 헤맷넹
신고

'Windows > .NET' 카테고리의 다른 글

ASP.NET + MSSQL > XML  (0) 2011.11.21
[ERROR] <%@ Page EnableEventValidation="true" %>  (0) 2011.11.14
ASP 무료 게시판 에디터  (1) 2011.11.14
ODBC 오류  (1) 2011.06.20
ERROR : Server Error in '/' Application.  (0) 2011.06.20

ASP 무료 게시판 에디터

Windows/.NET 2011.11.14 11:50
프리텍스트 박스
참고

www.FreeTextBox.com
http://www.dotnetkorea.com/boardview.asp?BoardName=Aspx&Num=145&ScrollAction=Page14
http://2005elc.elancer.co.kr/eTimes/page/eTimes_view.html?str=c2VsdW5vPTE5MA==
http://www.asp.net/learn/whitepapers/request-validation


깔끔하게 괜챃앗다

근데 이미지 업로드가 안되서..

http://ckeditor.com/
로 갈아탐... ckeditor도 깔끔하고 이쁘넹! +_+
신고

'Windows > .NET' 카테고리의 다른 글

ASP.NET + MSSQL > XML  (0) 2011.11.21
[ERROR] <%@ Page EnableEventValidation="true" %>  (0) 2011.11.14
ASP 무료 게시판 에디터  (1) 2011.11.14
ODBC 오류  (1) 2011.06.20
ERROR : Server Error in '/' Application.  (0) 2011.06.20

ODBC 오류

Windows/.NET 2011.06.20 16:25
ERROR [IM002] [Microsoft] [ODBC 드라이버 관리자] 데이터 원본 이름이 없고 기본 드라이버를 지정하지 않았습니다.

ODBC 관리자 > 제대로 설치되어있나 확인

Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) ODBC 드라이버의 설치 루틴이 없습니다. 드라이버를 다시 설치하십시오.

MS가 잘하는건 msdn 말고는 딱히 없는듯.. 물론 지들이 싸지른거라 수습을 해야되기 때문에 어쩔수없겟지만

윈7 64비트때문에 그런가 호환이 안됏다.. ㅓㅁㄴ얄너야레머

오늘따라 안되는게 왤케많아 ㅜ.ㅜ

http://support.microsoft.com/kb/2458256/ko
신고

'Windows > .NET' 카테고리의 다른 글

ASP.NET + MSSQL > XML  (0) 2011.11.21
[ERROR] <%@ Page EnableEventValidation="true" %>  (0) 2011.11.14
ASP 무료 게시판 에디터  (1) 2011.11.14
ODBC 오류  (1) 2011.06.20
ERROR : Server Error in '/' Application.  (0) 2011.06.20

ERROR : Server Error in '/' Application.

Windows/.NET 2011.06.20 15:52

Server Error in '/' Application.

Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level.  This error can be caused by a virtual directory not being configured as an application in IIS.

Source Error:

Line 17:             ASP.NET to identify an incoming user. 
Line 18:         -->
Line 19: 		<authentication mode="Windows"/>
Line 20: 		<!--
Line 21:             The <customErrors> section enables configuration 




시작>실행>inetmgr > 해당폴더 응용프로그램으로 변환

인식못할때..

=============
닷넷공부하면서 에러떠서 적어놧더니 메이플스토리가 왜 뜨지 -_-;

님들 컴퓨터문제가 아니라.. 서버쪽 문제니깐 기달려보세요...

글고 겜좀 그만하고 공부좀해서 효도하셈
신고

'Windows > .NET' 카테고리의 다른 글

ASP.NET + MSSQL > XML  (0) 2011.11.21
[ERROR] <%@ Page EnableEventValidation="true" %>  (0) 2011.11.14
ASP 무료 게시판 에디터  (1) 2011.11.14
ODBC 오류  (1) 2011.06.20
ERROR : Server Error in '/' Application.  (0) 2011.06.20

유니코드에서 char * 로 할당

Windows/API&MFC 2009.09.29 12:17

형변환 말고 할당할때..

CString str;
char temp[1024];

strcpy(temp, CT2A(str));

후 힘들다..

CW2A, CA2W로 한시간동안 잡고 뭐하는 짓이었는지.. ㅡ ㅡ
신고

'Windows > API&MFC' 카테고리의 다른 글

x86에서 CFILE::GetStatus 를 못받아오는 경우가 있따.  (0) 2014.06.19
유니코드에서 char * 로 할당  (0) 2009.09.29
리치 에디트  (0) 2009.09.28
1. API 기본소스  (0) 2009.07.12

리치 에디트

Windows/API&MFC 2009.09.28 13:15


◆ 안보일때, 초기화 작업을 수행해주어야 한다.

리소스편집기에서 리치에디트(Rich Edit)를 추가하면 실행도 안되고 디버깅도 에러난다.

검색해도 못찾겠다.

결국 리치에디트가 들어가있는 소스를 분석..

문제발생 1시간만에 해결..

HMODULE hMod = LoadLibrary( "Riched20.dll" );

다쓰고나서 FreeLibrary는 필수..

혹은 시작전에 AfxInitRichEdit();
한줄때문에.. 후.. 눈물난다.. 리치에디트하나 띄우는데... ㅜ ㅜ

※  m_RichEdit.LimitText(1024*1024); // 용량 1메가로 늘리기(기본설정 64KB).. 데브피아에서 본건데 참고로 스택영역에 넣으니깐 에러나더라..


★ 폰트 설정

 CHARFORMAT2 cf;
 memset(&cf, 0, sizeof(cf));
 cf.cbSize   = sizeof( cf );
 cf.dwMask   = CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | ~CFM_WEIGHT;
 cf.crTextColor = RGB( 255, 255, 255);
 cf.crBackColor  = RGB(0, 0, 0);
 cf.yHeight = 200;
 m_RichEdit.SetSelectionCharFormat(cf);

CHARFORMAT도 있고 CHARFORMAT2도 있다. 2가 확장된구조체..

쉬밤.. 힘드럿다 배경색도 바꾸느니라고..

신고

'Windows > API&MFC' 카테고리의 다른 글

x86에서 CFILE::GetStatus 를 못받아오는 경우가 있따.  (0) 2014.06.19
유니코드에서 char * 로 할당  (0) 2009.09.29
리치 에디트  (0) 2009.09.28
1. API 기본소스  (0) 2009.07.12

04. 프로세스 - CreateProcess

Windows/System 2009.08.21 22:10

BOOL CreateProcess함수를 이용하면 새로운 프로세스를 생성할 수 있다.

BOOL CreateProcess(
PCTSTR pszApplicationName,
PSECURITY_ATTRIBUTES psaProcess,
PSECURITY_ATTRIBUTES psaThread,
BOOL bInheritHandles,
DWORD fdwCreate,
PVOID pvEnvironment,
PCTSTR pszCurDir,
PSTARTUPINFO psiStartInfo,
PROCESS_INFORMATION ppiProcInfo);

스레드가 CreateProcess를 호출하면 시스템은 사용 카운트가 1인 프로세스 커널 오브젝트를 생성한다.
프로세스 커널 오브젝트는 프로세스 자체를 의미하는 것은 아니며, 운영체제가 프로세스를 관리하기 위한 목적으로 생성한 조그마한 데이터 구조체다. 프로세스 커널 오브젝트를 프로세스에 대한 각종 통계 정보를 가지고 있는 작은 데이터 구조체라고 생각할 수도 있다. 프로세스 커널 오브젝트가 생성되고 나면 시스템은 새로운 프로세스를 위한 가상 주소 공간을 생성하고, 실행 파일의 코드와 데이터 및 수행에 필요한 추가적인 DLL 파일들을 프로세스의 주소 공간 상에 로드한다.

다음 단계로, 시스템은 새로 생성된 프로세스의 주 스레드를 위한 스레드 커널 오브젝트(사용 카운트 1)를 생성한다. 주 스레드는 링커에 의해 진입점으로 지정된 C/C++ 런타임 시작 코드를 실행한다. 이러한 시작 코드는 종국에는 사용자가 작성한 WInMain, wWinMain, main, 또는 wmain함수를 호출하게 된다. 만일 시스템이 성공적으로 프로세스를 생성하고 주 스레드를 생성하였다면 CreateProces는 TRUE를 반환한다.

 ※ CreateProcess 함수는 새로 생성된 프로세스가 완전히 초기화되기 전에 TRUE를 반환한다. 이것은 운영체제의 로더가 새로 생성된 프로세스가 필요로 하는 모든 DLL을 로드하기 전에 CreateProcess가 반환될 수 있다는 의미이다. 만일 필요한 DLL이 없거나 올바르게 초기화가 진행되지 않으면 새로 생성된 프로세스는 곧바로 종료된다. 하지만 CreateProcess는 이미 TRUE를 반환했을 것이기 때문에 이 경우 부모 프로세스는 자식 프로세스에 어떠한 초기화 문제가 발생했는지 알 수 없다.

(1) pszApplicationName 과 pszCommandLine
 pszApplicationName과 pszCommandLine 매개변수로는 각각 프로세스를 생성할 실행 파일명과 새로운 프로세스에게 전달할 명령행 문자열을 지정하게 된다. 먼저 pszCommandLine 매개변수에 대해 알아보기로 하자
pszCommandLine 매개변수의 자료형이 PTSTR인 점에 주목할 필요가 있다. 이것은 우리가 전달하는 문자열이 CreateProcess 함수 내에서 변경될 수 있는 형태(non-constant string)로 전달되어야 함을 의미한다. CreateProcess는 내부적으로 우리가 전달하는 명령행 문자열에 변경 작업을 수행한다. 하지만 반환 직전에 그 내용을 원래의 값으로 돌려놓는다.

만일 명령행 문자열을 읽기 전용의 파일명 형태로 전달하게 되면 접근 위반이 발생하기 때문에 이 점은 매우 중요하다. 다음과 같이 코드를 작성하면 마이크로소프트 C/C++ 컴파일러는 "NOTEPAD"라는 문자열을 읽기 전용의 메모리에 배치하기 때문에 접근 위반을 유발하게 된다.

STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess(NULL, TEXT("NOTEPAD"), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

이러한 접근 위반은 CreateProcess가 내부적으로 전달된 문자열을 수정하려 할 때 발생하게 된다. (이전 버전의 마이크로소프트 C/C++ 컴파일러는 위와 같이 문자열을 전달하는 경우에도 읽기/쓰긱 ㅗ모두 가능한 메모리 상에 문자열을 배치하였으므로 CreateProcess를 호출하더라도 접근 위반을 유발하지 않았다. 이 문제를 해결하기 위한 최상의 방법은 다음의 예와 같이 문자열 상수를 임시 버퍼에 복사한 후 CreateProcess를 호출하는 것이다.

STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR szCommandLine[] = TEXT("NOTEPAD");
CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

마이크로소프트 C/C++ 컴파일러는 중복 문자열을 제거하고 문자열을 읽기 전용 섹션에 배치시킬 수 있도록 /Gf와 /GF 컴파일러 스위치를 제공한다(Edit & Continue와 같은 Visual Studio 디버거의 기능을 활성화하기 위해 /ZI 컴파일 스위치를 사용하면 /GF 스위치를 수반하게 된다.) 이러한 문제를 해결하는 가장 좋은 방법은 /GF 컴파일러 스위치를 사용하되 임시 버퍼를 이용하는 것이다. 물론 마이크로스프트가 CreateProcess를 수정해서 개발자가 임시 버퍼를 사용하지 않아도 되도록 함수 내부에서 전달된 문자열의 복사본을 만들어서 사용하도록 하면 될 것이다. 차기 버전의 윈도우에서는 이와 같이 변경되기를 기대해 본다.

흥미로운 사실은 윈도우 비스타에서 ANSI 버전의 CreateProcess를 위와 같은 방식으로 호출할 때에는 접근 위반이 발생하지 않는다는 것이다. 이는 유니코드로의 변경을 위해 문자열에 대한 복사본이 내부적으로 만들어지기 때문이다.

CreateProcess의 두 번째 매개변수인 pszCommandLine 을 이용하면 CreateProcess 가 새로운 프로세스를 생성하기 위해 필요한 추가 정보를 제공할 수 있다. pszCommandLine을 통해 전달되는 문자열의 첫 번째 토큰은 실행하고자 하는 프로그램의 파일명으로 간주되며, 확장자가 전달되지 않으면 .exe로 가정한다. CreateProcess는 실행 파일을 찾기 위해 다음과 같이 순차적으로 검색을 진행한다.

1. 생성할 프로세스의 실행 파일명에 포함된 디렉토리
2. 생성할 프로세스의 현재 디렉토리
3. 윈도우 시스템 디렉토리. 즉 GetSYstemDirectory가 반환하는 System32 서브폴더
4. 윈도우 디렉토리
5. PATH 환경변수에 포함된 디렉토리들

물론 생성할 프로세스의 파일명이 전체 경로를 포함하고 있는 경우라면 이러한 전체 경로만을 이용하여 실행 파일을 찾게 되고 나머지 디렉토리에서는 검색을 수행하지 않는다. 시스템이 실행 파일을 찾으면 실행 파일의 코드와 데이터는 새로운 프로세스의 주소 공간에 매핑된다. 이후 링커에 의해 애플리케잉션 진입점으로 지정된 C/C++ 런타임 시작 함수를 호출한다. 앞서 말한 바와 강이 C/C++ 런타임 시작 함수는 프로세스의 명령행을 검토하여 실행 파일명 다음으로 전달되는 첫 번째 인자를 가리키는포인터를 (w)WinMain의 pszCmdLine 매개변수를 통해 전달된다.

pszApplicationName 매개변수를 NULL로 지정하는 한(대부분의 경우 NULL)로 지정 이와 같이 작업이 수행된다. 하지만 pszApplicationName 매개변수로 실행 파일명을 담고 있는 문자열의 주소를 전달할 수도 있다. pszApplication 매개변수로 파일명을 지정하는 경우 파일명의 확장자를 .exe로 가정하지 않기 때문에 반드시 확장자를 포함하도록 파일명을 지정해야 한다. 이 경우 Create-Process 는 파일명에 경로명이 없다면 파일이 현재 디렉토리 상에 있을 것이라고 가정하게 된다. 따라서 파일이 현재 디렉토리에 존재하지 않으면 CreateProcess는 다른 디렉토리를 검색하지 않으며 실패를 반환한다.

pszApplicationName 매개변수로 파일명을 지정하는 경우라 하더라도 pszCommandLine 매개변수를 통해 새로운 프로세스를 위한 명령행 문자열을 전달할 수 있다. 예를 들어 CreateProcess를 다음과 같이 사용하는 경우를 생각해 보자.

// 전달하는 메모리는 읽기/ 쓰기가 가능한 메모리 상에 위치해야 한다.
TCHAR szPath[] = TEXT("WORDPAD README.TXT");

// 새로운 프로세스를 생성한다.
CreateProcess(TEXT("C:\\WINDOWS\\SYSTEM32\\NOTEPAD.EXE"), szPath, ...);

위 코드는 메모장 NotePad을 수행한다. 하지만 메모장의 명령행에는 WORDPAD README.TXT가 전달된다. 이것이 이상해 보이지만 CreateProcess는 이와 같이 동작한다. 사실 pszApplicationName 매개변수를 통해 실행 파일명을 지정할 수 있도록 한 것은 CreateProcess가 윈도우의 POSIX 서브 시스템을 지원하도록 하기 위해 포함시킨 것이다.

(2) psaProcess, psaThread, bInheritHandles
새로운 프로세스를 생성하기 위해 시스템은 새로운 프로세스 커널 오브젝트와 스레드 커널 오브젝트(프로세스의 주 스레드)를 생성해야 한다. 2개의 오브젝트들은 모두 커널 오브젝트이므로 부모 프로세스는 각각에 대해 보안 특성을 지정할 수 있어야 한다. CreateProcess 함수에서는 psaProcess와 psaThread 매개변수를 통해 프로세스 커널 오브젝트와 스레드 커널 오브젝트 각각에 대해 원하는 보안 특성을 지정할 수 있다. 기본 보안 해설자를 사용하길 원한다면 각 매개변수를 NULL로 지정하면 된다. 그렇지 않은 경우라면 SECURITY_ATTRIBUTES 구조체를 생성하여 프로세스 오브젝트와 스레드 오브젝트 각각에 대해 적절한 보안 권한을 설정하면 된다.

psaProcess와psaThread 매개변수로 SECURITY_ATTRIBUTES를 사용하는 또 다른 이유는 두개의 커널 오브젝트 핸들을 상속 가능하도록 생성하여 추후 부모 프로세스가 새로운 자식 프로세스를 생성할 때 이 커널 오브젝트들을 사용할 수 있도록 하기 위함이다.

커널 오브젝트 핸들 상속을 보여주기 위한 간단한 프로그램이다. A 프로세스는 CreateProcess를 호출할 때 psaProcess 매개변수로 bInheritHandle 값을 TRUE로 설정한 SECURITY_ATTRTI

신고

'Windows > System' 카테고리의 다른 글

04. 프로세스 - CreateProcess  (0) 2009.08.21
03. 프로세스  (0) 2009.08.21
02. 커널 오브젝트 下  (0) 2009.08.18
01. 커널 오브젝트 上  (3) 2009.08.18

03. 프로세스

Windows/System 2009.08.21 03:28
프로세스란 일반적으로 수행 중인 프로그램의 인스턴스 라고 정의한다.

프로세스의 구성요소
 ① 프로세스 커널 오브젝트 : 프로세스를 관리하기 위한 목적으로 운영체제가 사용하는 커널 오브젝트, 시스템은 프로세스에 대한 각종 통계 정보를 프로세스 커널 오브젝트에 저장하기도 한다.
 ② 주소 공간 : 실행 모듈이나 DLL(Dynamic-Link Library)의 코드와 데이터를 수용하는 주소 공간, 이러한 주소 공간은 스레드 스택이나 힙 할당과 같은 동적 메모리 할당에 사용되는 공간도 포함된다.

- 스레드
 프로세스는 자력으로 수행될 수 없다. 프로세스가 무언가를 수행하기 위해서는 반드시 프로세스의 컨텍스트(Context) 내에서 수행되는 스레드(Thread)가 있어야 한다. 스레드는 프로세스의 주소 공간 상에 위치하고 있는 코드를 수행할 책임이 있다. 하나의 프로세스는 다수의 스레드를 가질 수 있으며, 이러한 스레드들은 프로세스 주소 공간 내에서 "동시에" 코드를 수행한다. 이렇게 되려면 각 스레드들은 자신만의 CPU 레지스터 집합과 스택을 가져야만 한다. 각 프로세스는 프로세스 주소 공간 내의 코드를 수행 하기 위해 적어도 한 개의 스레드를 가지고 있다.

 프로세스가 생성되면 시스템은 자동적으로 첫 번째 스레드를 생성해 주는데, 이0를 주 스레드(Primary Thread)라고 부른다. 이 스레드는 추가적인 스레드를 생성할 수 있고, 이렇게 생성된 스레드들이 더욱더 많은 스레드를 만들어낼 수도 있다. 만일 프로세스의 주소 공간 내의 코드를 수행할 스레드가 없다면 프로세스는 계속해서 존재해야 할 이유가 없고, 따라서 시스템은 자동적으로 프로세스와 프로세스 주소 공간을 파괴한다.


- 스케줄링
 모든 스레드가 동시에 수행될 수 있도록 하기 위해 운영체제는 CPU 시간을 조금씩 나누어준다. 각 스레드들은 라운드 로빈(Round-Robin) 방식으로 주어지는 단위 시간(Quantum)만큼만 수행 될 수 있다. 이렇게 되면 마치 모든 스레드들이 동시에 수행되고 있는것처럼 보이게 된다.
다수의 CPU를 가지고 있는 머신의 경우 각 스레드에게 공평하게 CPU 시간을 나누어주는 알고리즘은 상당히 복잡하다. 마이크로소프트 윈도우의 경우 다수의 스레드를 동시에 수행시키기 위해 각 CPU별로 서로 다른 스레드를 수행하도록 스케줄링하고 있다. 윈도우 운영체제에서는 스레드에 대한 모든 관리와 스케줄링을 윈도우 커널이 담당한다. 따라서 다수의 CPU를 가지고 있는 머신의 장점을 사용하기 위해 코드를 변경해야 할 필요는 없다. 하지만 여러 개의 CPU를 가진 머신의 장점을 최대한 살리기 위해 애플리케이션의 알고리즘을 적절히 변경하는 것은 여전히 유효한 방법이다.


1. 윈도우 어플리케이션 작성

- 윈도우가 지원하는 애플리케이션

 ① GUI(Graphic User Interface) : 그래픽 폰트를 사용하며, 윈도우를 만들 수 있고, 메뉴를 가지기도 하고, 다이얼로그 박스를 통해 사용자와의 상호작용을 수행하기도 한다. 그리고 윈도우스러운 표준화된 모든 요소들을 사용하게 된다. 윈도우와 함께 배포되는 보조 프로그램(메모장, 계산기, 워드패드등)들은 대부분 GUI 기반의 애플리케이션이다.

 ② CUI(Console User Interface) : 텍스트를 기반으로 한다. 일반적으로 윈도우를 생성하지도 않고, 메시지를 처리하지도 않으며, 그래픽 유저 인터페이스를 필요로 하지도 않는다. 비록 CUI 기반의 애플리케이션도 화면 상에 단일의 윈도우 생성하고 그 안에서 수행되긴 하지만, 이 윈도우는 단순히 텍스트만을 출력한다. 명령 프롬프트(Command Promt)가 전형적인 CUI 기반 애플리케이션의 예이다.

 ※ 두 가지 형태의 애플리케이션은 경계가 명확하지 않다. CUI 기반의 애플리케이션도 다이얼로그 박스를 사용하는 것이 가능하다. 예를 들어 명령 쉘은 쉘이 제공하는 모든 명령어를 기억하는 대신에 그래픽 다이얼로그 박스에서 명령을 선택하여 수행할 수 있다 . 뿐만 아니라 GUI 기반의 애플리케이션도 텍스트 문자열을 콘솔 창에 출력할 수 있다.

- 링커 스위치(Linker Switch)
마이크로소프트트의 Visual Studio를 이용하여 애플리케이션 프로젝트를 생성하면, Visual Studio 통합 환경은 실행 파일의 형태에 알맞은 서브시스템 타입을 실행 파일에 포함시킬 수 있도록 다양한 링커 스위치를 설정한다.
CUI 기반 애플리케이션을 위한 링커 스위치 : /SUBSYSTEM:CONSOLE 
GUI 기반 애플리케이션을 위한 링커 스위치 : /SUBSYSTEM:WINDOWS

사용자가 애플리케이션을 수행하면 운영체제의 로더(Loader)는 실행 파일의 헤더를 확인하여 서브시스템 값을 가져온다. 만일 이 값이 CUI 기반의 애플리케이션이 콘솔 윈도우를 사용할 수 있도록 조치한다. 만일 CUI기반의 애플리케이션이 명령 프롬프트에서 수행되면 명령 프롬프트가 사용중인 윈도우를 사용하고, 윈도우 익스플로어에서 수행되면 새로운 콘솔 윈도우를 생성한다
 헤더로부터 확인한 서브시스템 값이 GUI기반의 애플리케이션을 의미하는 값이면 로더는 콘솔 윈도우를 생성하지 않고 애플리케이션을 바로 로드한다. 애플리케이션이 수행되면 운영체제는 애플리케이션이 어떤 형태인지에 대해 더 이상 신경 쓰지 않는다.
 윈도우 애플리케이션은 애플리케이션이 수행을 시작할 진입점 함수를 반드시 가져야 한다. C/C++ 개발자는 두 가지 형태의 진입점 함수를 사용할 수 있다.
 어떤 진입점 함수를 사용할지는 유니코드 문자열의 사용 여부에 달려 있다. 사실 운영체제는 우리가 작성한 진입점 함수를 직접 호출하지는 않으며, C/C++ 런타임에 의해 구현된 C/C++ 런타임 시작 함수(C++ Runtime Startup Function)를 호출한다. 이러한 함수는 링크 시 -entry:명령행 옵션(Command-Line Option)을 통해 설정된다. C/C++ 런타임 시작 함수는 malloc이나 free와 같은 함수가 호출될 수 있도록 C/C++ 런타임 라이브러리에 대한 초기화를 수행한다. 또한 개발자가 코드 상에서 선언한 각종 전역 오브젝트나 static 으로 선언된 C++  오브젝트들을 코드가 수행되기 전에 적절히 생성하는 역할을 수행한다.

[표] 애플리케이션 타입과 진입점
 애플리케이션 타입  진입점  실행 파일에 포함되는 런타임 시작 함수
 ANSI 문자(열) ,GUI 어플리케이션  _tWinMain(WinMain)  WinMainCRTStartup
 유니코드 문자(열), GUI 애플리케이션  _tWinMain(wWinMain)  wWinMainCRTStartup
 ANSI 문자(열), CUI 애플리케이션  _tmain(main)  mainCRTStartup
 유니코드 문자(열), CUI 애플리케이션   _tmain(wmain)  wmainCRTStartup

링커는 실행 파일을 링크하는 단계에서 적절한 C/C++ 런타임 시작 함수를 선택해야 한다.
① /SUBSYSTEM:WINDOWS : 링커 스위치가 설정되어 있으면 링커는 WInMain 이나 wWinMain 함수를 찾게 된다.
함수를 찾을 수 있는 경우 :  WinMainCRTStartup이나 wWinMainCRTStartup 함수를 호출하도록 설정한다.
함수가 찾을 수 없는 경우 :  외부 기호를 확인할 수 없습니다(unresolved external symbol) 에러를 반환한다.

 ② /SUBSYSTEM:CONSOLE : 링커 스위치가 지정되면 링커는 main 이나 wmain 함수를 찾는다.
 함수를 찾을 수 있는 경우 : mainCRTStartup이나 wmainCRTStartup 함수를 호출하도록 설정한다.
 함수가 찾을 수 없는 경우 :  외부 기호를 확인할 수 없습니다(unresolved external symbol) 에러를 반환한다.

프로젝트 설정에서 /SUBSYSTEM 링커 스위치를 완전히 제거할 수도 있다는 것은 잘 알려져 있지 않은 사실이다. 만일 이러한 링커 스위치를 제거하게 되면 링커는 자동적으로 애플리케이션에 적합한 설정 값을 찾아낸다. 링크 단계에서 링커는 코드에서 4개의 함수 중(WinMain, wWinMain, main, wmain) 어떤 것이 구현되었는지를 확인하고 적절한 서브시스템 설정을 추정한다. 이렇게 결정된 정보를 근간으로 어떤 C/C++ 시작함수가 실행 파일에 포함되어야 하는지를 결정하게 된다.

 모든 C/C++ 런타임 시작함수는 기본적으로 동일한 작업을 수행한다. 차이점이라면 C 런타임 라이브러리의 초기화 이후에 수행해야 할 진입점 함수가 어떤 것이냐에 따라 ANSI 문자열이나 유니코드 문자열을 처리해야 한다는 점 정도일 것이다. Visual C++에는 C/C++ 런타임 라이브러리의 소스 코드가 포함되어 있다. crtexe.c 파일을 살펴보면 4개의 시작 함수에 대한 구현 내용을 찾아볼 수 있는다.

- 시작 함수가 수행하는 작업
 ① 새로운 프로세스의 전체 명령행을 가리키는 포인터를 획득

 ② 새로운 프로세스의 환경변수를 가리키는 포인터를 획득

 ③ C/C++ 런타임 라이브러리의 전역변수를 초기화. 사용자 코드가 StdLib.h 파일을 인클루드하면 이 변수에 접근할 수 있다.
 변수명 타입   설명과 이 변수를 대체하는 윈도우 함수
 _osver  unsigned int  운영체제의 빌드 버전.
 예) 비스타 RTM은 6000이므로 _osver는 6000값을 가진다
 _winmajor  unsigned int  16비트로 나타낸 윈도우 major버전.
 윈도우 비스타의 경우 6.
 GetVersionEx 대체 사용 가능
 _winminor  unsigned int  16비트로 나타낸 윈도우 minor 버전.
 윈도우 비스타의 경우 0.
 GetVersionEx 대체 사용 가능
 _winver  unsinged int  (_winmajor << 8) + _winminor.
 GetVersionEx 대체 사용 가능
 __argc  unsigned int  명령행을 통해 전달된 인자의 개수.
 GetCommandLine을 대체 사용 가능
 __argv
 _wargv
 char
 wchar_t
 ANSI / 유니코드 문자열을 가리키는 __argc 크기의 배열
 배열의 각 요소는 명령행 인자를 가리킨다.
 _UNICODE가 정의되어 있으면 __argv가 NULL, 정의되어 있지 않으면 __wargv가 NULL이다.
 GetCommandLine을 대체 사용 가능
 _environ
 _wenviron
 char
 wchar_t
 ANSI/유니코드를 가리키는 배열. 각 배열 요소는 환경변수 문자열을 가리킨다. _UNICODE가 정의되어 있으면 _environ이 NULL, 정의되어 있지 않으면 _wenviron 이 NULL이다.
 GetEnviromentStrings, GetEnvironmentVariable 대체 사용 가능
 _pgmptr
 _wpgmptr
 char
 wchar_t
 ANSI/유니코드로 표현되는 수행 중인 프로그램의 전체 경로와 이름.
 _UNICODE가 정의도어 있으면 _pgmptr이 NULL, 정의되어 있지 않으면 _wpgmptr이 NULL이다.
 GetModuleFileName의 첫 번째 매개변수로 NULL을 전달하는 형태로 대체 사용 가능

④ 모든 전역 오브젝트와 static C++ 클래스 오브젝트의 생성자를 호출한다.


(1) 프로세스의 인스턴스 핸들

 모든 실행 파일과 DLL 파일은 프로세스의 메모리 공간 상에 로드될 때 고유의 인스턴스 핸들을 할당 받는다. 이러한 인스턴스 핸들은 (w)WinMain의 첫 번째 매개변수인 hInstanceExe를 통해 전달된다. 이 핸들 값은 보통 리소스를 로드할 때 사용된다.
ex) 실행 파일 이미지에 포함되어 있는 아이콘 리소스를 로드하려는 경우 다음의 함수를 호출해야 한다.
HICON LoadIcon(HINSTANCE hInstance, PCSTR pszIcon);

LoadIcon의 첫 번째 매개변수로는 리소스가 포함되어 있는 파일(실행 파일이나 DLL)의 인스턴스 핸들을 지정하면 된다. 많은 애플리케이션에서 (w)WinMain의 hInstanceExe 매개변수를 전역변수에 저장해 두어 실행 파일의 전체소스에서 이 값에 손쉽게 접근할 수 있도록 하곤 한다.

플랫폼 SDK 문서를 살펴보면 HMODULE 형 인자를 요구하는 함수들이 있음을 알 수 있다. 예를 들면 다음에 나오는 GetModuleFileName과 같은 함수가 있다.
DWORD GetModuleFileName(HMOUDLE hInstModule, PTSTR pszPath, DWORD cchPath);

WinMain의 hInstanceExe 매개변수의 실제 값은 시스템이 프로세스의 메모리 주소 공간 상에 실행 파일을 로드할 시작 메모리 주소(base memory address)다. 예를 들어 시스템이 실행 파일을 열어서 그 내용을 0x00400000에 로드하고자 한다면 (w)WinMain의 hInstanceExe 매개변수는 0x00400000을 가지게 된다.

실행 파일이 로드될 시작 주소는 링커에 의해 결정된다. 서로 다른 링커는 서로 다른 기본 시작 주소를 가질 수 있다. Visual Studio의 링커는 역사적인 이유로 0x00400000을 기본 시작 주소로 사용하고 있는데, 0x00400000은 윈도우 98에서 실행 파일을 로드할 수 있는 가장 하단의 메모리 주소였다. 애플리케이션이 로드되는 시작 주소는 마이크로소프트 링커의 경우 /BASE:address 옵션을 사용하여 변경할 수 있다.

 아래의 GetModuleHandle 함수는 실행 파일이나 DLL 파일이 프로세스의 메모리 공간 상의 어디에 로드되어 있는지를 가리키는 핸들/시작 주소를 반환한다.

HMODULE GetModuleHandle(PCTSTR pszModule);

이 함수를 호출할 때에는 호출하는 프로세스의 주소 공간에 로드되어 있는 실행 파일명이나 DLL 파일명을 '\0'으로 끝나는 문자열로 전달하면 된다. 시스템이 지정한 실행 파일이나 DLL 파일을 찾아내면 GetModuleHandle 함수는 파일이 로드된 시작 주소를 반환한다. 반면 시스템이 해당 파일을 찾을 수 없다면 NULL을 반환한다. GetModuleHandle을 호출할 때 pszModule 매개변수로 NULL 값을 전달할 수도 있는데, 이 경우 GetModuleHandle은 현재 수행 중인 실행 파일이 로드된 시작 주소를 반환한다. 만일 이 함수가 DLL 내에서 호출된다면 어떤 모듈에 포함되어 코드가 수행 중인지 알아내기 위한 두 가지 방법이 있다.

① 링커에 의해 정의되는 가상변수인 __ImageBase가 현재 수행 중인 모듈의 시작 주소를 가리키고 있다는 사실을 활용할 수 있다. 이 변수 값은 앞서 알아본바와 같이 C 런타임 시작 코드가 (w)WinMain 함수를 호출할 때 사용되는 값이다.

② 첫 번째 매개변수로 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS를 두 번째 매개변수로 현재 수행 중인 함수의 주소를 지정하여 GetModuleHandleEx함수를 호출한다. 마지막 매개변수로 전달되는 값은 HMODULE을 가리키는 포인터 값인데, 두번째 매개변수로 전달한 함수를 포함하고 있는 DLL의 시작주소를 반환해 준다.

※ 실제로 HMODULE과 HINSTANCE는 완전히 동일하다. 어떤 함수가 HMODULE을 요구한다면 HINSTANCE를 넘겨줘도 무방하며, 그 반대도 마찬가지다. 16비트 윈도우에서는 HMODULE과 HINSTANCE가 완전히 구분되는 자로형으로 존재했지만 지금은 혼용하고 있다.
신고

'Windows > System' 카테고리의 다른 글

04. 프로세스 - CreateProcess  (0) 2009.08.21
03. 프로세스  (0) 2009.08.21
02. 커널 오브젝트 下  (0) 2009.08.18
01. 커널 오브젝트 上  (3) 2009.08.18


티스토리 툴바