RegAsm

C#으로 만든 프로그램을 


dll로 만들때 RegAsm.exe을 사용하려고 검색 했는데


regasm a.dll /tlb:a.tlb 


이 명령어를 쓰면 된다길래 열심히 cmd에서 두드렸지 ㅋㅋㅋㅋ 


근데 그게 아니고 


C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Visual Studio 2010\Visual Studio Tools


여기에 있는 Visual Studio 명령 프롬프트에서 써야 하는 것이었다 흑흑  


 

C# - Excel 내용 읽어오기

Excel 내용을 읽는 것을 하고 있는데

Excel. range범위를


range = ESheet.get_Range("A1", missing); //A1 셀 선택 

range = range.get_Resize(5,5) // A1부터 5,5의 크기 


이런 식으로 설정 해줘야 해서.

이런 식으로는 텍스트를 읽어 올 수 있는데 

내가 모든 EXCEL 파일의 셀의 크기를 알 수 없어서 

읽어 오는 파일 마다 셀의 크기가 다른데 그럴 땐 어떻게 해야 하나 

하루 종일 찾았다 ㅜㅜ


(엑셀에서 셀이 만들어 질 수 있는 크기까지 찾아서 모든 크기안에 있는 내용을 찾으려고 했는데

데이터가 너무 커서 오버플로우 남 ㅋ  1048576 x 16384)


셀에 대한 메서드가 따로 있어서 

range를 설정 해 줄때 사용된 범위에 있는 마지막 셀을 이용하여 

아무 엑셀 파일을 선택하면 텍스트를 읽어 올 수 있게 설정해 주었다.


      public string ReadExcel(string path)

        {

           string filename = path;// string filename = "C:\\test.xlsx";

            object missing = System.Reflection.Missing.Value;


            Excel.Application EApp = new Excel.Application();


            Excel.Workbook EBook;

            Excel.Workbooks EBooks;


            Excel.Sheets ESheets;

            Excel._Worksheet ESheet;


            Excel.Range range;


            EApp.Visible = false;

//          EApp.WindowState = Excel.XlWindowState.xlMinimized;


            EBooks = EApp.Workbooks;

            EBook = EApp.Workbooks.Open(filename, missing, missing, missing, missing, missing, missing

               , missing, missing, missing, missing, missing, missing, missing, missing);

            

            ESheets = EBook.Worksheets;

            ESheet = (Excel._Worksheet)EBook.ActiveSheet;

            ESheet = (Excel._Worksheet)ESheets.get_Item(1);


            range = ESheet.get_Range("A1").SpecialCells(Excel.XlCellType.xlCellTypeLastCell);


           long row = range.Row;

            long column = range.Column;

            

String valueString = "";


            for (long rowCounter = 1; rowCounter <= row; rowCounter++)

            {

                for (long colCounter = 1; colCounter <= column; colCounter++)

                {

                    Excel.Range cell = (Excel.Range)ESheet.Cells[rowCounter, colCounter];


                    if (cell.Value == null)

                        valueString = string.Concat(valueString, " ");

                    else

                    {

                        valueString = string.Concat(valueString, cell.Value.ToString() + ",");

                        Console.Write(valueString);

                    }

                        textBox1.Text = valueString;


                }

                valueString = String.Concat(valueString,"\r\n");


            }




================================================================================
저 위의 함수를 이용해서 그동안 엑셀을 읽어 왔는데, 
데이터가 너무 클 경우에는 읽는 속도가 10분이 넘어감...ㅋㅋ( 2중 for문 때문인가ㅜㅜ )

그래서 새로운 방법을 알아 냄 
DataTable을 이용하여서 DataTable에 값을 저장 -> 이 부분이 진짜 빠름

나는 필요한게 String 형이여서 row[Col].ToString()으로 변환 해준다 

그래도 이전보다는 빨라졌당 1분 30초 정도 


using System.Data.OleDb;


      public string ReadExcel(string strFilePath)
        {
            // 엑셀 문서 내용 추출
            object missing = System.Reflection.Missing.Value;
            String valueString = "";

            string strProvider = string.Empty;
            strProvider = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" + strFilePath + @";Extended Properties=Excel 12.0";

            OleDbConnection excelConnection = new OleDbConnection(strProvider);
            excelConnection.Open();

            string strQuery = "SELECT * FROM [Sheet1$]";

            OleDbCommand dbCommand = new OleDbCommand(strQuery, excelConnection);
            OleDbDataAdapter dataAdapter = new OleDbDataAdapter(dbCommand);

            DataTable dTable = new DataTable();
            dataAdapter.Fill(dTable);

            // dTable에 추출된 내용을 String으로 변환
            foreach (DataRow row in dTable.Rows)
            {
                foreach (DataColumn Col in dTable.Columns)
                {
                    valueString += row[Col].ToString() + " ";
                }
            }
        
            dTable.Dispose();
            dataAdapter.Dispose();
            dbCommand.Dispose();

            excelConnection.Close();
            excelConnection.Dispose();

            return valueString;
        }







- 참고 

NamedRange.SpecialCells 메서드

셀에 대한 내용
http://technet.microsoft.com/ko-kr/subscriptions/microsoft.office.tools.excel.namedrange.specialcells

C# - Excel 창 접근하기

Application -> Books -> Book -> Sheets -> Sheet  순으로 설정 





        private void button1_Click(object sender, EventArgs e)

        {

            string filename = "C:\\test.xlsx";

            object missing = System.Reflection.Missing.Value;


            Excel.Application EApp;

            Excel.Workbook EBook; 


            Excel.Workbooks EBooks;

            Excel.Sheets ESheets;

            Excel._Worksheet ESheet;


            EApp = new Excel.Application();

            EApp.Visible = false;


            EBooks = EApp.Workbooks;

            EBook = EApp.Workbooks.Open(filename, missing, missing, missing, missing, missing, missing

                , missing, missing, missing, missing, missing, missing, missing, missing);

            ESheets = EBook.Worksheets;

            ESheet = (Excel._Worksheet)ESheets.get_Item(1);


//         Range 설정 해줘야 함 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

//아래 적어주면 지금 작업중인(filename에 해당하는) 엑셀 창이 뜬다.


                EApp.Visible = true;

                EApp.UserControl = true;



}

C# - 파일 선택 다이얼로그 띄우기





            OpenFileDialog ofd = new OpenFileDialog();


            ofd.Filter = "모든 파일 (*.*) | *.*";

            ofd.ShowDialog();


            string path = ofd.FileName;

            textPathName.Text = ofd.FileName;



1. ofd.Filter에는 다이얼로그 창에 나오는 파일 종류 선택 할 수 있다  

예를들어 MS워드파일만 다이얼로그 창에 나오게 하고 싶으면 

ofd.Filter =  "WodrDocuments(*.doc) | *.doc";


2. textPathName은 내가 도구상자에서 만들어 준 textBox 이름 이어서 

textPathName.Text 하여 string을 지정할 경우 해당하는 string이 textbox에 표시된다.  


아이디어가 고갈되었을 때의 처방전 20

아이디어가 고갈되었을 때의 처방전 20
1. 무의식을 활용하라
2, 종이에 적어라
3. 스케치북은 항상 필수
4, 한 걸음 떨어지는 것도 괜찮다
5. 시작한 것들을 먼저 마무리하라
6. 스튜디오의 분위기를 밝게 하라
7. 이전의 사례를 그대로 답습하지 말라
8. 예상하지 못할 만한 것들을 기대하라
9. 그럴싸하지 않아 보이는 곳이 노다지일 수 있다.
10. 마음의 지경을 넓혀라
11. 다른 크리에이티브 분야를 모색하라
12. 수동적인 흐름에 젖지 말라
13. 개인 시간을 가져라
14. 메모하는 습관이 중요하다
15. 의뢰 내용에 너무 얽매이지 않는다
16. 스스로의 지평선을 확장하라
17. 한계란 뛰어 넘으라고 있는 것이다.
18. 새로운 시각을 모색하라
19. 주변 환경에 변화를 주어라
작업 환경에 살짝 변화를 주는 것만으로도 생각이 전환된다. 사무실을 벗어나, 침대에서 잠옷 차림으로 스케치를 한다든지, 전철 안에서 작업을 시도해본다. 아니면 팀원들과 카페에서 브레인 스토밍을 하는 것도 좋은 방법이다.
20. 잠은 충분히 자도록 한다.
아이디어를 떠올렸다고 그날 바로 작품을 완성시킬 수는 없다. 또한 그렇게 해서도 안 된다. 사람이란 본능적으로 좋은 것과 나쁜 것을 구분하도록 되어 있기 때문에, 아이디어를 떠올린 후 잠을 자는 동안 그 아이디어에 대한 새로운 판단을 할 수 있게 된다. 아이디어도 숙성되어야 한다.

 

MMF(memory mapping file)

MMF 구현 과정

1. 파일 개방 - CreateFile 함수를 호출하여 파일을 열고 해당 파일의 핸들을 얻어 이 핸들로 파일을 조작한다.

2. 파일 연결 오브젝트 생성 - CreateFileMapping 함수를 호출하여 메모리에 연결할 파일 정보를 담고 있는 커널 오브젝트를 생성한다.

3. 가상 메모리에 파일 연결 - MapViewOfFile 함수를 호출하여 가상메뫼와 파일을 연결한다.  MapViewOfFile 함수의 반환되는 포인터를 가지고 메모리에 접근하면, 메모리가 변경시 파일에도 변경된 내용이 자동으로 반영된다. 



void main()

{

HANDLE hFileRead = INVALID_HANDLE_VALUE;

HANDLE hFileMap = INVALID_HANDLE_VALUE;

char *str ;


hFileRead = CreateFile("test.txt",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);


if(hFileRead==NULL)

printf("!CreateFile\n");

hFileMap = CreateFileMapping(hFileRead,NULL,PAGE_READWRITE,0,100,NULL);

if(hFileMap == NULL)

printf("!hFileMap\n");


str = (char *) MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,0);

if(str == NULL)

printf("!str");

// strcpy(str,"hello");

printf("%s\n",str);

// strcpy(str,"wpets'pdghsdo;fhasdjkfhasflkjas;dfdsaojgs;djgsakdlfsfa");


UnmapViewOfFile(str);

CloseHandle(hFileRead);

CloseHandle(hFileMap);




}

'c/c++' 카테고리의 다른 글

디버그 창에 출력하기  (0) 2012.11.16
ofstream 파일 이어쓰기  (0) 2012.11.02
파일 경로 분리  (0) 2012.11.01
한글 깨짐  (0) 2012.10.31
C++ 파일 크기 구하기  (0) 2012.09.24

작업 디렉터리

파일을 열때나 dll로 작업할때

파일경로를 지정하지 않고 파일 이름만 쓰고 싶은 경우가 있다.

 

그런 경우 그 파일을 어느 디렉토리에 저장해야 파일 이름만 적어도 프로젝트가 파일을 열 수 있을까?

 

나는 그 프로젝트와 관련된 폴더에 다 넣었었다ㅋㅋ

디버그 폴더에도 넣고, 프로젝트 폴더에도 넣고 어느 폴더 중 하나만 걸려라 하는 마음에ㅋㅋ

 

프로젝트 속성 페이지만 가도 알 수 있는데

 

ALT + F7을 눌러 ( [프로젝트] - [속성])

프로젝트 속성 페이지에 들어가

 

 

 

구성 속성 -> 디버깅 메뉴에 들어가면

작업 디렉터리가 있다.

여기서 보면 $(ProjectDir)로 표시되어 있을 건데

그 위치에서 파일을 가져 오는 것 같다.

 

이 ProjectDir의 위치를 알고 싶으면

옆에 ▼를 눌러 <편집....>을 선택하여

뜨는 창에서 매크로(M) 버튼을 눌러 확인하면 된다. 

 

값을 설정하지 않더라도 위치를 확인 할 수 있다

 

 

 

문자열 처리함수 정리(멀티바이트 -> 유니코드)

멀티 바이트 환경에서 사용하던 함수를 유니코드 환경에서 사용하려고 하면 사용이 안된다.

처음에 VS2008을 사용하면서 예전 책을 보면서 공부할 때 가장 많이 머리가 아프던 문제였다.

유니코드 환경에서 사용 할 수 있게 정의가 되어진 함수들은 같은 함수명을 써도 자동으로 처리가 되기 때문에

특별히 신경을 쓸 일은 없었다. 그러나 문자열처리 함수 같은경우는 아예 함수 이름이 바뀌었기 때문에 모른다면 사용 할 수가 없다.

그래서 문자열 처리 함수를 정리 할 겸 유니코드 환경에서 사용 할 수 있는 문자열 처리 함수를 정리해 보았다.

일단 기본적으로 멀티 바이트 환경에서 문자열 처리 함수의 접두어는 str 이었다 strlen, strcat, strstr 등등

그러나 유니코드 환경에서 접두어는 wcs이다. 이것만 기억해 둔다면 이미 문자열처리 함수의 절반은 안것이다.


1-1.strcpy -> wcscpy

:문자열을 복사하는 함수이다

원형 :

wchar_t *wcscpy(
wchar_t *strDestination, 복사 당하는 대상
const wchar_t *strSource 복사 하려는 소스
);

ex)

TCHAR str[256];

wcscpy(str,L"안녕하세요");

TextOut(hdc,0,0,str,wcslen(str));

:결과 = 0,0에 "안녕하세요" 문자열 출력



1-2. strncpy -> wcsncpy

:입력한 사이즈 만큼 문자열을 복사하는 함수이다

원형 :

wchar_t *wcsncpy(
wchar_t *strDest, 복사 당하는 대상
const wchar_t *strSource, 박사 하려는 소스
size_t count 복사하려는 개수
);

ex)

TCHAR str[256];

memset(str,0,sizeof(str)); NULL값으로 배열을 초기화

wcsncpy(str,L"안녕하세요", 2);

TextOut(hdc,0,0,str,wcslen(str));

:결과 = 0,0에 "안녕" 문자열 출력


2. strlen -> wcslen

: 입력 받은 문자열의 길이를 반환해준다.

sizeof와 다른점은 sizeof는 배열의 전체크기를 반환해주고

wcslen은 중간에 NULL을 만나면 NULL까지의 길이만 반환한다.

원형 :

size_t wcslen(
const wchar_t *str
);


3-1.strcat -> wcscat

: 두 문자열을 이어준다

원형 :

wchar_t *wcscat(
wchar_t *strDestination,
const wchar_t *strSource
);

ex)

wcscpy(str,L"안녕하세요");
wcscat(str,L"오냐");

TextOut(hdc,0,0,str,wcslen(str));

:결과 = 0,0에 "안녕하세요오냐" 출력


3-2.strncat -> wcsncat

: 입력한 사이즈만큼 대상에 소스를 이어준다

원형 :

wchar_t *wcsncat(
wchar_t *strDest,
const wchar_t *strSource,
size_t count
);

ex)

wcscpy(str,L"안녕하세요");
wcsncat(str,L"오냐",1);

TextOut(hdc,0,0,str,wcslen(str));

:결과 = 0,0에 "안녕하세요오" 출력


4-1.strcmp -> wcscmp

:대소문자를 구분하지 않고 문자열을 비교한다.

원형 :

int wcscmp(
const wchar_t *string1,
const wchar_t *string2
);

string1string2가 같으면 0

string1>string2 이면 양수

string1<string2 이면 음수

ex)

wcscpy(str,L"안녕하세요");

wcscpy(str2,L"하이");

if(wcscmp(str,str2) == 0){

TextOut(hdc,0,0,L"같다",2);

}else{

TextOut(hdc,0,0,L"다르다",3);

}

:출력 = 0,0에 "다르다" 출력


4-2.strncmp -> wcsncmp

:지정한 사이즈만큼 대소문자를 구분하지 않고 문자열을 비교한다.

원형 :

int wcsncmp(
const wchar_t *string1,
const wchar_t *string2,
size_t count
);

string1string2가 같으면 0

string1>string2 이면 양수

string1<string2 이면 음수

ex)

wcscpy(str,L"안녕하세요");

wcscpy(str2,L"안하이");

if(wcsncmp(str,str2,1) == 0){

TextOut(hdc,0,0,L"같다",2);

}else{

TextOut(hdc,0,0,L"다르다",3);

}

:출력 = 0,0에 "같다" 출력



5-1. stricmp -> wcsicmp

:대소문자를 구별하지 않고 문자열을 비교

원형 :

int _wcsicmp(
const wchar_t *string1,
const wchar_t *string2
);

string1string2가 같으면 0

string1>string2 이면 양수

string1<string2 이면 음수

ex)

wcscpy(str,L"ABCDE");

wcscpy(str2,L"abcde");

if(wcsicmp(str,str2) == 0){

TextOut(hdc,0,0,L"같다",2);

}else{

TextOut(hdc,0,0,L"다르다",3);

}

:출력 = 0,0에 "같다" 출력



5-2. strnicmp -> wcsnicmp

:대소문자를 구별하지 않고 문자열을 비교

원형 :

int _wcsnicmp(
const wchar_t *string1,
const wchar_t *string2,
size_t count
);

string1string2가 같으면 0

string1>string2 이면 양수

string1<string2 이면 음수

ex)

wcscpy(str,L"ABCDE");

wcscpy(str2,L"abcdefgh");

if(wcsnicmp(str,str2,5) == 0){

TextOut(hdc,0,0,L"같다",2);

}else{

TextOut(hdc,0,0,L"다르다",3);

}

:출력 = 0,0에 "같다" 출력



6-1.strchr -> wcschr

:문자열에서 한 문자를 찾아 그 문자가 있는 주소를 반환하여 준다. (문자열의 처음부터 검사한다)

:만약에 찾지 못했을 경우에는 NULL값을 반환해준다

원형:

wchar_t *wcschr(
wchar_t *str,
wchar_t c
);

ex)

wcscpy(str2,L"에요안녕하세요하이");

TCHAR dd = L'요';
TCHAR * ddd;

ddd = wcschr(str2,dd);

TextOut(hdc,0,0,ddd,wcslen(ddd));

:출력 = 0,0에 "요안녕하세요하이" 출력



6-2.strrchr -> wcsrchr

:문자열에서 한 문자를 찾아 그 문자가 있는 주소를 반환하여 준다. (문자열의 맨 마지막부터 검색한다)

:만약에 찾지 못했을 경우에는 NULL값을 반환해준다

원형:

wchar_t *wcsrchr(
wchar_t *str,
wchar_t c
); // C++ only

ex)

wcscpy(str2,L"에요안녕하세요하이");

TCHAR dd = L'요';
TCHAR * ddd;

ddd = wcsrchr(str2,dd);

TextOut(hdc,0,0,ddd,wcslen(ddd));

:출력 = 0,0에 "요하이" 출력



7.strstr -> wcsstr

:문자열에서 원하는 문자열을 찾아준다.

원형 :

wchar_t *wcsstr(
wchar_t *str,
const wchar_t *strSearch
);

ex)

wcscpy(str2,L"에요안녕하세요하이");

TCHAR * ddd;
ddd = wcsstr(str2,L"안녕");

TextOut(hdc,0,0,ddd,wcslen(ddd));

:출력 = "안녕하세요하이" 출력


8.strpbrk -> wcspbrk

: 첫번째 인수로 받은 문자열에서 두번째 인수로 받은 문자열중 한문자라도 빨리 나오는 문자의 주소를 반환해준다.

원형 :

wchar_t *wcspbrk(
wchar_t *str,
const wchar_t *strCharSet
); // C++ only

ex)

wcscpy(str2,L"에요안녕하세요하이");

TCHAR * ddd;

ddd = wcspbrk(str2,L"녕세"); '녕' 이나 '세' 이 두글자 중에 빨리 나오는 문자의 주소를 출력해준다

TextOut(hdc,0,0,ddd,wcslen(ddd));

:출력 = "녕하세요하이" 출력



9.strtok -> wcstok

: 첫번째 매개변수로 받은 문자열을 두번째 매개변수로 받은 토큰 문자로 나누어준다.

원형 :

wchar_t *wcstok(
wchar_t *strToken,
const wchar_t *strDelimit
);

ex)

wcscpy(str2,L"나의'가치'는 내가 결정하고, 당신의 '가치'는 당신이 결정한다");
TCHAR * ddd;

ddd = wcstok(str2,L" ,'"); //토큰은 여러개를 지정할 수 있다. 여기서는 공백(' ')과 콤마(',') 작은따옴표(')로 지정했다.
while(ddd != NULL){
TextOut(hdc,0,i,ddd,wcslen(ddd));
ddd = wcstok(NULL,L" ,'"); //검색을 계속 해야하기 때문에 NULL값을 매개변수로 넣어준다

i+=20;
}



wcstok의 방식은 문자열에서 처음 토큰을 발견하면 그 주소를 저장하고 두번째 토큰을 찾아내면 그 토큰을 NULL로 만들고

처음 토큰 주소를 반환해준다. 또한 wcstok함수는 함수 중간 결과를 자체적으로 정적변수를 사용하고 있다. 그렇기 때문에

계속 검색을 하고 싶으면 첫번째 매개변수로 NULL을 넣어주면 문자열이 끝날때 까지 검색을 한다.

검색이 끝나면 NULL을 반환해 준다.

wcstok함수도 매개변수로 받은 데이터를 손상시키기 때문에 데이터가 손상되지 않게 하려면 다른곳에 복사한 후에 써야한다.

또한 함수 자체적으로 정적 변수를 사용하고있기 때문에 멀티 스레드 환경에서 동시에 호출될 염려가 있으므로

동시에 호출되지 않도록 보호해 주어야 한다.

:출력 =

나의

가치

내가

결정하고

당신의

가치

당신이

결정한다



10-1.strset -> wcsset

: 첫번째 매개변수로 받은 문자열을 NULL문자 전까지 모두 두번째 문자로 바꾼다

원형 :

wchar_t *_wcsset(
wchar_t *str,
wchar_t c
);

ex)

wcscpy(str,L"ABCDE");

wcsset(str,L'd');
TextOut(hdc,0,0,str,wcslen(str));

:출력 = 0,0에 "ddddd" 문자열이 출력된다



10-2.strnset -> wcsnset

: 첫번째 매개변수로 받은 문자열을 입력받은 사이즈 만큼 두번째 문자로 바꾼다

원형 :

wchar_t *_wcsnset(
wchar_t *str,
wchar_t c,
size_t count
);

ex)

wcscpy(str,L"ABCDE");

wcsnset(str,L'd',2);
TextOut(hdc,0,0,str,wcslen(str));

:출력 = 0,0에 "ddCBD" 문자열이 출력된다



11.

strupr -> wcspur

strlwr -> wcslwr

: 지정한 문자열을 대문자로 치환(wcspur) 하거나 소문자로 치환(wcslwr)한다.

: 단 대문자나 소문자만 치환이 되고 한글이나 숫자는 치환되지 않는다.

: 이 함수도 매개변수로 받은 문자열을 변형시키기 때문에 변형되어서는 안되는 문자열이면 복사를 해놓고 사용해야 한다.

wcscpy(str,L"1abcdeABCDE아");

wcsupr(str);
TextOut(hdc,0,0,str,wcslen(str));

wcslwr(str);
TextOut(hdc,0,20,str,wcslen(str));

:출력 =

0,0에 "1ABCDEABCDE아" 출력

0,20에 "1abcdeabcde아" 출력

12.strrev -> wcsrev

: 지정한 문자열을 역순으로 배치한다. 한글도 역순으로 배치된다.

: 이 함수도 매개변수로 받은 문자열을 변형시키기 때문에 변형되어서는 안되는 문자열이면 복사를 해놓고 사용해야 한다.

원형 :

wchar_t *_wcsrev(
wchar_t *str
);

ex)

wcscpy(str,L"1abcdeABCDE아");

wcscpy(str2,L"나의 '가치'는 내가 결정하고, 당신의 '가치'는 당신이 결정한다");

wcsrev(str);
wcsrev(str2);

TextOut(hdc,0,0,str2,wcslen(str2));
TextOut(hdc,0,20,str,wcslen(str));

:출력 =

0,0에 "다한정결 이신당 는'치가' 의신당 ,고하정결 가내 는'치가' 의나" 출력

0,20에 "아EDCBAedcba1" 출력

 

[API] 여러 가지 출력 - 그래픽

COLORREF SetPixel(hdc, nXPos, nYPos, clrref)
DWORD MoveToEx(hdc, x, y, lpPoint)
BOOL LineTo(hdc, xEnd, yEnd)
BOOL Rectangle(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect)
BOOL Ellipse(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect)

[API]OWNERDRAW로 버튼 이미지 바꾸기

SendMessage()를 이용하여 버튼 이미지를 변경해 주면,

EnableWindow()로 버튼을 비활성화 시킬 경우 버튼이 회색으로 변해버린다.

 

이 문제를 해결하기 위해 버튼에 BS_OWNERDRAW 스타일을 추가하여

직접 이미지를 그려준다.

 

1. 버튼 생성

case WM_CREATE:

  CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_BITMAP | BS_OWNERDRAW,
   100,100,70,30,hWnd,(HMENU)IDC_BUTTON, hInst,NULL);


도구 상자를 이용하여 버튼을 추가했을 경우 속성에 Owner Draw 값을 True로 설정해주어야 한다. 

안해주면 WM_DRAWITEM 이벤트가 안옴




 

2. 이미지 로드

hBitmap[0] = LoadBitamp(hInst, MAKEINTRESOURCE(IDB_BITMAP1));

hBitmap[1] = LoadBitamp(hInst, MAKEINTRESOURCE(IDB_BITMAP2));

 

3. 이미지를 그려 줄 구조체, 변수 선언

 static LPDRAWITEMSTRUCT lpdis;
 static HDC memDC;

4. case WM_DRAWITEM에서 이미지 그려줌 

 case WM_DRAWITEM:
  lpdis = (LPDRAWITEMSTRUCT)lParam;

  if(lpdis->itemState & ODS_SELECTED) // 버튼이 눌린 상태(BUTTONDOWN)
  {
   memDC = CreateCompatibleDC(lpdis->hDC);
   SelectObject(memDC,hBitmap[1]);
   BitBlt(lpdis->hDC, 0,0,100,50,memDC,0,0,SRCCOPY);
   DeleteDC(memDC);
  }
  else // 버튼이 UP되어 있는 상태(BUTTONUP)
  {
   memDC = CreateCompatibleDC(lpdis->hDC);
   SelectObject(memDC,hBitmap[0]);
   BitBlt(lpdis->hDC, 0,0,100,50,memDC,0,0,SRCCOPY);
   DeleteDC(memDC);
  }
  break;

 

- 버튼을 눌렀을 때와, 누르지 않고 있을 때 이미지 변경

 

 

 

 

/************************* 참고

* Owner draw의 값으로 여러 경우에서 버튼 이미지를 변경 가능 하다 

*/

#define ODS_SELECTED 0x0001

#define ODS_GRAYED 0x0002

#define ODS_DISABLED 0x0004

#define ODS_CHECKED 0x0008

#define ODS_FOCUS 0x0010

#if(WINVER >= 0x0400)

#define ODS_DEFAULT 0x0020

#define ODS_COMBOBOXEDIT 0x1000

#endif /* WINVER >= 0x0400 */

#if(WINVER >= 0x0500)

#define ODS_HOTLIGHT 0x0040

#define ODS_INACTIVE 0x0080

#endif /* WINVER >= 0x0500 */



 

//3. static LPDRAWITEMSTRUCT lpdis; static HDC memDC; static HBITMAP hBitmap[2]; switch (message) { //1. case WM_CREATE: CreateWindow("button","",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_BITMAP | BS_OWNERDRAW, 100,100,70,30,hWnd,(HMENU)IDC_BUTTON, hInst,NULL); //2. hBitmap[0] = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1)); hBitmap[1] = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP2)); break; //4. case WM_DRAWITEM: lpdis = (LPDRAWITEMSTRUCT)lParam; if(lpdis->itemState & ODS_SELECTED) // 버튼이 눌린 상태(BUTTONDOWN) { memDC = CreateCompatibleDC(lpdis->hDC); SelectObject(memDC,hBitmap[1]); BitBlt(lpdis->hDC, 0,0,100,50,memDC,0,0,SRCCOPY); DeleteDC(memDC); } else // 버튼이 UP되어 있는 상태(BUTTONUP) { memDC = CreateCompatibleDC(lpdis->hDC); SelectObject(memDC,hBitmap[0]); BitBlt(lpdis->hDC, 0,0,100,50,memDC,0,0,SRCCOPY); DeleteDC(memDC); } break;             }