Visual Studio 2005 C++を利用しており、
実行ファイルからアプリ起動をしたいのですが、以下のソースでは起動しません。
関数が違うのでしょうか?
System::ApplicationIdentity(L"EXCEL.exe");
> System::ApplicationIdentity(L"EXCEL.exe");
何を参考にしていますか?
System::ApplicationIdentityクラスはアプリ起動用のクラスではないようですけど。
通常はProcess::Startメソッドを使うのかな。
http://msdn.microsoft.com/ja-jp/library/53ezey2s(VS.80).aspx
フルパスでないとだめだけど。
Blueさん
ありがとうございました。
System::Diagnostics::Process::Startで起動させることができました。
でもフルパスじゃないとダメなんですね。
アプリ(例.エクセル)の格納場所がユーザー毎に違う場合は、使用できないですね。う〜ん困った。。。
方法としてはいくつかあります。
ただしどれもExcelの場合です。
インストール情報をどこかに入れないと、いくらなんでもフルパスなしでは起動できません。
(環境変数に入れれば別だけど。自作アプリなら同じフォルダに入れておくとか?)
1.拡張子の関連付け情報からフルパスを取得する。(レジストリをたどる)
2.レジストリからインストールパスを取得する。(バージョンが違うと面倒かな。)
3.タイプライブラリを使って起動する。
(#importせず、IDispatch::GetIDsOfNamesを駆使するとバージョンを気にせずにすむ。
ただし、かなり難易度は高い。またC++/CLIだとさらに面倒。)
他にもあるかな。。。
試したことないからわかりませんが、APIのShellExecute関数で"Excel.exe"のみで起動できませんかね?
ShellExecute(NULL, "open", "Excel.exe", NULL, NULL, SW_SHOWNORMAL);
みたいな感じ?
ちょっといい加減ですみません>_<
ShellExecuteでもパスが通ってないと開けないでしょう。
拡張子に関連づいているファイルであればShellExecuteで開けるでしょうけど。
(ShellExcute(NULL, "open", "XXX.xls" ・・・みたいに)
1の方法を
http://dobon.net/vb/dotnet/system/findassociatedexe.html
より記述してみました。
bool GetShellAppPath(System::String^% path, System::String^ ext)
{
bool bResult = false;
if ((ext != nullptr) && (ext->Length > 0))
{
if (ext[0] != L'.') {
ext = ext->Insert(0, L".");
}
Microsoft::Win32::RegistryKey^ regKey =
Microsoft::Win32::Registry::ClassesRoot->OpenSubKey(ext);
if (regKey != nullptr)
{
System::String^ fileType = static_cast<System::String^>(regKey->GetValue(L""));
regKey->Close();
regKey =
Microsoft::Win32::Registry::ClassesRoot->OpenSubKey(System::String::Format(L"{0}\\\\shell\\\\open\\\\command", fileType));
if (regKey != nullptr)
{
System::String^ command = static_cast<System::String^>(regKey->GetValue(L""));
regKey->Close();
command = command->Trim();
int index;
// "xxxx\xx xxx\xxx.exe" %1 形式の場合
if (command->IndexOf(L'"') == 0)
{
index = command->IndexOf(L'"', 1);
if (index > 0)
{
path = command->Substring(1, index - 1);
bResult = true;
}
}
// xxxx\xxxxx\xxx.exe %1 形式の場合
else
{
index = command->IndexOf(L' ', 0);
if (index > 0) {
path = command->Substring(0, index);
}
else {
path = command;
}
bResult = true;
}
}
}
}
return bResult;
}
使用例
String^ path;
if (GetShellAppPath(path, L"xls")) {
MessageBox::Show(path);
}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
以下にキーがあれば、ShellExecute()でも行けるかも知れません。
試したことはありませんが。
もっとも、ソレに期待するのもどうか…というのはありますが。
# スタートメニューの「ファイル名を指定して実行」は行けた。
# コマンドプロンプトからは不可。(環境変数pathには無いので当然か?)
# コマンドプロンプトからでも、start excel.exeなら行けた。
レジストリから引っ張るくらいなら
AssocQueryString
でいいのでは?↓こんなん。
#include <shlwapi.h> //AssocQueryString
#pragma comment(lib, "shlwapi.lib")
〜・・・〜
char path[MAX_PATH + 1] = {0};
DWORD size = MAX_PATH;
HRESULT const hr = ::AssocQueryStringA(
ASSOCF_NOTRUNCATE, ASSOCSTR_EXECUTABLE, "c:\\dummy.xls", "open", path, &size);
if ( SUCCEEDED(hr) && size > 0 ){
//パス取得OK、ShellExecute()でもCreateProcessでもお好みで。
}else{
//Excelがインストールされてないか、もしくは関連付け情報が消されたor上書きされた
}
必要環境も今なら問題ないでしょ。たぶん。
> Windows 2000, Windows NT 4.0 with Internet Explorer 5, Windows 98, Windows 95 with Internet Explorer 5
みなさん、ありがとうございます。
System::Diagnostics::Process::Start("excel.exe");
でエクセル起動はできました。
エクセル起動はできたのですが、マクロ起動って、""内にどういう記述をすればよいのでしょうか?
よろしくお願いします。m(__)m
>エクセル起動はできたのですが、マクロ起動って、""内にどういう記述をすればよいのでしょうか?
Process::Startでは無理です。
適当なファイルを用意して、Openイベントとかに記述するか、
やはりタイプライブラリを使うしかないです。
(Excelのバージョンに依存せずに記述するのは至難の業。
ちょっとやそっとではできない。→掲示板で質問してどうにかなるものではない。)
# というかExcelとかマクロが記述されるアプリ限定になってきているのでは?
自分だったら、別途vbsファイルを用意する手で逃げるかも。
>AssocQueryStringA
は知りませんでした。
結局Excelのマクロを実行、ってのが目的?
なら最初からそう書けばBlueさんの回答で終わってたのに。
タイプライブラリを使った方法までやる気があるなら↓かな。
http://www.ujasiri.com/prglib/vc/excel/vc_excel.html
そのものズバリのサンプルもある。
Excelのバージョンを選ばずにってのは無理。
少なくともサポート対象のバージョンは全部テストが必要。
C++/CLIの場合、タイプライブラリを扱う上で注意しないといけない点があります。
http://forums.microsoft.com/msdn-ja/ShowPost.aspx?PostID=2651529&SiteID=7
>Excelのバージョンを選ばずにってのは無理。
IDispatch::GetIDsOfNamesを使えばある程度は依存せずに書けると思います。
参考)http://support.microsoft.com/default.aspx/kb/216686/ja
まぁテストは必須ですが。
vbsでやるなら、ScriptControlで直接スクリプト実行って手もありです。
void ExecuteVBScript(System::String^ statement)
{
Type^ t = Type::GetTypeFromProgID("MSScriptControl.ScriptControl");
Object^ obj = Activator::CreateInstance(t);
try {
t->InvokeMember(
"Language", System::Reflection::BindingFlags::SetProperty,
nullptr, obj, gcnew array<Object^>{"vbscript"});
t->InvokeMember(
"ExecuteStatement", System::Reflection::BindingFlags::InvokeMethod,
nullptr, obj, gcnew array<Object^>{statement});
}
finally {
System::Runtime::InteropServices::Marshal::ReleaseComObject(obj);
}
}
使用例
String^ statement = "Dim excel\n"
"Set excel = CreateObject(\"Excel.Application\")\n"
"excel.Visible = True\n"
"excel.Workbooks.Open \"c:\\test.xls\"\n"
"excel.Run \"macro\"\n";
ExecuteVBScript(statement);
対象のエクセルファイルを開いてマクロを自動実行したいのであれば、Excel
のマクロ側で行うのはダメなのでしょうか?
確かWorkbook_Openあたりだったかな・・・
後は、そのExcelファイルを開くだけ(関連付けされているのが前提で良ければ
ShellExecuteでも可能かと)
状況に合わせて実行するマクロを変えたいのであれば、皆さんの言うとおりVBS
を使った方がいいかもしれませんね。
みなさん
ありがとうございます。
対象のエクセルファイルを開いてエクセル側でマクロを実行するようにいたします。
ツイート | ![]() |