質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

6039閲覧

C/C++の実行ファイルから Excelの最大行数取得

BeatStar

総合スコア4958

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/01/10 02:50

C/C++でやっています。

( 再投稿になります。 )

基本的にはMinGWで組んでいるのですが、C/C++からExcel操作ができたらいいなと思い、

VC++で Excel操作をするクラスオブジェクトを組んでいます。

ほとんどサイトからの拝借ですが、エクセルの最大行数の取得ができません。

Excel VBA だと

Dim MaxRow As Long Dim MaxCol As Long ' 1番目のシートで使われているセルの最大行数 MaxRow = ThisWorkBook.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row ' 1番目のシートで使われているセルの最大列数 MaxCol = ThisWorkBook.Worksheets(nSheet).cells(1, Columns.Count).End(xlToLeft).Column

でできるアレです。

「Excelで使える最大行数・最大列数」

ではなく、

「現在なんらかの値が入っている (= 使われている ) 最大行数・最大列数」

です。

ソースコード自体は 「【技術部】[C++] C++でのExcel操作まとめ - UMYA.net」というページから拝借して

Excel::_ApplicationPtr等のようなオブジェクトは クラスのメンバ変数 として保持し、クラスにまとめました。

インターフェース IExcel クラスを定義し、これを継承して CExcel クラス を生成。

動的リンクにしたいので このままでは使用不可能なので COMのようにして

IExcel* CreateExcelInstance( void );

という関数で IExcel型として生成して、

bool WriteExcel( IExcel* pExcel, long nSheet, long nRow, long nCol, const char *data );

のような関数にオブジェクトを渡して間接的に操作する方法にしています。

C++

1/* 定義だけです。実装は上記サイト等から 2 拝借したものです。 3 なので、定義のみとします。 4 イメージとして。 */ 5 6// 必要なヘッダファイルはすでにインクルード済みとします。 7 8// 必要なタイプライブラリ? も すでにインポート済みとします。 9 10 11// Interface 12class IExcel 13{ 14 public: 15 virtual ~IExcel(){} 16 17 virtual bool Open( const char *ExcelFilePath ) = 0; 18 virtual bool Write( long nSheet, long nRow, long nCol, const char *data ) = 0; 19 virtual bool Read( long nSheet, long nRow, long nCol, char *result ) = 0; 20 virtual long CountRow( long nSheet, long nCol ) = 0; 21 virtual bool Save( void ) = 0; 22 virtual bool Kill( void ) = 0; 23}; 24 25 26 27// 実装クラス 28class CExcel : public IExcel 29{ 30 private: 31 bool bVisible; 32 private: 33 bool bRunning; 34 private: 35 Excel::_ApplicationPtr Excel; 36 Excel::WorkbooksPtr WorkBooks; // エクセル本体用 37 Excel::_WorkbookPtr WorkBook; // エクセルブック用 38 protected: 39 void WcharToCString( WCHAR *wstr, char *str ); 40 void ToStrCell( long nRow, long nCol, char *result ); 41 public: 42 CExcel( bool bVisible ); 43 ~CExcel(); 44 45 bool Run( void ); 46 bool Open( const char *ExcelFilePath ); 47 bool Write( long nSheet, long nRow, long nCol, const char *data ); 48 bool Read( long nSheet, long nRow, long nCol, char *result ); 49 long CountRow( long nSheet, long nCol ); 50 bool Save( void ); 51 bool Kill( void ); 52}; 53 54 55// 実行ファイルから使えるようにする関数群。 56// これらを使用して間接的に操作する。 57 58FUNCTION_DEFINITION 59IExcel* CreateExcelInstance( bool bVisible ){ 60 try{ 61 return new CExcel( bVisible ); 62 }catch( int e ){ 63 return NULL; 64 } 65} 66 67FUNCTION_DEFINITION 68void DestroyExcelInstance( IExcel* pExcel ){ 69 delete pExcel; 70} 71 72FUNCTION_DEFINITION 73bool OpenExcelFile( IExcel* pExcel, const char *ExcelFilePath ){ 74 return pExcel->Open( ExcelFilePath ); 75} 76 77FUNCTION_DEFINITION 78bool KillExcel( IExcel* pExcel ){ 79 return pExcel->Kill(); 80} 81 82FUNCTION_DEFINITION 83bool WriteExcel( IExcel* pExcel, long nSheet, long nRow, long nCol, const char *data ){ 84 return pExcel->Write( nSheet, nRow, nCol, data ); 85} 86 87FUNCTION_DEFINITION 88bool ReadExcel( IExcel* pExcel, long nSheet, long nRow, long nCol, char *result ){ 89 return pExcel->Read( nSheet, nRow, nCol, result ); 90} 91 92 93FUNCTION_DEFINITION 94bool SaveExcelFile( IExcel* pExcel ){ 95 return pExcel->Save(); 96} 97

のようにしています。

たとえば、

シート1 をデータベースのように ( 疑似データベース ) して

"A11" セルから開始するとします。

( A1~ A10 ぐらいまでは タイトルや 情報等を載せるとして。 )

名前 - ふりがな - 年齢 - 住所 - 電話番号 - ... - 備考

のようにあって、

データベースのようにするので、追加されたりするので最大行数はすぐにはわからないとします。

この場合、このC/C++の実行ファイルから追加・削除等をするとするならいいですが、

Excelに直接入れるときもあるとします。

その場合、最大行数がわからないので 追加できません。

大阪太郎 - おおさかたろう - 20歳 - 大阪府(略) - ...
東京二郎 - とうきょうじろう - 21歳 - 東京都(略) - ...
京都三郎 - きょうとさぶろう - 22歳 - 京都府(略) - ...

と三件あったら、

A11 から開始しているとしているので、

大阪太郎 = A11, 東京二郎 = A12, 京都三郎 = A13

となり、

最大行数: 13

と返ってくるようにしたいのです。

( できれば最大列数も。 )

以前質問したときの回答では

C++

1// 先ほどあったクラス CExcel のメンバ関数とする 2long CExcel::CountRow( long nSheet, long nCol ){ 3 long row = -1; 4 5 //ワークシート内で使用されているセル範囲を取得 6 Excel::RangePtr pRange = Work_sheet->UsedRange; 7 8 //セル範囲の行数を取得 9 row = pRange->Count; // 方法1 10 11 //セル範囲の列数を取得 12 // row = pRange->Count; 13 14 row = pRange->End[Excel::xlDown]->Row; // 方法2 15return row; 16} 17

のようなやり方を教えていただきました。

しかし、自宅に帰ってやってみると

方法1 でやると戻り値が 234

方法2 をコメントアウトし、方法1 で試すと 戻り値が long max = 234

方法1 をコメントアウトし、方法2 でやると 戻り値 が long max = 11

となってしまいます。

方法2が近いと思うのですが、A11から開始し A13 までは埋まっているので 13 が返ってくるのを期待していたのですが...

期待している戻り値: 13

for文で開始行から 適当に最大値 3000 までの行を Readメンバ関数 ( CExcel::Read ) で 読み取り、
読み取れなかった場合、break でループを抜けて戻り値として返す。

というやり方を思いついたのでやってみたところ、方法1 と同じになってしまいました。

どうすれば最大行数を取得できるのでしょうか?

[環境等]
言語 : C/C++
コンパイラ : VC++2010 Express ( DLL側 ), MinGW ( 実行ファイル側 )
Excelバージョン: Excel 2007
知りたいこと : C/C++から Excel操作するときに 指定シートの ( なんらかのデータが書き込まれている ) セルの「最大行数」と「最大列数」の求め方

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

UserRangeプロパティは値だけでなく、書式が設定されていても使用済みとして認識してしまうようですので、期待した結果になりません。
また、End(方向)では空白セルがあると、そこでカウントをやめてしまうようです。

なので、CurrentRegionを使ってみてはいかがでしょうか?空白行と空白列で囲まれた範囲(Rangeオブジェクト)を返すプロパティですが、この範囲が示す一番右下のセルの行番号・列番号を取得するというやり方です。

VBAで書くとこんな感じです

VBA

1 Dim maxrow As Integer 2 Dim maxcol As Integer 3 With Range("A11").CurrentRegion 4 maxrow = .Cells(.Rows.Count, .Columns.Count).Row 5 maxcol = .Cells(.Rows.Count, .Columns.Count).Column 6 End With

追加(2017/01/20)
C++で書く場合、COMを扱ういろいろ方法があるのはご存じだと思いますが、私が最近MFC経由でしか使っていませんでしたので、MFCで書かせていただきます。(ビルドしてないので、ちゃんと動くかわかりませんが、ニュアンスをつかんでもらえれば)。

C++

1 CVariant varOption((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 2 CRange range(pWorksheet.get_Range("A11", varOption)); 3 CRange Current(Range.get_CurrentRegion()); 4 CRange Rows(Current.get_Rows()); 5 CRange Columns(Current.get_Columns()); 6 int rowsCount = Rows.get_Count(); 7 int columnsCount = Columns.get_Count(); 8 CRange maxCell (Current.get_Range(rowsCount, columnsCount)); 9 int maxrow = maxCell.get_row(); 10 int maxcol = maxCell.get_Column();

本来でしたら、エラーチェックとか厳密にしないといけないのですが、ちょっと見づらくなりますので省いています。また、MFCでのラッパークラスでは、ExcelのプロパティであるCellsやRows、ColumnsはすべてRangeとして扱うので、上記のような書き方になります。

投稿2017/01/10 03:56

編集2017/01/20 09:57
KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2017/01/10 08:27

今外出先で手元に試せるものがないので、チェックしてみます。
BeatStar

2017/01/20 04:16

すみませんが、C/C++でのコード例を書いて頂けませんか? COM使い慣れていなくて推測すらできないです。 "CurrentRegion" で検索してみても使い方までは書いていなかったので。 お願い致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問