エクセルのハイパーリンクを作るやつ
04/26 フォルダの中身をエクセルのハイパーリンクにするやつを作りました。
05/02 UNICODE対応にしたので記事を更新しました。
05/04 ログ機能強化とフォルダ構成の変更を行いました。
main.h
//---------------------------------------------------------------------------- /// @file main.h /// @brief エクセルハイパーリンクメーカーヘッダ /// @details エクセルハイパーリンクメーカーです。 //---------------------------------------------------------------------------- /// @mainpage エクセルハイパーリンクメーカー /// /// @section 概要 /// エクセルハイパーリンクを作成します。 /// /// @section history 履歴 /// - 2015/05/01 開発を開始しました。 /// - 2015/05/02 ワイド文字のファイル名が開けない問題が分かったのでワイド文字対応にしました。 /// - 2015/05/03 ログ出力を改良しました。 /// /// @version 0.2.1 /// @date 2015/05/03 /// @author Copyright (C) 2015 hidakas1961 All rights reserved. //---------------------------------------------------------------------------- #pragma once //---------------------------------------------------------------------------- // グローバル関数 //---------------------------------------------------------------------------- /// @brief ワイド文字メイン関数 /// @param [in] argc コマンドライン引数の個数 /// @param [in] argv コマンドライン引数の文字列配列 /// @return 終了コード /// @details ワイド文字(Unicode?)バージョンのメイン関数です。 int wmain( int argc, wchar_t * argv[] );
main.cpp
//----------------------------------------------------------------------------
/// @file main.cpp
/// @brief エクセルハイパーリンクメーカー
/// @details エクセルハイパーリンクメーカーです。
//----------------------------------------------------------------------------
#include "main.h"
#include <TLogStream.h>
#include <locale.h>
#include <codecvt>
#include <conio.h>
//----------------------------------------------------------------------------
// 名前空間使用宣言
//----------------------------------------------------------------------------
using namespace std;
using namespace Common;
//----------------------------------------------------------------------------
// ローカル変数
//----------------------------------------------------------------------------
static const size_t maxpath = 1024; ///< フルパス最大文字数
static const size_t maxdepth = 100; ///< 最大ディレクトリ深さ
static bool hidden = false; ///< 非表示ファイル許可フラグ
static bool sysfile = false; ///< システムファイル許可フラグ
static wofstream * pfout = 0; ///< ファイル出力ストリームポインタ
static wostream * pout = 0; ///< 出力ストリームポインタ
static size_t count = 0; ///< リンク数カウンタ
static wchar_t root[ maxpath ]; ///< 入力ディレクトリ名
static bool nexts[ maxdepth ]; ///< 次ファイル有無フラグテーブル
//----------------------------------------------------------------------------
// ローカル関数
//----------------------------------------------------------------------------
/// @brief ファイルスキップ判定関数
/// @param [in] data ファイル検索データ
/// @return なし
/// @details ファイルをスキップするか判定します。
static bool IsSkip( WIN32_FIND_DATAW & data )
{
LogOut().Begin( __func__ );
LogOut().Hex ( "data ", data );
bool result = false;
if ( ! wcscmp( data.cFileName, L"." ) || ! wcscmp( data.cFileName, L".." ) )
{
result = true;
}
else if ( data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN )
{
result = ! hidden;
}
else if ( data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM )
{
result = ! sysfile;
}
LogOut().Data( "result", result );
LogOut().End ( __func__ );
return result;
}
/// @brief 属性情報出力関数
/// @param [in] path パス
/// @param [in] pdata ファイル検索データポインタ
/// @return なし
/// @details 属性情報を出力します。
static void OutputAttributes( const wchar_t * path, WIN32_FIND_DATAW * pdata = 0 )
{
LogOut().Begin( __func__ );
LogOut().Data ( "path", path );
// ファイル属性を取得します。
DWORD attr;
if ( pdata )
{
// ファイル検索データからファイル属性を取得します。
attr = pdata->dwFileAttributes;
}
else
{
// ファイルパスからファイル属性を取得します。
attr = GetFileAttributesW( path );
}
if ( attr != static_cast< DWORD >( -1 ) )
{
// ディレクトリでないか調べます。
if ( ! ( attr & FILE_ATTRIBUTE_DIRECTORY ) )
{
// 拡張子を取得します。
wchar_t ext[ _MAX_EXT ];
_wsplitpath_s( path, 0, 0, 0, 0, 0, 0, ext, _MAX_EXT );
if ( ext[ 0 ] == L'.' )
{
* pout << ( ext + 1 );
}
else
{
* pout << L"なし";
}
}
}
* pout << L"\t";
LogOut().End( __func__ );
}
/// @brief インデント出力関数
/// @param [in] depth ディレクトリ深さ
/// @return なし
/// @details インデントを出力します。
static void OutputIndent( size_t depth )
{
LogOut().Begin( __func__ );
LogOut().Data ( "depth", depth );
// ディレクトリ深さを巡回します。
for ( size_t i = 0; i < depth; i++ )
{
// ディレクトリ深さを調べます。
if ( i == depth - 1 )
{
// 次のファイル有無フラグを調べます。
if ( nexts[ i ] )
{
* pout << L"├";
}
else
{
* pout << L"└";
}
}
// 次のファイル有無フラグを調べます。
else if ( nexts[ i ] )
{
* pout << L"│";
}
* pout << L"\t";
}
LogOut().End( __func__ );
}
/// @brief ハイパーリンク式出力関数
/// @param [in] path パス
/// @param [in] name 表示名
/// @return なし
/// @details ハイパーリンク式を出力します。
static void OutputHyperLink( const wchar_t * path, const wchar_t * name )
{
LogOut().Begin( __func__ );
LogOut().Data ( "path ", path );
LogOut().Data ( "name ", name );
LogOut().Data ( "count", count++ );
* pout << L"=HYPERLINK(\"" << path << L"\",\"" << name << L"\")" << endl;
LogOut().End( __func__ );
}
/// @brief ディレクトリ出力関数
/// @param [in] subdir サブディレクトリ
/// @param [in] depth ディレクトリ深さ
/// @return なし
/// @details ディレクトリを出力します。
static void OutputDirectory( const wchar_t * subdir = 0, size_t depth = 0 )
{
LogOut().Begin( __func__ );
LogOut().Data ( "subdir", subdir );
LogOut().Data ( "depth ", depth );
// 開始ディレクトリをコピーします。
wchar_t path[ maxpath ];
wcscpy_s( path, root );
size_t len = wcslen( path );
if ( path[ len - 1 ] != '\\' )
{
wcscat_s( path, L"\\" );
len++;
}
// サブディレクトリを追加します。
size_t len2 = len;
if ( subdir )
{
wcscat_s( path, subdir );
len2 = wcslen( path );
if ( path[ len2 - 1 ] != '\\' )
{
wcscat_s( path, L"\\" );
len2++;
}
}
// ワイルドカードを追加します。
wcscat_s( path, L"*.*" );
// ファイルを検索します。
WIN32_FIND_DATAW data, next;
HANDLE handle = FindFirstFileW( path, & data );
if ( handle != INVALID_HANDLE_VALUE )
{
// 先頭ファイルを検索します。
bool result;
while ( ( result = FindNextFileW( handle, & data ) != FALSE ) && IsSkip( data ) );
// 検索ファイルを巡回します。
for ( ; result; data = next )
{
// 次のファイルを検索します。
while ( ( result = FindNextFileW( handle, & next ) != FALSE ) && IsSkip( next ) );
// 次のファイル有無テーブルを設定します。
nexts[ depth ] = result;
// パスを作成します。
path[ len2 ] = '\0';
wcscat_s( path, data.cFileName );
// 属性情報を出力します。
OutputAttributes( path, & data );
// インデントを出力します。
OutputIndent( depth + 1 );
// ハイパーリンク式を出力します。
OutputHyperLink( path, data.cFileName );
// サブディレクトリでかつリパースポイントでないか調べます。
if ( ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) && ! ( data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) )
{
// サブディレクトリを出力します。
OutputDirectory( path + len, depth + 1 );
}
}
FindClose( handle );
}
LogOut().End( __func__ );
}
//----------------------------------------------------------------------------
// グローバル関数
//----------------------------------------------------------------------------
// ワイド文字メイン関数
int wmain( int argc, wchar_t * argv[] )
{
#ifdef _LOGFILE
// ログファイルを作成します。
CreateLog( _LOGFILE );
#endif // _LOGFILE
LogOut().Begin( __func__ );
// ロケールを設定します。
setlocale( LC_ALL, "Japanese" );
// タイトルを表示します。
LogOut().Line ( "≪エクセルハイパーリンクメーカー≫" );
cout << "≪エクセルハイパーリンクメーカー≫" << endl << endl;
bool error = false; ///< エラーフラグ
const wchar_t * dirname = 0; ///< ディレクトリ名
const wchar_t * outfile = 0; ///< 出力ファイル名
// コマンドライン引数を巡回します。
for ( int i = 1; i < argc; i++ )
{
// オプションスイッチか調べます。
if ( argv[ i ][ 0 ] == '-' )
{
// オプションスイッチの種類を調べます。
if ( ! wcscmp( argv[ i ] + 1, L"o" ) )
{
// 出力ファイル名を設定します。
if ( ! outfile )
{
if ( i + 1 < argc && argv[ i + 1 ][ 0 ] != '-' )
{
outfile = argv[ ++i ];
}
else
{
error = true;
cout << endl << "出力ファイル名がありません。" << endl;
wcout << L"\"" << argv[ i ] << L"\"" << endl;
break;
}
}
else
{
error = true;
cout << endl << "出力パスオプションが重複しています。" << endl;
wcout << L"\"" << argv[ i ] << L"\"" << endl;
break;
}
}
else if ( ! wcscmp( argv[ i ] + 1, L"hidden" ) )
{
// 非表示ファイル許可フラグをセットします。
if ( ! hidden )
{
hidden = true;
wcout << L"\"" << argv[ i ] << L"\" : 非表示ファイル許可" << endl;
}
else
{
error = true;
cout << endl << "非表示ファイル許可オプションが重複しています。" << endl;
wcout << L"\"" << argv[ i ] << L"\"" << endl;
break;
}
}
else if ( ! wcscmp( argv[ i ] + 1, L"system" ) )
{
// システムファイル許可フラグをセットします。
if ( ! sysfile )
{
sysfile = true;
wcout << L"\"" << argv[ i ] << L"\" : システムファイル許可" << endl;
}
else
{
error = true;
cout << endl << "システムファイル許可オプションが重複しています。" << endl;
wcout << L"\"" << argv[ i ] << L"\"" << endl;
break;
}
}
else
{
error = true;
cout << endl << "不明なオプションです。" << endl;
wcout << L"\"" << argv[ i ] << L"\"" << endl;
break;
}
}
// ディレクトリ名を調べます。
else if ( ! dirname )
{
// ディレクトリ名を設定します。
dirname = argv[ i ];
}
else
{
error = true;
cout << endl << "余分な引数です。" << endl;
wcout << L"\"" << argv[ i ] << L"\"" << endl;
break;
}
}
// エラーフラグを調べます。
while ( ! error )
{
// ディレクトリ名を調べます。
if ( ! dirname )
{
// カレントディレクトリを設定します。
dirname = L".";
}
// 入力ディレクトリ名のフルパスを取得します。
if ( GetFullPathNameW( dirname, maxpath, root, 0 ) )
{
wcout << L"入力ディレクトリ : \"" << root << L"\"" << endl;
// 入力ディレクトリが存在するか調べます。
DWORD attr = GetFileAttributesW( root );
if ( attr != static_cast< DWORD >( -1 ) )
{
// ディレクトリか調べます。
if ( attr & FILE_ATTRIBUTE_DIRECTORY )
{
// 出力ファイル名を調べます。
if ( outfile )
{
// フルパスを取得します。
wchar_t path[ maxpath ];
if ( GetFullPathNameW( outfile, maxpath, path, 0 ) )
{
wcout << L"出力ファイル名 : \"" << path << L"\"" << endl;
// 出力パスがディレクトリ名でないか調べます。
DWORD attr = GetFileAttributesW( path );
if ( attr != static_cast< DWORD >( -1 ) )
{
if ( attr & FILE_ATTRIBUTE_DIRECTORY )
{
error = true;
cout << endl << "出力ファイル名はディレクトリです。" << endl;
break;
}
}
// ファイル出力ストリームを作成します。
pfout = new wofstream( path, ios::binary );
// 出力モードを設定します。
pfout->imbue( locale( locale(""), new codecvt_utf16< wchar_t, 0x10ffff, static_cast< codecvt_mode >( generate_header | little_endian ) >() ) );
// 出力ストリームポインタを設定します。
pout = pfout;
}
else
{
error = true;
cout << endl << "不正なファイル名です。" << endl;
break;
}
}
else
{
// 出力ストリームポインタを設定します。
pout = & wcout;
}
}
else
{
error = true;
cout << endl << "ディレクトリではありません。" << endl;
break;
}
}
else
{
error = true;
cout << endl << "入力ディレクトリが存在しません。" << endl;
break;
}
}
else
{
error = true;
cout << endl << "不正なディレクトリ名です。" << endl;
break;
}
// タイトル行を出力します。
* pout << L"拡張子\tパス" << endl;
// 開始ディレクトリの属性情報を出力します。
OutputAttributes( root );
// 開始ディレクトリのインデントを出力します。
OutputIndent( 0 );
// 開始ディレクトリのハイパーリンクを出力します。
OutputHyperLink( root, root );
// サブディレクトリを出力します。
OutputDirectory();
// 出力ストリームを削除します。
if ( pfout )
{
pfout->close();
delete pfout;
}
cout << endl << "正常に終了しました。" << endl;
break;
}
#ifdef _DEBUG
// キー入力を要求します。
cout << endl << "何か押してください。" << endl;
_getch();
#endif // _DEBUG
LogOut().End( __func__ );
return 0;
}
ソースコード
以下のプロジェクトをソリューションに追加してビルドしてください。
開発環境は Windows Vista VC++ 2010 Express です。
共通ライブラリ
Excelハイパーリンクメーカー
以上です。