피터지고 치열하게 삶을 유지하다  
Front Page
Notice | Keyword | Tag | Location | Guestbook | Admin | Write Article   
 
디버깅에 해당하는 글 1건
2007/06/27   MFC ComboBox, ListBox - auto sorting과 관련된 실수 (2)


MFC ComboBox, ListBox - auto sorting과 관련된 실수
아래 프로그램은 쭌이 최근 진행중인 프로젝트에 필요해서 만든 시리얼 생성 및 검증 프로그램이다.

컴퓨터에 설치된 네트워크 인테페이스 카드의 맥 주소를 시리얼 키 생성의 소스로 사용함으로서
해당 시리얼 키는 생성시 지정한 네트워크 카드가 설치된 시스템에서만 유효하게 된다.

이때 시스템에 있는 네크워크 인터페이스 카드를 나열하기 위해 ComboBox를 사용하였다.
아래 보이는 그림처럼 디폴트 Style은 Sort 속성이 true로 되어 있다.

즉, AddString() 메서드를 사용해 Combo Item을 추가하면 자동으로 정렬이 된다.

사용자 삽입 이미지


사용자 삽입 이미지

다음은 WMI를 이용 시스템에 설치된 네트워크 카드를 검색하면서 ComboBox(m_ctrlEtherList_Combo)
에 검색된 네트워크 카드의 Description을 추가하는 소스의 일부이다.

또한 시리얼 키의 중요한 데이타인 맥 주소들을 기억하기 위해 ComboBox의 SetItemDataPtr() 메서드를 이용 다른 코드에서 맥 주소 참조가 가능하도록 해 주었다.

결론적으로 이 코드는 심각한 버그를 가지고 있다.

[CODE]
     CoInitialize(NULL);
     try
     {  
          WbemScripting::ISWbemLocatorPtr locator;
          locator.CreateInstance(WbemScripting::CLSID_SWbemLocator);
          if (locator != NULL)
          {
             WbemScripting::ISWbemServicesPtr services =
                   locator->ConnectServer(".","root\\cimv2","","","","",0,NULL);
             WbemScripting::ISWbemObjectSetPtr objects =
                services->ExecQuery("Select * from Win32_NetworkAdapter
                   where AdapterTypeID = 0
                   and Description != 'Packet Scheduler Miniport'
                   and Description != '패킷 스케줄러 미니 포트'","WQL",0x10,NULL);
             IEnumVARIANTPtr obj_enum = objects->Get_NewEnum();
             ULONG fetched;
             VARIANT var;
             int count = 0;
             while (obj_enum->Next(1,&var,&fetched) == S_OK)
             {
                  WbemScripting::ISWbemObjectPtr object = var;
                  WbemScripting::ISWbemPropertySetPtr properties =
                           object->Properties_;
                  WbemScripting::ISWbemPropertyPtr prop =
                           properties->Item("Description",0);
                  m_ctrlEtherList_Combo.AddString(
                                    (const char*)_bstr_t(prop->GetValue()));
                  prop = properties->Item("MACAddress",0);
                  CString *pMacAddress = new CString(
                                    (const char*)_bstr_t(prop->GetValue()));
                  m_ctrlEtherList_Combo.SetItemDataPtr(count,pMacAddress);
                  count++;
             }
          }
     }
     catch (_com_error err)
     {
          CString msg = _T("WMI Query Error ocured: ");
          msg += err.ErrorMessage();
          AfxMessageBox(msg);
          CoUninitialize();
          return FALSE;
     }
     CoUninitialize();

     if(m_ctrlEtherList_Combo.GetCount() > 0)
     {
          m_ctrlEtherList_Combo.SetCurSel(0);
          m_strMacAddress = *((CString*)m_ctrlEtherList_Combo.GetItemDataPtr(0));
          m_strSerialKey = GetSerialKey(m_strMacAddress);
          UpdateData(FALSE);
     }
[/CODE]

Line 49  :  m_strMacAddress = *((CString*)m_ctrlEtherList_Combo.GetItemDataPtr(0));

에서 런타임 시 Assertion 에러가 발생한다.

개발에 쓰인 내 컴에서는 천만 다행(--;)으로 에러 없이 통과 했던 코드가 쭌 시스템에서 바로 폭발하였다.
도대체 무엇 때문일까? 코드의 어느 부분이 잘못된 것일까?

바로 원인은 Line 31 : m_ctrlEtherList_Combo.SetItemDataPtr(count,pMacAddress); 에 있었다.

다음의 시나리오를 가정해 보자.

  * 시스템에 3개의 네트워크 인터페이스가 있다.

  * WMI로 검색하면 다음의 순으로 인터페이스를 리턴한다.
     0. Realteck Fast Ethernet
     1. Intel Wireless Fast Ehternet
     2. 3Com Fast Ethernet

  * ComboBox 에 들어가면서 정렬된다면 다음의 순이 될 것이다.
     0. 3Com Fast Ethernet
     1. Intel Wireless Fast Ehternet
     2. Realteck Fast Ethernet

만약  Line 31을 다음과 같이 수정하여 디버깅 한다면 3번 모두 0을 리턴할 것이다.
   
Line 31 : int iIndex = m_ctrlEtherList_Combo.SetItemDataPtr(count,pMacAddress);

따라서 Line 49에서 에러가 발생한 이유가 설명된다.

새로 추가한 아이템은 계속 0번째에 추가되며, 다른 아이템들을 밀어 내는데 count를 1나씩 증가하면서 맥 주소를 설정해 줌으로서 결과적으로 맥 주소는 2번째 Item에만 설정되고, 0번째, 1번째 item에는 설정되지 않게 된것이다.

이때 Line 49에서 0번째 Item의 맥 주소를 받을려고 하는데, 쓰레기 값이나 NULL 값이 리턴됨으로서 잘못된 메모리 주소가 되어 에러가 발생한 것이다.

그렇다면 sort 속성과 상관 없이 코드가 옳바르게 동작할려면 어떻게 고쳐야 할까?

[CODE]
   int iIndex = m_ctrlEtherList_Combo.AddString(
                         (const char*)_bstr_t(prop->GetValue()));
   prop = properties->Item("MACAddress",0);
   CString *pMacAddress = new CString(
                         (const char*)_bstr_t(prop->GetValue()));
   m_ctrlEtherList_Combo.SetItemDataPtr(iIndex,pMacAddress);
[/CODE]

첫 코드 처럼 count로 속단하고 index를 순차적으로 늘리는 것은 잘못된 방법이다.

AddString 함수는 Item 추가후 해당 item이 최종적으로 위치하게 된 Index를 리턴해 준다.
sort 속성이 false 라면 0 부터 순차적으로 늘어날 것이며, true라면 정렬이 이루어진 후의 0부터 몇 번째에 위치하는지의 값을 리턴해 줄 것이다.

따라서 Line 1 : int iIndex = m_ctrlEtherList_Combo.AddString(
                                           (const char*)_bstr_t(prop->GetValue()));

AddString() 메서드의 리턴 값을 받아 옳바른 Index 값을 얻은 후 Line 6 처럼 해당 Index 값을 사용하여 연관된 다른 동작을 하는 것이 문제가 발생할 소지를 없앨 수 있다.

Line 6 : m_ctrlEtherList_Combo.SetItemDataPtr(iIndex,pMacAddress);


MFC의 ComboBox 나 ListBox 사용시 AddString() 다음에 index값을 가지고 다른 기능을 하고자 할때는 반드시 AddString의 리턴 값을 index로 사용하자.

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기
Tag :
Track this back : http://www.codeforum.net/blog/pitoosung/trackback/95
Commented by rou at 2008/02/15 02:08  r x
oups here it s better...
Thanks from France :D:D:D
Replied by 피투성 at 2008/02/15 23:10 x
i wish you good luck

name    password    homepage
 hidden


BLOG main image
피투성의 IT 분투기
 Notice
(2009.11.30) - ㅠ.ㅠ 안녕! 서버 H/W 시스템 교체(서버보드 사망, HP Workstation으로 교체)
(2008.2.2) IP : 195.225.178.29 - 스팸 차단 조치
(2008.1.14) 오후 06:34 ~ 08:07 : 시스템 복구
(2008.1.14) 오전 00:25(?) : 시스템 다운 - 흠 심각하군!
(2008.1.13) 오후 11:31 : 시스템 리부팅됨
(2008.1.13) 시스템 복구 : 오전(?)~오후 1:00
 Category
전체 (148)
프로그래밍 (42)
IT 세상속으로 (42)
세상 엿보기 (26)
지하창고 (18)
책의 향기 (12)
생각의 힘(바둑) (4)
OCR-내가 다 읽어줄께 (1)
두발의 짐승 (2)
지능형 로봇 (1)
 Calendar
«   2010/09   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
 Recent Entries
투명 Display 그리고 Augm... (2)
64bits(x64) Windows OS...
NFS & Eclipse & CDT & In...
행복에 대해 생각하며
Virtual Audio Cable (가...
 Recent Comments
^^ 안녕! 축하축하. 난 아...
피투성 - 03/16
오랜만에들림니다 아이폰...
쭌 - 03/15
Thanks for your kind tra...
hyungju - 2009
정보 감사합니다 덕분에...
허수 - 2009
관리자만 볼 수 있는 댓글...
- 2009
 Recent Trackbacks
내가 생각하는 한의학의...
Life Is Always Emergency
FreeBSD 6.2, 64bit, 메모...
엘레노아의 작업로그
알약 백신 제대로 사용하...
촌철살인
유용한 블로그 툴 몇개..
ENTClic@blog...just anot...
국내의 검색엔진에 등록하...
케이알선의 이야기
 Archive
2010/01
2009/12
2009/07
2008/09
2008/03
 Link Site
00_피투성의 지식창고_00
 Visitor Statistics
Total : 70560
Today : 54
Yesterday : 46
텍스트큐브 배너
Eolin
rss