MFC File Icon Drag and Drop

Programming/MFC 2016. 8. 30. 11:19 Posted by TanSanC
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

MFC File Icon Drag and Drop










드래그앤드랍기능을 쓰고 싶은


Dialog 나 ListControl 을 리소스 뷰에서 선택한다.











속성 항목


[동작] [Accept Files] 항목을 True 로 바꾼다.



Files 을 드래그앤드랍으로 받을 수 있게 된다.












해당 컴포넌트에 드래그앤드랍이 발생할 경우


OnDropFiles(HDROP hDropInfo)


함수로 메시지가 들어오게 된다.











해당 함수를 오버라이딩 하는 방법은


해당 컴포넌트의 Dialog 클래스를


클래스 뷰에서 선택하고 속성 창을 연다.






WM_DROPFILES 메시지에 OnDropFiles 를 활성화 시켜준다.







그러면 Dialog 클래스 cpp 파일에 OnDropFiles 함수가 생성된다.






다음 코드를 OnDropFiles(HDROP hDropInfo) 함수에 추가하여 실행하여 본다.





  int nFiles;


char szPathName[MAX_PATH];  // 파일 경로명이 들어간다.


CString strFileName;


// 드래그앤드롭된 파일의 갯수

nFiles = ::DragQueryFile(hDropInfo, 0xFFFFFFFF, szPathName, MAX_PATH);


for (int i = 0; i < nFiles; i++)

{

// 파일의 경로 얻어옴

::DragQueryFile(hDropInfo, i, szPathName, MAX_PATH);

MessageBox(szPathName, "DropAndDropFile");

}










CDateTimeCtrl 사용법

Programming/C,CPP,CS 2016. 8. 25. 17:56 Posted by TanSanC
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

CDateTimeCtrl 사용법



이름

설명

CDateTimeCtrl::CloseMonthCal

현재 날짜 및 시간 선택 컨트롤을 닫습니다.

CDateTimeCtrl::Create

날짜 및 시간 선택 컨트롤을 만들고이에 연결 된 CDateTimeCtrl 개체입니다.

CDateTimeCtrl::GetDateTimePickerInfo

현재 날짜 및 시간 선택 컨트롤에 대 한 정보를 검색합니다.

CDateTimeCtrl::GetIdealSize

현재 날짜나 시간을 표시 하는 데 필요한 시간 및 날짜 선택 컨트롤의 이상적인 크기를 반환 합니다.

CDateTimeCtrl::GetMonthCalColor

월 달력에서 날짜 및 시간 선택 컨트롤의 특정된 부분에 대 한 색을 검색합니다.

CDateTimeCtrl::GetMonthCalCtrl

검색은 CMonthCalCtrl 개체의 날짜 및 시간 선택 컨트롤에 연결 합니다.

CDateTimeCtrl::GetMonthCalFont

현재 날짜 및 시간 선택 컨트롤의 자식 컨트롤에서 사용 되는 글꼴을 검색 합니다.

CDateTimeCtrl::GetMonthCalStyle

현재 날짜 및 시간 선택 컨트롤의 스타일을 가져옵니다.

CDateTimeCtrl::GetRange

현재 최소 및 최대 허용 시스템 시간 날짜 및 시간 선택 컨트롤을 검색 합니다.

CDateTimeCtrl::GetTime

날짜 및 시간 선택 컨트롤에서 현재 선택한 시간을 검색 하 고 지정 된 배치 SYSTEMTIME 구조.

CDateTimeCtrl::SetFormat

지정 된 형식 문자열에 따라 날짜 및 시간 선택 컨트롤의 표시를 설정합니다.

CDateTimeCtrl::SetMonthCalColor

월 달력에서 날짜 및 시간 선택 컨트롤의 특정된 부분에 대 한 색을 설정합니다.

CDateTimeCtrl::SetMonthCalFont

날짜 및 시간 선택 컨트롤의 자식 컨트롤을 사용 하는 글꼴을 설정 합니다.

CDateTimeCtrl::SetMonthCalStyle

현재 날짜 및 시간 선택 컨트롤의 스타일을 설정합니다.

CDateTimeCtrl::SetRange

날짜 및 시간 선택 컨트롤에 대 한 최소 및 최대 허용 된 시스템 시간을 설정합니다.

CDateTimeCtrl::SetTime

날짜 및 시간 선택 컨트롤에는 시간을 설정합니다.




// set with a CTime
CTime timeTime(1998, 4, 3, 0, 0, 0);
VERIFY(m_DateTimeCtrl.SetTime(&timeTime));

// set with a COleDateTime object
COleDateTime oletimeTime(1998, 4, 3, 0, 0, 0);
VERIFY(m_DateTimeCtrl.SetTime(oletimeTime));

// set using the SYSTEMTIME
SYSTEMTIME sysTime;
memset(&sysTime, 0, sizeof(sysTime));
sysTime.wYear = 1998;
sysTime.wMonth = 4;
sysTime.wDay = 3;
VERIFY(m_DateTimeCtrl.SetTime(&sysTime));
void CDateTimeDlg::OnBnClickedTimebutton()
{
   // get as a CTime
   CTime timeTime;
   DWORD dwResult = m_DateTimeCtrl.GetTime(timeTime);
   if (dwResult == GDT_VALID)
   {
      // the user checked the box and specified data
      CString str;

      // is it a time-only control, or a date-only control?
      if ((m_DateTimeCtrl.GetStyle() & DTS_TIMEFORMAT) == DTS_TIMEFORMAT)
         str = timeTime.Format(_T("%X"));
      else
         str = timeTime.Format(_T("%x"));
      AfxMessageBox(str);
   }
   else
   {
      // the user unmarked the "none" box
      AfxMessageBox(_T("Time not set!"));
   }

   // Calling as SYSTIME is much the same, but calling for a COleDateTime
   // has us test the state of the COleDateTime object for validity to 
   // see if the user did or didn't check the "none" box.
}











336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

MFC Dialog 가 이상한 위치에 배치, (0,0)에 배치



MFC TabCtrl 기반의 Dialog 를 Child로 배치 하였을때






Tab 별 Child Dialog 가 (0,0) 위치에 배치되어


TabCtrl 이 보이지 않는 경우가 발생하는 경우,













Child Dialog 가 OnInitDialog 실행 중 예외처리나 비정상 처리로 인해


제대로 된 값을 반환하지 못하는 경우


그런 상태가 발생 할 수 있다.





예외처리 시 return 으로


OnInitDialog 를 정상적으로 종료시킨 후 


동작시켜야 한다.










Apache License, Version 2.0

Programming/C,CPP,CS 2016. 8. 22. 11:24 Posted by TanSanC
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Apache License, Version 2.0




http://www.apache.org/licenses/LICENSE-2.0




아파치 라이센스와 같은 라이센스 관련 번역 사이트


https://www.olis.or.kr/ossw/license/license/detail.do?lid=1002&mapcode=010001¤tPage=





 Apache License


Version 2.0, January 2004

http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.

"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:

  1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
  2. You must cause any modified files to carry prominent notices stating that You changed the files; and
  3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
  4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 

    You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS


Log4cxx ChainSaw Appender

Programming/C,CPP,CS 2016. 8. 22. 11:01 Posted by TanSanC
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Log4cxx ChainSaw Appender






Log4cxx 에 발생하는 Log 를 ChainSaw 서버로 보내면 쉽게 Log를 관리 할 수 있다.


https://logging.apache.org/chainsaw/





Apache Chainsaw configured for two XML socket receivers






Windows 의 경우 


Unix/Dos Standalone 버전을 받아서



chainsaw.bat 파일을 실행시키면



ChainSaw 화면이 뜬다.









336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

log4cxx MFC Client 와 log4j Java Server 연결



MFC Client 는 로그를 파일과 서버로 보내고,


Java Server 는 여러개의 MFC Client 가 보내는 로그를 저장한다.




테스트 환경은


MFC Client 와 Java Server 가 동일 호스트 이다.




MFC Client


log4j.rootLogger=DEBUG, filelog, remoteserver


rootLogger 에 필요한 로그 Appender 를 추가한다.


remoteserver라는 Appender 를 설정한다.


SocketAppender 를 사용하고, localhost:4445 에 연결한다.


# using remoteserver appender

log4j.appender.remoteserver=org.apache.log4j.net.SocketAppender

log4j.appender.remoteserver.remoteHost=localhost

log4j.appender.remoteserver.port=4445

log4j.appender.remoteserver.locationInfo=true

log4j.appender.remoteserver.ReconnectionDelay=10000






Java Server



테스트에서는 


log4j-1.2.17 버전을 사용하였다.


log4j-1.2.17.zip



압축을 푼 후 jar 파일을 Library 로 add 한다.





서버의 설정은 log4j-server.properties


RollingFileAppender 를 사용하여


파일 단위로 Log 를 저장한다.




log4j.rootLogger=DEBUG, file

log4j.appender.file=org.apache.log4j.RollingFileAppender

log4j.appender.file.File=logfile.log

log4j.appender.file.MaxFileSize=1MB

log4j.appender.file.MaxBackupIndex=1

log4j.appender.file.layout=org.apache.log4j.PatternLayout

log4j.appender.file.layout.ConversionPattern=[%d] [%t] [%m]%n





Java Server Code



public class Test

{

public static void main(String[] args) {

        try  

        {  

       

        String[] arguments = {"4445", "log4j-server.properties"};  

        SimpleSocketServer.main(arguments);  


        }  

        catch (Exception ex)  

        {  

          System.out.println(ex.getMessage());

        }  

}

}





336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

fatal error LNK1169: 여러 번 정의된 기호가 있습니다.


아주 간단한 실수를 하였을때도 발생하는데....



그 중의 하나는 같은 이름의 함수를 여러 번 정의할 경우 발생한다.







Test용 main cpp 파일을 include 했는데, 까먹고


새로운 main 함수를 만들어서 발생함..






중복되는 main 함수를 정리해주면 됨.

MFC CTextProgressCtrl

Programming/MFC 2016. 8. 17. 15:50 Posted by TanSanC
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

MFC CTextProgressCtrl




코드만 가져다가 ProgressCtrl 을 TextProgressCtrl 로 변환 시켜서 사용할 수 있다.






MemDC 가 필요한데 VS2010 이상 버전에서는


CGridCtrl 을 참고하여 추가 설정이 필요하다.

(시스템에 존재하는 MemDC 클래스와 중복되기 때문)












http://www.codeproject.com/Articles/80/Progress-Control-with-Text


Progress Control with Text

























This is a simple CProgressCtrl derived class that allows text to be displayed on top of the progress bar in much the same way as many "Setup" programs display the progress of long operations.

The control is extremely simple and allows the same operations as a standard CProgressCtrl, as well as: 

void SetShowText(BOOL bShow);Specifies whether or not the text for the control will be displayed during updates
COLORREF SetBarColor(COLORREF crBarClr = CLR_DEFAULT);Specifies the colour of the progress control bar, and returns the previous colour. If the colour is set asCLR_DEFAULT then the Windows default colour is used.
COLORREF GetBarColor();Returns the colour of the progress control bar, orCLR_DEFAULT if the default Windows colours are being used.
COLORREF SetBarBkColor(COLORREF crBarClr = CLR_DEFAULT);Specifies the colour for the control's background, and returns the previous background colour. If the colour is set as CLR_DEFAULT then the Windows default colour is used.
COLORREF GetBarBkColor();Returns the colour of the control's background, orCLR_DEFAULT if the default Windows colours are being used.
COLORREF SetTextColor(COLORREF crBarClr = CLR_DEFAULT);Specifies the colour of the text, and returns the previous colour. If the colour is set as CLR_DEFAULT then the Windows default colour is used.
COLORREF GetTextColor();Returns the colour of the text, or CLR_DEFAULT if the default Windows colours are being used.
COLORREF SetTextBkColor(COLORREF crBarClr = CLR_DEFAULT);Specifies the background colour of the text, and returns the previous background colour. If the colour is set asCLR_DEFAULT then the Windows default colour is used.
COLORREF GetTextBkColor();Returns the background colour of the text, orCLR_DEFAULT if the default Windows colours are being used.
BOOL SetShowPercent(BOOL bShow)Sets whether or not to show the percentage value of the bar, and returns the old value
DWORD AlignText(DWORD dwAlignment = DT_CENTER)Sets the text alignment and returns the old value
BOOL SetMarquee(BOOL bOn, UINT uMsecBetweenUpdate)Sets whether or not the progress control is in marquee mode, as well as the interval in milliseconds between steps of the marquee block
int SetMarqueeOptions(int nBarSize)Sets the size of the marquee as a percentage of the total control width

To set the text to be displayed use the standard CWnd::SetWindowText. If you call SetShowText(TRUE) but do not specify any window text using CWnd::SetWindowText, then the percentage fraction of progress will be displayed as default.

To use the control, just include a CProgressCtrl in your app as per usual (either dynamically or by using a dialog template) and change the variable type from CProgressCtrl to CTextProgressCtrl. (Make sure you include TextProgressCtrl.h)

At present the progress is only displayed as a smooth bar, and colours are strictly windows default colours. (These may be changed in the future versions.)

Acknowledgements
Thanks to Keith Rule for his CMemDC class.

Updates

Pete Arends went to town on the code. His updates:

  1. Set the font used to the parent window font
  2. Added SetTextColour() and GetTextColour() functions
  3. Added a bunch of message handlers, so the control now responds to the standard progress bar PBM_*messages. It is now possible to control the text progress control by sending messages to it. (works great from a worker thread).
  4. Added 2 new messages PBM_SETSHOWTEXT and PBM_SETTEXTCOLOR.
  5. Added an OnGetPos() handler. The function GetPos() now works!!

Thanks Pete!

3 Jan 05: Kriz has also extended the code with two basic methods that allow switching between the three alignment styles LEFTCENTER and RIGHT - even on the fly if that's needed.

Changes to the code

  • Created a protected DWORD member m_dwTextStyle
  • Disabled all dwTextStyle variables in OnPaint or replaced them by
    m_dwTextStyle
  • Added two methods called AlignText and AlignTextInvalidate

Syntax

BOOL AlignText(DWORD aligment = DT_CENTER);
BOOL AlignTextInvalidate(DWORD aligment = DT_CENTER);

Params/Return:

"alignment" can be DT_LEFTDT_CENTER (default) or DT_RIGHT. Using the invalidating version forces the control to repaint itself automatically. Both methods will return FALSE if a wrong alignment flag was given, otherwise they will return TRUE to the caller.

Thank you Kriz!

I've also updated the code so it compiles in VC7.X.

9 mar 06: Tony Bommarito has updated the code to include more settings for colours, made corrections to vertical text mode and added a new marquee mode.

26 Feb 07: Tony Mommarito has provided further updates:

  • Fixed bug where outside edge of progress bar wasn't drawn on XP when using an application manifest.
  • Added complete turn-off of marquee mode in a slightly different manner than that suggested in Robert Pickford message.
  • Fixed Unicode compile bug reported in dev75040 message.
  • Added three SLN and VCPROJ file sets; one each for VS2002, VS2003 and VS2005. By removing the VS… extension from the proper set, any of the three IDEs can be used.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)







CRuntieClass Reflection

Programming/C,CPP,CS 2016. 8. 17. 14:25 Posted by TanSanC
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

최근에 Open Platform으로 갖춰야 할것 중 하나가 개발 툴인데, 
IDE같은 개발 툴들은 대부분 Import, Plug-in, User Defined Control(ActiveX control) 등과 같이, System이 개발 된 당시에는 존제하지 않았던 class 나 객체들을 자연스럽게 설치, 추가하여 사용할 수 있도록 해주는 부분들이 매우 많은 범위에 존제합니다..
이때 framework  구현부는 실제 class의 실체를 모른 상태에서 runtime시에 binding 되는 class의 객체를 생성해야 할 때가 있다.

class의 인스턴스 생성방법은 다들 알다시피 new를 통해 생성합니다.

BaseClass * pInstance = new SubClass; 

바꾸어 말하면 우리는 반드시 SubClass를 알고 있어야 한다는 것입니다. 그래야만 instance를 생성 할 수 있습니다.

아래와 같이 CameraPlugIn class를 framework에서 모르는 상태라고 한다면 절대 instance를 만들 수 없다는 예기죠.


IPlugIn * pPlugIn = new CameraPlugIn; 



만약 우리가  CameraPlugIn를 모르는 상태 즉,  PlugIn Framework 개발당시에는 CameraPlugIn이라는 class를 모르는 상태에서  camera.dll또는 lib을 download받아서, 이를 link 또는 load 해서 사용할 수 있는 기능을 제공하려 할때,
class를 모르는 상태에서 class 를 runtime시에 동적으로 search 하고 instance를 생성할 수 있도록 하는 기술이 필요하게됩니다.

이러한 기술을 리플렉션( Reflection) 이라한다.

C# 에서도 이와같은 리플렉션은 지원하고 있고, Runtime중에 type binding을 지원하는 Dyanimc 이라는 새로운 타입이 추가될 예정이라고 합니다.

그외  루비, 스몰토크, PHP, 파이썬, 펄 등의 언어에서는 리플렉션 객체를 제공하며, 대부분 유사한 형태를 띄고 있습니다.


아쉽게도 C++ 에서는 공식적으로 지원하지 않는 기능이지만, 전세계의 수많은 똑똑한 개발자 분들이 이런 기능을 다양한 방법으로 제공하고 있습니다.

아마 MFC의 CRuntimeClass는 리플랙션과 비슷한 기능을 위해 만들어진 가벼운 Macro 정도이고 실제 훨씬 편리하고 플랙서블한 그런 library들도 많이 있으니 관심이 있다면 구글링으로 찾아보셔도 좋을 것입니다.


그중 하나의 기술 (?, 그렇죠 말그대로 Programming 테크닉이라 불리울 만한 기술이죠. )MFC에서 Runtime class 라는 것이 있습니다.


저도 나름 이와 비슷한 아이디어를 떠올리면서 구현을 했었는데 , 거의 구현이 완료되고 나서 생각해보니 MFC에 이런게 있었다는 것이 생각이나, Source code를 뒤져봤답니다.

역시나 이미 상용화되어서 아주 ~~ 아주 잘 쓰고 있는 메크로들이라 그런지, 제가 생각했던 개념과 유사한 뼈대위에 많은 살들이 붙어있더군요.
(!! 메크로에 Templete 까지 넣어서 만들었을 줄이야 ㅠ_ㅠ)

회사에서 사용하기 위해 작성한 코드가 좋은 예가 될수 있을텐데, 회사의 자산이라 공개를 할 수 없어서  MFC의 Runtime class의 내용을 살펴보는 것으로 대신 하겠습니다.

저는 사실 한 일주일 쯤 해서  이런 고민에 빠져 있었습니다.

만약 내가 개발 툴을 만들어주고, application 개발자는 자기가 짠 class를 이 개발툴에 plug-in 한 후에 ,
개발 툴에서 재공하는 Generator 를 이용해  Generator("TestClass") 라고 하면 testclass의 instance를 만들어준다고 합시다.
이때 개발툴을 개발할 당시에는 TestClass를 모르고 있기 때문에 일반적인 개발 방법으론, 이를 구현할 수가 없습니다.
즉, Runtime 중에 class를 register하고 이를 parsing하여 instance를 생성 시킬 수 있는 기술이 필요하다.!!

class라는 게 어찌 보면 type인데, 내가 type을 모른 상태에서 object를 생성할 수 있을까?
예를 들면 
Object* pA = CreateInstance("TestClass");
라고하면 pA는 class TestClass 로 생성이되는 이런걸 만들고 싶었습니다.
하지만 흔히 이렇게 사용할 수 있으려면, 기본적으로 TestClass를 CreateInstance 내에서 알고 있어야 합니다. 
그래야 "TestClass" 라는 스트링을 parsing한 다음에 TestClass로 생성을 해줄 수가 있기 때문입니다.
그래서 대부분 이런 코딩을 하겠죠?


Object* CreateInstance(char* pClassName)
{
       :
        if(strcmp(pClassName,"TestClass")==0)
                return (Object*)new TestClass;
}

CreateInstance를 제너럴하게 만들고 싶어서 pClassName 으로 들어오는 class이름이 무엇이든간에 이에 맞는 class를 찾아서 있으면 해당 class의 instance를 생성해주고, 없으면 null 을 return하기를 원한다면? 어떻게 만들까? 음... class들을 관리하는 table과 class name,그리고 class generator을 만들어서 구현 할 수 있을것 입니다.

Object* CreateInstance(char* pClassName)
{
       :
       for(;;)
        if(strcmp(pClassName,gClassTable[i].szName)==0)
                return (Object*) gClassTable[i].Construct();
}

그런데, CreateInstance라는 함수를 만들때는 "TestClass라는 것이 없는데 , 앞으로 누군가가 만들것이다." 라고 한다면? 흠 흠.. 이경우는 난감한가요? 분명 이렇게 되어야 합니다. gClassTable 에 RegisterClass라는 API를 만들어서 이름과 생성자를 등록하여 사용할 수 있도록 해야합니다.

void RegisterClass(char* classname, Object *(*fpConstruct)())
{
      :
    gClassTable[i].szName = classname;
    gClassTable[i].Construct= fpConstruct;
}

가 있어야 되겠죠. 헌데 이렇게 되면 상당히 귀찮아지는 것이 fpConstruct를 만드는 일이 됩니다. 이럴때 나온 개념이 runtimeclass라는 넘이 됩니다. MFC의 CRuntimeClass를 살펴보면, 클레스 전체를 살펴보면 좋겠지만.. 대충 필요한 것들.. 핵심이 될만한 것들만 언급하자면,

struct CRuntimeClass
{
// Attributes
1) LPCSTR m_lpszClassName;
2) CRuntimeClass* m_pBaseClass;
3) CObject* CreateObject();
4) static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
5) CRuntimeClass* m_pNextClass;       // linked list of registered classes
}

아마 가장 핵심이 되는 것이 위의 1)~4) 까지의 내용일 겁니다. 왜냐? 다음 RuntimeClass를 만드는 메크로들을 보면 알 수 있습니다.

#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
#define DECLARE_DYNAMIC(class_name) \
public: \
 static const CRuntimeClass class##class_name; \
 virtual CRuntimeClass* GetRuntimeClass() const; \

#define _DECLARE_DYNAMIC(class_name) \
public: \
 static CRuntimeClass class##class_name; \
 virtual CRuntimeClass* GetRuntimeClass() const; \

#define IMPLEMENT_RUNTIMECLASS(class_name) \
 const CRuntimeClass class_name::class##class_name = { \
  #class_name, sizeof(class class_name), \
   }; \  
 CRuntimeClass* class_name::GetRuntimeClass() const \
  { return RUNTIME_CLASS(class_name); } \

이런 메크로들이 있습니다. 약간 길죠?. IMPLEMENT_RUNTIMECLASS 는 설명하기 귀찮은 것들은 다 뺐습니다. 이렇게 메크로만 보면 "뭐하자는 거지?" 라고 의문이 드는 것들이 실제 사용하는 예를 보면 "아하!!" 라고 하게 됩니다.

in MyTestControl.hpp--------------- 
class MyTestControl
{
   _DECLARE_DYNAMIC(MyTestControl)   //<-- static const Runtimeclass  classMyTestControl 가
                                                            // MyTestControl class안에 정의된다.

   :
   :

};
in MyTestControl.cpp--------------- 
파일 맨 위에
IMPLEMENT_RUNTIMECLASS(class_name) // static 객체인 MyTestControl::classMyTestControl 를 초기화 한다.

in MyTestApp.cpp

void main(void)
{
   AfxInitClass(RUNTIME_CLASS(MyTestControl));
   
   CRuntimeClass::CreateObject("MyTestControl");
  
}

대충의 설명을 하자면 ,
1. Runtime class로 선언하고자 하는 class 내부에 DECLARE_DYNAMIC(classname) 을 해주고나면, static runtime class 하나가 생기는데 "class"+classname 의 형태로 된다.
2. 이 "classMyTestControl"라고 새로 만들어진 static runtimeclass 는 멤버함수인 3).의 CreateObject() 를 MyTestControl를 생성할 수 있는 함수로 만든다.
3. 그 형식은 아래와 같다.

CreateObject() 
{
  return new MyTestControl;
}

따라서 우리는 메크로에 의해 생성된 classMyTestControl 이라는 runtime class를 이용해서 MyTestControl이라는 class의 instance를 생성할 수 있게 됩니다.


 마지막으로 한가지 설명 안하고 넘어간 것이 있는데.

5) CRuntimeClass* m_pNextClass;       // linked list of registered classes

이 녀석에 대한 내용이다. 이게 왜 있는가? 제가 개발할때, 위와 같은 구현을 완료하고 나서 Register 단계( MFC에서는 AfxInitClass 단계일듯하다.)에서 결국 table을 만들고, table과 Runtime class를 묶는 작업을 하고, search하는 함수를 만들고... 등등을 작업했었다.

CSystemClassFactroy
{
 list runtimeClass;
 RegisterClass(CRuntimeCalss);
};

application에서 사용할때는 아래와 같이 register를 해야 되는 상황이 있었습니다.

main()
{
   // application 초기화
   Factroy.RegisterClass(MyTestControl);
    :
    :

}

이때 문득 MFC에서는 어떻게 하지? 라는 생각이 들어 이 RuntimeClass를 살펴본바... m_pNextClass 를 이용해서 각 register시에 RuntimeClass들을 줄줄이 사탕으로 엮어놓은 것이라 추측 할수 있었다.!!! 아하.!! 요렇게 하면 runtime class를 managing 하는 manager class가 필요 없겠구나.!! 하는 필(feel)을 받고, 제 코드도 요렇게 바꿨답니다. ㅎㅎ 



찾아보기 키워드!!! 

[SEAL Reflex] 
[LibReflection] 

[XCppRefl 라이브러리]

 
<참고 링크>
[MSDN : C++ 리플렉션 in Visual C++ ]http://msdn.microsoft.com/ko-kr/library/y0114hz2(VS.90).aspx


336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

MFC Grid control 2.27 ReadOnly, CheckBox Button





// Make cell row,col read-only

m_Grid.SetItemState(row, col, m_Grid.GetItemState(row, col) | GVIS_READONLY);





// Make cell row,col CheckBox Button

m_Grid.SetCellType(row, col, RUNTIME_CLASS(CGridCellCheck));











http://www.codeproject.com/Articles/8/MFC-Grid-control-2-27