Iwao Dev

気付いたことをメモしています.

この画面は、簡易表示です

MFC

MAPI の MapiFileDesc の配列

MFC を使用している方法では,

    LateDelete	ld ;    //  MultiByte の必要があるようなので,UNICODE の時のバッファをここに登録
    //	添付ファイルの準備
    CArray<:MapiFileDesc,MapiFileDesc>	fileDescA ;
    int	fileCount = 0 ;
    int	index = 0 ;
    for (index=0 ; index<PathNames.GetSize() ; index++) {
        CString	    pathName = PathNames[index] ;
        if (::FileIsNothing  (pathName))	{	continue ;	}
        if (::FileIsDirectory(pathName))	{	continue ;	}
        MapiFileDesc	fileDesc ;
        memset(&fileDesc,0,sizeof(MapiFileDesc)) ;
        fileDesc.nPosition		= (ULONG)-1 ;
    #ifdef	_UNICODE
        fileDesc.lpszPathName	= SendMail__ChangeMultiByte(PathNames[index],&ld) ;
        fileDesc.lpszFileName	= SendMail__ChangeMultiByte(FileNames[index],&ld) ;
    #else
        fileDesc.lpszPathName	= LPSTR(LPCTSTR(PathNames[index])) ;
        fileDesc.lpszFileName	= LPSTR(LPCTSTR(FileNames[index])) ;
    #endif
        fileDescA.Add(fileDesc) ;
        fileCount++ ;
        }

MFC を使用しないコードは,

    std::vector<MapiFileDesc>	fileDescA ;
    std::vector<std::string>	pathNameA ;
    std::vector<std::string>	fileNameA ;
    int	index = 0 ;
    {
        for (index=0 ; index<PathNames.GetSize() ; index++) {
            {
                tstring	pathName = PathNames[index] ;
                if (::File_IsNothing  (pathName))	{	continue ;	}
                if (::File_IsDirectory(pathName))	{	continue ;	}
                }
            std::string	pathName= ::To__string(PathNames[index]) ;
            std::string	fileName= ::To__string(FileNames[index]) ;
            pathNameA.push_back(pathName) ;
            fileNameA.push_back(fileName) ;
            }
        {
            for (size_t index=0 ; index<pathNameA.size()&&index<fileNameA.size() ; index++) {
                MapiFileDesc	fileDesc ;
                memset(&fileDesc,0,sizeof(MapiFileDesc)) ;
                fileDesc.nPosition	= (ULONG)-1 ;
                fileDesc.lpszPathName	= &(pathNameA[index])[0] ;
                fileDesc.lpszFileName	= &(fileNameA[index])[0] ;
                fileDescA.push_back(fileDesc) ;
                }
            }
        }

詳しくは見てないが,幾つかの方法が書かれていたので
Sending Email with MAPI


MapiRecipDesc.lpszAddress の “smtp:”
以前コードを直したのが 2002/4 であまり情報がなかった様に思う.
個人的に書いた内容が「Outlook で配信不能になる
参考になりそうな所
Email mit Dateien perWinAPI versenden??
MAPISendMail
MSDN MapiRecipDesc structure
Sending email using MAPI causes error on ‘ResolveName’ function in Window7


S_Mail.hxx



VC 6 LNK2001 __beginthreadex

空のコンソール AP プロジェクトで,Afx.h を追加でインクルードしてビルドすると,

--------------------構成: MkBG_up - Win32 Debug--------------------
リンク中...
nafxcwd.lib(thrdcore.obj) : error LNK2001: 外部シンボル "__endthreadex" は未解決です
nafxcwd.lib(thrdcore.obj) : error LNK2001: 外部シンボル "__beginthreadex" は未解決です
c:\Temp\Test_3D\MkBG_up\Debug.060/MkBG_up.exe : fatal error LNK1120: 外部参照 2 が未解決です。
link.exe の実行エラー
MkBG_up.exe - エラー 3、警告 0

プロジェクトの設定で「共有 DLL で MFC を使用」などに変更.



CObArray <--> CObList

CObList の形式のデータを配列として処理したかったので,その相互変換(Sort_ind.hxx 内).


#ifdef		_MFC_VER
//*******************************************************************************
//	ObList	->	ObArray
//	Create	:	2017/10/30
//*******************************************************************************
inline	bool	To_ObArray	(const CObList& src,CObArray* dstAry)
{
	if (dstAry == NULL)		{	return	false ;		}
	dstAry->RemoveAll() ;
	{
		POSITION pos = src.GetHeadPosition();
		while (pos != NULL)	{
			CObject*	pObj = src.GetNext(pos);
			dstAry->Add(pObj) ;
			}
		}
	return	true ;
	}

//*******************************************************************************
//	ObArray	->	ObList
//	Create	:	2017/10/30
//*******************************************************************************
inline	bool	To_ObList	(const CObArray& src,CObList* dstLst)
{
	if (dstLst == NULL)		{	return	false ;		}
	dstLst->RemoveAll() ;
	{
		for (INT_PTR index=0 ; index<src.GetSize() ; index++) {
			CObject*	pObj = src[index] ;
			dstLst->AddTail(pObj) ;
			}
		}
	return	true ;
	}

#endif	//	_MFC_VER


CHttpFile でのアップロード

CHttpFile を使用したアップロードのコードを整理.
サーバ側は先日の php と同様.



//*******************************************************************************
//	send request define
//	Create	:	2017/08/28
//*******************************************************************************
#define	C_CRLF			_T("\r\n") ;
#define	CT_ct_mp_fd_b_		_T("Content-Type: multipart/form-data; boundary=")
#define	CT_boundary__		_T("--")
#define	CD_cd_f_d_n_		_T("Content-Disposition: form-data; name=")
#define	CD_cd__fn_		_T("; filename=") ;
#define	CT_ct_a_o_s		_T("Content-Type: application/octet-stream")

//*******************************************************************************
//	make send data
//	Create	:	2017/08/28
//*******************************************************************************
inline	v_char	Make_send_data	(LPCTSTR upFile,LPCTSTR ___boundary)
{
	v_char	up_Data = v_c_LoadText(upFile) ;
	v_char	sndData ;
	{
		tstring	ct_boundary	= ___boundary ;
		tstring	file_img	= ::QuotM_Add(_T("file_img")) ;
		tstring	fileName	= ::QuotM_Add(::Path_GetName(upFile)) ;
		tstring	dataPre ;
		tstring	dataPst ;
		dataPre+=	CT_boundary__	+	ct_boundary				+	C_CRLF ;
		dataPre+=	CD_cd_f_d_n_	+	file_img	+	CD_cd__fn_	;
		dataPre+=							fileName	+	C_CRLF ;
		dataPre+=	T_ct_a_o_s								C_CRLF ;
		dataPre+=										C_CRLF ;
		dataPst+=										C_CRLF ;
		dataPst+=	CT_boundary__	+	 ct_boundary	+	CT_boundary__		C_CRLF ;
		v_char	vc_pref = ::To_v_char(::To__string(dataPre.c_str())) ;
		v_char	vc_post = ::To_v_char(::To__string(dataPst.c_str())) ;
		sndData.insert(sndData.end(),vc_pref.begin(),vc_pref.end()) ;
		sndData.insert(sndData.end(),up_Data.begin(),up_Data.end()) ;
		sndData.insert(sndData.end(),vc_post.begin(),vc_post.end()) ;
		}
	#ifdef	_DEBUG
	{
		::i_Dump(sndData,(::Path_GetName(upFile)+_T(".txt")).c_str()) ;
		}
	#endif
	return	sndData ;
	}

//*******************************************************************************
//	upload
//	Create	:	2017/08/28
//*******************************************************************************
inline	bool	UploadFile	(LPCTSTR svrName,LPCTSTR php,LPCTSTR upFile)
{
	{
		if (::File_IsNothing(upFile))			{	return	false ;		}
	//	if (::File_GetSize  (upFile) > 2048*1024)	{	return	false ;		}
		}
	tstring	head ;
	v_char	sndData ;
	{
		tstring	___boundary = _T("-----UpFile__2017_08_30") ;
			___boundary = _T("-----") + ::Path_GetName(_T(__FILE__)) + _T("__") + ::Now_Format(_T("%H%M%S")) ;
		head	= CT_ct_mp_fd_b_	+ ___boundary ;
		sndData = Make_send_data(upFile,  ___boundary.c_str()) ;
		}
	tstring	serverN = svrName ;
	tstring	portStr ;
	{
		v_tstring	strAry = ::String_Split(svrName,false,_T(":")) ;
		if (strAry.size() >= 2) {
			serverN = strAry[0] ;
			portStr = strAry[1] ;
			}
		}
	INTERNET_PORT	nPort = 0 ;
			nPort = ::ttou2(portStr) ;
	tstring		userAgent = _T("drop_up") ;
			userAgent = ::Path_GetName(_T(__FILE__)).c_str() ;
	#ifdef	_WIN32
	{
		userAgent = ::Path_GetName(::i_GetModuleFileName()) ;
		{
			tstring	osVer	= _T("Windows NT ") + ::To_tstring_rz(::GetWinVer_exe()) ;
				osVer	+=  tstring(_T(" "))+ Bracket_Add(::GetWinVerStr_exe(),_T('(')).c_str() ;
			userAgent += _T(" ") + osVer ;
			userAgent += EXE_AddVerBuildStr() ;
			}
		}
	#endif
	CInternetSession	session(userAgent.c_str()) ;
	CHttpConnection*	pServer = NULL ;
	CHttpFile*		pFile = NULL ;
	DWORD			dwStatus = 0 ;
	try	{
				pServer = session.GetHttpConnection(serverN.c_str(),nPort) ;
				if (pServer == NULL)				{	return	false ;		}
			{
				CString	headStr = head.c_str() ;
				pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_POST,	php) ;
				if (pFile == NULL)				{	return	false ;		}
				pFile->SendRequest(headStr,(LPVOID)(&sndData[0]),DWORD(sndData.size())) ;
				pFile->QueryInfoStatusCode(dwStatus) ;
				}
			{
				delete	(pFile) ;
				delete	(pServer) ;
				}
		}
	catch	(CInternetException* e) {
		CString	errMsg ;
		e->GetErrorMessage(errMsg.GetBuffer(1024),1024) ;
		errMsg.ReleaseBuffer() ;
		std::tout << LPCTSTR(errMsg) << std::endl ;
		return	false ;
		}
	session.Close() ;
	return	true ;
	}

//*******************************************************************************
//	upload files
//	Create	:	2017/08/29
//*******************************************************************************
inline	bool	UploadFiles	(c_v_tstring& upFiles)
{
	v_tstring	svr_php = ::UF_get_server_php() ;
	tstring		serverN = svr_php[0] ;
	tstring		phpName = svr_php[1] ;
	for (size_t index=0 ; index<upFiles.size() ; index++) {
		tstring	upFile = upFiles[index] ;
		if (::File_IsNothing(upFile))		{	continue ;		}
		if (!::UploadFile(serverN.c_str(),phpName.c_str(),upFile.c_str()))	{
			return	false ;
			}
		}
	return	true ;
	}

UpFile.hxx



データ送信 CHttpFile

送信するデータの中身をどの様に指定するかわかってないので,CHttpFile でもう一度やり直し.
MSDN CHttpFile クラスにあるサンプルのコードで,前回と同様にデータが送れることは確認.


content.txt を用意して,あればそれを読込んで送る様に変更.
   CString strData = _T(“Some very long data to be POSTed here!”);
   {
     CString dataFile = _T(“./content3.txt”) ;
     if (::File_IsExist(dataFile)) {
       strData = ::LoadText(dataFile).c_str() ;
       }
     }


Content-Type: multipart/form-data; boundary=—-WebKitFormBoundaryHQUnqULNgae5Y5HW
——WebKitFormBoundaryHQUnqULNgae5Y5HW
Content-Disposition: form-data; name=”file_imo”; filename=”up_Cube.imo”
Content-Type: application/octet-stream

v 0 0 -5
v 0 0 0
v 0 5 0
v 0 5 -5
v 5 0 -5
v 5 5 -5
v 5 0 0
v 5 5 0
f 1 2 3 4
f 5 1 4 6
f 7 5 6 8
f 2 7 8 3
f 3 8 6 4
f 2 1 5 7

——WebKitFormBoundaryHQUnqULNgae5Y5HW
Content-Disposition: form-data; name=”file_htm”; filename=”up_Cube.htm”
Content-Type: application/octet-stream
 
<!DOCTYPE html>
<html lang=”ja” >
<head >
<meta charset=”UTF-8″ />
< script src=”/_lib/js/webgl/threejs/r84/build/three.js”> </script>
< script src=”/_lib/js/webgl/threejs/r84/examples/js/Detector.js”> </script>
< script src=”/_lib/js/webgl/threejs/r84/examples/js/controls/OrbitControls.js”> </script>
< script src=”/_lib/js/webgl/threejs/r84/examples/js/loaders/MTLLoader.js”> </script>
< script src=”/_lib/js/i_lib/threejs/r84/IMOLoader.js”> </script>
< script src=”/_lib/js/i_lib/threejs/r84/c_3js_4.js”> </script>
< script src=”/_lib/js/i_lib/2017.03/filePath.js”> </script>
</head>
<body>

var imoFile=’up_Cube.imo’;
ThreeStart3 (imoFile,5,5,5) ;

</body>
</html>
 
——WebKitFormBoundaryHQUnqULNgae5Y5HW–
 


データは送られているが,PHP の $_FILES にうまく設定されていない.
   $str = var_export($_FILES,true) ;
ヘッダ部分の指定が間違っていたみたいで,
   CString strHead ;
   {
     CString dataFile = _T(“./content3.txt”) ;
     if (::File_IsExist(dataFile)) {
       strData = ::LoadText(dataFile).c_str() ;
       {
         v_tstring strAry = ::String_SplitLine(strData) ;
         if (strAry.size() > 0) {
           strHead = strAry[0].c_str() ;
           strAry.erase(strAry.begin()) ;
           strData = ::String_Join_Line(strAry).c_str() ;
           }
         }
       }
     }
送信部分も,SendRequestEx から SendRequest に変更.
   pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_POST, _T(“/…/t_mfc_h/t_mfc_h.php”)) ;
   pFile->SendRequest(strHead,(LPVOID)LPCTSTR(strData),strData.GetLength()) ;
   pFile->QueryInfoStatusCode(dwStatus) ;


  • Categories:

ダイアログバーに CCheckListBox

通常のダイアログに CCheckListBox を追加するには,次のような手順.
  CCheckListBox の利用
ダイアログバーでは,次の様にしてもデータが表示されない.
  CCheckListBox* clb = (CCheckListBox*)m_wndDlgBar.GetDlgItem(IDC_CHECK_LB) ;
  clb->AddString(“….”) ;


以前作成した,オーナー描画のドロップダウンを思い出しコードを見ると,
  CMainFrame に変数を追加して,サブクラス化している.
  CMainFrame::OnCreate でダイアログバーを Create した後,
    m_ODCB.SubclassDlgItem(IDC_COMBO,&m_wndDlgBar) ;
このコードの最初は,2004/07.
手元にある幾つかの本を見たが見つからなかった.
何を参考にしたかは今となっては不明.


LBN_SELCHANGE で選択された状態がイマイチ.
 内容を更新(PostMessage)するとインデックス 0 の項目に薄い点線が付く.
SendMessage として更新後,選ばれていた項目を SetCurSel することで対応.



コンソール AP で MFC

コンソール AP で,MFC(AfxWin.h など)に依存したコードを利用


新しく書いたものは,次の様なコードで可能.
  #include “EnhMetaF.hxx”
  #include “i_Trace.hxx”
  
  int _tmain(int argc, TCHAR* argv[])
  {
     _tsetlocale(LC_ALL,_T(“”)) ;
     {
       EnhMetaF emf ;
       CMetaFileDC*mfdc = emf.GetDC() ;
       mfdc->Rectangle(10,10,30,20) ;
     }
     return 0 ;
     }


古いコードは,うまく対応できてないので…
  #undef _CONSOLE
  #include <AfxWin.h>
  #include <AfxExt.h>
  #include <AfxCmn.h>
  #ifdef _WIN32
  #define _WINDOWS
  #endif
  #include “MessCon.hxx”
  #include “MessBar.hxx”
  #ifdef MessageBar
     #undef MessageBar
     #define MessageBar MessageCon
     #undef I_SUPPORT_MESSAGE_MFC
  #endif
  #include “MessWrap.hxx”
  // …
  int _tmain(int argc, TCHAR* argv[])
  {
     #ifdef _MFC_VER
     if (!::AfxWinInit(::GetModuleHandle(NULL),NULL,::GetCommandLine(),0)) {
       return 1 ;
       }
     #else
     _tsetlocale(LC_ALL,_T(“”)) ;
     #endif
    //  …
     }


undef の幾つかは,自コードの対応のために必要.



EnumFilesTree で無限ループ

フォルダ以下の全てのファイルを列挙する関数

v_tstring	EnumFilesTree	(LPCTSTR path)
{
	v_tstring	foundFiles = ::EnumFiles(path) ;
	v_tstring	foundFolds = ::ExtractFolders(foundFiles) ;
	for (size_t index=0 ; index<foundFolds.size() ; index++) {
		tstring		subFold = foundFolds[index] ;
		v_tstring	chFiles = ::EnumFiles(subFold.c_str()) ;
		v_tstring	chFolds = ::ExtractFolders(chFiles) ;
		foundFolds.insert(foundFolds.end(),chFolds.begin(),chFolds.end()) ;
		foundFiles.insert(foundFiles.end(),chFiles.begin(),chFiles.end()) ;
		}
	return	foundFiles ;
	}

今まで特に問題なく動作していたが,
先週末 VC 14 i3DV のデバッグ版を実行すると無限ループに.
Release 版や,VC 12 のデバッグ版などでは OK .


昨日は,別の PC 環境だったため再現せず.


今日デバッガを使用して調査すると,
 フォルダの「作成日時」が正しくない.
 /wordpress/dev/2016/09/15/
そのため,_wstat64 が正しく帰ってこない.


v_tstring	EnumFiles	(LPCTSTR path_,const bool skipDot=true)
{
	tstring	path = ::Path_DelLastSP(path_) ;
	if (!File_IsDirectory(path.c_str()))	{
		path = ::Path_GetDir(path) ;
		}
	v_tstring	foundFiles ;
	#if		defined	__GNUC__
		foundFiles = ::EnumFiles_GNUC	(path,skipDot) ;
	#elif	defined	_MFC_VER
		foundFiles = ::EnumFiles_MFC	(path,skipDot) ;
	#elif	defined	_MSC_VER
		foundFiles = ::EnumFiles_MSC	(path,skipDot) ;
	#endif
	return	foundFiles ;
	}

ここの,File_IsDirectory(…) で,stat を利用している.


次の様に ::GetFileAttributes(…) の判断を追加.

	if (!::File_IsDirectory(path.c_str()))	{
		#if	(_MSC_VER == 1900)
		{
			if (!::FA_Is_Directory(path)) {
				path = ::Path_GetDir(path) ;
				}
			}
		#else
		{
			path = ::Path_GetDir(path) ;
			}
		#endif
		}

EnumFile.hxx



HICON -> DIB

i_DIB	GetIcon_DIB	(LPCTSTR filePath,const long size=300)
{
    i_DIB	dib ;
    HICON	hIcon  = ::DImageS_GetIcon(filePath) ;
    if (hIcon != NULL)	{
        MemoryDC	memDC ;
        memDC.Init(CSize(size,size),32) ;
        CDC*		mem_dc = memDC.GetMemoryDC() ;
        mem_dc->FillSolidRect(CRect(0,0,size,size),RGB(240,240,255)) ;
        ::Icon_Draw(mem_dc->GetSafeHdc(),CRect(10,10,size-10,size-10),hIcon,TRUE,TRUE) ;
        dib = ::ToDIB(memDC) ;
        memDC.Term() ;
        ::DestroyIcon(hIcon) ;
        }
    return	dib ;
    }


CFileStatus でアサート

ファイルの作成日時が正しくない?と CFileStatus でうまく動作しない.
ctime_error


このファイルは,プログラミング Windows 第5版の CD を Mac でコピーしたもの.
このファイルを CFile::GetStatus とすると,アサートなど.
VC 8 の場合,ATLTime.inl CTime コンストラクタの 200 行目付近で
  if(m_time == -1)
  {
    AtlThrow(E_INVALIDARG);
    }


—————————
TsHBMP
—————————
パラメータが間違っています。
—————————
OK
—————————
cfilestatus_assert


CFileStatus を使わずに,stat を使用する様に書換えてある程度は動作する様になった.
VC 14 では,stat がエラーで帰ってくる.この対応方法は不明.
CFileStatus を使用している所はかなりあるため,すべてに対応するにはしばらくかかる.
今回は Shell Extension でダウンしたため,その部分のみ対応.


  • Categories:

高 DPI – 2

CMetaFileDC::CreateEnhanced の lpBounds を指定していたが,うまくなかった様で NULL に.
また,これとは異なるが再生デバイスが異なる場合うまくなかったので,
 ENHMETAHEADER の rclFrame ではなく rclBounds に変更.


何を参考にしたのか不明だが,幅を求めるのに TEXTMETRIC だけを使用していた.幾つかあり.
CComboBox::SetDroppedWidth
CListBox::SetHorizontalExtent
CDC::GetTextExtent


高 DPI – 1
高 DPI – 3



error LNK2005 LNK2001

プロジェクト生成時に「MFC を使用しない」としたコンソール AP で Afx.h をインクルードした場合


リンク中…
nafxcwd.lib(afxmem.obj) : error LNK2005: “void * __cdecl operator new(unsigned int)” (??2@YAPAXI@Z) はすでに LIBCD.lib(new.obj) で定義されています
nafxcwd.lib(afxmem.obj) : error LNK2005: “void __cdecl operator delete(void *)” (??3@YAXPAX@Z) はすでに LIBCD.lib(dbgdel.obj) で定義されています

nafxcwd.lib(thrdcore.obj) : error LNK2001: 外部シンボル “__endthreadex” は未解決です
nafxcwd.lib(thrdcore.obj) : error LNK2001: 外部シンボル “__beginthreadex” は未解決です


プロジェクトの設定で「共有 DLL で MFC を使う」などに変更.



tstring Unit::ToName の呼び出し後エラー

もともと CString Unit::ToName(…) だった関数の戻り値を tstring に変更した.
利用している所の多くは,コンパイルエラーとなり Unit::ToName(…).c_str() と修正したが...
次の様な可変引数の修正が漏れていた.
CString unitStr ; unitStr.Format(_T(“%d_%s”),…,Unit::ToName(…)) ;



VC 8 で _ATL_VER が定義される?

先日書いたコードを MFC ダイアログベースの AP で利用してみると,CRegKey の未定義エラー.
コードは,次の様に「_ATL_VER が定義されていれば…」としている.
  #ifdef _ATL_VER
     CRegKey reg ;
     …
  #endif


—— ビルド開始: プロジェクト: SmpMG, 構成: Debug Win32 ——
コンパイルしています…
SmpMGDlg.cpp
…\i_RegGet.hxx(36) : error C2065: ‘CRegKey’ : 定義されていない識別子です。
…\i_RegGet.hxx(36) : error C2146: 構文エラー : ‘;’ が、識別子 ‘reg’ の前に必要です。
…\i_RegGet.hxx(36) : error C2065: ‘reg’ : 定義されていない識別子です。
…\i_RegGet.hxx(37) : error C2228: ‘.Open’ の左側はクラス、構造体、共用体でなければなりません
…\i_RegGet.hxx(39) : error C2228: ‘.QueryDWORDValue’ の左側はクラス、構造体、共用体でなければなりません
SmpMG – エラー 5、警告 0
========== ビルド: 0 正常終了、1 失敗、0 更新、0 スキップ ==========


VC 6 や,VC 8 のコンソール AP としての利用はうまくいっている.
自分で書いた部分では,_ATL_VER が定義される様なインクルードは追加してない.
_ATL_VER は (VS8)\VC\atlmfc\include\AtlDef.h にある.


StdAfx.h でインクルードしているものを順に追いかけていくと,
AfxDisp.h 内で Atlナントカ.h がインクルードされている.
同様の部分の VC 6 の方では Atl~.h はなさそう.


どの様にするのがベターなのかわからないが,AtlBase.h をインクルードする様にした.
  #ifdef _ATL_VER
  #include <AtlBase.h>
  #endif


  • Categories:

ファイル ‘新しいテキスト ドキュメント.txt’ を作成できません。

ちょっと変な状態に陥ったのでメモ.


\\DevS\Documents\MICS\Plan\MICSDat\Test_2015 01-03\9LM-2U-J6TRi-2S7M.001\
\\DevS\Documents\MICS\Plan\MICSDat\Test_2014_12\ などでは
[Window Title]
ファイルを作成できません
[Content]
ファイル ‘新しいテキスト ドキュメント.txt’ を作成できません。
開かれている共有ファイルが多すぎます。
[OK]
DevS_SaveError


\\DevS\Documents\MICS\Plan\MICSDat\ だと戻ってこない(エクスプローラが応答なしになる)
\\DevS\Documents\MICS\Plan\ などでは正しく生成できる.


ログオフ時,\\DevS\Documents\MICS\Plan\MICSDat\新しいテキスト ドキュメント.txt ができていた.
再ログオン後,直後はできなかったがしばらくすると可能となった.


現象はどーってことない(再起動すれば直る)が,
問題は,MFC で作成した普通の AP でドキュメントが消失したこと.
その AP は,自動的に %Temp% にバックアップを保持するので完全に失ったわけではないが,
標準の MFC のシリアライズ動作ではうまくないのか?



コンソール AP でレジストリ読み取り

コンソール AP で,レジストリを読み取るために以下の様な関数を用意した.


  int Reg_GetInt (HKEY hKey,LPCTSTR subKey,LPCTSTR ent,const int defValue=0)
  {
     DWORD value = defValue ;
  #ifdef _ATL_VER
     {
       CRegKey reg ;
       reg.Open(hKey,subKey) ;
     #if (_ATL_VER >= 0x700)
       reg.QueryDWORDValue(ent,value) ;
     #else
       reg.QueryValue(value,ent) ;
     #endif
       }
  #else
     {
       HKEY hSecKey = NULL ;
       LONG openStatus = ::RegOpenKeyEx(hKey,subKey,0,KEY_READ,&hSecKey) ;
       if (hSecKey == NULL) { return value ; }
       DWORD type = REG_NONE ;
       DWORD count = sizeof(DWORD) ;
       LONG queryStatus = ::RegQueryValueEx(hSecKey,ent,NULL,&type,(LPBYTE)&value,&count) ;
       ::RegCloseKey(hSecKey) ;
       }
  #endif
     return int(value) ;
     }
*::Reg~ などのエラーチェックは省いている.
呼出すのはこんな感じ.
  int value = ::Reg_GetInt(HKEY_CURRENT_USER,_T(“Software\\Iwao\\Test\\RegAcc”),_T(“T_RegKey_DW”)) ;


CWinApp::GetProfileInt などが使えないかとやってみたが,…
1. AfxGetApp() を呼びだしても,NULL で戻ってくる.
  次の様に領域を確保.
    CWinApp theApp;
2. SetRegistryKey(key) が直接呼びたせないので,
  class C_SRK_WinApp : public CWinApp {
  public:
       void SetRegKey (LPCTSTR key) { SetRegistryKey(key) ; }
     } ;
  変数の確保は次の様に変更.
    C_SRK_WinApp theApp ;
3. SetRegistryKey の中で ASSERT(m_pszAppName != NULL)
  以下を追加して,CWinApp を初期化.
     AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0) ;
4. これで CWinApp::GetProfileInt は利用できるようになるが,CWinApp::m_pszProfileName が邪魔.
   C_SRK_WinApp* app = (C_SRK_WinApp*)AfxGetApp() ;
   int val = app->GetProfileInt(_T(“Test\\RegAcc”),_T(“T_RegKey_DW”),0) ;
  HKCU\Software\Iwao\(m_pszProfileName)\Test\RegAcc となってしまう.
5. m_pszProfileName を _T(“”) とすることにより,意図した値を取得できる様にはなった.
   C_SRK_WinApp* app = (C_SRK_WinApp*)AfxGetApp() ;
   if (app != NULL) {
     AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0) ;
     app->SetRegKey(_T(“Iwao”)) ;
     free((void*)app->m_pszProfileName) ;
     app->m_pszProfileName = _tcsdup(_T(“”)) ;
     int val = app->GetProfileInt(_T(“Test\\RegAcc”),_T(“T_RegKey_DW”),0) ;
     }


コンソール AP で CWinApp::GetProfileInt などを使うことは,やめ.



COleDataSource を利用した Drag

以前 DoDragDrop で少し調べたが,その時は途中になっていた.
その時の内容で,例えば CListBox に表示されてるファイルリストのすべてを,CListBox の外側でドラッグするすることはできる.
  void CDragLBDlg::OnLButtonDown(UINT nFlags, CPoint point)
  {
    CStringArray sa ;
    ::ToStringArray(FileNames,&sa) ;
    ::StringArrayToDoDragFiles(sa) ;
    }


CListCtrl であれば,OnBegindragXxxx が利用できるので,
  void CDragLVDlg::OnBegindragListFiles(NMHDR* pNMHDR, LRESULT* pResult)
  {
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    {
      CStringArray sa ;
      for (int index=0 ; index<m_ListFiles.GetItemCount() ; index++) {
        if (m_ListFiles.GetItemState(index,LVIS_SELECTED) == LVIS_SELECTED) {
          tstring str = FileNames[index] ;
          sa.Add(str.c_str()) ;
          }
        }
      if (sa.GetSize() > 0) {
        ::StringArrayToDoDragFiles(sa) ;
        }
      }
    *pResult = 0;
    }


今回やりたかったのは,CListBox の項目のドラッグ.
ドラッグ部分は CListCtrl とほぼ同様となると思われるが,ドラッグ開始のタイミングが取れない.
CDragListBox と開始時の動きは似ているが,MFC のコードを見るとちょっと難しそう.
いろいろと検索すると,CListBox のサブクラス化で対応するみたいとわかったが,手順が...
動的なサブクラス化と言うらしい.
Inside Visual C++ には,囲み記事に CNonNumericEdit がある.
利用する手順はわかるが,作成する手順がわからない
今も利用はしている CView からの VXxxxView ファミリがあるが,10 年以上前で手順は覚えてない.


いろいろ探して「MFC クラスウィザード」を利用することがわかった.
今まで,よく見ていたダイアログなのに...
DynamicSubclassing
後は,WM_LBUTTONDOWN を処理する様にして,
  void CMyListBox::OnLButtonDown(UINT nFlags, CPoint point)
  {
    CListBox::OnLButtonDown(nFlags, point);
    int sel = GetCurSel() ;
    if (sel == LB_ERR) { return ; }
    CString str ;
    GetText(sel,str) ;
    CStringArray sa ;
    sa.Add(str) ;
    ::StringArrayToDoDragFiles(sa) ;
    }
ダイアログに追加したリスボックスで,これを利用する様にダイアログのヘッダを修正.


MSDN CTRLTEST サンプル
テクニカル ノート 14
標準コントロールからのコントロールの派生
[MSVC] MFCを使用しての動的サブクラス化
Create Client Windows, Drag and Drop Between Listboxes


2014/08/11 追記
COleDataSource を利用して,他の AP に CF_HDROP で渡そうとすると,
—————————
Microsoft Visual C++ Debug Library
—————————
Debug Assertion Failed!
Program: …Documents\Visual Studio 2010\Projects\TestVC10\Debug\T_SC.exe
File: f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\cmdtarg.cpp
Line: 43
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
—————————
中止(A) 再試行(R) 無視(I)
—————————
COleDataSource_Error
COleDataSource の使い方が間違っていた.
開放する時に delete ではうまくない.
データ オブジェクトとデータ ソース : 作成と破棄



モードレスダイアログの動作が,…

VC 7 以降,MDI AP のモードレスダイアログが独立して動作してしまう現象があった.
その AP は,VC 4 の頃作成したもので CMainFrame::OnCreate 内でモードレスダイアログを作成している.
VC 6 までは特に問題なかったが,VC 7 以降タスクバーにアイコンが 2 つ存在する状態になってしまっていた.
過去に何度か対応方法を調べたが,わからずそのままとなっていた.


今日別の事を調べていて,「モードレスダイアログで親子にならなくする」方法が目に留まった.
CDialog::Create で,デフォルトの NULL ではなく,GetDesktopWindow() を与えるというもの.
VC 7 AP のダイアログの情報を,Spy++ で見ると,親ウィンドウが (なし) になっている.
今度はデバッガで,Create の付近を追いかけると AfxGetMainWnd() で NULL がかえっている.
ThrdCore.cpp より
CWnd* CWinThread::GetMainWnd()
{
  if (m_pActiveWnd != NULL)
    return m_pActiveWnd;
  if (m_pMainWnd != NULL)
    return m_pMainWnd;
  return CWnd::GetActiveWindow();
}


CXxxApp::InitInstance で以下の部分を修正.
  CMainFrame* pMainFrame = new CMainFrame;
  m_pMainWnd = pMainFrame;   // ここを追加
  if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
    return FALSE;
  m_pMainWnd = pMainFrame;



CSplitterWnd – 2

SDI で,MDI の「新しいウィンドウを開く」で 4 つのビューを表示した様な動作が欲しかったので,調べてみた.
動的な分割ウィンドウである程度の所まではできそう.


1. MainFrm.h の CMainFrame に以下を追加.
    CSplitterWnd m_wndSplitter;
    virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
2. CMainFrame::OnCreateClient の追加.
    BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
      {
        if (!m_wndSplitter.Create(this,2, 2,CSize(10, 10), pContext,
            WS_CHILD | WS_VISIBLE /* | WS_HSCROLL | WS_VSCROLL */ | SPLS_DYNAMIC_SPLIT)) {
          TRACE0(“Failed to create split bar “);
          return FALSE;
          }
        return TRUE;
        }
      }
    スクロールバーを付加したくなかったので,6 つ目のウィンドウスタイルを変更している.
テスト用に分割動作をコマンドとして実装.
    void CMainFrame::OnSplit()
    {
      if (IsSplit) {
        if (m_wndSplitter.GetColumnCount() > 1) { m_wndSplitter.DeleteColumn (1) ; }
        if (m_wndSplitter.GetRowCount() > 1) { m_wndSplitter.DeleteRow (1) ; }
        IsSplit = !IsSplit ;
        }
      else {
        CRect rect ;
        m_wndSplitter.GetClientRect(&rect) ;
        if (m_wndSplitter.GetColumnCount() == 1) { m_wndSplitter.SplitColumn (rect.Width()/2) ; }
        if (m_wndSplitter.GetRowCount() == 1) { m_wndSplitter.SplitRow (rect.Height()/2) ; }
        IsSplit = !IsSplit ;
        }
      }


2 x 2 の分割ウィンドウのコントロールの ID (Spy++ で確認)
  左上(0,0)  E900  AFX_IDW_PANE_FIRST
  右上(0,1)  E901
  左下(1,0)  E910
  右下(1,1)  E911


ビューの OnDraw を以下の様に書き換えると
  void CSpltWView::OnDraw(CDC* pDC)
  {
    int row = -1 ;
    int clm = -1 ;
    CMainFrame* mw = (CMainFrame*)AfxGetMainWnd() ;
    CSplitterWnd* sw = &mw->m_wndSplitter ;
    CString str ;
    if (sw->IsChildPane(this,&row,&clm)) {
      int id = sw->IdFromRowCol(row,clm) ;
      CString tmp1 ; tmp1.Format(_T(“row = %d , clm = %d”),row,clm) ;
      CString tmp2 ; tmp2.Format(_T(“IdFromRowCol = %04X”), id) ;
      str += tmp1 + _T(“\r\n”) ;
      str += tmp2 + _T(“\r\n”) ;
      }
    {
      UINT nID = GetDlgCtrlID() ;
      CString tmp ; tmp.Format(_T(“GetDlgCtrlID = %04X”),nID) ;
      str += tmp + _T(“\r\n”) ;
      }
    {
      CWnd* pw = GetParent() ;
      CString tmp1 ; tmp1.Format(_T(“Splitter = %08x “),sw->GetSafeHwnd()) ;
      CString tmp2 ; tmp2.Format(_T(“Parent = %08x “),pw->GetSafeHwnd()) ;
      str += tmp1 + _T(“\r\n”) ;
      str += tmp2 + _T(“\r\n”) ;
      }
    CRect rect ;
    GetClientRect(rect) ;
    rect.top = rect.left = 10 ;
    pDC->DrawText(str,rect,0) ;
    }
SplitW_1
MFC の ソースを眺めていると CView::GetParentSplitter があったので,間接的にはそれを使えば良さそう.


ビューでどの位置かを求めるだけなら,
    short texNo = 0 ;
    {
      UINT nID = GetDlgCtrlID() ;
      switch (nID) {
        case AFX_IDW_PANE_FIRST + 0x00 : texNo = 1 ; break ;
        case AFX_IDW_PANE_FIRST + 0x01 : texNo = 2 ; break ;
        case AFX_IDW_PANE_FIRST + 0x10 : texNo = 3 ; break ;
        case AFX_IDW_PANE_FIRST + 0x11 : texNo = 4 ; break ;
        }
      }



MFC DLL → Static – 2

VC 6 位で生成したプロジェクトを,VC 7 ~ VC 11 まで順に変換して利用してきたもの.
「共有 DLL で MFC を使う」から「スタティック ライブラリで MFC を使用する」に変更してビルドすると,
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\atlmfc\include\afx.h(24):
  fatal error C1189: #error : Building MFC application with /MD[d]
   (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
プロジェクトの「プロパティページ」-「構成プロパティ」-「C/C++」-「コード生成」-「ランタイム ライブラリ」を
  「マルチスレッド DLL (/MD)」から「マルチスレッド (/MT)」に変更.


ビルドは通る様になったが,起動時メインフレーム表示直後にアプリケーションエラー.
  プロジェクトのプロパティで,「リンカ」-「デバッグ」-「デバッグ情報の生成」で「はい (/DEBUG)」に.
  ビルドして実行すると,
  C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\atlmfc\src\mfc\docsingl.cpp
    CSingleDocTemplate::SetDefaultTitle(CDocument* pDocument) の
       ENSURE(strDocName.LoadString(AFX_IDS_UNTITLED));
BLConv_DLL_Static_Error
プロジェクトのプロパティ,「リソース」-「プリプロセッサの定義」に “_AFXDLL;” があったので削除.



OCX x64

MFC を利用した x86 の ocx の 64 ビット化.


しばらくやってないので,Win XP 32 ビット環境の VC 6 で,スケルトンの作成から.
ActiveX Controls Inside Out を見ながら,スケルトンを作成.
そのままビルドして,ActiveX コントロール テスト コンテナ で,挿入してテスト.
OnDraw のEllipse を DrawText に書換え.
  void C????Ctrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
  {
//   pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
//   pdc->Ellipse(rcBounds);
    v_tstring buildMacros = ::Debug_GetMacroCC_v() ;
    CString macroStr = ::String_Join(buildMacros,_T(“\r\n”)).c_str() ;
    CRect rect = rcBounds ;
    pdc->DrawText(macroStr,rect,0) ;
    }
Debug_GetMacroCC_v は次の様なコード.
  inline std::vector Debug_GetMacroCC_v (void)
  {
    std::vector typeAry ;
    #ifdef _WIN64
      typeAry.push_back(_T(“_WIN64 “)) ;
    #elif _WIN32
      typeAry.push_back(_T(“_WIN32 “)) ;
    #endif
    // …
    #ifdef _MFC_VER
      typeAry.push_back(_T(“_MFC_VER “)+::utot(_MFC_VER,16)+_T(” “)) ;
    #endif
    #ifdef _UNICODE
      typeAry.push_back(_T(“_UNICODE “)) ;
    #endif
    // …
    return typeAry ;
    }
WinXP_ActiveX_CTC


今度は,Win 7 x64 環境で,VC 9 を利用しての確認.
「ActiveX コントロール テスト コンテナ」は,以前のバージョンとは異なり標準では存在しない.
検索するとサンプルにあるとのこと.
Win 7 環境には C:\…\VC2010Samples\C++\MFC\ole\TstCon があったので VC 10 でビルド.
VC 9 でスケルトンから作成して,OnDraw を同様に書換え.
また,構成マネージャを使用して x64 を追加.
それぞれの Release 版でビルド.
コントロールの登録は,管理者として起動した「コマンドプロンプト」で行っている.
それぞれの ocx のフォルダに移動し,regsvr32 ~.ocx として登録.
この時,ocx により?自動的に regsvr32 の 64 / 32 ビットそれぞれで登録されているみたい.
Win_7_ActiveX_CTC
Excel 2010 で試すには,コントロールの挿入のために開発タブを有効にする必要がある.
Excel_Dev_Tab


  • Categories:

MFC 追加でメモリリーク

MFC を利用しないコードを VC 6 でテストしていて,
  コンソール AP として作成したスケルトンに,::oGetFileSize を追加.
  MFC を利用した,::GetFileSize と動作を比べるために,
    プロジェクトの設定を変更(共有 DLL で MFC を使用).
    main 関数が存在するソースに Afx.h などの include を追加.
  ビルドして実行すると,メモリリークが発生するようになった.
  main 関数内を全てコメントにしてもあまり変わらない.


MFC サポートありで,コンソール AP を作成.
  同様に oGetFileSize と GetFileSize を追加.
  ビルド,実行すると特に問題ない.
  StdAfx.h 内の Afx.h などを tmain のソース内に移動.
  リビルドすると,メモリリーク発生.
どうも,Afx.h より前の iostream などが関係している.
また,リビルドしないと現象が変わらない.


StdAfx.h に iostream の include を追加
  #define VC_EXTRALEAN
  #include <iostream>
  #include <afx.h>


Detected memory leaks!
Dumping objects ->
{51} normal block at 0x00032440, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
{50} normal block at 0x00034F68, 40 bytes long.
Data: < |L > 14 7C 4C 10 16 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.
スレッド 0x1218 終了、終了コード 0 (0x0)。
プログラム ‘C:\…\T_Con2\Debug\T_Con2.exe’ はコード 0 (0x0) で終了しました。



CLI + MFC

CLR コンソール アプリケーションを作成.
Console::WriteLine を追加.


#include “stdafx.h”
using namespace System;
int main(array ^args)
{
  Console::WriteLine(L”Hello World”);
#ifdef _WIN32
  Console::WriteLine(L”WIN32″);
#endif
#ifdef __cplusplus_cli
  Console::WriteLine(L”CLI”);
#endif
#ifdef __CLR_VER
  Console::WriteLine(__CLR_VER);
#endif
#ifdef _MFC_VER
  Console::WriteLine(_MFC_VER);
#endif
  return 0;
  }
実行すると,
C:\…>”C:\…\debug\ConAp.exe”
Hello World
WIN32
CLI
20050727


これに MFC の機能を追加しようとしたがわからなかったので.MFC コンソール AP を作成して /clr を追加することにした.


#include “stdafx.h”
#include “ConMFC.h”
//
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//
using namespace System;
// 唯一のアプリケーション オブジェクトです。
CWinApp theApp;
//
using namespace std;
//
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
  int nRetCode = 0;
//
  if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))  {
    _tprintf(_T(“致命的なエラー: MFC の初期化ができませんでした。\n”));
    nRetCode = 1;
  }
  else {
    // TODO: アプリケーションの動作を記述するコードをここに挿入してください。
  }
  Console::WriteLine(L”Hello World”);
#ifdef _WIN32
  Console::WriteLine(L”WIN32″);
#endif
#ifdef __cplusplus_cli
  Console::WriteLine(L”CLI”);
#endif
#ifdef __CLR_VER
  Console::WriteLine(__CLR_VER);
#endif
#ifdef _MFC_VER
  Console::WriteLine(_MFC_VER);
#endif
  return nRetCode;
}
実行すると,
C:\…>”C:\…\debug\ConMFC.exe”
Hello World
WIN32
CLI
20050727
2048


CLR のバージョンは,2.0.50727
MFC は 0x0800
VC 定義済みマクロ



ツールバーが印刷プレビューでうまくない

追加したツールバーでフローティング不可の時,印刷プレビューでの表示がうまくない.
ToolBar_Preview
CFrameWnd::OnSetPreviewMode を見ると,
  AFX_IDW_CONTROLBAR_FIRST ~ + 31 の範囲では ShowControlBar を呼出している.



MDI のステータスバー

以下の情報と,The MFC Answer Book とで.
すべての MDI 子ウィンドウのステータス バーを作成する方法
How to Create a Status Bar in Every MDI Child Window
static UINT indicators[] = { ID_INDICATOR_MDI } ; として,ID をシンボルブラウザで追加.
ビルド,実行すると,CChildFrame::OnCreate のステータスバーの Create で失敗.
 String Table で定義されてないとダメな様で適当な文字列を追加.
 ビューで,OnUpdateIndicatorMDI を追加(表示されないメニューに ID を追加して ClassWizard で).
  pCmdUI->SetText(_T(“ステータスバーに表示する情報”)) ;
これで実行すると,追加した文字列の幅で表示された.
MDI_StatusBar
CChildFrame::OnCreate の,
ステータスバーを生成した後,SetPaneInfo(0,ID,SBPS_STRETCH,0)
  これにより,ウィンドウ幅いっぱいに.
MDI_StatusBar_Width
幅は広がったが表示される文字列は,128 文字まで?


  • Categories:

DImage の利用

Shell Extension を利用した画像表示.ダイアログにファイルをドロップすると表示する様に.
1. CStatic を用意.ピクチャコントロールを配置して ClassWizard で変数を追加.
2. DImageS の領域を確保.通常はヘッダに.
3. OnDropFiles で
    // CString dropFile = …. ;
    ImageS.SetFileName(dropFile) ;
    ImageS.Draw(&m_Image) ;
    {
      m_Image.ShowWindow(SW_HIDE) ;
      m_Image.ShowWindow(SW_SHOW) ;
      }
    // …
4. OnPaint で
    ImageS.Draw(&m_Image) ;
DImage_Sample
DImage では,ImageDMF が追加される.
DImage.zip



HTML の表示

SVG をダイアログ上に表示したくなったので,CHtmlView などを利用してみた.
Spy++ で見ると,クラス名が “Internet Explorer_Server” となる.
HtmlView.zip


SDI で CHtmlView を利用
1. AppWizard のステップ 6 で,CHtmlView を選択する.

2. ビューのソースの CXxxxView::OnInitialUpdate() を,適当なアドレスに修正する.
  Navigate2(_T(“http://iwaoalles.wordpress.com/”),NULL,NULL);


ダイアログで,WebBrowser Control を利用
1. プロジェクトにコンポーネントを追加する.

2. 追加したコントロールの変数を割り当てる(ここでは,m_WebBrowse とした).
3. OnInitDialog などで
 m_WebBrowse.Navigate(_T(“http://iwaoalles.wordpress.com/”),NULL,NULL,NULL,NULL) ;


ダイアログで,CHtmlView を利用
1. CHtmlView* の変数を定義する(ここでは,WebView とした).
2. OnInitDialog で
  CRect rect ;
  GetClientRect(&rect) ;
  rect.top = 25 ;
  CRuntimeClass* pClass= RUNTIME_CLASS(CHtmlView) ;
  WebView = (CHtmlView*)(pClass->CreateObject()) ;
  WebView->Create(NULL,NULL,WS_VISIBLE|WS_CHILD,rect,this,0,NULL) ;
  WebView->SendMessage(WM_INITIALUPDATE) ;
  WebView->Navigate(_T(“http://iwaoalles.wordpress.com/”)) ;



BDoc ファミリ

コンパイルで以下の様なエラーになった場合
c:\…\DocIB.cxx(77) : error C2065: ‘BDocCSV_D’ : 定義されていない識別子です。
c:\…\DocIB.cxx(77) : error C2146: 構文エラー : ‘;’ が、識別子 ‘bdcsv’ の前に必要です。
c:\…\DocIB.cxx(77) : error C2065: ‘bdcsv’ : 定義されていない識別子です。
c:\…\DocIB.cxx(78) : error C2228: ‘.Read’ : 左側がクラス、構造体、共用体ではありません。
c:\…\DocIB.cxx(79) : error C2228: ‘.BDoc_Draw’ : 左側がクラス、構造体、共用体ではありません。
c:\…\DocIB.cxx(79) : error C2653: ‘BDoc_Draw’ : 識別子がクラス名でも名前空間名でもありません。

DocIB.cxx のインクルードする場所をもう少し前にすることによりエラーはなくなるが,…


実行時,いろいろな所でダウンする(表面化しないこともあり).
BDoc_Draw と BDocCSV_D の定義の不整合が原因.
BDoc ファミリや,AccessItemND を見直さなければならないがちょっと時間が取れない.


ひとまず,App.h に BDoc_D.hxx をインクルードすることにより対応する.
#include “MetaFile.hxx”
#include “MemoryDC.hxx”
#include “BDoc_D_.hxx”



CFont::CreatePointFont でアサート

—————————
Microsoft Visual C++ Debug Library
—————————
Debug Assertion Failed!

Program: C:\WINDOWS\explorer.exe
File: wingdix.cpp
Line: 269

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)
—————————
中止(A) 再試行(R) 無視(I)
—————————

ここ 1 年位のコードで何個かあったので,…
呼び元で与えられた pDC が CMetaFileDC の場合,m_hAttribDC が NULL となるため.
コードを書いた段階では画面やプリンタだったが,今回 Text → EMF で表面化した.
修正は以下の様な感じ.
// font.CreatePointFont(120,faceName,pDC) ;
if (pDC->m_hAttribDC == NULL){ font.CreatePointFont(120,faceName,NULL) ; }
else { font.CreatePointFont(120,faceName,pDC) ; }



CCheckListBox の利用

1. 通常の手順で,リストボックスをダイアログに貼り付ける.
2. コントロールのプロパティを「オーナー描画」-「固定」,「文字列あり」-「チェック」に変更する.
3. クラスウィザードなどを利用して,コントロールの変数(CListBox)を登録する.
4. ヘッダファイルを開いて,CListBox を CCheckListBox に変更する.
5. 項目の追加は,CListBox などと同様に AddString など.
6. チェックの指定は,SetCheck で.


  • Categories:

Shell Extension InfoTip の追加

Shell Extension の作成 InfoTip

1.プロジェクトの作成
 MFC App Wizard(dll)
  「スタティックライブラリを使用した DLL」を選択
  「オートメーション」のサポート
2.クラスファクトリの作成
 Class Wizard で,クラスの新規作成
  基本クラスは CCmdTarget
  「タイプ ID で作成」
3.ヘッダ部に INTERFACE_PART の追加
 BEGIN_INTERFACE_PART(QueryInfoT,IQueryInfo)
  STDMETHOD (GetInfoFlags) (DWORD* pdwFlags) ;
  STDMETHOD (GetInfoTip ) (DWORD dwFlags,LPWSTR* ppwszTip) ;
 END_INTERFACE_PART (QueryInfoT)
 …
 BEGIN_INTERFACE_PART(PersistFile,IPersistFile)
 …
4.必要な変数を追加
 InfoTip の場合,FileName など
5.ソースに INTERFACE_MAP の追加
 BEGIN_INTERFACE_MAP(CI_ShellExt,CCmdTarget)
  INTERFACE_PART (CI_ShellExt,IID_IQueryInfo,QueryInfoT)
  INTERFACE_PART (CI_ShellExt,IID_IPersistFile,PersistFile)
 END_INTERFACE_MAP ()
6.CI_ShellExt::XQueryInfoT::~ の実装
 幾つかはある程度決まったコードになる.
CI_ShellExt::XQueryInfoT::GetInfoTipは,ppwszTipに表示する文字列を返す.


METHOD_PROLOGUE pThisでCCmdTargetの派生クラスにアクセス可能になる.


レジストリへの登録
[HKEY_CURRENT_USER\Software\Classes\CLSID\{56D044C5-9F47-4CD3-B130-9E52BE7460F3}]
@=”I.ShellExt”

[HKEY_CURRENT_USER\Software\Classes\CLSID\{56D044C5-9F47-4CD3-B130-9E52BE7460F3}\InProcServer32]
@=”C:\\Documents and Settings\\All Users\\Documents\\VC_TEST\\IShlExt\\Release\\I_Shl_E.dll”
“ThreadingModel”=”Apartment”

[HKEY_CURRENT_USER\Software\Classes\CLSID\{56D044C5-9F47-4CD3-B130-9E52BE7460F3}\ProgID]
@=”I.ShellExt”

拡張子の登録例
[HKEY_CURRENT_USER\Software\Classes\.Test_ShellExt\ShellEx\{00021500-0000-0000-C000-000000000046}]
@=”{56D044C5-9F47-4CD3-B130-9E52BE7460F3}”


{56D044C5-9F47-4CD3-B130-9E52BE7460F3} の部分は,ソースの IMPLEMENT_OLECREATE の前の行のコメントより


今回使用したコードは,IShlExt.zip


参考にしたのは,
Debugging with the Shell

MSDN Magazine 2000/04 新しいinfotip,アイコンオーバーレイ,シェルエクステンション
Windows 2000 UI Innovations: Enhance Your User’s Experience with New Infotip and Icon Overlay Shell Extensions

MSDN Magazine 2000/07 ハイパーテキストテンプレートファイルのカスタマイズによるエクスプローラの表示の拡張

Windows 95 ユーザーインターフェイス プログラミング


ExtractImage を実装してエラーになった場合
I_ShlExt.obj:error LNK2001:外部シンボル “_IID_IExtractImage” は未解決です
#include <initguid.h> を I_ShlExt.cpp の StdAfx.h の次に追加.


  • Categories:

HBITMAP から画像サイズ取得

昨日,クリップボードからの取得で画像サイズを求める方法がわからなかった.
  HBITMAP hbm = (HBITMAP)::GetClipboardData(CF_BITMAP) ;
  if (hbm != NULL) {
    CSize bmpSize(10,10) ;
    {
      BITMAP bm ;
      ::ZeroMemory(&bm,sizeof(BITMAP)) ;
      if (::GetObject(hbm, sizeof(BITMAP),&bm)!=0) {
        bmpSize.cx = bm.bmWidth ;
        bmpSize.cy = bm.bmHeight;
        }
      }
    …
    }
CBitmap で保持している場合は,
  CBitmap bitmap ;
  if (bitmap.LoadBitmap(bmp_ID)) {
    BITMAP bm ;
    bitmap.GetBitmap(&bm) ;
    CRect rect = CRect(0,0,bm.bmWidth,bm.bmHeight) ;
    …
    }
HENHMETAFILE では,
  HENHMETAFILE hemf = (HENHMETAFILE)::GetClipboardData(CF_ENHMETAFILE) ;
  if (hemf !=NULL) {
    ENHMETAHEADER emh ;
    ZeroMemory(&emh,sizeof(ENHMETAHEADER)) ;
    emh.nSize = sizeof(ENHMETAHEADER) ;
    if (::GetEnhMetaFileHeader(hemf,sizeof(emh),&emh) != 0) {
      CRect rectB ;
      rectB.top = emh.rclBounds.top ;
      rectB.left = emh.rclBounds.left ;
      rectB.right = emh.rclBounds.right ;
      rectB.bottom= emh.rclBounds.bottom ;
      CRect rectF ;
      rectF.top = emh.rclFrame .top ;
      rectF.left = emh.rclFrame .left ;
      rectF.right = emh.rclFrame .right ;
      rectF.bottom= emh.rclFrame .bottom ;
      }
    }



ダイアログベース.exe サイレントモード

次の様なコードで,AfxWinMain でエラーになってしまう.
BOOL CReszPicApp::InitInstance()
{
  …
  CReszPicDlg dlg;
  m_pMainWnd = &dlg;
  if (_tcslen(m_lpCmdLine) != 0) {
    dlg.EnumDIB() ;
    dlg.ResizeDIB() ;
    return FALSE ;
    }
  INT_PTR nResponse = dlg.DoModal();
  …
  }


—————————
Microsoft Visual C++
—————————
ハンドルされていない例外 は ReszPic.exe (MFC42D.DLL) にあります: 0xC0000005: Access Violation。
—————————
OK
—————————


WinMain.cpp
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
  …
  // Perform specific initializations
  if (!pThread->InitInstance()) {
    if (pThread->m_pMainWnd != NULL) {
      TRACE0(“Warning: Destroying non-NULL m_pMainWnd\n”);
      pThread->m_pMainWnd->DestroyWindow();
      }
    nReturnCode = pThread->ExitInstance();
    goto InitFailure;
    }
  …
  }


m_pMainWnd への設定より前に,サイレントモードでの動作を行えば良い.
  CReszPicDlg dlg;
  // m_pMainWnd = &dlg;
  if (_tcslen(m_lpCmdLine) != 0) {
    dlg.EnumDIB() ;
    dlg.ResizeDIB() ;
    return FALSE ;
    }
  m_pMainWnd = &dlg;
  INT_PTR nResponse = dlg.DoModal();


Message クラスなどで,AfxGetMainWnd()->GetSafeHwnd()==NULL の時の判断が抜けていたので修正.
AfxGetMainWnd()==NULL は多くの所で対応しているが,
AfxGetMainWnd()->GetSafeHwnd()==NULL は抜けがかなりありそう.



CView の OnFilePrint を抜き出し

OnFilePrint の関係を Print クラスとして抜き出しました.
ダイアログベースの exe や,ビューの表示対象と異なるオブジェクトの印刷などに利用できると思います.
利用方法はこんな感じ.
class PrintTest : public Print {
public:
  virtual void OnPrint (CDC* pDC, CPrintInfo*pInfo) {
    CRect rect = pInfo->m_rectDraw ;
    {
      pDC->TextOut(0,0,_T(“ここが印刷のためのコードです.”)) ;
      }
    return ;
    }
  virtual BOOL OnPreparePrinting ( CPrintInfo* pInfo) {
    pInfo->SetMaxPage(5) ;
    return DoPreparePrinting(pInfo) ;
    }
  virtual CString GetDocumentTitle (void) {
    return _T(“通常はドキュメント名を戻します.”) ;
    }
} ;
印刷が押されると,
void CAboutDlg::OnPrint()
{
  PrintTest pt ;
  if (pt.OnFilePrint()) {
    OnOK() ;
    }
  }
Print.zip

マルチページ ドキュメント


  • Categories:

DDV を働かせたい

あまり DDV は使用しないが,数値で簡単な範囲チェックをやりたかった.
最大文字数などは指定しておけば勝手にやってくれるが,値のチェックはそうではない.

適当な(チェックしたい)タイミングで UpdateData(TRUE) を呼んでやればよい.
例えば,
void CXxxxDlg::OnChangeXxx() { UpdateData(TRUE) ; }
EN_UPDATE とどちらが良いかは不明.

本当は範囲を超えた時の入力をはじきたいが,それは簡単にはできなかった.



Copy SrcFolder\*.txt DstFolder

あるフォルダの複数ファイルのコピーと移動.
 Files_Copy_or_Move を直接利用するのではなく,FolderCopyFiles , FolderMoveFiles を利用します.
//*******************************************************************************
// 関数名 :あるフォルダ直下のファイルのコピーと移動
// 作成日 :’11/11/04
//*******************************************************************************
BOOL Files_Copy_or_Move (LPCTSTR src_Name,LPCTSTR dstPath,const BOOL isDelSrc,const BOOL exist)
{
  CString srcPath = src_Name ;
  CString srcName = _T(“*.*”) ;
  if (CString(srcPath).IsEmpty()) { return FALSE ; }
  if (!::FileIsDirectory(src_Name)) {
    srcPath = ::GetFileDir (src_Name) ;
    srcName = ::GetFileName (src_Name) ;
    }
  if (srcPath == dstPath) { return FALSE ; }
  if (::FileIsNothing(srcPath)) { return FALSE ; } // 元のフォルダが存在しない
  if (::FileIsNothing(dstPath)) {
    if (!::CreateFolder(dstPath)) { return FALSE ; }
    }
  {
    CStringArray srcFiles ;
    ::FolderEnumFiles(srcPath,&srcFiles,srcName) ;
    for (int index=0 ; index<srcFiles.GetSize() ; index++) {
      CString srcFPath = srcFiles[index] ;
      CString srcFName = ::GetFileName(srcFPath) ;
      CString newFName = ::FolderAddLastSP(dstPath) + srcFName ;
      if (!::CopyFile(srcFPath,newFName,exist)) {
        continue ;
        }
      if (isDelSrc) { // 元のファイルは削除? (移動の場合?)
        CFile::Remove(srcFPath) ;
        }
      }
    }
  return TRUE ;
  }

inline BOOL FolderCopyFiles (LPCTSTR srcName, LPCTSTR dstPath, const BOOL exist)
{ return Files_Copy_or_Move ( srcName, dstPath, FALSE, exist) ; }
inline BOOL FolderMoveFiles (LPCTSTR srcName, LPCTSTR dstPath, const BOOL exist=FALSE)
{ return Files_Copy_or_Move ( srcName, dstPath, TRUE, exist) ; }



GetLastError と FormatMessage

以前,以下を作成していた(Error.hxx )
inline CString Error::FormatMessage(const DWORD error)
{
  CString message ;
  LPVOID lpMessageBuffer = NULL ;
  if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
      NULL,error,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
      (LPTSTR)&lpMessageBuffer,0,NULL)) {
    message = LPTSTR(lpMessageBuffer) ;
    ::LocalFree(lpMessageBuffer) ;
    }
  return message ;
  }



FindNoCase

同じ関数を作ってしまったので,...
CharFnc.hxx より
//*******************************************************************************
// 関数名 :大文字/小文字を区別せずに検索
// 作成日 :’11/09/07
//*******************************************************************************
inline
int FindNoCase (LPCTSTR str1,LPCTSTR str2)
{
  CString fStr1 = str1 ;
  int fIndex = fStr1.Find(str2) ;
  if (fIndex >= 0) { return fIndex ; } // 大文字/小文字を区別して見つかった?
  CString fStr2 = str2 ;
  fStr1.MakeLower() ;
  fStr2.MakeLower() ;
  return fStr1.Find(fStr2) ; // 大文字/小文字を区別せずに(小文字にして)検索
  }

他にも,
PathName.hxx
//*******************************************************************************
// 関数名 :ファイル拡張子取得(text.DAT->dat) 小文字で
// 作成日 :’11/06/09
//*******************************************************************************
inline
CString GetFileExtLow (LPCTSTR pathName)
{
  CString ext = ::GetFileExt(pathName) ;
  ext.MakeLower() ;
  return ext ;
  }



BDH_Modify クラスを用意

BDH_Modify クラスを用意しました.
 class BDH_Modify {
 public:
   BDH_Modify () { Modified = FALSE ; }
 public:
  virtual BOOL IsModified (void) const { return Modified ; }
  virtual BOOL SetModifiedFlag (const BOOL mod=TRUE) { Modified = mod ; return TRUE ; }
  virtual BOOL CanClose (void) { return SaveModified() ; }
 public:
  virtual CString GetPathName (void) const { return _T(“ファイル”) ; }
  virtual BOOL DoFileSave (void) { return FALSE ; }
 public:
  virtual BOOL SaveModified (void) ;
 protected:
  BOOL Modified ;
  } ;

 inline
 BOOL BDH_Modify::SaveModified (void)
 {
  if (!IsModified()) { return TRUE ; }
  CString name = GetPathName() ;
  if (name.Find(‘\\’) >= 0) {
   name = ::GetFileName(name) ;
   }
  // VC98\MFC\SRC\DocCore.cpp CDocument::SaveModified() より
  CString prompt ;
  AfxFormatString1(prompt,AFX_IDP_ASK_TO_SAVE,name) ;
  switch (AfxMessageBox(prompt,MB_YESNOCANCEL,AFX_IDP_ASK_TO_SAVE)) {
   case IDCANCEL: return FALSE ; break ;
   case IDYES : if (!DoFileSave()) { return FALSE ; } break ;
   case IDNO : break ;
   default : break ;
   }
   return TRUE ;
  }

ダイアログベースなどで利用するために作成しました.
以下の様に利用しています.
 #include “BDH_Mod.hxx”
 class BDModCSV : public BDocCSV , public BDH_Modify {
 public:
  virtual BOOL Clear (void) { SetModifiedFlag(FALSE) ; return BDocCSV::Clear() ; }
 public:
  virtual void Serialize (CArchive& ar) { SetModifiedFlag(FALSE) ; BDocCSV::Serialize(ar) ; }
  } ;

 class Masters : public BDModCSV
 {
  // …
  virtual CString GetPathName (void) const { return GetFilePath() ; }
  virtual BOOL DoFileSave (void) { return FileWrite(GetFilePath()) ; }
  } ;

 BOOL Masters::AddMaster1 (Master* reg)
 {
  SetModifiedFlag(TRUE) ;
  // …
  }

 void CEditCNDlg::OnCancel()
 {
  Masters* masters = Mast_S->GetSelected() ;
  if (masters != NULL && !masters->CanClose()) { return ; }
  CDialog::OnCancel();
  }



UNICODE と VC6 → VC8 一部修正

UNICODE と VC6 → VC8  2009/12

VC6 UNICODE

wWinMainCRTStartup

VC6 → VC8

http://cid-535f5973454c1292.skydrive.live.com/self.aspx/.Public/MFC/VC6%e2%86%92VC8.txt

「全般」-「出力ディレクトリ」,「中間ディレクトリ」 .\$(ConfigurationName)
「プリコンパイル済みヘッダファイル」 $(IntDir)/$(TargetName).pch
「C/C++」-「出力ファイル」
 「ASMリスト...」
 「オブジェクト...」
 「プログラムデータベース...」
$(IntDir)/
「リンカ」-「全般」の「出力ファイル」 $(OutDir)/$(ProjectName).exe
リンカ」-「デバッグ」
 「プログラムデータベースファイルの生成」
$(OutDir)/$(ProjectName).pdb
「リソース」-「全般」の「リソースファイル名」 $(IntDir)/$(InputName).res
「MIDL」-「出力」の「タイプライブラリ」 $(IntDir)/$(ProjectName).tlb
「ブラウザ情報」-「全般」の「出力ファイル」 $(OutDir)/$(ProjectName).bsc

 



CListCtrl の列数の取得

CListCtrl の列数の取得
  int colCount = 0 ;
  // C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC\WinCtrl6.cpp
  // CListCtrl::GetColumnOrderArray より
  {
    CHeaderCtrl* pCtrl = ctrl->GetHeaderCtrl() ;
    if (pCtrl != NULL) { colCount = pCtrl->GetItemCount() ; }
    }


CListCtrl::GetItemCount では行数



CArray&saAry

CStringArray の配列を使用する時の制限?

c:\program files\microsoft visual studio\vc98\mfc\include\afxtempl.h(86) : error C2582: ‘operator ” 関数は ” 内では使用できません。
c:\program files\microsoft visual studio\vc98\mfc\include\afxtempl.h(406) : コンパイルされたクラスのテンプレートのインスタンス化 ‘void __stdcall CopyElements(class CStringArray *,const class CStringArray *,int)’ の参照を確認してください
  以下の様なコードでコメントにした Copy があると,エラーとなる.
  {
    CArray<CStringArray,CStringArray> saAry ;
    CArray<CStringArray,CStringArray> saA ;
  // saAry.Copy(saA) ;
    }

他にもいろいろとエラーになったが,うまく抜き出せなかった.
関数などの引数として与える時に,最初 const としていたためか?
const を外して,それなりにコードを書けば通るようになったみたい.
これらを利用して書いたコードは,ListBD_C.hxx



CString::ReleaseBuffer で Assert

CString::GetBuffer を使用して,ReleaseBuffer を忘れているバグがあった.
現象は,内容をコピーした別の CString で ReleaseBuffer した時にアサート.
—————————
Microsoft Visual C++ Debug Library
—————————
Debug Assertion Failed!
Program: …\…\TInet\Debug.060\TInet.exe
File: strcore.cpp
Line: 512
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
—————————
中止(A) 再試行(R) 無視(I)
—————————

他にも,GetLength で 0 になる.



DoDragDrop ですぐに抜ける?

以下の様なコードで,COleDataSource::DoDragDrop の部分がすぐ抜ける.
  CStringArray sa ;
  ::ListBoxToStringArray(m_DropList,&sa,TRUE) ;
  {
    CByteArray ba ;
    ::StringArrayToString2Z(sa,&ba) ;
    int len = ba.GetSize() ;
    HDROP hDrop = (HDROP)::GlobalAlloc(GHND,sizeof(DROPFILES) + len + sizeof(TCHAR)) ;
    if (hDrop == NULL) { return ; }
    LPDROPFILES lpdf = (LPDROPFILES)::GlobalLock(hDrop) ;
    lpdf->pFiles= sizeof(DROPFILES) ;
    lpdf->pt.x = 0 ;
    lpdf->pt.y = 0 ;
    lpdf->fNC = FALSE ;
    lpdf->fWide = FALSE ;
    #ifdef _UNICODE
    lpdf->fWide = TRUE ;
    #endif
    LPCTSTR lpFileNames = LPCTSTR(LPCSTR(lpdf)+lpdf->pFiles) ;
    memmove(LPVOID(lpFileNames),ba.GetData(),len) ;
    ::GlobalUnlock(hDrop) ;
    {
      COleDataSource* ods = new COleDataSource ;
      ods->CacheGlobalData(CF_HDROP,hDrop) ;
      ods->DoDragDrop() ;
      delete ods ;
      }
    }

AfxOleInit() を呼出していなかった.


[VC50] Windows 95 標準コントロールのドラッグアンドドロップサンプル http://support.microsoft.com/kb/152092/ja


2014/08/11 追記
上のコードで,delete ods はうまくない.
データ オブジェクトとデータ ソース : 作成と破棄



CInternetFile::ReadString

CInternetFile::ReadString
VC 6 UNICODE.exe で,文字化けと,中身がうまく処理されない.MBCS.exe はOK.
文字化けは,CHAR から TCHAR への変換を正しく処理することにより対応.
それでも,まだ改行の位置で戻らず,終端も正しくない(デバッグ版ではゴミ ‘0xCD’ が入る).
どうも,VC 6 や 7 では,うまく処理できないみたい.VC 8 では期待した動作と思われる.

  CHttpConnection* pServer = pServer = session.GetHttpConnection (svrName) ;
  CHttpFile* pFile = pServer->OpenRequest (CHttpConnection::HTTP_VERB_GET,name) ;
  pFile-> SendRequest () ;
  {
    CString buf ;
    while (pFile->ReadString(buf)) {
      CString tmp = ::ToStringTC(LPCSTR(LPCTSTR(buf))) ;
      rBuf.Add(tmp) ;
      }
    ::StringArrayToString(rBuf,rData) ;
    }

http://support.microsoft.com/kb/329071
 PRB: CInternetFile::ReadString Does Not Convert Non-Unicode Text to Unicode Text



MS11-025 その後

以前,KB2465367 などの影響を受けたが,その対応版 KB2538218 のコードの抜粋
typedef BOOL (WINAPI *PFNFINDACTCTXSECTIONSTRING)(DWORD, const GUID *, ULONG, LPCTSTR, PACTCTX_SECTION_KEYED_DATA);
static HINSTANCE _AfxLoadLangDLL(LPCTSTR pszFormat, LPCTSTR pszPath, LCID lcid)
{
 TCHAR szLangDLL[_MAX_PATH+14];
 TCHAR szLangCode[4];
 HINSTANCE hInstance = NULL;
 if (lcid == LOCALE_SYSTEM_DEFAULT) {
  Checked::tcscpy_s(szLangCode, _countof(szLangCode), _T("LOC"));
  }
 else {
  int nResult;
  nResult = ::GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, szLangCode, 4);
  if (nResult == 0)
    return NULL;
  ASSERT( nResult == 4 );
  }
 int ret;
 ATL_CRT_ERRORCHECK_SPRINTF(ret = _sntprintf_s(szLangDLL,_countof(szLangDLL),_countof(szLangDLL)-1,pszFormat,pszPath,szLangCode));
 if(ret == -1 || ret >= _countof(szLangDLL)) {
  ASSERT(FALSE);
  return NULL;
  }
 TCHAR *pszFilename = ::PathFindFileName(szLangDLL);
 ACTCTX_SECTION_KEYED_DATA data = {sizeof(data)};
 HMODULE hKernel = GetModuleHandle(_T("KERNEL32"));
 PFNFINDACTCTXSECTIONSTRING pfnFindActCtxSectionString = NULL;
 if (hKernel != NULL) {
  #ifdef _UNICODE
   pfnFindActCtxSectionString = (PFNFINDACTCTXSECTIONSTRING)GetProcAddress(hKernel, "FindActCtxSectionStringW");
  #else
   pfnFindActCtxSectionString = (PFNFINDACTCTXSECTIONSTRING)GetProcAddress(hKernel, "FindActCtxSectionStringA");
  #endif
  }
 if (pfnFindActCtxSectionString &&
 pfnFindActCtxSectionString(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, pszFilename, &data)) {
  // Load using the dll name only…
  hInstance = ::LoadLibraryEx(pszFilename, NULL, 0);
  }
 else {
  // Load using the full path…
  hInstance = ::LoadLibraryEx(szLangDLL, NULL, 0);
  }
 return hInstance;
 }



List.exe 起動時,アプリケーションエラー

以前は通っていたデバッグ用 exe をビルドし直したら,起動時にアプリケーションエラーになる様になってしまった.

原因は,アプリケーションクラス内に確保された Profile .
なぜ宣言されていたのかは今となっては不明.
ListApp.h 内をコメントにして OK .

以下が初期化される前に Profile::GetInt が通ることによりエラーとなる.
_CriticalS_ Profile::CS ;

またこのタイミング(アプリケーションクラスのコンストラクタ)では,SetRegistoryKey が指定されていないので,Profile クラスを利用すること自体がうまくないと思われる.



DECLARE_SERIAL を忘れると…

IMPLEMENT_SERIAL (T_BaseDoc, CObject,0) の所で
C:\…\T_BDDoc.cpp(63) : error C2039: ‘CreateObject’ : ‘T_BaseDoc’ のメンバではありません。
    c:\…\t_bd_.hpp(28) : ‘T_BaseDoc’ の宣言を確認してください。
C:\…\T_BDDoc.cpp(63) : error C2509: ‘_GetBaseClass’ : このメンバ関数は、’T_BaseDoc’ クラス内で宣言されていません。
C:\…\T_BDDoc.cpp(63) : error C2039: ‘classT_BaseDoc’ : ‘T_BaseDoc’ のメンバではありません。
    c:\…\t_bd_.hpp(28) : ‘T_BaseDoc’ の宣言を確認してください。
C:\…\T_BDDoc.cpp(63) : error C2039: ‘CreateObject’ : ‘T_BaseDoc’ のメンバではありません。
    c:\…\t_bd_.hpp(28) : ‘T_BaseDoc’ の宣言を確認してください。
C:\…\T_BDDoc.cpp(63) : error C2509: ‘GetRuntimeClass’ : このメンバ関数は、’T_BaseDoc’ クラス内で宣言されていません。
C:\…\T_BDDoc.cpp(63) : error C2039: ‘classT_BaseDoc’ : ‘T_BaseDoc’ のメンバではありません。
    c:\…\t_bd_.hpp(28) : ‘T_BaseDoc’ の宣言を確認してください。
C:\…\T_BDDoc.cpp(63) : error C2039: ‘classT_BaseDoc’ : ‘T_BaseDoc’ のメンバではありません。
    c:\…\t_bd_.hpp(28) : ‘T_BaseDoc’ の宣言を確認してください。
 



MS11-025 の影響?

2011/06/16 追記
2011/06/15 に MS11-025 が更新されたので,以下は古い情報になります.


 
どちらかというと,以下の影響
Microsoft Visual C++ 2005 Service Pack 1 再頒布可能パッケージ (KB2467175)
Microsoft Visual C++ 2008 Service Pack 1 再頒布可能パッケージ (KB2467174)
MS11-025

Win 7 で,AFX_IDS_~ の表示が英語になってしまう.
 Open , Save As , 印刷プレビューのボタン
 All Files (*.*)
 Failed to create empty document.
 C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\l.jpn

AppCore.cpp の _AfxLoadLangDLL と思うが,うまく確かめられない.
ここが呼ばれる前のコードを切り出して lcid は 1041 で,JPN が求まっている所までは確認.

デバッグ版では,MFC90JPN.dll がロードされている(デバッガやリソースモニターで確認).
C:\Windows\WinSxS\x86_microsoft.vc90.mfcloc_1fc8b3b9a1e18e3b_9.0.30729.5570_none_4977a39175471b31\MFC90JPN.DLL

リリース版に,デバッグ情報を付加して動作を見ると
SXS: Invalid parameter(s) passed to FindActCtxSection*()
 dwFlags = 0x00000001
 ReturnedData = 0018F58C
  ->cbSize = 0

FindActCtxSection を検索すると,
Visual C++ MFC and ATL FindActCtxSection
そこからのリンクは Martin’s Blog 自動翻訳


_AfxLoadLangDLL のコードを比べると,
Microsoft Visual Studio 2005 Service Pack 1 (KB2465367) 適用前
static HINSTANCE _AfxLoadLangDLL(LPCTSTR pszFormat, LPCTSTR pszPath, LCID lcid)
{
 …
 int ret;
 ATL_CRT_ERRORCHECK_SPRINTF(ret = _sntprintf_s(szLangDLL,_countof(szLangDLL),
     _countof(szLangDLL)-1,pszFormat,pszPath,szLangCode));
 if(ret == -1 || ret >= _countof(szLangDLL)) {
  ASSERT(FALSE);
  return NULL;
  }
 hInstance = ::LoadLibrary(szLangDLL);
 return hInstance;
 }

適用後
static HINSTANCE _AfxLoadLangDLL(LPCTSTR pszFormat, LPCTSTR pszPath, LCID lcid)
{
 …
 int ret;
 ATL_CRT_ERRORCHECK_SPRINTF(ret = _sntprintf_s(szLangDLL,_countof(szLangDLL),
     _countof(szLangDLL)-1,pszFormat,pszPath,szLangCode));
 if(ret == -1 || ret >= _countof(szLangDLL)) {
  ASSERT(FALSE);
  return NULL;
  }
 TCHAR *pszFilename = ::PathFindFileName(szLangDLL);
 ACTCTX_SECTION_KEYED_DATA data;
 if (FindActCtxSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
    ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,pszFilename, &data) ) {
  // Load using the dll name only…
  hInstance = ::LoadLibraryEx(pszFilename, NULL, LOAD_LIBRARY_AS_DATAFILE);
  }
 else {    // Load using the full path…
  hInstance = ::LoadLibraryEx(szLangDLL, NULL, 0);
  }

 return hInstance;
 }

FindActCtxSectionString によって,Win 2K では動作しなくなるらしい.


2011/05/10 追記
Ted’s Blog Fixing problems with FindActCtxSectionString in MFC security updates
 static.exe での Win2K 対応と,ACTCTX_SECTION_KEYED_DATA の初期化など
 
比べてもあまり意味はないが,VC 2010 では
static HINSTANCE _AfxLoadLangDLL(LPCTSTR pszFormat, LPCTSTR pszPath, LCID lcid)
{
  TCHAR szLangDLL[_MAX_PATH+14];
  TCHAR szLangCode[4];
  HINSTANCE hInstance;
  if (lcid == LOCALE_SYSTEM_DEFAULT) {
    Checked::tcscpy_s(szLangCode, _countof(szLangCode), _T(“LOC”));
    }
  else {
    int nResult;
    nResult = ::GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, szLangCode, 4);
    if (nResult == 0)
      return NULL;
    ASSERT( nResult == 4 );
    }
  int ret;
  ATL_CRT_ERRORCHECK_SPRINTF(ret = _sntprintf_s(szLangDLL,_countof(szLangDLL),
               _countof(szLangDLL)-1,pszFormat,pszPath,szLangCode));
  if(ret == -1 || ret >= _countof(szLangDLL)) {
    ASSERT(FALSE);
    return NULL;
    }
  hInstance = ::LoadLibraryEx(szLangDLL, NULL, 0);
  return hInstance;
  }  

pszPath は “C:\Windows\system32\” になっている.
 



VC 2010 ドキュメントのプレビュー

サムネイル void CXxxDoc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
プレビュー void CXxxView::OnDraw(CDC* pDC)

プレビューの方はそれなりに動作している様だが,サムネイルの方はちょっと動きが違う様な?




    top

    %d人のブロガーが「いいね」をつけました。