none
VS2015/_MBCSで_splitpath()で文字列「表」が処理中の_ISMBBLEAD()がコメントで\マーク扱いになる

    質問

  • いつもお世話になっております。

    VS2015UD2で作業しています。

    以前VS2010で_MBCSにて、_splitpath()→_tsplitpath_helper()→_FUNC_NAME()の流れのなかで文字列「表」が文字化けせずにいたのですが、VS2015では_splitpath()→common_splitpath_internal()内で下記のようにコメントされてしまっています。

    仕様変更でしょうか?_MBCSにて実現するに、何か方法がございますでしょうか?

    ...\Windows Kits\10\Source\10.0.10586.0\ucrt\filesystem\splitpath.cpp Line:48
    
    
    template <typename Character, typename ResetPolicy, typename BufferCountTransformer>
    static errno_t __cdecl common_splitpath_internal(
        Character const*              const path,
        component_buffers<Character>* const components,
        ResetPolicy                   const reset_buffer,
        BufferCountTransformer        const transform_buffer_count
        ) throw()
    
    {
    ...
        for (; *p != '\0'; ++p)
        {
            // CRT_REFACTOR TODO Multibyte support
            // if (_ISMBBLEAD(*p))
            // {
            //     ++p;
            // }
            // else
            if (*p == '/' || *p == '\\')
            {
                last_slash = p + 1; // Point one past for later copy
            }
            else if (*p == '.')
            {
                last_dot = p;
            }
        }
    ...
    }

    初歩的なところではないかと思いますが、どうぞご教示の程、宜しくお願いいたします。

    2016年5月23日 8:52

回答

  • マルチバイトのパス的には不具合といえるかも知れませんね。。

    対症療法的ですが、下記の回避方法が思いつきました。

    1.分解時にパスをマルチバイト→UNICODEに変換し、_wsplitpathで分解後、分解された文字列をUNICODE→マルチバイトへ変換する。

    2.上記の_splitpathのコードを参考に自分で分解する。

    3.#include <filesystem>のtr2::sys::pathを使って分解する。

    4.Shlwapi.libのAPI、PathFindExtension、PathFindFileName、Path*** などを使って分解する。
    • 編集済み kenjinoteMVP 2016年5月23日 10:12
    • 回答としてマーク SHIN109 2016年5月24日 2:59
    2016年5月23日 10:08

すべての返信

  • まぁコメントの通りかと。修正せずにリリースしたということは、対応する気があまりない、と。

    修正要求すれば対応してくれるのかもしれませんが…ビジネスインパクトを確認されるかも?

    2016年5月23日 9:11
  • マルチバイトのパス的には不具合といえるかも知れませんね。。

    対症療法的ですが、下記の回避方法が思いつきました。

    1.分解時にパスをマルチバイト→UNICODEに変換し、_wsplitpathで分解後、分解された文字列をUNICODE→マルチバイトへ変換する。

    2.上記の_splitpathのコードを参考に自分で分解する。

    3.#include <filesystem>のtr2::sys::pathを使って分解する。

    4.Shlwapi.libのAPI、PathFindExtension、PathFindFileName、Path*** などを使って分解する。
    • 編集済み kenjinoteMVP 2016年5月23日 10:12
    • 回答としてマーク SHIN109 2016年5月24日 2:59
    2016年5月23日 10:08
  • 佐祐理 様、kenjinote 様

    レスありがとうございました。

    やはりですね。
    おっしゃるとおりマルチバイトの_splitpath()なので戻してほしいなと思います。
    ビジネスインパクトを問われると報告しづらくなってきますね。


    回避方法いただきましてありがとうございます。一番目にて下記のように回避しました。

    	//_splitpath(szBufPath, drive,dir,fname,ext);
    	setlocale(LC_ALL, "Japanese");
    	wchar_t wszBufPath[_MAX_PATH], wdrive[_MAX_DRIVE], wdir[_MAX_DIR], wfname[_MAX_FNAME], wext[_MAX_EXT];
    
    	mbstowcs(wszBufPath, szBufPath, strlen(szBufPath) + 1);
    	_wsplitpath(wszBufPath, wdrive, wdir, wfname, wext);
    	wcstombs(drive, wdrive, _MAX_DRIVE);
    	wcstombs(dir, wdir, _MAX_DIR);
    	wcstombs(fname, wfname, _MAX_FNAME);
    	wcstombs(ext, wext, _MAX_EXT);
    


    ご教示ありがとうございました。
    kenjinote様のご回答を「回答としてマーク」させていただきます。

    ありがとうございました。

    2016年5月24日 2:50
  • 一旦閉じましたが、同様案件の現象がありました。

    CFileDialogのGetNextPathName()の返す文字列についてもファイル複数選択の際、ファイル名に「表」や「能」などの0x5cの関係が含まれている場合、フルパスが戻されないという現象が発生しました。VS2010では戻っています。
    以下のtsplitpath_s()にてその箇所がありました。

    tsplitpath_s()も_splitpath()に通るなりしているのではと思うのですが、もうUnicode前提ということにも感じますが、いかがでしょうか?

    どうぞ宜しくお願いいたします。


    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\dlgfile.cpp(1012):CString CFileDialog::GetNextPathName(POSITION& pos) const

    CString CFileDialog::GetNextPathName(POSITION& pos) const
    {
    ...
    
    	CString strBasePath = m_ofn.lpstrFile;
    	if (!bExplorer)
    	{
    		LPTSTR lpszPath = m_ofn.lpstrFile;
    		while(*lpszPath != chDelimiter)
    			lpszPath = _tcsinc(lpszPath);
    		strBasePath = strBasePath.Left(int(lpszPath - m_ofn.lpstrFile));
    	}
    
    	LPTSTR lpszFileName = lpsz;
    	CString strFileName = lpsz;
    
    ...
    
    	TCHAR strDrive[_MAX_DRIVE], strDir[_MAX_DIR], strName[_MAX_FNAME], strExt[_MAX_EXT];
     //<========
    	Checked::tsplitpath_s(strFileName, strDrive, _MAX_DRIVE, strDir, _MAX_DIR, strName, _MAX_FNAME, strExt, _MAX_EXT);
    	TCHAR strPath[_MAX_PATH];
    	if (*strDrive || *strDir)
    	{ //<========ここへ入る
    		Checked::tcscpy_s(strPath, _countof(strPath), strFileName);
    	}
    	else
    	{
    		if ((strBasePath.GetLength() != 3) || (strBasePath[1] != ':') || (strBasePath[2] != '\\'))
    		{
    			strBasePath += _T("\\");
    		}
    		Checked::tsplitpath_s(strBasePath, strDrive, _MAX_DRIVE, strDir, _MAX_DIR, NULL, 0, NULL, 0);
    		Checked::tmakepath_s(strPath, _MAX_PATH, strDrive, strDir, strName, strExt);
    	}
    	
    	return strPath;
    }

    2016年5月26日 1:17
  • だから最初の私のコメント通りなのでは?

    MSはTODOコメントを残したまま正式リリースすることを決めた。動かないのは意図通りかと。VS2013までは動作していたので、degrade、regressionである旨を伝えたら修正に応じるかもしれません。

    2016年5月26日 21:05
  • Connect に上げてみました。
    https://connect.microsoft.com/VisualStudio/feedback/details/2751258/splitpath-for-mbcs-is-broken-in-vc2015

    あくまで急ぎではない不具合を報告する場所なので、緊急性が高い場合は、Microsoft の有償サポートを利用することとなっています。

    現状においては、過去資産を引き継いだ案件であれば、VC2015 への移行を取りやめるのが保守的な対応かと思います。
    新作であれば Unicode 文字セットを考えてもらった方が良いでしょう。マルチバイト文字セットでは Unicode 文字を含むファイルパスを扱えませんから。

    2016年5月26日 22:09
    モデレータ
  • 佐祐理 様、Azulean 様

    レスありがとうございます。
    やはりおっしゃるとおりですね。すみません、ありがとうございました。

    Azulean 様にはフィードバックにも挙げていただき、ありがとうございました。

    修正も待ってみたいと思います。
    ご丁寧にご教示いただき、ありがとうございました。

    2016年5月27日 1:08
  • 修正も待ってみたいと思います。

    念のために書いておきますが、Connect は不具合報告の場所となりますが、修正を強く求められる場所ではありません。
    修正しないといった判断から、次のアップデート(数ヶ月後?)、次のメジャーバージョン(数ヶ月~1年後ぐらい?)といった判断もあり得ます。
    「今開発しているソフトウェアに間に合うか」と考えると、多くの場合は「間に合わない」ことが多い報告方法だと捉えてください。

    VC2013 以前に戻れる備え(リスクヘッジ)をしている、あるいはすでに戻っていて修正が来たら 2015 に再移行するという対応であれば、「待つ」という判断はありかもしれません。

    2016年5月27日 13:53
    モデレータ
  • Azulean 様

    レスありがとうございます。

    はい。恐れ入ります。ありがとうございます。
    時期は不明な点、心得ております。ありがとうございます。

    どうもOFN_ALLOWMULTISELECTで複数個選択時に2つ目以降のファイル名で現象発生するみたいでしたので、正しいかどうか判りませんが、一応呼出し全部をクラスをオーバーライドしたものに取り換えて、その中でGetNextPathName()もオーバーライドしてパスを調整することで回避することにしました。

    ありがとうございました。

    2016年5月28日 1:05