VC++からExcel,Wordを操作したかった
以下、昔の記事です。
僕は開発屋という仕事をしている。今のところVBとVCの狭間をあっちへ行ったり、こっちへ行ったりという風に仕事をしていた。(最近でこそVCの方に落ち着いてきたが)
VBとVCの間を行き来してて思ったのは、当然といえば当然なのだが、VBの適用範囲の狭さである。
例えば、スレッドがない、名前付けパイプがない、メールスロットがない、などなど。
VBでもやろうと思えばできないことはないのだが、結局API関数をDECLAREしなきゃいけない。つまり、Win32SDKの力を借りなければ何もできないのである。
だが、VBにはそれを補って余りある使い勝手のよさがある。最近ではDirectXへの対応もできていると聞いた。
今後もVBはすたれることはないだろう。
ただ、VBでできることはVCで全て出来るという考えが僕にはあった。
・・・しかし、僕の頭を長年にわたって支配し続けるものが一つあった。
Excel,Wordの制御である。
MicrosoftOfficeを代表する2大ソフトExcel,Wordの名前を聞いたことのないサラリーマンはいないと思う。
一太郎とWordがそのシェアを争っていたのはいつのことやら、他Officeファミリーとの親和性がWordが一太郎との距離を開け始め、いつの間にやら、コンピュータースクールで教材として取り上げられるNo1,No2ソフトとなってしまった。新規に事務系バイトを始めるにしても、Excel,Wordができると言うだけで人より抜きんでることができる。
それぐらいExcel,Wordは普及している。
VBとOfficeの親和性の高さはもはや自明の理でもある。
例えば、OfficeにはVBAというVBに準じた言語が存在する。このVBAはVBとほぼ同一のものであると言っても、過言ではない。
VBA上のコードをVBにそのまま移植しても動作可能であるし、逆もまた可である。
VBからExcelを操作する場合には以下のようなコードを使用する。
Set obj as New Excel.Application
または、
Dim obj as Excel.Application
Set obj = CreateObject("Excel.Application.8") ' Excel97の場合
または、
Dim obj as Excel.Workbook
Set obj = GetObject("c:tempsampl.xls")
っというところだろうか。
これらのことはVBのヘルプ上に記述されている。
しかし、VC++においては、Excelの操作方法はあまり具体的には書かれていない。
ちなみにMicrosoftのサポート技術情報には以下のように書かれている。
[MSVC] MFC で Excel の OLE オートメーション を使用するには
AppWizard を使用し OLE オートメーション を ON にしてアプリケーションを新規作成します。
ClassWizard で Excel の OLB ファイルを使って COleDispatchDriver から派生させた Application クラスを自動作成させます。
コーディング例
void CEeeeDlg::OnButton1() { Application MyExcel; // ClassWizard と Excel の OLB ファイル // で作成したクラス COleVariant variant; // VARIANT 型 MyExcel.CreateDispatch("Excel.Application.5"); // 接続 variant.ChangeType(VT_NULL); MyExcel.Help(variant,variant); // Excel の機能の Help AfxMessageBox("一時停止"); MyExcel.Quit(); // Excel の機能の Quit MyExcel.ReleaseDispatch(); // 切断 } |
悪いが、これでは実際にCellにデータを設定するにはどうすればいいか、などということは全く分からない。
さらに付け加えると、このままではExcel97を操作することはできない。カンの鋭い方ならお気づきだと思うが、"Excel.Application.5"はExcel95用のクラス名称である。
話を先に進めよう。結論から言うと、以下のような記述でExcelの操作が可能になる。
Excelに"HELLO!!"と表示するコードだ。
少々長いのがたまにキズだが、我慢してほしい。
1.AppWizard を使用し OLE オートメーション を ON にしてアプリケーションを新規作成する。
2.ClassWizard で Excel の OLB ファイルを使って COleDispatchDriver から派生させた クラスApplication,Workbook,Workbookを自動作成させる。
ただし、正しいOLBファイルを選択する必要がある。Excel97の場合はexcel8.olbのはず。
コーディング例
_Application Xlap; Workbooks Xlbks; _Workbook Xlbk; Sheets Xlsts; _Worksheet Xlst; Range Xlcells; Range Xlcell; CLSID clsid; LPDISPATCH pDisp; LPUNKNOWN pUnk; COleVariant varnull; // Applicationオブジェクトの取得 ::CLSIDFromProgID(L"Excel.Application.8", &clsid); if(::GetActiveObject(clsid, NULL, &pUnk) == S_OK) { // 既にExcelが起動されている場合 pUnk>QueryInterface(IID_IDispatch, (void**) &pDisp ); Xlap.AttachDispatch(pDisp); } else { Xlap.CreateDispatch("Excel.Application.8"); } // Workbooksオブジェクトの取得 Xlbks.AttachDispatch( Xlap.GetWorkbooks()); // Workbookオブジェクトの取得 // Workbookは.xlsファイルに相当する。 varnull.ChangeType(VT_NULL); Xlbk.AttachDispatch(Xlbks.Add(varnull)); // Sheetsオブジェクトの設定 Xlsts.AttachDispatch(Xlbk.GetWorksheets()); // Worksheetオブジェクトの取得 // この場合は一つ目のシート Xlst.AttachDispatch(Xlsts.GetItem(COleVariant*1; // Cel(Row=1, Cel=2)を取得 Xlcel.AttachDispatch(Xlcells.GetItem2(COleVariant*2; となる。 とりあえず、上記のような方法でExcelの操作が可能になる。(ただしExcel97)。 あとは応用だ。Wordもほぼ似たような感じだと思って間違いない。 多分、インターネットでもそれほど扱われていない内容だと思う。掲載されていない内容だからこそ散々苦労した。 OLEの本で調べる?値段が高いよ、あの手の本は。 もし、「ここにも掲載されていたよ」という情報があるならば、ご一報願いたい。 少なくとも、僕は見たことがない。 *1:long) 1, VT_I4))); *2:long) 1, VT_I4), COleVariant((long) 2, VT_I4))); |
また、Xlcells.GetItem2という定義されていない部分が出てきたと思う。
これは、クラスRangeに、Range::GetItemを少々いじった以下のような関数を加える必要がある。
LPDISPATCH Range::GetItem2(const VARIANT& RowIndex, const VARIANT& ColumnIndex) { LPDISPATCH result; static BYTE parms[] = VTS_VARIANT VTS_VARIANT; InvokeHelper(0xaa, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result, parms, &RowIndex, &ColumnIndex); return result; } |
Ragne::GetItemと比較してもらえれば分かると思うが、VT_VARIANTの部分がVT_DISPATCHに変わっている。
VBにおいては、
Dim app as New Excel.Application
Dim obj as Object
Set obj = app.GetWorkbooks
みたいな書き方があるが、VC++(というかMFC)においては、
ap as _Application ;
bks as Workbooks ;
ap.CreateDispatch("Excel.Application.8");
bks.AttachDispatch(ap.GetWorkbooks(