Iwao Dev

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

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

MFC

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

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;

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ


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) ;
    }


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 ;
        }
      }
この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ


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));
アプリケーション エラー
プロジェクトのプロパティ,「リソース」-「プリプロセッサの定義」に “_AFXDLL;” があったので削除.

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ


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 ;
    }


今度は,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 ビットそれぞれで登録されているみたい.

Excel 2010 で試すには,コントロールの挿入のために開発タブを有効にする必要がある.

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ

  • 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) で終了しました。

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ


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 定義済みマクロ

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ


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

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

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ


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 文字まで?

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ

  • 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 サンプル
DImage では,ImageDMF が追加される.
DImage.zip

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ


HTML の表示

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


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

2. ビューのソースの CXxxxView::OnInitialUpdate() を,適当なアドレスに修正する.
  Navigate2(_T(“https://mish.myds.me/wordpress/dev/“),NULL,NULL);


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

2. 追加したコントロールの変数を割り当てる(ここでは,m_WebBrowse とした).
3. OnInitDialog などで
 m_WebBrowse.Navigate(_T(“https://mish.myds.me/wordpress/dev/“),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(“https://mish.myds.me/wordpress/dev/“)) ;

この投稿は役に立ちましたか? 役に立った 役に立たなかった 0 人中 0 人がこの 投稿 は役に立ったと言っています。

  にほんブログ村 IT技術ブログへ



    top

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