ページ 11

ショートカットの作成

Posted: 2015年2月20日(金) 11:52
by yosuke.25_u
こちらの記事を参考にして、ショートカットを作るプログラムを作成したのですがエラーがでます。

http://dixq.net/forum/viewtopic.php?f=3&t=6193

やりたい事は、キーボードから入力された文字列を型に格納し、「https://www.google.co.jp/search?q=」のあとに付けたショートカットの作成です
ですが以下のコードを実行すると、TEXTの部分で ";"が必要です とエラーがでてきます。

どうすればいいのでしょうか。
また、このプログラムではデスクトップかスタートメニューにしかショートカットが作成できませんが、指定したパスに作成するにはどうすればいいのでしょうか。


#define _CRT_SECURE_NO_WARNINGS
#include <shlobj.h>
#include <iostream>
using namespace std;

int main(void)
{

char A;//型の宣言
cin >> A;//型に格納

LPCTSTR programPath = TEXT("https://www.google.co.jp/search?q=" A); // URL&A
wchar_t linkPath[MAX_PATH]; // ショートカット名はユニコード限定

// デスクトップフォルダ取得(デスクトップかスタートメニューにしか作れない)
LPITEMIDLIST pidl;
SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &pidl);
SHGetPathFromIDListW(pidl, linkPath);
wcscat(linkPath, L"\\URL.lnk");

IShellLink* sl;
IPersistFile* pf;
CoInitialize(NULL); // COMライブラリを初期化
if (CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&sl) == S_OK)
{
if (sl->QueryInterface(IID_IPersistFile,(void **)&pf) == S_OK)
{
sl->SetPath(programPath); // プログラムパス
sl->SetDescription(NULL); // 説明(= ツールチップス)
sl->SetArguments(NULL); // コマンドライン引数
sl->SetWorkingDirectory(NULL); // 作業ディレクトリ
sl->SetIconLocation(NULL, 0); // Iconのパスまたはインデックス
sl->SetShowCmd(SW_SHOWNORMAL); // 起動時のウィンドウ表示
pf->Save(linkPath, TRUE); // ショートカットを保存
pf->Release(); // IPersistFileへのポインタを破棄
pf = NULL;
}
sl->Release(); // IShellLinkへのポインタを破棄
sl = NULL;
}
CoUninitialize (); // COMライブラリをクローズ
return 0;
}

まだ始めて一ヶ月ちょっとですので、詳しい説明やコードがあると助かります。

Re: ショートカットの作成

Posted: 2015年2月20日(金) 13:33
by みけCAT
コードはBBcodeを有効にした状態でcodeタグで囲み、かつ適切なインデントをしていただけると、見やすくて助かります。
yosuke.25_u さんが書きました:やりたい事は、キーボードから入力された文字列を型に格納し、「https://www.google.co.jp/search?q=」のあとに付けたショートカットの作成です
ですが以下のコードを実行すると、TEXTの部分で ";"が必要です とエラーがでてきます。

どうすればいいのでしょうか。
言語が明示されていないようですが、cinが利用されていることなどからC++と仮定します。
  • C++はawkと違い、文字列を並べただけでは結合できません。
  • char型は1文字(1バイト?)しか格納できないので、一般の「文字列」は格納できません。
とりあえずこちらの環境で動くようにしてみました。

コード:

#define _CRT_SECURE_NO_WARNINGS
#include <shlobj.h>
#include <iostream>
#include <string>
using namespace std;

int main(void)
{

	string A;//型の宣言
	getline(cin, A);//型に格納

	string programPathData = string("https://www.google.co.jp/search?q=") + A;
	const char* programPath = programPathData.c_str(); // URL&A
	wchar_t linkPath[MAX_PATH]; // ショートカット名はユニコード限定

	// デスクトップフォルダ取得(デスクトップかスタートメニューにしか作れない)
	LPITEMIDLIST pidl;
	SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &pidl);
	SHGetPathFromIDListW(pidl, linkPath);
	wcscat(linkPath, L"\\URL.lnk");

	IShellLinkA* sl;
	IPersistFile* pf;
	CoInitialize(NULL); // COMライブラリを初期化
	if (CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&sl) == S_OK)
	{
		if (sl->QueryInterface(IID_IPersistFile,(void **)&pf) == S_OK)
		{
			sl->SetPath(programPath); // プログラムパス
			sl->SetDescription(NULL); // 説明(= ツールチップス)
			sl->SetArguments(NULL); // コマンドライン引数
			sl->SetWorkingDirectory(NULL); // 作業ディレクトリ
			sl->SetIconLocation(NULL, 0); // Iconのパスまたはインデックス
			sl->SetShowCmd(SW_SHOWNORMAL); // 起動時のウィンドウ表示
			pf->Save(linkPath, TRUE); // ショートカットを保存
			pf->Release(); // IPersistFileへのポインタを破棄
			pf = NULL;
		}
		sl->Release(); // IShellLinkへのポインタを破棄
		sl = NULL;
	}
	CoUninitialize(); // COMライブラリをクローズ
	return 0;
}

Re: ショートカットの作成

Posted: 2015年2月20日(金) 13:48
by みけCAT
yosuke.25_u さんが書きました:また、このプログラムではデスクトップかスタートメニューにしかショートカットが作成できませんが、指定したパスに作成するにはどうすればいいのでしょうか。
一旦デスクトップに作成し、MoveFileW()で移動するというのはどうでしょうか?

コード:

#define _CRT_SECURE_NO_WARNINGS
#include <shlobj.h>
#include <rpc.h>
#include <iostream>
#include <string>
using namespace std;

int main(void)
{

	string A;//型の宣言
	getline(cin, A);//型に格納

	string programPathData = string("https://www.google.co.jp/search?q=") + A;
	const char* programPath = programPathData.c_str(); // URL&A
	wchar_t linkPath[MAX_PATH]; // ショートカット名はユニコード限定

	// デスクトップフォルダ取得(デスクトップかスタートメニューにしか作れない)
	LPITEMIDLIST pidl;
	SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &pidl);
	SHGetPathFromIDListW(pidl, linkPath);
	// かぶりにくいように、UUIDでファイル名を決める
	UUID uuid;
	unsigned char *uuid_str;
	wchar_t uuid_unicode[64];
	UuidCreate(&uuid);
	UuidToStringA(&uuid, &uuid_str);
	if(MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (const char *)uuid_str, -1, uuid_unicode, sizeof(uuid_unicode)) == 0)
	{
		int code = GetLastError();
		cout << "MultiByteToWideChar() error code = " << code << endl;
		return 1;
	}
	RpcStringFreeA(&uuid_str);
	wcscat(linkPath, L"\\");
	wcscat(linkPath, uuid_unicode);
	wcscat(linkPath, L".lnk");

	// 本当にショートカットを作りたい場所
	const wchar_t *actualLinkPath = L"D:\\test.lnk";

	IShellLinkA* sl;
	IPersistFile* pf;
	CoInitialize(NULL); // COMライブラリを初期化
	if (CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&sl) == S_OK)
	{
		if (sl->QueryInterface(IID_IPersistFile,(void **)&pf) == S_OK)
		{
			sl->SetPath(programPath); // プログラムパス
			sl->SetDescription(NULL); // 説明(= ツールチップス)
			sl->SetArguments(NULL); // コマンドライン引数
			sl->SetWorkingDirectory(NULL); // 作業ディレクトリ
			sl->SetIconLocation(NULL, 0); // Iconのパスまたはインデックス
			sl->SetShowCmd(SW_SHOWNORMAL); // 起動時のウィンドウ表示
			pf->Save(linkPath, TRUE); // ショートカットを保存
			pf->Release(); // IPersistFileへのポインタを破棄
			pf = NULL;
		}
		sl->Release(); // IShellLinkへのポインタを破棄
		sl = NULL;
	}
	CoUninitialize(); // COMライブラリをクローズ

	// ショートカットを移動
	if (MoveFileW(linkPath, actualLinkPath) == 0)
	{
		int code = GetLastError();
		cout << "MoveFileW() failed code = " << code << endl;
		return 1;
	}
	return 0;
}
コンパイル方法

コード:

$ g++ -Wall -Wextra -s -static -o hoge.exe hoge.cpp -lole32 -luuid -lrpcrt4
参考サイト

Re: ショートカットの作成

Posted: 2015年2月20日(金) 22:33
by YuO
ちゃんとMSDNに当たりましょう。
MSDNには,シェルリンクを作成するためのコードがちゃんと記述されています。
オフトピック
lpszPathLinkの型がLPCWSTRではなくLPCSTRである点など,関数仕様に疑義はありますが
references) 最後のページに書かれているコードの,lpszPathLinkの引数型をLPCWSTRにし,MultiByteToWideCharで変換する部分を削り,main関数を追加して実行しましたが,普通にCSIDL_DESKTOP (CSIDL_DESKTOPDIRECTORY) や CSIDL_STARTMENU 以外にも作成できました。
というか,SHGetSpecialFolderLocation でわざわざデスクトップのIDListを取得して,そのIDListのディレクトリ名を取得し,そこへショートカットファイルの名前を追加しているプログラムですから,デスクトップに作成されるのは当然です。
# ちなみに,SHGetSpecialFolderPathでIDList経由せずにCSIDLから直接パスを取得できます。
任意フォルダのIDListはSHSimpleIDListFromPathで取得できますが,CSIDL使う関数群やSHSimpleIDListFromPathはDeprecatedなので,使う必要性がなければ使わないことが望ましいです。
SHGetFolderLocation等はSHGetKnownFolderIDList等で代替できますし。