Mesoscopic Programming

タコさんプログラミング専門

VC++のフィルター設定とかめんどくさいので

04/25 補助用のツールを作りました。
05/02 UNICODE 対応にしました。
05/04 ログ機能強化とフォルダ構成の変更を行いました。

main.h

//----------------------------------------------------------------------------
/// @file    main.h
/// @brief   VCプロジェクトファイルメーカーヘッダ
/// @details VCプロジェクトファイルメーカーです。
//----------------------------------------------------------------------------
/// @mainpage VCプロジェクトファイルメーカー
///
/// @section 概要
///          VCプロジェクトファイルを作成します。
///
/// @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   VCプロジェクトファイルメーカー
/// @details VCプロジェクトファイルメーカーです。
//----------------------------------------------------------------------------

#include "main.h"
#include <TLogStream.h>
#include <locale.h>
#include <codecvt>
#include <conio.h>

//----------------------------------------------------------------------------
// 名前空間使用宣言
//----------------------------------------------------------------------------

using namespace std;
using namespace Common;

//----------------------------------------------------------------------------
// ローカル変数
//----------------------------------------------------------------------------

/// アイテムグループ出力タイプ
enum enumItemType
{
    ITEM_FILTER,       ///< フィルターファイル用のフィルターアイテムグループ
    ITEM_FILTER_FILE,  ///< フィルターファイル用のファイルアイテムグループ
    ITEM_PROJECT_FILE, ///< プロジェクトファイル用のファイルアイテムグループ
};

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] item   アイテムタイプ
/// @param   [in] subdir サブディレクトリ
/// @param   [in] depth  ディレクトリ深さ
/// @return  なし
/// @details ディレクトリを出力します。
static void OutputDirectory( int item, const wchar_t * subdir = 0, size_t depth = 0 )
{
    LogOut().Begin( __func__ );
    LogOut().Data ( "item  ", item );
    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 );

            // アイテムの種類を調べます。
            if ( item == ITEM_FILTER )
            {
                if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
                {
                    * pout << L"    <Filter Include=\"" << ( path + len ) << L"\" />" << endl;
                }
            }
            else if ( item == ITEM_FILTER_FILE )
            {
                if ( ! ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
                {
                    if ( subdir )
                    {
                        * pout << L"    <None Include=\"" << ( path + len ) << L"\">" << endl;
                        * pout << L"      <Filter>" << subdir << L"</Filter>" << endl;
                        * pout << L"    </None>" << endl;
                    }
                    else
                    {
                        * pout << L"    <None Include=\"" << ( path + len ) << L"\" />" << endl;
                    }
                }
            }
            else if ( item == ITEM_PROJECT_FILE )
            {
                if ( ! ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
                {
                    * pout << L"    <None Include=\"" << ( path + len ) << L"\" />" << endl;
                }
            }

            // サブディレクトリでかつリパースポイントでないか調べます。
            if ( ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) && ! ( data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) )
            {
                // サブディレクトリを出力します。
                OutputDirectory( item, 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 ( "≪VCプロジェクトファイルメーカー≫" );

    cout << "≪VCプロジェクトファイルメーカー≫" << 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"以下のテキストを \"~.vcxproj.filters\" にコピーしてください。" << endl;
        * pout << L"~ここから~" << endl;
        * pout << L"<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl;
        * pout << L"<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">" << endl;
        * pout << L"  <ItemGroup>" << endl;

        // フィルターグループを出力します。
        OutputDirectory( ITEM_FILTER );

        * pout << L"  </ItemGroup>" << endl;

        // ファイルグループを出力します。
        * pout << L"  <ItemGroup>" << endl;

        OutputDirectory( ITEM_FILTER_FILE );

        * pout << L"  </ItemGroup>" << endl;
        * pout << L"</Project>" << endl;
        * pout << L"~ここまで~" << endl;

        // プロジェクトファイル用のテキストを出力します。
        * pout << endl << L"以下のテキストを \"~.vcxproj\" の適当な場所に挿入してください。" << endl;
        * pout << L"~ここから~" << endl;
        * pout << L"  <ItemGroup>" << endl;

        // ファイルグループを出力します。
        OutputDirectory( ITEM_PROJECT_FILE );

        * pout << L"  </ItemGroup>" << endl;
        * pout << L"~ここまで~" << endl;

        // 出力ストリームを削除します。
        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 です。
共通ライブラリ
VCプロジェクトファイルメーカー

以上です。