プログラミング


プログラミング関連のページです。 主に、Visual C++・MFCの備忘録です。

  • 開発環境(初代)
    • Visual Studio .NET 2003
    • パソコン
      • 型式 LaVie G (2004年秋冬モデル)
      • CPU Pentium M 1.6GHz
      • HDD 60GB
      • メモリ 1GB
  • 開発環境(2代目)
    • Visual Studio 2017
    • パソコン
      • 型式 LaVie NS (2015年秋冬モデル)
      • CPU Core i7 2.5GHz
      • HDD 1TB
      • メモリ 8GB

COMの呼び出しのタイムアウト間隔を変更する

MFCアプリケーションから、WordやExcelなどのCOMを呼び出して実行する際に、処理に時間が掛かることがあります。あまり時間が掛かり過ぎるとタイムアウトになり「サーバー使用中」のメッセージが頻繁に出てくるため、場合によっては煩わしくなってしまいます。

com_timeout.png


そこで下記のコードの様に、“SetMessagePendingDelay”関数でタイムアウト間隔をミリ秒単位で変更することで、メッセージの出てくる頻度を抑えることができます。
#include <afxole.h>

BOOL CSampleApp::InitInstance()
{
	// OLE ライブラリを初期化します。
	if (!AfxOleInit())
	{
		AfxMessageBox(_T("OLEライブラリ 初期化失敗"));
		return FALSE;
	}

	// COMの呼び出しのタイムアウト間隔を設定(ミリ秒)
	AfxOleGetMessageFilter()->SetMessagePendingDelay(10000);
}
参考URL(Microsoft サポート)
COM を使用した処理に長時間を要するとき [サーバー使用中] ダイアログ ボックスが表示されないようにする方法

INIファイルに情報を保存する

Visual C++ で作成したMFCアプリケーションでは、アプリケーションの情報などを保存する時に、”WriteProfileInt”や”WriteProfileString”を使うとデフォルトでレジストリに保存されます。 レジストリではなくiniファイルに保存するためには、CWinApp派生クラスのInitInstanceにある”SetRegistryKey”のある行をコメントアウトする必要があります。
// TODO: この文字列を、会社名または組織名などの、 
// 適切な文字列に変更してください。 
//SetRegistryKey(_T("アプリケーション ウィザードで生成されたローカル アプリケーション")); 
LoadStdProfileSettings(4);  // 標準の INI ファイルのオプションをロードします (MRU を含む)
しかしこのままでは、WINDOWSフォルダ内にiniファイルが保存されてしまします。iniファイルの保存する場所を指定するには、CWinApp派生クラスのInitInstanceにコードを追加します。
#include "shlwapi.h"
 
if(m_pszProfileName)
{
    TCHAR szPath[MAX_PATH];
 
    ::GetModuleFileName(NULL, szPath, MAX_PATH);  // 実行ファイルのパスを取得
    ::PathRenameExtension(szPath, _T(".ini"));  // 拡張子をiniへ変更
    free ((void*)m_pszProfileName);  // メモリの解放
    m_pszProfileName = _tcsdup(szPath);  // 新しいパスを設定 
}
上記の例では、実行ファイルと同じ場所にiniファイルを作成します。

C++でクラス名を判定する

プログラミングをしていると、時々クラス名を取得したいときがあります。
MFCの「CObject」の派生クラスだと、CObject::IsKindOf で判定することができます。

では、普通のクラスの場合は、どうしたら良いのか?
調べると、下記のコードのように typeid を使うことで、普通のクラス名の取得・判定をすることができることがわかりました。
#include "typeinfo.h"
 
	// クラス名を取得
	const type_info& id = typeid(*this);

	if (typeid(CSample) == id)
	{
		// クラス名は「CSample」です。
	}

エディットコントロールでドラッグドロップ

#keywords(VC++,MFC,ドラッグドロップ)

エディットコントロールでドラッグドロップ [#qd70c813]

MFCアプリケーションのエディットコントロールに、ドラッグドロップでファイルを受けるには、コントロールのプロパティで「Acccept Files」を”True”にすれば、ファイルを受けることができます。
しかしこれだけでは、受けることができるだけでファイル名を取得したり、表示することはできません。

そこで、下記のようなクラスを作成しました。エディットコントロールをサブクラス化することで、ドラッグドロップするとファイル名が表示されるとともに、メンバ変数にファイルのパスが格納されます。
// DropEdit.h
 
#pragma once
 
// CDropEdit
 
class CDropEdit : public CEdit
{
	DECLARE_DYNAMIC(CDropEdit)
 
public:
	CDropEdit();
	virtual ~CDropEdit();
 
protected:
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnDropFiles(HDROP hDropInfo);
	CString m_szFilePath;
};
// DropEdit.cpp
#include "stdafx.h"
#include "DropEdit.h"
#include ".\dropedit.h"
 
// CDropEdit
 
IMPLEMENT_DYNAMIC(CDropEdit, CEdit)
CDropEdit::CDropEdit()
{
	m_szFilePath = _T("");
}
 
CDropEdit::~CDropEdit()
{
}
 
BEGIN_MESSAGE_MAP(CDropEdit, CEdit)
	ON_WM_DROPFILES()
END_MESSAGE_MAP()
 
// CDropEdit メッセージ ハンドラ
 
void CDropEdit::OnDropFiles(HDROP hDropInfo)
{
	UINT nFiles;	// ドロップファイル数
	UINT nSize;	// ファイル名サイズ
	CString szName;	// 文字列
 
	// ドロップされたファイル数を取得
	nFiles = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0);
 
	if (nFiles < 1)
	{
		return;
	}
 
	nSize = DragQueryFile(hDropInfo, 0, NULL, 0);
	DragQueryFile(hDropInfo, 0, szName.GetBuffer(nSize + 1), nSize + 1);
	szName.ReleaseBuffer();
 
	m_szFilePath = szName;
	int nPos = szName.ReverseFind('\\');
	szName = szName.Mid(nPos + 1);
 
	SetWindowText(szName);
 
	CEdit::OnDropFiles(hDropInfo);
}
OK キャンセル 確認 その他