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

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

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

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

Q&A

解決済

2回答

3354閲覧

c++でのGetCellDataについて

beginner101

総合スコア18

C++

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

0グッド

0クリップ

投稿2018/12/25 06:01

編集2018/12/25 06:44

前提・実現したいこと

Com初心者です。
現在cellからデータを取り出すコードを書いている途中で、
参考にと渡されたコードがあるのですが、
どういった処理を行っているのかいまいちわかっていないことと、
Variantを使用していますが、VariantInit()やVariantClear()がありません。
これって解放されていることになってるのでしょうか。

該当のソースコード

.h void GetCellData(const char* sc,const char* ec,CStringArray &dt,bool formula = false); void GetCellData(int cols,int rows,int cole,int rowe,CStringArray &dt,bool formula = false); CExcelCtrl(); virtual ~CExcelCtrl(); _Application m_excel; .cpp CExcelCtrl::CExcelCtrl() { CoInitialize(NULL); } CExcelCtrl::~CExcelCtrl() { CoUninitialize(); } void CExcelCtrl::GetCellData(int cols,int rows,int cole,int rowe,CStringArray &dt,bool formula) { CString sc,ec; sc.Format("%s%d",Num2Col(cols),rows); ec.Format("%s%d",Num2Col(cole),rowe); GetCellData(sc,ec,dt,formula); } void CExcelCtrl::GetCellData(const char* sc,const char* ec,CStringArray &dt,bool formula) { try{ _Worksheet ws = m_excel.GetActiveSheet(); Range range = ws.GetRange(COleVariant(sc),COleVariant(ec)); COleVariant data; if(formula) data = range.GetFormula(); else data = range.GetValue(vtMissing); COleSafeArray sa; sa.Attach(data); long rowmax,colmax; sa.GetUBound(1,&rowmax); sa.GetUBound(2,&colmax); CString str; VARIANT val; long idx[2]; dt.RemoveAll(); for(long row = 1;row <= rowmax;row++){ idx[0] = row; for(long col = 1;col <= colmax;col++){ idx[1] = col; sa.GetElement(idx,&val); switch(val.vt){ case VT_R8: str.Format("%1.2f", val.dblVal); break; case VT_BSTR: str.Format("%s",(CString)val.bstrVal); ::SysFreeString(val.bstrVal); break; case VT_EMPTY: str.Empty(); break; } dt.Add(str); } } }catch(COleDispatchException *e){ AfxMessageBox(e->m_strDescription,MB_ICONEXCLAMATION); dt.RemoveAll(); } }

補足情報(FW/ツールのバージョンなど)

windows10/64bit
visual studio 2017

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

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

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

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

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

guest

回答2

0

ベストアンサー

Variantを使用していますが、VariantInit()やVariantClear()がありません。
これって解放されていることになってるのでしょうか。

この辺はC++とマイクロソフトのMFC(Microsoft Foundation Class)と言うものをある程度理解しないと分かりづらいのですが、C言語で生でCOMを扱う際のVARIANT型などをC++のクラスでラップしたCOleVariantクラス
COleSafeArray クラスがあり、これらクラスのメソッドであるClear等に隠されています。
ご提示のコードは一見そのClearメソッドすら見えないのでアレレ?となってしまいますが、これらクラスのデストラクター内でも呼ばれていたりして、クラスのインスタンスが破棄されるときに適切に呼び出されます。

ご提示のコードの場合はautoでCOleSafeArray saを宣言したのち、sa.Attach(data)で実体が当てはめられ、そのインスタンス変数のスコープの終わりでデストラクトされる際にClearが呼ばれます。MFCはVisual Studio のバージョンにもよりますがソースコードが提供されています。Visual Studio を適切にインストールした後でデバッグ時にトレースするとそのコードに行き当たりますので、実際に追ってみるとよいです。C言語でのCOMプログラミングの参考にもなります。例えばCOleSafeArrayクラスですと、デバッグでのトレース時に下図のように行き当たります。

イメージ説明
COMは(もともと難解な上に)最近ではCやC++を使ったサンプルや情報が少ないので大変かもしれませんが、がんばってください。

投稿2018/12/25 07:05

dodox86

総合スコア9183

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

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

beginner101

2018/12/25 07:19

ご回答ありがとうございます。 なるほど別のところに用意されていて、書いて無くても大丈夫だったのですか。 ここら辺が理解できなかったので、助かりました。
guest

0

vt含めた各メンバは sa.GetElement(で適切に代入されているはずなのでVariantInit()VariantClear()は不要と思われます。
なお、配列操作部分のコードは基本的にColesafearray::getelementのサンプルコードと同一のようです。
一点気になるのはVT_BSTRの場合に::SysFreeStringが必要かどうですが、ヘルプのコードには記載されていませんね。
VARIANT型を知ってみるVARIANT型を使ってみるによるとBSTR型の場合は必要そうに思えますが、元のCOleSafeArray内部で解放しているので不要なのかもしれません。

投稿2018/12/25 07:05

can110

総合スコア38256

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

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

beginner101

2018/12/25 07:22

ご回答ありがとうございます。 サンプルコードの提示もありがたいです。(ここを参考にしたのがわかりました。) 一旦SysFreeStringを抜きにして、解放されているか確かめてみます。
beginner101

2018/12/26 04:03

そこを削除したらメモリリークが発生しました。 何故か分かりますでしょうか。
can110

2018/12/26 04:33

すみません。明確な理由は分かりません。 ということは、ヘルプサンプルでもメモリーリーク発生するということでしょうか?
atata0319

2018/12/26 04:45

これはサンプルの不具合ですね。この場合は明示的にSysFreeStringが必要になります。内部で使用されているAPIのSafeArrayGetElementは格納されている値のコピーを返します。APIのサンプルでは適切に解放するコードになっていますね。
beginner101

2018/12/26 05:09

ご回答ありがとうございます。 なるほど解放に必要なコードがサンプルに無いんですね。 このままコードで試したらメモリは解放されていたので、bstrを使用する場合、 SysFreeStringは必要と覚えておきます。
can110

2018/12/26 05:25 編集

atata0319さん、コメント&情報ありがとうございます。 あらら、サンプルの不具合なんですね… ちなみにですが、SafeArrayGetElement利用のAPIサンプルの公開URLをもしご存知でしたら教えていただけないでしょうか? SysFreeStringが必要である根拠なり(サンプルコード)が知りたいのですが、ネット上では http://forums.codeguru.com/showthread.php?157122-SafeArrayGetElement-problem しかヒットしませんでした。
can110

2018/12/26 06:10

> ~すべてVariantClearで解放していますが~ なるほど。VariantClearとSysFreeStringの関係に気づけませんでした。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問