MFCでExcelを読み込みたい

[戻る]
ひまわり 2015/10/05(月) 00:51:00
環境:MFC、Office2007、VS2012

MFCでExcelファイルを読み込むソフトを作成しています。
「A1」と指定したセルを読み込む事は出来たのですが、
列/行の終端を読み込む方法が分かりません。

ファイルの全ての内容を読み込みたいのですが
1セルずつ読み込んでいては時間がかかりそうですし、
ぱっと終端を判別する方法は無いでしょうか?

ググってもMFCでExcelの読み書きのサイトは少なく、
基本的な事しか書かれておらず参考になりません。
良い解説サイトなどもご存知でしたら教えてください。

AR 2015/10/06(火) 10:30:45
 1行まとめて取得とか、方法があるなら私も知りたいです。

 ですが、例えばCListCtrlとかのテキストも1カラムごとに情報を取り出しますが、そ
れと同じだと思います。
 通常のCOMインターフェイスを使うと1セルずつ読み出す以外の方法はなかったと思い
ます。

 終端の判別も空欄がX個続く場所が見つかったら終端とみなす・・・といった判別をし
てますね。

Bull 2015/10/06(火) 22:06:09
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;


少し前まで、非常に詳細に解説しているサイトがあって、
よく参考にさせてもらっていたのですが、最近見てみると
残念ですがなくなったしまったようです。

ひまわり 2015/10/07(水) 23:46:29
自分で少し調べてみたところ、
CRangeのSpecialCellsメソッドを使えば良さそう・・・
というところまでは分かりました。

が、セットする値が何を指定すれば良いのかがわかりません。
MSDNにもCRangeのクラス説明が無いですし、解説サイトも見つけられずお手上げです。


>Bullさん
ありがとうございます。
提示していただいた内容はExcelに書き込む内容ですよね?
Excelの内容を読み込み、かつシートのセルの終端が知りたいのです。

自分も、その解説サイトのアドレスは見つけられたのですが
ページが無くなってますね。残念(T_T

YuO [E-Mail] 2015/10/08(木) 10:02:53
ExcelをCOMとして扱っているとすると,Worksheetの使用しているセルの範囲は,Worksheetオブ
ジェクトのUsedRangeプロパティを使うことで取得できます。
https://msdn.microsoft.com/ja-jp/library/office/ff840732.aspx

OOXMLのSpreadsheetMLを直接読み書きしているならば,
・dimension要素のref属性に範囲が書かれています
・そもそも,使用されているセルにしかc要素が存在しません
という2点が使えるかと思います。

Bull 2015/10/08(木) 23:02:45
>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(L"Excel.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();
    }
}

古いスレッドには追加発言できません。