COM上でRangeをCellsで使うには。

[戻る]
初心者 2014/02/02(日) 16:10:37
前回質問させて頂いて、解決させていただいたものです。その時はありがとうございま
した。

環境:VC++2008EE Windows vist,-7にてCOMにてExcelを使うソフトを作ってい
ます。(Excelをデータベースとして利用)

(以下のpWorksheetや、pRangeはIDispatchです。)
大体できたのですが、改良を加えて(加えさせられて)います。
Excelシートを読むときの範囲指定にpWorksheet, L"Range"として var.vt=VT_BSTR;   
var.bstrVal="A20:c30"としていますが、これをVBAでいう、Range(Cells(i,j).Address
():Cells(k,l).Address())のようにするか、もしくは、直接Cellsを使って範囲指定した
いのですが、どなたかご存知の方教えてください。
ちなみにpWorksheet, L"Cells"としてvar.vt=VT_BSTR;   var.bstrVal="20,1"
にてpRangeを取得した(間違い?)と思って、pRange、L"Resize"を実行するとえらーに
なります。どうしてもRangeとCellsが関連付けできません。教えてください。

初心者 2014/02/03(月) 01:12:58
方法は見つかりました。

以下は、Range(Cells(10,8).Address():Cells(20,20).Address())
[ Range(H10:j20) ]の例です。
IDispatch *pWoksheetでL"Cells"をvar.bstrVal = L"0,8"にてInvoke一回実施。
これでC(カラム)方向がIDispatchにて還ります。("H=8"が還る。)
これを例えば、IDispatch *pArea = varResult.pdispValとします。

そしてpAreaにて再度L"Cells"をvar.bstrVal = L"0,10"にてInvoke実施するとR(row)方
向が還り、Cells(10,8)が作成されます。

pAreaをL"Address"にてInvoke実施すると、varResult.bstrValに"$H$10"が還ってきてま
す。

次は次の"20:20"ですが、同じことを繰り返すと、varResult.bstrValに"$J$20"が還って
きてます。

これを文字列の結合で"$H$10:$j$20"を作成して"Range"のvar.bstrVal=エリア
とすれば、うまくいくのですが・・・・・・

もっと簡単な方法があるような気がして・・・・
どなたかご存じなしでしょうか。

蒼の洞窟 2014/02/03(月) 10:40:10
Cellsで一発で目的のアドレスのRangeをとるには
引数として、列番号と行番号を渡す必要があります。

>>Range(Cells(i,j).Address():Cells(k,l).Address())
なら、Resizeプロパティを使ったほうが楽かもしれません。

列数をi→k、行数をj→lにするので単純に引き算した値をRisizeに渡せばいいです。

VARIANT varIndex[2];
VariantInit(&varIndex[0]);
varIndex[0].vt = VT_I4;
varIndex[0].lVal = 1; // 列番号
VariantInit(&varIndex[1]);
varIndex[1].vt = VT_I4;
varIndex[1].lVal = 1; // 行番号
VariantInit(&varResult);
Invoke(pWorksheet, L"Cells", DISPATCH_PROPERTYGET, varIndex, 2, &varResult);
pRange = varResult.pdispVal;

VariantInit(&varResult);
Invoke(pRange, L"Address", DISPATCH_PROPERTYGET, NULL, 0, &varResult);
BSTR bstrAddress = SysAllocString(varResult.bstrVal);

// bstrAddress : $A$1

SysFreeString(bstrAddress);

VARIANT varSize[2];
VariantInit(&varSize[0]);
varSize[0].vt = VT_I4;
varSize[0].lVal = 5; // 5列増やす→A,B,C,D,E
VariantInit(&varSize[1]);
varSize[1].vt = VT_I4;
varSize[1].lVal = 3; // 3行増やす→1,2,3
VariantInit(&varResult);
Invoke(pRange, L"Resize", DISPATCH_PROPERTYGET, varSize, 2, &varResult);
IDispatch* pRange2 = varResult.pdispVal;

VariantInit(&varResult);
Invoke(pRange2, L"Address", DISPATCH_PROPERTYGET, NULL, 0, &varResult);
bstrAddress = SysAllocString(varResult.bstrVal);

// bstrAddress : $A$1:$E$3

SysFreeString(bstrAddress);

pRange2->Release();

初心者 2014/02/03(月) 12:05:25
蒼の洞窟さん、今回もありがとうございます。今日は時間がないので、今夜試してみます
。
教えていただいた、オブジェクトブラウザやOleView.exeにておおよその方向性がわかる
ようになりました。ただ、戻り値がわからないので試行錯誤の連続です。

ところで、この前のHyperlinksのことで、もう少し教えてください。このまえのだと、
Rangeの範囲でリンクのみをまとめたリストで帰ってくるのですが、、リンクがないセル
はNULLなどでリストを埋めたリスト、つまりRangeの行数と戻りのリストが同じ数
といったようなことはできないのでしょうか。
すみません、甘えた質問で・・・

蒼の洞窟 2014/02/03(月) 13:25:09
そんな便利な関数はないので自作してください。
HyperlinkオブジェクトからRangeオブジェクトがとれるのでそこから
ColumnプロパティとRowプロパティでセルの位置がわかります。

Rangeオブジェクトを1セルずつループしてHyperlinks→Hyperlinkと取得したほうが
やりやすいかもね。

というか、左上のセルとその横何列、下何行ってわかっていれば、Offset使って
ループしたほうがいいかな。

初心者 2014/02/03(月) 21:21:22
[[解決]]
蒼の洞窟さん、いつも親切な回答ありがとうございます。
本当に感謝いたします。

@:RangeとCellsの件
最初の私の考え方(sheet→Cells→Renge→Resize)があっていたことにびっくりやら、方
向性が間違っていなかったこと安心やら、まあ、驚きました。蒼の洞窟さんに教えてい
ただいた、オブジェクトブラウザやOleView.exeのおかげです。(i,j)の情報入力の方法
が間違っていたのですね。この記入方法はSAFEARRAYへのアクセス方法に似ているな〜〜
と思いました。(COMっていうかInvoke関係の手法なんでしょうか・・・)

A:Hyperlinksの件
甘えた質問にも親切な回答、大変ありがとうございます。
私もSAFEARRAY的な挑戦(試行錯誤)をしてみましたが、全てエラーで・・・・
今は、Rangeオブジェクトを1セルずつループにてListViewに落としています。
教えていただいた、『HyperlinkオブジェクトからRangeオブジェクト・・・』や
『Offset』を試してみて今のソフトにあったものを見つけます。

本当にありがとうございました。(御礼!)

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