あらかたと申します
現在COMの勉強中です
http://homepage1.nifty.com/MADIA/vb/vb_ ... 30011.html
を自分なりにC++のコードに書き直してみました。
int main() {
CoInitialize(0);
IShellFolderViewDual2 *fid=NULL;
Folder *fldr;
FolderItems *fis;
CoCreateInstance(CLSID_ShellFolderView,NULL,CLSCTX_INPROC_SERVER,IID_IShellFolderViewDual2,(LPVOID *)&fld);
fld->get_Folder(&fldr); //←ここでfldrがNULLになります ・・・・・・・・・☆
fldr->Items(&fis);
FolderItem *fi;
VARIANT vr;
VariantInit( &vr );
vr.vt = VT_UI4;
vr.uintVal = 0;
fis->Item(vr,&fi);
BSTR buf;
fi->get_Path(&buf);
fi->Release();
fis->Release();
fldr->Release();
fld->Release();
CoUninitialize();
return 0;
}
ここで質問がいくつかあります。
1.なぜ☆の行でNULLになるのか?
2.これだとひとつのフォルダパスしか取得できない(と思っています)が参考ページの
For Each O In CreateObject("Shell.Application").Windows
はどうやるのでしょうか?
その他、このコードよりも効率的な方法があれば教えてください。よろしくお願いします
C++でエクスプローラを開いている時、そのパスを取得したい。
Re: C++でエクスプローラを開いている時、そのパスを取得したい。
再びすみません。開発環境書き忘れていました
OS:XP 32bit
IDE:Visual Studio 2008
あとコード貼り付けの規約を見落としていました。
OS:XP 32bit
IDE:Visual Studio 2008
あとコード貼り付けの規約を見落としていました。
int main() {
CoInitialize(0);
IShellFolderViewDual2 *fid=NULL;
Folder *fldr;
FolderItems *fis;
CoCreateInstance(CLSID_ShellFolderView,NULL,CLSCTX_INPROC_SERVER,IID_IShellFolderViewDual2,(LPVOID *)&fld);
fld->get_Folder(&fldr); //←ここでfldrがNULLになります ・・・・・・・・・☆
fldr->Items(&fis);
FolderItem *fi;
VARIANT vr;
VariantInit( &vr );
vr.vt = VT_UI4;
vr.uintVal = 0;
fis->Item(vr,&fi);
BSTR buf;
fi->get_Path(&buf);
fi->Release();
fis->Release();
fldr->Release();
fld->Release();
CoUninitialize();
return 0;
}
Re: C++でエクスプローラを開いている時、そのパスを取得したい。
色々調べながら書いて見ました。以下のページを参考にしています。
戻り値によるエラー判定はコードが読みにくくなるので、エラーハンドリングで例外を使うようにアレンジしています。
http://www.sol.dti.ne.jp/~yoshinor/ni/ni0003.html
私も完全に理解しているわけではないので、正しいかどうかは怪しいですが、コードの説明をすると、
はじめに、IShellWindowsのインスタンスを作成します。(これで、シェルが管理しているウインドウが得られる?)
Countプロパティを取得し、ウインドウの数を得る。
Itemメソッドにより、InternetExplorerオブジェクトが得られるらしい。
IEオブジェクトのLocationURLプロパティでエクスプローラーのパスが得られる。
(ちなみに、ブラウザのIEで何らかのページを開いているときは、そのURLも表示されました。)
なお、以下のコードはVC2010で作成したものなので、コンパイルできないなどの問題がありましたら言ってください。
戻り値によるエラー判定はコードが読みにくくなるので、エラーハンドリングで例外を使うようにアレンジしています。
http://www.sol.dti.ne.jp/~yoshinor/ni/ni0003.html
私も完全に理解しているわけではないので、正しいかどうかは怪しいですが、コードの説明をすると、
はじめに、IShellWindowsのインスタンスを作成します。(これで、シェルが管理しているウインドウが得られる?)
Countプロパティを取得し、ウインドウの数を得る。
Itemメソッドにより、InternetExplorerオブジェクトが得られるらしい。
IEオブジェクトのLocationURLプロパティでエクスプローラーのパスが得られる。
(ちなみに、ブラウザのIEで何らかのページを開いているときは、そのURLも表示されました。)
なお、以下のコードはVC2010で作成したものなので、コンパイルできないなどの問題がありましたら言ってください。
#pragma comment(lib, "comsuppw.lib")
#include <Windows.h>
#include <ShlObj.h>
#include <comutil.h> // _variant_t
#include <iostream>
#include <vector>
#include <exception>
// メンバー名からディスパッチIDを得る
DISPID GetIDOfName(IDispatch *object, OLECHAR *member)
{
DISPID id;
if (FAILED(object->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_USER_DEFAULT, &id))) {
throw std::exception("failed: GetIDOfName");
}
return id;
}
// プロパティを取得
_variant_t GetProperty(IDispatch *object, OLECHAR *member)
{
DISPID id = GetIDOfName(object, member);
DISPPARAMS params = {NULL, NULL, 0, 0};
VARIANT result;
if (FAILED(object->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &result, NULL, NULL))) {
throw std::exception("failed: GetProperty");
}
return _variant_t(result);
}
// メソッドを呼ぶ
_variant_t CallMethod(IDispatch *object, OLECHAR *method, std::vector<_variant_t> &args)
{
DISPID id = GetIDOfName(object, method);
// DISPPARAMS の設定
DISPPARAMS params = {NULL, NULL, 0, 0};
if (!args.empty()) {
params.rgvarg = &args[0];
params.cArgs = args.size();
}
VARIANT result;
if (FAILED(object->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL, NULL))) {
throw std::exception("failed: CallMethod");
}
return _variant_t(result);
}
// メソッドを呼ぶ(1引数バージョン)
_variant_t CallMethod(IDispatch *object, OLECHAR *method, _variant_t arg1)
{
std::vector<_variant_t> args;
args.push_back(arg1);
return CallMethod(object, method, args);
}
void main2()
{
IShellWindows *sw;
if (FAILED(CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&sw)))) {
throw std::exception("failed: CoCreateInstance");
}
// このコメントは処理のイメージ
// count = sw.Count;
long count = GetProperty(sw, L"Count");
for (long i = 0; i < count; ++i) {
// ie = sw.Item(i);
IDispatch *ie = CallMethod(sw, L"Item", _variant_t(i, VT_I4));
// url = ie.LocationURL;
_bstr_t url = GetProperty(ie, L"LocationURL");
std::wcout << url.GetBSTR() << std::endl;
}
sw->Release();
}
int main()
{
// 日本語表示のため
std::wcout.imbue(std::locale("japanese"));
CoInitialize(nullptr);
try {
main2();
} catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
CoUninitialize();
return 0;
}
Re: C++でエクスプローラを開いている時、そのパスを取得したい。
a5ua さん、誠にありがとうございます。
おかげ様で目的を果たせました。(しかもIEのURLも取得できるとは!)
IShellWindowsを使えばよかったのですね。
nullptrが定義されていない以外は問題なかったです。
IID_PPV_ARGSなど初見の文法もあり大変勉強になりました。
今後のためにもお聞きしたいのですが、
IShellWindowsに用意されているメソッドなどを直接呼び出さなかったのはなぜですか?
よろしければ返信ください
おかげ様で目的を果たせました。(しかもIEのURLも取得できるとは!)
IShellWindowsを使えばよかったのですね。
nullptrが定義されていない以外は問題なかったです。
IID_PPV_ARGSなど初見の文法もあり大変勉強になりました。
今後のためにもお聞きしたいのですが、
IShellWindowsに用意されているメソッドなどを直接呼び出さなかったのはなぜですか?
よろしければ返信ください
Re: C++でエクスプローラを開いている時、そのパスを取得したい。
もちろん、sw->get_Count(&count);のように直接呼んでもできます。あらかた さんが書きました: IShellWindowsに用意されているメソッドなどを直接呼び出さなかったのはなぜですか?
今回は、それ以降が、すべてIDispatchインターフェースを通した操作になっているので、統一してみたという程度のものです。(IShellWindowsはIDispatchを継承している)
ところで、前述のInternetExplorerオブジェクトは、C++ではIWebBrowserインターフェースだと思われます。
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
IDispatch::QueryInterfaceなどで、インターフェースを取得すれば、直接プロパティの取得や、メソッド呼び出しができそうです。
- tk-xleader
- 記事: 158
- 登録日時: 13年前
- 連絡を取る:
Re: C++でエクスプローラを開いている時、そのパスを取得したい。
エクスプローラー限定ですが、全てメソッドの直接呼出しでエクスプローラの表示パスを得るとすると、おおよそこんなコードになります。
IPersistFolder2 インターフェイスが GetCurFolder メソッドを持っていて、これを使えばエクスプローラーが表示しているフォルダのPIDLが得られます。そしてPIDLさえ取得してしまえば、SHGetPathFromIDList API によってパス文字列に変換できます。
訂正 : デバッグ用の余計なコードを削除
#include<iostream>
#include<algorithm>
#include<windows.h>
#include<shlobj.h>
#include<shlwapi.h>
#ifdef UNICODE
#define tcout wcout
#else
#define tcout cout
#endif
namespace my{
/**
COM用のスマートポインタテンプレートクラス
即席なので穴だらけ…
*/
template<typename T>
class com_ptr{
T* ptr;
public:
com_ptr():ptr(NULL){}
explicit com_ptr(T* ptr_):ptr(_ptr){
ptr->AddRef();
}
com_ptr(const com_ptr<T>& obj):ptr(obj.ptr){
if(ptr)ptr->AddRef();
}
template<typename U>
com_ptr(const com_ptr<U>& other):ptr(NULL){
if(other->QueryInterface(ptr) != S_OK){
ptr = NULL;
}
}
~com_ptr(){
this->release();
}
com_ptr& operator=(com_ptr other){
this->swap(other);
return *this;
}
void swap(com_ptr<T>& other)throw(){
std::swap(this->ptr,other.ptr);
}
void release(){
if(ptr){
ptr->Release();
ptr = NULL;
}
}
bool operator==(const com_ptr&other){
return this->ptr == other.ptr;
}
bool operator!=(const com_ptr&other){
return !((*this) == other);
}
T* get()const{return ptr;}
operator T*()const{return ptr;}
T& operator*()const{return *ptr;}
T* operator->()const{return ptr;}
T** resetptr(){
this->release();
return &ptr;
}
};
}
int main(){
std::wcout.imbue(std::locale(""));
my::com_ptr<::IShellWindows>shellWindows;
::CoInitialize(NULL);
if(FAILED(::CoCreateInstance(::CLSID_ShellWindows,NULL,CLSCTX_ALL,IID_PPV_ARGS(shellWindows.resetptr())))){
::CoUninitialize();
return -1;
}
long count;
shellWindows->get_Count(&count);
::VARIANT index = {};
index.vt = VT_I4;
index.lVal = 0;
for(; index.lVal < count; index.lVal++){
my::com_ptr<::IDispatch>pDispatch;
if(shellWindows->Item(index,pDispatch.resetptr()) != S_OK){
continue;
}
my::com_ptr<::IShellBrowser>pShellBrowser;
if(IUnknown_QueryService(pDispatch,SID_STopLevelBrowser,IID_PPV_ARGS(pShellBrowser.resetptr())) != S_OK){
continue;
}
my::com_ptr<::IShellView>pShellView;
pShellBrowser->QueryActiveShellView(pShellView.resetptr());
my::com_ptr<::IFolderView>pFolderView;
if(pShellView->QueryInterface(IID_PPV_ARGS(pFolderView.resetptr())) != S_OK){
continue;
}
my::com_ptr<::IShellFolder>pShellFolder;
if(pFolderView->GetFolder(IID_PPV_ARGS(pShellFolder.resetptr())) != S_OK){
continue;
}
my::com_ptr<::IPersistFolder2>pPersistFolder;
if(pShellFolder->QueryInterface(IID_PPV_ARGS(pPersistFolder.resetptr())) != S_OK){
continue;
}
::LPITEMIDLIST pidl;
pPersistFolder->GetCurFolder(&pidl);
TCHAR pathbuf[MAX_PATH+10] = {};
::SHGetPathFromIDList(pidl,pathbuf);
std::tcout<<pathbuf<<std::endl;
}
::CoUninitialize();
}
訂正 : デバッグ用の余計なコードを削除
- tk-xleader
- 記事: 158
- 登録日時: 13年前
- 連絡を取る:
Re: C++でエクスプローラを開いている時、そのパスを取得したい。
てかせっかくcom_ptrテンプレートに変換用コンストラクタがあるのだから、それを使わないと、何のために実装したのか?と言う話になりますね…
#include<iostream>
#include<algorithm>
#define NOMINMAX
#include<windows.h>
#include<shlobj.h>
#include<shlwapi.h>
#ifdef UNICODE
#define tcout wcout
#else
#define tcout cout
#endif
namespace my{
/**
COM用のスマートポインタテンプレートクラス
即製なので穴だらけ…
*/
template<typename T>
class com_ptr{
T* ptr;
public:
com_ptr():ptr(NULL){}
explicit com_ptr(T* ptr_):ptr(_ptr){
ptr->AddRef();
}
com_ptr(const com_ptr<T>& obj):ptr(obj.ptr){
if(ptr)ptr->AddRef();
}
template<typename U>
com_ptr(const com_ptr<U>& other):ptr(NULL){
if(other->QueryInterface(IID_PPV_ARGS(ptr)) != S_OK){
ptr = NULL;
}
}
~com_ptr(){
this->release();
}
com_ptr& operator=(com_ptr other){
this->swap(other);
return *this;
}
void swap(com_ptr<T>& other)throw(){
std::swap(this->ptr,other.ptr);
}
void release(){
if(ptr){
ptr->Release();
ptr = NULL;
}
}
bool operator==(const com_ptr&other){
return this->ptr == other.ptr;
}
bool operator!=(const com_ptr&other){
return !((*this) == other);
}
T* get(){return ptr;}
operator T*(){return ptr;}
bool operator!(){return !ptr;}
T& operator*()const{return *ptr;}
T* operator->()const{return ptr;}
T** resetptr(){
this->release();
return &ptr;
}
};
}
int main(){
std::wcout.imbue(std::locale(""));
my::com_ptr<::IShellWindows>shellWindows;
::CoInitialize(NULL);
if(FAILED(::CoCreateInstance(::CLSID_ShellWindows,NULL,CLSCTX_ALL,IID_PPV_ARGS(shellWindows.resetptr())))){
::CoUninitialize();
return -1;
}
long count;
shellWindows->get_Count(&count);
::VARIANT index = {};
index.vt = VT_I4;
index.lVal = 0;
for(; index.lVal < count; index.lVal++){
my::com_ptr<::IDispatch>pDispatch;
if(shellWindows->Item(index,pDispatch.resetptr()) != S_OK){
continue;
}
my::com_ptr<::IShellBrowser>pShellBrowser;
if(IUnknown_QueryService(pDispatch,SID_STopLevelBrowser,IID_PPV_ARGS(pShellBrowser.resetptr())) != S_OK){
continue;
}
my::com_ptr<::IShellView>pShellView;
pShellBrowser->QueryActiveShellView(pShellView.resetptr());
my::com_ptr<::IFolderView>pFolderView(pShellView);
if(!pFolderView){
continue;
}
my::com_ptr<::IShellFolder>pShellFolder;
if(pFolderView->GetFolder(IID_PPV_ARGS(pShellFolder.resetptr())) != S_OK){
continue;
}
my::com_ptr<::IPersistFolder2>pPersistFolder(pShellFolder);
if(!pPersistFolder){
continue;
}
::LPITEMIDLIST pidl;
pPersistFolder->GetCurFolder(&pidl);
TCHAR pathbuf[MAX_PATH+10] = {};
::SHGetPathFromIDList(pidl,pathbuf);
std::tcout<<pathbuf<<std::endl;
}
::CoUninitialize();
}
Re: C++でエクスプローラを開いている時、そのパスを取得したい。
a5ua さん、tkmakwins15さん
ありがとうございます。
それぞれ別の取得方法で参考になります。
この返信までには提示くださったコードなどを理解するつもりでしたが、
調べれば調べるほど様々なCOMオブジェクトが出てくるので整理が追いつきません。
理解できない部分が明確になってからまた質問したいと思います。
そのときはまたご教授ください。本当にありがとうございました。
ありがとうございます。
それぞれ別の取得方法で参考になります。
この返信までには提示くださったコードなどを理解するつもりでしたが、
調べれば調べるほど様々なCOMオブジェクトが出てくるので整理が追いつきません。
理解できない部分が明確になってからまた質問したいと思います。
そのときはまたご教授ください。本当にありがとうございました。