본문 바로가기

Application Programming Interface/Windows API

Win32 C++에서 Microsoft Excel 파일 다루는 방법

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

Win32 C++에서 Microsoft Excel 파일 다루는 방법

본 포스팅에서는 C#에서 Microsoft Excel 파일 다루는 방법(http://tapito.tistory.com/582)을 참고하여 Win32 C++ 개발 환경에서 MFC를 사용하지 않고 OLE/Automation으로 Microsoft Excel 파일을 읽고 쓰는 방법에 대해 설명합니다. 프로젝트 생성 및 초기 코드에 대해서는 설명하지 않습니다.

1단계. Microsoft Excel Application 로드하기 및 종료하기

1-1. Microsoft Excel Application 실행하기

Excel.Application형 인스턴스를 생성하는 것으로써 Microsoft Excel Application이 내부적으로 실행됩니다. Excel.Application.Quit 메서드를 호출하는 것으로써 Microsoft Excel Applicatipn이 종료됩니다.

/* Example */
HRESULT hResult;
CLSID clsid;

IDispatch * pXlApplication = NULL;

/* ... */

/* OLE Initialization */
hResult = OleInitialize(NULL);
// hResult의 결과에 따른 후속 조치...

/* Excel.Application 클래스의 GUID를 얻기 */
hResult = CLSIDFromProgID(OLESTR("Excel.Application"), &clsid);
// hResult의 결과에 따른 후속 조치...


/* Excel.Application 클래스의 인스턴스 생성 */
hResult = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (LPVOID *)&pXlApplication);
// hResult의 결과에 따른 후속 조치...
/* ... */

 

1-2. Microsoft Excel Application 종료하기

Microsoft Excel Application의 종료는 다음과 같습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;

/* ... */

/* Excel.Application.Quit 메서드의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Quit");
hResult = pXlApplication->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Application.Quit 메서드 호출 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = (VARIANTARG *)NULL;
dispParams.rgdispidNamedArgs = (DISPID *)NULL;
VariantInit(&variant);
hResult = pXlApplication->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &variant, NULL, NULL);
// hResult의 결과에 따른 후속 조치...

/* Excel.Application형 객체의 해제 */
pXlApplication->Release();

/* OLE Uninitialization */
OleUninitialize();

2단계. Workbook의 생성, 열기, 저장, 다른 이름으로 저장 및 닫기

2-1. Workbook 새로 만들기

Application을 로드했으면 새 파일(워크북)을 만들어보겠습니다. 새 워크북을 만드는 방법은 다음과 같이 Excel.Application.Workbooks 컬렉션 객체를 얻은 뒤 Excel.Application.Workbooks.Add 메서드를 실행하면 됩니다. 그러면 Application이 내부적으로 새 워크북을 하나 띄우고 이를 객체 형태로 반환하게 됩니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;

/* Excel.Application.Workbooks 객체의 DISPIP 얻기 */
lpszName = (OLECHAR *)OLESTR("Workbooks");
hResult = pXlApplication->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...
	
/* Excel.Application.Workbooks 객체 얻기 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = (VARIANTARG *)NULL;
dispParams.rgdispidNamedArgs = (DISPID *)NULL;
VariantInit(&variant);
hResult = pXlApplication->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, NULL, NULL);
// hResult의 결과에 따른 후속 조치...
pXlWorkbooks = variant.pdispVal;

/* Excel.Application.Workbooks.Add 메서드의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Add");
hResult = pXlWorkbooks->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Application.Workbooks.Add 메서드 호출 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = (VARIANTARG *)NULL;
dispParams.rgdispidNamedArgs = (DISPID *)NULL;
VariantInit(&variant);
hResult = pXlWorkbooks->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, NULL, NULL);
// hResult의 결과에 따른 후속 조치...
pXlWorkbook = variant.pdispVal;

/* ... 생략 ... */

 

2-2. Workbook 열기

이미 존재하는 엑셀 파일을 열고자 할 때는 Excel.Workbooks.Open 메서드를 호출합니다. 이 메서드는 파일 경로를 받고 부가적으로 각종 선택 옵션을 받아 엑셀 파일을 열고 Workbook 객체를 반환합니다. 이 메서드의 원형은 다음과 같습니다.

Excel.Application.Workbooks.Open 메서드의 원형은 다음과 같습니다.

Workbook Open(
    /* 00 */ string Filename
    /* 01 */ [, Object UpdateLinks]
    /* 02 */ [, Object ReadOnly]
    /* 03 */ [, Object Format]
    /* 04 */ [, Object Password]
    /* 05 */ [, Object WriteResPassword]
    /* 06 */ [, Object IgnoreReadOnlyRecommended]
    /* 07 */ [, Object Origin]
    /* 08 */ [, Object Delimiter]
    /* 09 */ [, Object Editable]
    /* 10 */ [, Object Notify]
    /* 11 */ [, Object Converter]
    /* 12 */ [, Object AddToMru]
    /* 13 */ [, Object Local]
    /* 14 */ [, Object CorruptLoad]
);

 

이 때 메서드로 전달되는 매개변수 중 자주 쓰이는 것은 다음과 같습니다.

Filename:
(필수) 열 파일의 경로입니다.
ReadOnly:
(선택) 읽기 전용 여부입니다. 읽기 전용이면 true, 그렇지 않으면 false 또는 매개변수를 생략합니다.
Password:
(선택) 파일의 열기 암호입니다. 이 매개변수가 생략된 상태에서 암호가 걸린 파일을 열 경우 사용자에게 별도의 암호 입력창이 표시됩니다.
WriteResPassword:
(선택) 파일의 수정 암호입니다. 이 매개변수가 생략된 상태에서 암호가 걸린 파일을 열 경우 사용자에게 별도의 암호 입력창이 표시됩니다.
Format:
(선택) 파일의 형식입니다. 이 형식은 Microsoft.Office.Interop.Excel.XlFileFormat에서 열거하는 형식 중 하나이며, .xlsx 파일은 xlOpenXMLWorkbook이고 .xlsm 파일은 xlOpenXMLWorkbookMacroEnabled입니다.
Origin:
(선택) 위의 Format: 매개변수가 텍스트 파일을 지정할 때 사용되는 매개변수입니다. 해당 텍스트 파일이 어떤 플랫폼에서 작성되었는지를 명시하는 매개변수로서 줄바꿈을 표현할 때 CR/LF 또는 LF 단독으로 쓰이는지 여부를 구분하기 위해 사용되는 매개변수입니다. Microsoft.Office.Interop.Excel.XlPlatform에서 열거하는 형식 중 하나입니다.
Delimiter:
(선택) 위의 Format: 매개변수가 텍스트 파일을 지정할 때 사용되는 매개변수입니다. 값과 값 사이를 구분해주는 문자를 전달합니다.

 

위 메서드를 사용하여 파일을 열어보겠습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;

/* ... */

/* Excel.Application.Workbooks.Open 메서드의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Open");
hResult = pXlWorkbooks->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Workbooks.Open 메서드 호출 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("E:\\test2.xlsx"));
dispParams.rgdispidNamedArgs[0] = 0;
VariantInit(&variant);
hResult = pXlWorkbooks->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &variant, &excepInfo, NULL);
SysFreeString(dispParams.rgvarg[0].bstrVal);
delete[] dispParams.rgvarg;
delete[] dispParams.rgdispidNamedArgs;
// hResult의 결과에 따른 후속 조치...
pXlWorkbook = variant.pdispVal;

/* ... */

 

2-3. Workbook의 저장

이미 경로가 지정된 Workbook을 저장하고자 할 때는 다음과 같이 Excel.Workbook.Save 메서드를 사용합니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;

/* ... */

/* Excel.Workbook.Save 메서드의 DISP 얻기 */
lpszName = (OLECHAR *)OLESTR("Save");
hResult = pXlWorkbook->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Application.Workbooks.Save 메서드 호출 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&variant);
hResult = pXlWorkbook->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &variant, NULL, NULL);
// hResult의 결과에 따른 후속 조치...

/* ... */

 

2-4. Workbook의 다른 이름으로 저장

경로를 새로 지정하여 Workbook을 저장하고자 할 때는 다음과 같이 Excel.Workbook.SaveAs 메서드를 사용합니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;

/* ... */

/* Excel.Workbook.SaveAs 메서드의 DISP 얻기 */
lpszName = (OLECHAR *)OLESTR("SaveAs");
hResult = pXlWorkbook->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Application.Workbooks.SaveAs 메서드 호출 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("E:\\test2.xlsx"));
dispParams.rgdispidNamedArgs[0] = (DISPID)0;
VariantInit(&variant);
hResult = pXlWorkbook->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &variant, NULL, NULL);
SysFreeString(dispParams.rgvarg[0].bstrVal);
delete[] dispParams.rgvarg;
delete[] dispParams.rgdispidNamedArgs;
// hResult의 결과에 따른 후속 조치...

/* ... */

 

2-5. Workbook의 닫기

열거나 생성한 엑셀 문서를 닫으려면 Excel.Workbook.Close 메서드를 호출합니다.

/* Example */
/* Excel.Workbook.Close 메서드의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Close");
hResult = pXlWorkbooks->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Workbook.Close 메서드 호출 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&variant);
hResult = pXlWorkbooks->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, NULL, NULL);
// hResult의 결과에 따른 후속 조치...
pXlWorkbook = variant.pdispVal;

/* ... */

 

3단계. Worksheet의 추가, 삭제, 순서변경, 이름변경

엑셀 파일(Workbook)을 열거나 생성하였다면 Workbook에 새 Worksheet를 추가, 삭제 및 변경하는 작업을 해보겠습니다. 해당 작업은 Excel.Worksheets 이하의 메서드 및 프로퍼티로 수행이 가능하며, 이 멤버들이 소속된 Excel.Worksheets형 객체는 Excel.Workbook.Worksheets 속성을 통해 얻을 수 있습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;

/* Excel.Worksheets 객체의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Worksheets");
hResult = pXlWorkbook->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Worksheets 객체 얻기 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&variant);
hResult = pXlWorkbook->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, NULL, NULL);
// hResult의 결과에 따른 후속 조치...
pXlWorksheets = variant.pdispVal;

 

3-1. Worksheet의 추가

Worksheet의 추가는 Excel.Worksheets.Add 메서드를 호출하여 수행합니다.

Excel.Worksheets.Add 메서드의 원형은 다음과 같으며 순서를 지정하는 매개변수 없이 호출할 경우 새 워크시트는 가장 첫번째 순서로 삽입됩니다.

Worksheet Add(
    /* 00 */ [Worksheet Before]
    /* 01 */ [, Worksheet After] 
    /* 02 */ [, VARIANT Count] 
    /* 03 */ [, VARIANT Type]
);

 

Before:
이미 존재하는 Worksheet 객체를 지정합니다. 이 객체 이전 순서로 새 Worksheet를 추가합니다.
After:
이미 존재하는 Worksheet 객체를 지정합니다. 이 객체 다음 순서로 새 Worksheet를 추가합니다.
Count:
새로 추가할 Worksheet의 개수를 지정합니다.
Type:
Worksheet의 유형을 지정합니다. Microsoft.Office.Interop.Excel.XlSheetType 열거자에서 정의된 유형 중 하나를 전달합니다.

 

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;
IDispatch * pXlWorksheet = NULL;

/* ... */

/* Excel.Worksheets.Add 메서드의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Add");
hResult = pXlWorksheets->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// ... hResult에 따라 후속 처리

/* Excel.Worksheets.Add 메서드 호출 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&variant);
hResult = pXlWorksheets->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &variant, &excepInfo, NULL);
// ... hResult에 따라 후속 처리
pXlWorksheet = variant.pdispVal;

 

3-2. Worksheet의 삭제

Worksheet의 삭제는 Excel.Worksheet.Delete 메서드를 사용하여 수행합니다. 이 메서드의 원형은 다음과 같습니다.

void Delete();

 

이 메서드를 활용하여 임의의 워크시트 객체에 대해 삭제를 해보겠습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;
IDispatch * pXlWorksheet = NULL;

/* ... */

/* Excel.Worksheet.Delete 메서드의 DISP 얻기 */
lpszName = (OLECHAR *)OLESTR("Delete");
hResult = pXlWorksheet->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// ... hResult에 따라 후속 처리

/* Excel.Worksheet.Delete 메서드 호출 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&variant);
hResult = pXlWorksheet->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &variant, &excepInfo, NULL);
// ... hResult에 따라 후속 처리

/* ... */

 

3-3. Worksheet의 순서 변경

Worksheet의 순서 변경을 위해 Excel.Worksheet.Move 메서드를 사용합니다. 이 메서드의 원형은 다음과 같습니다.

void Move(
    /* 01 */ [Worksheet Before]
    /* 02 */ [, Worksheet After]
)

매개 변수는 BeforeAfter의 2가지가 있는데 반드시 둘 중 하나에만 매개변수가 전달되어야 합니다. 매개변수가 없이 호출되거나 두 매개변수에 모두 객체가 전달되어서는 안됩니다. 이 매개변수는 Excel.Worksheet형 객체를 받으며 After 매개변수에 객체가 전달될 경우 이 워크시트는 매개변수로 전달된 워크시트의 바로 앞으로 옮겨집니다. Before 매개변수에 객체가 전달될 경우 이 워크시트는 매개변수로 전달된 워크시트의 바로 뒤로 옮겨집니다. Sheet2 이름의 워크시트를 Sheet1의 워크시트 바로 뒤로 이동해보겠습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;
UINT uArgErr = 0;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;
IDispatch * pXlWorksheet1 = NULL;
IDispatch * pXlWorksheet2 = NULL;

/* ... */

/* Excel.Worksheets.Item 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Item");
hResult = pXlWorksheets->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Worksheets.Item 프로퍼티에서 "Sheet1" 워크시트 객체 얻기 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = NULL;
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("Sheet1"));
VariantInit(&variant);
hResult = pXlWorksheets->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, &exceptInfo, &uArgErr);
SysFreeString(dispParams.rgvarg[0].bstrVal);
delete[] dispParams.rgvarg;
// hResult의 결과에 따른 후속 조치...
pXlWorksheet1 = variant.pdispVal;

/* Excel.Worksheets.Item 프로퍼티에서 "Sheet2" 워크시트 객체 얻기 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&dispParams.rgvarg[0]);
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("Sheet2"));
VariantInit(&variant);
hResult = pXlWorksheets->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, &exceptInfo, &uArgErr);
SysFreeString(dispParams.rgvarg[0].bstrVal);
delete[] dispParams.rgvarg;
// hResult의 결과에 따른 후속 조치...
pXlWorksheet2 = variant.pdispVal;

/* Excel.Worksheet.Move 메서드의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Move");
hResult = pXlWorksheet2->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Worksheets.Move 메서드 실행 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
VariantInit(&dispParams.rgvarg[0]);
dispParams.rgvarg[0].vt = VT_DISPATCH;
dispParams.rgvarg[0].pdispVal = pXlWorksheet1;
dispParams.rgdispidNamedArgs[0] = 1;
VariantInit(&variant);
hResult = pXlWorksheet2->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &variant, NULL, NULL);
delete[] dispParams.rgvarg;
delete[] dispParams.rgdispidNamedArgs;
// hResult의 결과에 따른 후속 조치...

/* ... */

 

4단계. Cell 데이터 가져오기 및 수정하기

4-1. 범위 또는 1개의 셀 가져오기

위의 단계를 거쳐 Worksheet 객체를 얻었다면 이 Worksheet에 들어있는 각 셀에 데이터를 기록하거나 불러올 수 있습니다. 하나 이상의 셀을 나타내는 자료형은 Excel.Range이고 Excel.Worksheet.Cells 프로퍼티를 통해 접근 가능합니다. 특정 셀을 지정하려면 Excel.Range.Item 프로퍼티를 사용하여 얻을 수 있습니다.

/* property */ Range Range.Item(
    /* 01 */ [VARIANT RowIndex]
    /* 02 */ [, VARIANT ColumnIndex]
);
RowIndox
행 번호입니다.
ColumnIndex
열 번호입니다.

 

예를 들어, A1 셀을 선택하는 코드는 다음과 같습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;
UINT uArgErr = 0;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;
IDispatch * pXlWorksheet = NULL;
IDispatch * pXlRangeCells = NULL;
IDispatch * pXlRangeCell = NULL;

/* ... */

/* Excel.Worksheet.Cells 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Cells");
hResult = pXlWorksheet->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Worksheet.Cells 프로퍼티에서 Range 객체 얻기 */
dispParams.cArgs = 0;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = NULL;
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&variant);
hResult = pXlWorksheet->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, NULL, NULL);
// hResult의 결과에 따른 후속 조치...
pXlRangeCells = variant.pdispVal;

/* Excel.Range.Item 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Item");
hResult = pXlRangeCells->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Range.Item 프로퍼티에서 한 셀을 나타내는 Range 객체 얻기 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 0;
dispParams.rgvarg = new VARIANTARG[2];
dispParams.rgdispidNamedArgs = NULL;
VariantInit(&dispParams.rgvarg[0]);
dispParams.rgvarg[0].vt = VT_I4;
dispParams.rgvarg[0].intVal = 1;
VariantInit(&dispParams.rgvarg[1]);
dispParams.rgvarg[1].vt = VT_I4;
dispParams.rgvarg[1].intVal = 1;
VariantInit(&variant);
hResult = pXlRangeCells->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, &excepInfo, &uArgErr);
delete[] dispParams.rgvarg;
// hResult의 결과에 따른 후속 조치...
pXlRangeCell = variant.pdispVal;

/* ... */

 

만일 A1:C3와 같이 여러 셀을 선택하여 가져오고자 할 때는 다음과 같이 Excel.Worksheet.Range 프로퍼티를 통해 가져올 수 있습니다.

/* property */ Range Range.Range(
    /* 00 */ VARIANT Cell1
    /* 01 */ [, VARIANT Cell2]
);

 

위 프로퍼티를 사용하여 $A$1:$C$3 범위를 가져오겠습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;
UINT uArgErr = 0;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;
IDispatch * pXlWorksheet = NULL;
IDispatch * pXlRangeRange = NULL;

/* ... */

/* Excel.Worksheet.Range 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Range");
hResult = pXlWorksheet->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Worksheet.Range 프로퍼티에서 Range 객체 얻기 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
VariantInit(&dispParams.rgvarg[0]);
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("$A$1:$C$3"));
dispParams.rgdispidNamedArgs[0] = 0;
VariantInit(&variant);
hResult = pXlWorksheet->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, &excepInfo, &uArgErr);
// hResult의 결과에 따른 후속 조치...
pXlRangeRange = variant.pdispVal;

/* ... */

 

4-2. 셀에 식 또는 값을 가져오거나 설정하기

셀에 값을 기록하거나 셀에 기록된 값을 가져오는 속성은 Excel.Range.Value입니다.

/* property */ VARIANT Range.Value(
    /* 00 */ [VARIANT RangeValueDataType]
);

 

위 속성을 사용하여 A1 셀에 정수 '1'을 기록해보겠습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;
UINT uArgErr = 0;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;
IDispatch * pXlWorksheet = NULL;
IDispatch * pXlRangeRange = NULL;

/* ... */

/* Excel.Worksheet.Range 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Range");
hResult = pXlWorksheet->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Worksheet.Range 프로퍼티에서 Range 객체 얻기 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
VariantInit(&dispParams.rgvarg[0]);
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("$A$1"));
dispParams.rgdispidNamedArgs[0] = 0;
VariantInit(&variant);
hResult = pXlWorksheet->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, &excepInfo, &uArgErr);
// hResult의 결과에 따른 후속 조치...
pXlRangeRange = variant.pdispVal;

/* Excel.Range.Value 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Value");
hResult = pXlRangeRange->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Range.Value 프로퍼티에 정수 1 기록 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
dispParams.rgvarg[0].vt = VT_INT;
dispParams.rgvarg[0].intVal = 1; // 정수 1
dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
VariantInit(&variant);
hResult = pXlRangeRange->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &dispParams, &variant, NULL, NULL);
delete[] dispParams.rgvarg;
delete[] dispParams.rgdispidNamedArgs;
// hResult의 결과에 따른 후속 조치...

 

셀에 수식을 기록하거나 셀에 기록된 수식을 가져오는 속성은 Microsoft.Office.Interop.Excel.Range.Formula입니다.

/* property */ VARIANT Range.Formula;

이 프로퍼티를 활용하여 =SUM($A$1:$A$100)의 수식을 기록해보겠습니다.

/* Example */
HRESULT hResult;
CLSID clsid;
OLECHAR * lpszName = NULL;
DISPID dispid;
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
VARIANT variant;
EXCEPINFO excepInfo;
UINT uArgErr = 0;

IDispatch * pXlApplication = NULL;
IDispatch * pXlWorkbooks = NULL;
IDispatch * pXlWorkbook = NULL;
IDispatch * pXlWorksheets = NULL;
IDispatch * pXlWorksheet = NULL;
IDispatch * pXlRangeRange = NULL;

/* ... */

/* Excel.Worksheet.Range 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Range");
hResult = pXlWorksheet->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Worksheet.Range 프로퍼티에서 Range 객체 얻기 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
VariantInit(&dispParams.rgvarg[0]);
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("$A$1"));
dispParams.rgdispidNamedArgs[0] = 0;
VariantInit(&variant);
hResult = pXlWorksheet->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &variant, &excepInfo, &uArgErr);
// hResult의 결과에 따른 후속 조치...
pXlRangeRange = variant.pdispVal;

/* Excel.Range.Formula 프로퍼티의 DISPID 얻기 */
lpszName = (OLECHAR *)OLESTR("Formula");
hResult = pXlRangeRange->GetIDsOfNames(IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid);
// hResult의 결과에 따른 후속 조치...

/* Excel.Range.Formula 프로퍼티에 수식 기록 */
dispParams.cArgs = 1;
dispParams.cNamedArgs = 1;
dispParams.rgvarg = new VARIANTARG[1];
dispParams.rgdispidNamedArgs = new DISPID[1];
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(OLESTR("=SUM($A$1:$A$100)"));
dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
VariantInit(&variant);
hResult = pXlRangeRange->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &dispParams, &variant, NULL, NULL);
SysFreeString(dispParams.rgvarg[0].bstrVal);
delete[] dispParams.rgvarg;
delete[] dispParams.rgdispidNamedArgs;
// hResult의 결과에 따른 후속 조치...

/* ... */