MFC 기반의 Excel Automation(자동화) 예제

엑셀 오토메이션 (자동화)

개인적으로 사용해 본  소프트웨어 중 가장 잘 만들었다고 생각되는것을 하나만 꼽으라면 단연 엑셀 입니다.

문서의 작성이나, 자료 처리, 통계, 수식 계산 등 다양한 분야에 활용되고 있으며, 오피스 제품군 중 독보적 존재감이라 생각합니다.

이번 시간에는 C++ 과 MFC를 이용해 엑셀파일을 제어하는 방법에 대해 살펴보겠습니다.

파이썬에서는 openpyxl 등 모듈을 통해 쉽게 핸들링 가능하지만, C++은 코드로 구현하기가 보다 원초적이며, 어렵습니다.

약 15년 쯤 전에 C++, MFC를 이용해 탈질설비의 주요 요소(Factors, 약 30가지)를 입력받아 엑셀로 설계 출력값 (장비 치수, 허용치, 소요 자재량 등)을 일괄 계산해 주는 소프트웨어를 만든 기억이 납니다.

바로 살펴보도록 하겠습니다.

아래 코드는 Windows 10, Visual Studio 2017, Office 2016 환경에서 제작되었습니다.


프로젝트 생성

1. VS 실행, 프로젝트 생성, 대화상자 프로젝트 생성



2. 고급기능 탭, 자동화 체크, 마침



3. 프로젝트 생성 후 솔루션 탐색기, 프로젝트 우클릭, 추가, 새항목



4. MFC 탭, TypeLib MFC 클래스 선택



5. TypeLib 추가, 파일 선택, 위치 열기(아이콘)


예전에 작업할때는 레지스트리에 등록된 'Microsoft Excel xx.0 Object Library' 가 보였는데, 오피스 버전(2016) 때문인지 VS 2017 때문인지 이젠 보이지 않습니다.

파일로 설정하고 오피스가 설치된 경로로 가서 직접 Excel.exe를 선택해 필요한 클래스 인터페이스를 추가해 보겠습니다.

6. Excel 설치 경로로 이동, Excel.exe 선택



7. 인터페이스 선택 창에서 필요한 것 선택



예제에 사용된 인터페이스 목록
  • _Application
  • _Workbook
  • _Worksheet
  • Border, Borders
  • Font
  • Range
  • Style, Styles
  • Workbooks, Worksheets
8. 해당 인터페이스 클래스 생성 및 헤더(*.h) 추가 확인



9. 빌드 후 다수 에러 발생



10. 추가한 모든 excel 관련 .h 파일의 #import 구문 주석처리

각 엑셀관련 추가 헤더파일을 모두 열어 3번라인에 주석 처리합니다. 이미 엑셀 TypeLib를 추가하며 import 되어있습니다.



11. 빌드 후 CRange.h 에서 에러 발생



12. 해당 함수 앞 _붙임 or 해당 함수 전체 주석


음. 에러 원인은 잘 모르겠습니다.

이제 Excel TypeLib 코드 추가 완료되었으며, 빌드 오류가 없어야 합니다.

이제 C++, MFC 기반 Excel 개발 환경이 준비된 상태 입니다.

소스코드 작성

1. 대화상자 프로젝트생성, 리소스를 아래와 같이 추가.(버튼 4개)


차후 해당 버튼 이벤트를 감지해 엑셀관련 코드를 실행할 용도입니다.

2. Dlg.h 파일에 아래 멤버 함수 추가
class CexcelDlg : public CDialogEx
{
    생략....

protected:
    void OnClickedButton(unsigned int id);
    void ExcelTest1();
    void ExcelTest2();
    void ExcelTest3();
    void ExcelTest4();
};

OnClickedButton() 함수는 앞서 만든 버튼과 연결할 이벤트 처리 함수입니다.

ExcelTest1~4() 함수는 버튼이 눌러지면 호출되는 함수이며, 자세한 쓰임은 뒤에 설명드리겠습니다.

3. Dlg.cpp 파일에 Excel header 파일 추가
// excel headers
#include "CApplication.h"
#include "CCellFormat.h"
#include "CRange.h"
#include "CStyle.h"
#include "CStyles.h"
#include "CWorkbook.h"
#include "CWorkbooks.h"
#include "CWorksheet.h"
#include "CWorksheets.h"
#include "CFont0.h"
#include "CBorder.h"
#include "CBorders.h"
 
4. Dlg.cpp 파일 BEGIN_MESSAGE_MAP() 처리
BEGIN_MESSAGE_MAP(CexcelDlg, CDialogEx)
 ON_WM_CLOSE()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC_BUTTON4, &CexcelDlg::OnClickedButton)
END_MESSAGE_MAP()

5번 라인의 ON_CONTROL_RANGE() 에 처리할 통보 메시지 코드와 시작컨트롤 아이디, 끝 컨트롤 아이디, 호출될 함수를 입력합니다.

4개의 버튼 마다 이벤트처리함수를 따라 추가하면 번거로우므로, 한꺼번에 처리하고 OnClickedButton(unsigned int id) 함수의 전달인자인 id 로 버튼 컨트롤 아이디를 받아 처리합니다.

5. Dlg.cpp 파일에 OnClickedButton() 함수 정의
void CexcelDlg::OnClickedButton(unsigned int id)
{
    switch (id)
    {
    case IDC_BUTTON1:
        ExcelTest1();
        break;
    case IDC_BUTTON2:
        ExcelTest2();
        break;
    case IDC_BUTTON3:
        ExcelTest3();
        break;
    case IDC_BUTTON4:
        ExcelTest4();
        break;
    }
}
이제 버튼을 클릭하면 이 함수가 호출되며, 각 버튼의 ID에 맞게 ExcelTest1~4() 함수가 호출됩니다.

6. ExcelTest1() 함수 (엑셀 파일 열기, 값 쓰기)
void CexcelDlg::ExcelTest1()
{
    CApplication app;    

    // 엑셀 시작
    if (!app.CreateDispatch(_T("Excel.Application")))
    {
        AfxMessageBox(_T("Couldn't start Excel."));
    }
    else
    {
        //열리는 과정이 보이게
        app.put_Visible(true);        
    }

    // workbook 생성
    app.put_SheetsInNewWorkbook(1);        

    CWorkbooks wbs;
    CWorkbook wb;    

    COleVariant covTrue((short)TRUE);
    COleVariant    covFalse((short)FALSE);
    COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
    
    // books 연결
    wbs.AttachDispatch(app.get_Workbooks());
    // book 연결
    wb.AttachDispatch(wbs.Add(covOptional));    

    // sheets 생성, 연결
    CWorksheets wss;
    wss = wb.get_Sheets();

    // sheet 생성, 연결 (1번 시트)
    CWorksheet ws;
    ws = wss.get_Item(COleVariant((short)1));

    // sheet 이름 변경
    ws.put_Name(_T("test sheet 1"));

    // range 생성, 연결
    CRange range;
    range.AttachDispatch(ws.get_Cells(), true);    

    // range 값 쓰기
    for (int i = 1; i <= 10; i++)
    {
        CString strRow;
        strRow.Format(_T("ROW%d"), i);
        range.put_Item(COleVariant((long)1), COleVariant(long(i)), COleVariant(strRow));
    }

    // 연결 끊기
    range.ReleaseDispatch();
    ws.ReleaseDispatch();
    wss.ReleaseDispatch();
    wb.ReleaseDispatch();
    wbs.ReleaseDispatch();
    app.ReleaseDispatch();
}
코드가 복잡하므로 먼저 분석하기 보다는, 일단 맨 아래 첨부된 소스코드를 다운받아 실행 후 엑셀 파일이 자동으로 생성되어 값이 써지는 모습을 관찰 한 후 코드를 분석해보기 바랍니다.

코드의 동작방식은 Excel App을 생성, 워크북, 워크시트 생성, 워크시트 셀 연결, 값쓰기로 이어지는 흐름입니다.

클래스를 유심히 살펴보면 CWorksheets, CWorksheet 등 복수, 단수형 이름 클래스가 존재하는데 이는 엑셀파일에서 여러개의 워크시트들이 존재하고 하나의 활성 워크시트에서 작업이 이루어지기 때문입니다.

51번 라인의 CRange 객체는 put_Item(행번호, 열번호, 값) 함수로 워크시트에 값을 써주는 역할입니다. 주의해야할 점은 행번호, 열번호는 1번부터 시작합니다.

또한 엑셀 관련 클래스가 대부분 VARIANT 구조체로 값을 주고 받게 되어있으며, 모든 타입(정수, 실수, 문자열 등)에 대응해야 하므로 구조체가 복잡합니다.

따라서 코드에서는 VARIANT 구조체의 Wrapper class인 MFC COleVariant class를 활용해 구현하였습니다.

해당 함수의 수행 결과는 아래와 같이 엑셀이 자동 실행되어 값이 써집니다.



7. ExcelTest2() 함수 (셀 병합, 폰트변경, 정렬)

ExcelTest1() 에서 이미 엑셀 파일 열기, 연결은 살펴보았으므로 생략합니다.
void CexcelDlg::ExcelTest2()
{
    생략...

    // range 생성
    CRange range;    

    // range 값 쓰기 (merge)
    range = ws.get_Range(COleVariant(_T("A1")), COleVariant(_T("E2")));
    range.Merge(COleVariant(0L));
    range.put_Value2(COleVariant(_T("Merge Cell")));
    
    // Font
    CFont0 font = range.get_Font();
    font.put_Bold(covTrue);
    font.put_Size(COleVariant(16L));
    font.put_Color(COleVariant((double)RGB(0, 0, 255)));
    
    // Alignment
    // Top:        -4160
    // Bottom:    -4107
    // Left:    -4131
    // Center:    -4108
    // Right:    -4152
    range.put_HorizontalAlignment(COleVariant(short(-4108)));

    // 연결 끊기
    font.ReleaseDispatch();
    range.ReleaseDispatch();
    ws.ReleaseDispatch();
    wss.ReleaseDispatch();
    wb.ReleaseDispatch();
    wbs.ReleaseDispatch();
    app.ReleaseDispatch();
}
CFont 클래스는 특이하게 이름이 뒤에 '0' 이 붙는데 아마도, MFC의 CFont class와 이름충돌을 피하기 위함인 것 같습니다.

여기서 사용되는 CFont0 class는 엑셀의 폰트 class입니다.

25번 라인의 put_HorizontalAlignment() 함수를 통해 셀 범위의 정렬을 수행하는데, 인자값은 주석으로 명시해 두었습니다.

아마도 이런 정수계열 상수값이 정의된 헤더파일이나 클래스가 존재할거 같은데 문서화가 부실해 찾기가 힘드네요.

결과는 아래와 같습니다.


8. ExcelTest3() 함수 (테두리, 선 그리기)
void CexcelDlg::ExcelTest3()
{
    생략...

    // range 생성
    CRange range;
    range.AttachDispatch(ws.get_Cells(), true);

    // 범위 지정
    range = ws.get_Range(COleVariant(_T("B2")), COleVariant(_T("D3")));

    // borders (전체 테두리)
    CBorders borders;    
    borders = range.get_Borders();
    borders.put_LineStyle(COleVariant((short)1));


    // 범위 지정
    range = ws.get_Range(COleVariant(_T("B5")), COleVariant(_T("D6")));

    // border (부분 테두리, 상하좌우)
    CBorder bl, bt, bd, br;
    borders = range.get_Borders();

    // BORDERLEFT:    7
    // BORDERTOP:    8
    // BORDERBOTTOM:9
    // BORDERRIGHT:    10
    // BORDERINNERL:11
    bl = borders.get_Item(7L);
    bt = borders.get_Item(8L);
    bd = borders.get_Item(9L);
    br = borders.get_Item(10L);

    // line style with thickness
    // Continuous     1
    // xlDash - 4115
    // xlDashDot     4
    // xlDashDotDot    5
    // xlDot - 4118
    // xlDouble - 4119
    // xlLineStyleNone - 4142
    // xlSlantDashDot     13
        
    signed short thick = 3;
    bl.put_LineStyle(COleVariant((short)1));
    bl.put_Weight(COleVariant(thick));

    bt.put_LineStyle(COleVariant((short)2));
    bt.put_Weight(COleVariant(thick));

    bd.put_LineStyle(COleVariant((short)4));
    bd.put_Weight(COleVariant(thick));

    br.put_LineStyle(COleVariant((short)-4119));
    br.put_Weight(COleVariant((short)4));    

    // 연결 끊기    
    borders.ReleaseDispatch();
    range.ReleaseDispatch();
    ws.ReleaseDispatch();
    wss.ReleaseDispatch();
    wb.ReleaseDispatch();
    wbs.ReleaseDispatch();
    app.ReleaseDispatch();
}

CBorder 클래스를 이용해 해당 범위 셀의 상, 하, 좌, 우 테두리를 각자 다른 선으로 그려주는 예제입니다.

CBorder class 메소드인 put_LineStyle() 함수로 선의 종류를, put_Weight() 함수로 선의 두께를 결정합니다.

55번 라인 put_LineStyle() 함수의 4번 선종류가 이중선인데 특이하게 선 두께가 4 만 동작하네요.

결과는 아래와 같습니다.


9. ExcelTest4() 함수 (엑셀 수식, Formula 적용하기)
void CexcelDlg::ExcelTest4()
{
    생략...

    // range 생성, 연결
    CRange range;
    range.AttachDispatch(ws.get_Cells(), true);

    // range 값 쓰기
    for (long i = 1; i <= 10; i++)
    {        
        range.put_Item(COleVariant((long)i), COleVariant(long(1)), COleVariant(i));
    }

    // 함수 적용
    range = ws.get_Range(COleVariant(_T("A1")), COleVariant(_T("A10")));

    CRange sum = ws.get_Range(COleVariant(_T("A11")), COleVariant(_T("A11")));
    sum.put_Formula(COleVariant(_T("=SUM(A1:A10)")));
    CBorders bd = sum.get_Borders();
    bd.put_LineStyle(COleVariant(short(1)));

    // 연결 끊기
    range.ReleaseDispatch();
    ws.ReleaseDispatch();
    wss.ReleaseDispatch();
    wb.ReleaseDispatch();
    wbs.ReleaseDispatch();
    app.ReleaseDispatch();
}

A1 ~ A10번 셀에 숫자를 1부터 10까지 기록하고 A11번 셀에 put_Formula() 함수를 이용해 엑셀의 "=SUM(A1:A10)" 함계 수식을 적용해 보았습니다.

CRange class의 메소드인 put_Formula() 함수 전달인자로 수식 문자열을 적용합니다.

결과는 아래와 같습니다.




이상으로 모든 코드 분석을 마칩니다.

감사합니다.

소스코드 링크 : 엑셀 예제

댓글

  1. 안녕하세요.. 차근차근 따라해보고싶은데 초반부터 막혀서 댓글 답니다ㅠㅠ
    인터페이스 선택 창에서 인터페이스를 선택하고 확인을 누르니까
    "지정한 키가 사전에 없습니다." 라고 뜨는데 이것을 해결할라면 어떻게 해야하나요 ?
    아니면 키를 수동으로 지정할 수 있나요 ? 아니면 인터페이스를 수동으로 지정할 수 있는지 궁급합니다!

    답글삭제
    답글
    1. 프로젝트 생성시 자동화가 미체크 되었거나 엑셀이 제대로 설치되어 있는지 확인이 필요합니다.

      삭제
  2. 안녕하세요 엑셀 연동은 되는데 저장은 어떻게 하는지 알수있을까요?

    답글삭제
    답글
    1. CWorkbook 클래스 객체에서 연결 끊기 전 다음과 같이 구현하면 됩니다.

      CWorkbook wb;
      COleVariant vtOpt ((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
      // 워크북
      wb.SaveAs(COleVariant(_T("D:\\test.xlsx")), vtOpt, vtOpt, vtOpt, vtOpt, vtOpt, 0, vtOpt, vtOpt, vtOpt, vtOpt, vtOpt);

      삭제
    2. 와 진짜 감사합니다 선생님 ㅠㅠ

      삭제
  3. 안녕하세요. 좋은 정보 감사합니다.
    염치없이 질문 하나 드립니다.
    이미지도 삽입 할 수 있나요? 어떤식으로 하는지 궁금합니다.

    그리고 엑셀 연동 관련해서 조금 더 공부해 보고 싶은데, 참고 자료를 알 수 있을까요?
    답변 부탁드립니다.
    수고하세요.

    답글삭제
    답글
    1. 워크시트를 연결 후 아래와 같이 작성하면 이미지 삽입이 가능합니다.
      단, Pictures, Picture 인터페이스가 필요합니다.

      COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
      CPictures pics = ws.Pictures(covOptional);
      CRange r = ws.get_Range(COleVariant(_T("A2")), COleVariant(_T("A2")));
      r.Select();
      CPicture pic = pics.Insert(_T("D://a.bmp"), covOptional);

      참고자료는 개발처인 MS의 Doc를 참조바랍니다.

      https://docs.microsoft.com/en-us/previous-versions/office/troubleshoot/office-developer/automate-excel-from-c

      삭제
  4. 안녕하세요 Excle Automation 을 이용하여 꺾은선 그래프를 출력하고 싶은데 방법을 알 수 있을까요? 구글링으로 ChartWizard를 이용해야한다는 것 까지는 알았습니다만. 어떻게 사용해야하는지, 혹은 다른 방법이 있는지 알고싶습니다.

    답글삭제
  5. 저도 차트를 해본적은 없는데 검색해보니 자료가 있네요.

    인터페이스에 _Chart, Charts 를 추가하고 아래 링크를 참조바랍니다.

    https://www.codeproject.com/Articles/476238/Automating-Excel-2007-and-creating-charts-using-Cp

    답글삭제
  6. 안녕하십니까. 자료 잘 보았습니다.
    c++ Thread를 이용하여 멀티 스레드 생성후 각 스레드에서 엑셀 파일을 생성하는 작업을 한다면 동작을 할까요?

    답글삭제
    답글
    1. 네 잘 동작합니다.

      위 예제는 엑셀오토메이션을 간단히 설명하기 위해 만든 예제라 메인쓰레드에서 동작하게 만들었습니다.

      일반적으로 엑셀파일 쓰기 작업은 지연을 동반하게 되므로 쓰레드에서 생성해 사용하는것이 좋습니다.

      쓰레드는 MFC Thread, C++ 11 Thread 등 아무 상관이 없습니다. 다만 하나의 엑셀작업을 여러쓰레드에서 나누어 진행한다면 Mutex, or Critical Section을 이용해 동기화만 처리하면 됩니다.

      삭제
  7. 안녕하십니까. 자료 잘 보았습니다.
    c++ Thread를 이용하여 멀티 스레드 생성후 각 스레드에서 엑셀 파일을 생성하는 작업을 한다면 동작을 할까요?

    답글삭제
  8. 안녕하십니까. 답변 감사합니다. 제 질문의 설명이 조금 부족했던 것 같아 한번더 질문 드립니다.

    가령 4개의 Thread를 생성했다고 치면
    4개의 Thread에 app.CreateDispatch()를 이용하여 Excel을 띄워서 각각 서로 다른 네개의 xlsx 파일을 동시에 만들고 저장후 닫을때 CApplication::Quit()을 호출하여도 문제가 없는건지에 대한 질문이었습니다.

    CApplication 개체를 Thread 마다 생성하여 사용하여도 문제가 없는 것인가요?

    답글삭제
    답글
    1. 안녕하세요. 재미있는 질문이네요.

      엑셀 오토메이션의 CApplication 클래스를 각 쓰레드마다 여러개 생성해 본적은 없지만, 싱글턴 클래스 (하나의 객체만 생성 가능) 가 아닐거라 예상합니다.

      왜냐하면 엑셀프로그램 사용시 여러개의 엑셀프로세스를 띄워서 작업이 가능한 것을 보면 유추할 수 있습니다.

      따라서 CApplication의 객체를 각 쓰레드에서 생성해도 문제가 없을 것으로 판단됩니다.

      삭제
  9. 안녕하세요 좋은 자료가 있어 따라하던중 오류가 발생하여 문의드립니다.

    'C:\\Program Files\\Microsoft Office\\Office14\\EXCEL.EXE'의 식별자가 이미 매크로입니다.

    이런 오류가 발생시 어떻게 해야하나요?

    답글삭제
  10. 안녕하세요. 좋은 정보 감사합니다.
    put_Visible(TRUE) 상태에서 열린 엑셀창을 사용자가 닫았을 때 프로그램에서 알 수 있는 방법 없을까요?
    get_Visible() 함수로 매순간 확인하려니 부하가 큽니다.

    답글삭제
    답글
    1. 개발처의 문서화가 부실해 가능할지는 모르겠습니다.

      떠오르는 생각은 몇가지 있는데...

      1. CApplication를 서브클래싱후 상속받은 클래스에서 부모(CApplication)이벤트 처리 함수가 있는지 확인 후 재정의 하고 여기서 visible 상태 메시지를 캡쳐해 처리.

      (근데 개발처 참조 문서가 없어 이벤트 관련 함수가 있는지, 오버라이딩 가능한지 모르겠네요.)

      2. 쉬운 방법은 써주신 대로 쓰레드하나 만들어서 적당히 슬립하며 visible 체크 후, 사용자 정의 이벤트 만들어 처리.

      삭제
  11. 안녕하세요 office excel 2010 이 아닌 오피스365 의 excel 365 사용하려면 어떻게 해야될까요?

    답글삭제
    답글
    1. 안녕하세요.

      오피스 365는 웹기반으로 알고 있는데 오토메이션이 되는지는 잘 모르겠습니다.

      삭제
  12. 정말 감사합니다. 좋은 자료입니다.!

    답글삭제
  13. 파일 저장 후 Release 해줘도 프로세스에는 남아 있던데 확실히 종료 시킬 수 있는 방법이 있을까요? 현재 프로세스 강종으로 하고 있습니다만 답이 아닌거 같아서요. 도움 부탁드립니다.

    답글삭제
  14. 실행된 엑셀앱을 의미하는 거라면 app.Quit() 함수를 사용하면 됩니다.

    답글삭제
  15. 안녕하세요. 예제 따라서 해보았는데 if (!app.CreateDispatch(_T("Excel.Application")))
    앱 오픈 부분에서 260ms ~ 330ms 시간이 걸리는데 로그를 매번 쓰고 있어서 속도 저하 때문에 어려운 부분이 있습니다. 해결 방안이 있을가요?

    답글삭제
    답글
    1. Class로 만든후 생성자에서 app open을 1회 해주었지만 매번 create를 해주지 않으면 다른 Function 호출 할 경우 죽는 현상이 나오네요.

      삭제
    2. 우리가 만든 클래스가 아니므로 당연히 불가능합니다.

      삭제
  16. 이 예제 프로그램을 실행한 뒤로 다른 프로그램에서 엑셀을 제어할 때 예제 프로그램이 계속 실행됩니다
    레지스트리 변경이 되서 영향이 있는 것 같은데 조심하세요

    답글삭제
    답글
    1. 제가 작성하고 공개한 예제 게시물에 레지스트리를 변경하는 코드가 어디 있나요?

      본인의 의견을 주장할때는 근거를 뒷바침하는 객관적인 자료를 제시하기 바랍니다.

      공개된 예제코드 어디에도 레지스트리를 변경하는 Windows API Function 호출은 없으며 있다고 해도 OS에서 User Account Control에 의해 알람이 뜨게 됩니다.

      삭제
  17. 안녕하세요 좋은자료 감사 드립니다.
    혹시 새로운 엑셀을 실행시키는것이 아니라 기존에 있던 엑셀파일을 read 해서 그 안에 데이터를 출력하려고 하는데 기존에 있는 엑셀파일을 어떻게 불러올까요?

    답글삭제
    답글
    1. wbs의 Open() 함수를 이용해 파일을 열고, range의 get_value() 로 값을 읽으면 됩니다.

      삭제
  18. 안녕하세요 정말 필요했던 자료인데 감사 드립니다.
    혹시, 셀의 행이나 열의 너비를 바꾸는 방법을 알 수 있을까요?
    감사합니다.

    답글삭제
    답글
    1. Range 헤더에서 검색하면 set_width or put_width 류의 setter, getter 가 존재할 것으로 추측됩니다.

      삭제
  19. 혹시 조건부 서식을 어떻게 쓰는 것을 아십니까?

    답글삭제
    답글
    1. 조건부 서식이 IF를 의미하는 것이라면 예제의 SUM 함수를 쓰는 것과 동일하게 진행하면 됩니다.

      삭제
    2. 선생님, 아래 코드는 C#으로 조건부 서식을 이용해서 셀에 데이터에 따라 Color로 표시해 주는 코드인데요. microsoft사 엡사이트에는 C#과 VB로 예시 코드를 제공하지만 C++ MFC 예시 코드는 없습니다. 아래처럼 MFC로 선택한 range에 조건부 서식을 적용할 수 있는지 아십니까?

      ApplicationClass excelApplication = null;
      Workbook newWorkbook = null;
      Worksheet targetSheet = null;
      ColorScale cfColorScale = null;
      IconSetCondition cfIconSet = null;
      string paramWorkbookPath = @"C:\Temp\Test.xlsx";
      object paramMissing = Type.Missing;
      excelApplication = new ApplicationClass();
      newWorkbook =
      excelApplication.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);
      targetSheet = (Worksheet)(newWorkbook.Worksheets[1]);
      targetSheet.Name = "Conditional Formatting";
      // Fill cells A1:A10 with sample data.
      targetSheet.get_Range("A1",
      paramMissing).set_Value(XlRangeValueDataType.xlRangeValueDefault, 1);
      targetSheet.get_Range("A2", paramMissing).set_Value(XlRangeValueDataType.xlRangeValueDefault, 2);
      targetSheet.get_Range("A1:A2",
      paramMissing).AutoFill(targetSheet.get_Range("A1:A10", paramMissing), XlAutoFillType.xlFillSeries);

      // Create a two-color ColorScale object for the created sample data
      // range.
      cfColorScale = (ColorScale)(targetSheet.get_Range("A1:A10",
      Type.Missing).FormatConditions.AddColorScale(2));

      // Set the minimum threshold to red (0x000000FF) and maximum threshold
      // to blue (0x00FF0000).
      cfColorScale.ColorScaleCriteria[1].FormatColor.Color = 0x000000FF;
      cfColorScale.ColorScaleCriteria[2].FormatColor.Color = 0x00FF0000;

      https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2007/bb404903(v=office.12)?redirectedfrom=MSDN

      삭제
    3. 이 게시물 예제의 내용에 셀 범위지정 및 엑셀 함수사용과 관련된 코드작성 예시가 포함되어 있습니다.

      삭제
  20. 혹시 ‘구성원이 없습니다.’ 라고 뜨는데 해결방안이 있을까요?

    답글삭제
    답글
    1. 엑셀, VS 가 제대로 설치되어 있는지 확인바랍니다.

      삭제
    2. 제가 구형버전을 사용해서 그런 것 같습니다. 감사합니다.

      삭제
  21. AutoFit 은 문장에 맞춰 칼럼폭을 조정해주는걸로 알고있습니다. 칼럼폭을 고정한 후 글자를 '셀에 맞춤' 으로 설정하는 방법이 있나요?

    답글삭제
    답글
    1. 엑셀에 기능이 있다면 당연히 있을텐데, 문서화가 잘 되어 있지 않아 이런 세부적인 부분까지는 설정함수나 설정치를 잘 모르겠습니다.

      삭제
    2. 해결했습니다 감사합니다. 셀속성의 사용자 지정을 할 수 있을까요? Number 관련쪽은 몇개의 함수가 보이던데 공백을 추가하여 '들여쓰기' 를 하려고 합니다.

      삭제
    3. Range Class의 메서드로,

      void SetAddIndent(const VARIANT& newValue);
      void SetIndentLevel(const VARIANT& newValue);
      void InsertIndent(long InsertAmount);

      등이 보이는데 사용해 본 경험이 없어 불확실 합니다.
      (indent는 들여쓰기 입니다)

      삭제
    4. 감사합니다 한번 해볼께요

      삭제
  22. 혹시... 대량의 데이터를 빠르게 넣을수 있을까요?

    답글삭제
    답글
    1. 대량의 데이터가 정량적으로 몇개인지는 알 수 없지만 이 게시물이 엑셀 데이터를 넣는 방법을 설명하고 있으므로 직접 2중 반복문 형태로 입력을 시도해 보면 좋을 것 같습니다.

      삭제
  23. 위와 비슷한 방법으로 엑셀을 사용하고 있는데요...
    혹시... 프로그램이 Excel을 자동정리 중에 저는 다른 엑셀 작업을 할수 있게 하는 방법이 있을까요?
    부탁드립니다

    답글삭제
    답글
    1. 서로 다른 엑셀 파일이라면 프로세스가 다르므로 동시에 작업을 진행하는데 문제가 없고, 하나의 엑셀 프로세스에서 여러 작업을 동시에 진행하는 경우라도 쓰레드 동기화 처리만 해주면 문제없을 것으로 판단합니다.

      삭제

댓글 쓰기

이 블로그의 인기 게시물

Qt Designer 설치하기

PyQt5 기반 동영상 플레이어앱 만들기