環境:MFC、Office2007、VS2012
MFCでExcelファイルを読み込むソフトを作成しています。
「A1」と指定したセルを読み込む事は出来たのですが、
列/行の終端を読み込む方法が分かりません。
ファイルの全ての内容を読み込みたいのですが
1セルずつ読み込んでいては時間がかかりそうですし、
ぱっと終端を判別する方法は無いでしょうか?
ググってもMFCでExcelの読み書きのサイトは少なく、
基本的な事しか書かれておらず参考になりません。
良い解説サイトなどもご存知でしたら教えてください。
1行まとめて取得とか、方法があるなら私も知りたいです。
ですが、例えばCListCtrlとかのテキストも1カラムごとに情報を取り出しますが、そ
れと同じだと思います。
通常のCOMインターフェイスを使うと1セルずつ読み出す以外の方法はなかったと思い
ます。
終端の判別も空欄がX個続く場所が見つかったら終端とみなす・・・といった判別をし
てますね。
MFCでの方法はよくわからないのですが、タイプライブラリを使う方法でよくやっています。
COMでn×mの配列をSafeArrayを使って、書き込んだり読み込んだり出来ます。
大雑把に書くとこんな感じ
//アクティブ・シートを取得
_WorksheetPtr pSheet = pXL->ActiveSheet;
variant_t arr;
arr.vt = VT_ARRAY | VT_VARIANT;
{
SAFEARRAYBOUND sab[2];
sab[0].lLbound = 1; sab[0].cElements = 15;
sab[1].lLbound = 1; sab[1].cElements = 15;
arr.parray = SafeArrayCreate(VT_VARIANT, 2, sab);
}
//データを格納
for (int i = 1; i < 15; i++){
for(int j = 1; j < 15; j++){
variant_t tmp;
tmp = (long)(i + j);
// Add to safearray...
long indices[] = { i, j };
SafeArrayPutElement(arr.parray, indices, (void *)&tmp);
}
}
//配列をExcelへ出力
pSheet->Range[A1][O15]->Value2 = arr;
少し前まで、非常に詳細に解説しているサイトがあって、
よく参考にさせてもらっていたのですが、最近見てみると
残念ですがなくなったしまったようです。
自分で少し調べてみたところ、
CRangeのSpecialCellsメソッドを使えば良さそう・・・
というところまでは分かりました。
が、セットする値が何を指定すれば良いのかがわかりません。
MSDNにもCRangeのクラス説明が無いですし、解説サイトも見つけられずお手上げです。
>Bullさん
ありがとうございます。
提示していただいた内容はExcelに書き込む内容ですよね?
Excelの内容を読み込み、かつシートのセルの終端が知りたいのです。
自分も、その解説サイトのアドレスは見つけられたのですが
ページが無くなってますね。残念(T_T
ExcelをCOMとして扱っているとすると,Worksheetの使用しているセルの範囲は,Worksheetオブ
ジェクトのUsedRangeプロパティを使うことで取得できます。
https://msdn.microsoft.com/ja-jp/library/office/ff840732.aspx
OOXMLのSpreadsheetMLを直接読み書きしているならば,
・dimension要素のref属性に範囲が書かれています
・そもそも,使用されているセルにしかc要素が存在しません
という2点が使えるかと思います。
>Excelの内容を読み込み、かつシートのセルの終端が知りたいのです。
MFCは使用していませんが、こんな感じでできます。
#include <iostream>
#include <iomanip>
#include <string>
#include <comutil.h>
#pragma warning (disable:4192)
//Excelを操作するためのタイプライブラリを読みこむ(Excel2013用)
#import C:\Program Files\Microsoft Office
15\root\vfs\ProgramFilesCommonX86\Microsoft Shared\OFFICE15\MSO.DLL no_auto_exclude
auto_rename
#import C:\Program Files\Microsoft Office
15\root\vfs\ProgramFilesCommonX86\Microsoft Shared\VBA\VBA6\Vbe6ext.olb
#import C:\Program Files\Microsoft Office 15\root\office15\EXCEL.EXE
no_auto_exclude auto_search auto_rename dual_interfaces
using namespace Excel; //名前空間の定義
struct StartOle {
StartOle() { CoInitialize(NULL); }
~StartOle() { CoUninitialize(); }
} _inst_StartOle;
void dump_com_error(_com_error &e)
{
std::cerr << Oops - hit an error!\n;
std::cerr << \tCode = << std::setw(8) << std::hex << e.Error() << '\n';
std::cerr << \tCode meaning = << e.ErrorMessage() << '\n';
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
std::cerr << \tSource = << (LPCTSTR) bstrSource << '\n';
std::cerr << \tDescription = << (LPCTSTR) bstrDescription << '\n';
}
int main(int argc, char* argv[])
{
_ApplicationPtr pXL;
//Excelの起動
if (SUCCEEDED(pXL.CreateInstance(LExcel.Application))) {
try {
pXL->Visible[0] = VARIANT_TRUE;
//ワークブックを開く
WorkbooksPtr pBooks = pXL->Workbooks;
_WorkbookPtr pBook = pBooks->Open(bstr_t(Book1.xlsx));
//アクティブ・シートを取得
_WorksheetPtr pSheet = pXL->ActiveSheet;
RangePtr pCells = pSheet->UsedRange;
pCells->Select(); //セル範囲を選択
//セル範囲のデータを取得
variant_t data = pCells->Value2;
long index[2];
long lNumRows;
long lNumCols;
SafeArrayGetUBound(data.parray, 1, &lNumRows);
SafeArrayGetUBound(data.parray, 2, &lNumCols);
for (int r = 1; r <= lNumRows; r++) {
index[0] = r;
for (int c = 1; c <= lNumCols; c++) {
index[1] = c;
variant_t val;
SafeArrayGetElement(data.parray, index,
&val);
switch(val.vt)
{
case VT_R8:
{
std::cout << std::setw(5) <<
val.dblVal;
break;
}
case VT_BSTR:
{
std::wcout << val.bstrVal <<
L ;
break;
}
case VT_EMPTY:
{
std::cout << ' ';
break;
}
}
}
std::cout << \n;
}
::Sleep(2 * 1000);
pXL->WindowState[0] = xlMinimized;
std::cout << 動作確認のために一時停止:;
std::string buff;
std::getline(std::cin, buff);
pBook->Saved[0] = VARIANT_TRUE;
pBook->Close();
pBook.Release();
pBooks.Release();
}
catch (_com_error &e) {
dump_com_error(e);
return 1;
}
pXL->Quit();
pXL.Release();
}
}