VC 6 MFC でオートメーション利用
「Class Wizard」-「クラスの追加」-「タイプライブラリから」
InitInstance 内の追加のコード
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
{ // 利用をこのブロックにまとめてます
AfxOleInit() ;
IAsPln2D to2D ;
if (!to2D.CreateDispatch(_T(“PAtoMHD.AsPln2D”))) {
return FALSE ;
}
CString selFile = to2D.BrowseFile(_T(“.\\*.mhd”),_T(“mhd を選択してください”)) ;
if (!selFile.IsEmpty()) {
if (to2D.Load(selFile)) {
to2D.Save(selFile+_T(“.svg”)) ;
}
}
return FALSE ;
}
CTestDlg dlg;
…
#import を利用する方法
アプリケーションクラスのソースに
#import “C:\…\SVG\PAtoMHD\Release\PAtoMHD.tlb”
InitInstance に
{
AfxOleInit() ;
PAtoMHD::IAsPln2DPtr to2D ;
if (to2D.CreateInstance(__uuidof(PAtoMHD::AsPln2D)) != S_OK) {
return FALSE ;
}
CString selFile = LPCTSTR(to2D->BrowseFile(_T(“.\\*.mhd”),_T(“mhd を…”))) ;
if (!selFile.IsEmpty()) {
if (to2D->Load(LPCTSTR(selFile))) {
to2D->Save(LPCTSTR(selFile+_T(“.svg”))) ;
}
}
return FALSE ;
}
CreateInstance の時の PAtoMHD::AsPln2D がわからなかった.
PAtoMHD::IAsPln2D としてしまっていた.
ipx , PartsA , PartsA_C3D
2012/04/25 以前の PartsA などの ipx の読込みは,CArchive::ReadString を利用していた.
今回,Parts ファミリのファイルアクセスは,LoadText ,SaveText に置き換える.
ReadString を利用していた時の動作
PartsA_C3D::ImportTxt より PartsA::SerializeTxt が呼ばれる.
PACnv3.exe!PartsA::SerializeTxt(CArchive & ar={…}) 行 464
PACnv3.exe!PartsA::Serialize(CArchive & ar={…}) 行 361
PACnv3.exe!PartsA_C3D::ImportTxt(… * pathName) 行 336
PACnv3.exe!PartsA_C3D::Import(… * pathName) 行 137
PACnv3.exe!CPACnv3Doc::OnOpenDocument(… * lpszPathName) 行 177
PartsA_C3D::ImportTxt で,exe と ipx の種類により,ReadString で読める形式でコピーする.
FileMBWC.hxx GetReadTextName により,
UNICODE.exe の場合,UTF-16 のテキストファイルにコピーする.
PartsA::Serialize を呼出す前には,BOM を読み飛ばした位置にポインタがある.
FileMBWC.hxx SerializeTextBOM(ar) により,UNICODE.exe の場合に飛ばす.
* PartsA_C3D を利用してない exe では,形式が異なるファイルは読み出せなかった.
VxxxxV などの exe は,PartsA::Serialize としているのでこれにあたる.
ReadString を利用しない様にしたので,PartsA_C3D::ImportTxt は,シンプルになった.
BOOL PartsA_C3D::ImportTxt (LPCTSTR pathName)
{
if (!PartsA::IsTextFile(pathName)) { return FALSE ; }
CString str ;
if (!::LoadText(pathName,str)) { return FALSE ; }
return PartsA::ImportTxt(str) ;
}
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/“)) ;
コード分析による修正
VC 9
~\CharFnc.hxx(155) : warning C6284: オブジェクトがパラメータ '3' として渡されました。 ~\CharFnc.hxx(155) : warning C6284: オブジェクトがパラメータ '5' として渡されました。 str.Format(_T("(%*s,%*s)"),width, ToString(value.x) ,width, ToString(value.y) ) ; str.Format(_T("(%*s,%*s)"),width,LPCTSTR(ToString(value.x)),width,LPCTSTR(ToString(value.y))) ; 間違って LPCSTR としてしまうと,_UNICODE では error C2440: '' : 'CString' から 'LPCSTR' に変換できません。 LPSTR としてしまうと, error C2440: '' : 'CString' から 'LPSTR' に変換できません。
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 の使い方
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 の次に追加.
XML の読込テスト – 4
全ては表現できてないが,msxml.dll により読込んだデータの関連はこんな感じか?
IXMLDOMDocument | ||||||
documentElement | ——– | IXMLDOMElement | ||||
attributes | ——– | IXMLDOMNamedNodeMap | ||||
length | ||||||
item 0 | ——– | IXMLDOMAttribute | ||||
: | ||||||
item n-1 | name | |||||
value | ||||||
childNodes | ——– | IXMLDOMNodeList | ||||
length | ||||||
item 0 | ——– | IXMLDOMElement | ||||
: | ||||||
: | ||||||
item n-1 | ——– | IXMLDOMNode | ||||
text | ||||||
nodeName | ||||||
tagName | ||||||
XML の読込テスト – 3
BOOL ReadElement( MSXML::IXMLDOMElementPtr pElement, long indent ) { CString tab = _T("\t\t\t\t\t\t\t\t\t\t\t\t\t") ; CString lsp = tab.Left(indent) ; if (pElement == NULL) { return FALSE ; } MSXML::IXMLDOMNodeListPtr pNode = pElement->GetchildNodes() ; { CString node = LPCTSTR(pElement->GetnodeName()) ; CString tagN = LPCTSTR(pElement->GettagName()) ; CString text ; // if (pNode->Getlength() == 0) { text = LPCTSTR(pElement->Gettext()) ; // } MSXML::IXMLDOMNamedNodeMapPtr aMap = pElement->Getattributes() ; CString str ; if (aMap != NULL) { str = ::ToString(aMap->Getlength()) ; for (int aIndex=0 ; aIndex<aMap->Getlength() ; aIndex++) { MSXML::IXMLDOMAttributePtr attr = aMap->Getitem(aIndex) ; if (attr == NULL) { continue ; } str += CString(_T("\t")) + LPCTSTR(attr->Getname()) ; str += CString(_T(" ")) + ::ToStringTC(LPCWSTR(attr->Getvalue().bstrVal)) ; } } cout << LPCTSTR(lsp) << LPCTSTR(node) << _T("\t") << LPCTSTR(text) << _T("\t") << LPCTSTR(str) << endl ; for (int index=0 ; index<pNode->Getlength() ; index++) { MSXML::IXMLDOMElementPtr child = pNode->Getitem(index) ; ReadElement(child,indent+1) ; } } return TRUE ; }
attr->value が,VARIANT で,VT_BSTR
これを LPCTSTR とすることは出来ず,::ToStringTC をしている.
::ToStringTC は引数とコンパイルオプションにより char* ⇔ wchar* が可能
今回の場合,内部では ::WideCharToMultiByte で変換している.
要素の内容の取得はこんな感じか?
// text = LPCTSTR(pElement->Gettext()) ; if (pNode->Getlength() > 0) { MSXML::IXMLDOMNodePtr pText = pNode->Getitem(0) ; if (pText != NULL) { text = LPCTSTR(pText->text) ; } }
XML の読込テスト – 2
要素へのアクセスはこんな感じと思われるが,Gettext の使い方がよくわからない.
BOOL ReadElement(MSXML::IXMLDOMElementPtr pElement,long indent)
{
CString tab = _T(“\t\t\t\t\t\t\t\t\t\t\t\t\t”) ;
CString lsp = tab.Left(indent) ;
if (pElement == NULL) { return FALSE ; }
MSXML::IXMLDOMNodeListPtr pNode = pElement->GetchildNodes() ;
{
CString node = LPCTSTR(pElement->GetnodeName()) ;
CString tagN = LPCTSTR(pElement->GettagName()) ;
CString text ;
// if (pNode->Getlength() == 0) {
text = LPCTSTR(pElement->Gettext()) ;
// }
cout << LPCTSTR(lsp) << LPCTSTR(node) << _T(“\t”) << LPCTSTR(text) << endl ;
for (int index=0 ; index<pNode->Getlength() ; index++) {
MSXML::IXMLDOMElementPtr child = pNode->Getitem(index) ;
ReadElement(child,indent+1) ;
}
}
return TRUE ;
}
BOOL TestXML (void)
{
…
if (pDoc->load(LPCTSTR(loadFile)) == VARIANT_TRUE) {
{
MSXML::IXMLDOMElementPtr root = pDoc->documentElement ;
ReadElement(root,0) ;
}
}
…
}
XML の読込テスト
// L_xml_2.cpp : コンソール アプリケーション用のエントリ ポイントの定義
//
#include “StdAfx.h”
#include “L_xml_2.h”
#import <msxml.dll> named_guids
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
BOOL TestXML (void)
{
HRESULT hr = ::CoInitialize(NULL) ;
if (FAILED(hr)) { return FALSE ; }
{
MSXML::IXMLDOMDocumentPtr pDoc = NULL ;
hr = pDoc.CreateInstance(MSXML::CLSID_DOMDocument) ;
if (FAILED(hr)) { return FALSE ; }
CString loadFile = _T(“test.xml”) ;
{
if (pDoc->load(LPCTSTR(loadFile)) == VARIANT_TRUE) {
printf(“%s\r\n”,(LPCSTR)pDoc->xml) ;
{
MSXML::IXMLDOMElementPtr root = pDoc->documentElement ;
CString tagN = LPCTSTR(root->tagName) ;
CString text = LPCTSTR(root->text) ;
printf(“<%s>%s\r\n”,tagN,text) ;
MSXML::IXMLDOMNodeListPtr nodeL = root->childNodes ;
for (int index=0 ; index<nodeL->Getlength() ; index++) {
MSXML::IXMLDOMElementPtr child = nodeL->Getitem(index) ;
CString tagN = LPCTSTR(child->tagName) ;
CString text = LPCTSTR(child->text) ;
printf(“<%s>%s\r\n”,tagN,text) ;
}
}
}
else {
printf(_T(“error … %s\r\n%s\r\n”),loadFile,(LPCSTR)pDoc->parseError->Getreason()) ;
}
}
}
::CoUninitialize() ;
return TRUE ;
}
/////////////////////////////////////////////////////////////////////////////
// 唯一のアプリケーション オブジェクト
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// MFC の初期化および初期化失敗時のエラーの出力
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: 必要に応じてエラー コードを変更してください。
cerr << _T(“Fatal Error: MFC initialization failed”) << endl;
nRetCode = 1;
}
else
{
/*
// TODO: この位置にアプリケーションの動作を記述してください。
CString strHello;
strHello.LoadString(IDS_HELLO);
cout << (LPCTSTR)strHello << endl;
*/
TestXML() ;
}
return nRetCode;
}
勘違いをしていたので, ±×÷
UNICODE で,±×÷ はそれぞれ,U+00B1 , U+00D7 , U+00F7 になる.
以下は,よく参考にさせてもらっている所
文字コード(日本語漢字コード表)
文字列の縦方向の配置
svg:text の配置で,横方向の指定(text-anchor=”middle”)はあるが,縦方向はなさそうだったので…
if (fabs(incX) > 1e-7 || fabs(incY) > 1e-7) {
CString moveStr = _T(“translate(“)+ToString(pnt.x)+_T(“,”)+ToString(pnt.y)+_T(“)\t”) ;
CString rot_Str ;
CString skewStr ;
if (fabs(incX) > 1e-7) {
rot_Str = _T(“rotate(“)+ToString(0-incX)+_T(“,0,0)\t”) ;
}
if (fabs(incY) > 1e-7) {
skewStr = _T(“skewX(“) + ToString(0+incY) + _T(“)\t”) ;
}
CString vAlign ;
{
P2 move = P2(0,0+txH.GetHeight()/3) ;
vAlign = _T(“translate(“) + ToString(move.x) + _T(“,“) + ToString(move.y) + _T(“)\t”) ;
}
th.AddAttribute (_T(“transform”), moveStr + rot_Str + skewStr + vAlign ) ;
}
else {
th.AddAttribute (_T(“x”), ::ToString(pnt.x)) ;
th.AddAttribute (_T(“y”), ::ToString(pnt.y+txH.GetHeight()/3)) ;
}
文字列と文字の回転
{
TextH txH = parts1.GetTextH (thIndex) ;
P3 pnt = parts1.GetPTextH(thIndex) ;
XmlOut_E th(_T(“text”),txH.GetText()) ;
{
th.AddAttribute (_T(“text-anchor”), _T(“middle”) ) ;
th.AddAttribute (_T(“font-size”), ::ToString(txH.GetHeight())) ;
}
if (fabs(txH.GetIncX()) > 1e-7 || fabs(txH.GetIncY()) > 1e-7) {
CString moveStr = _T(“translate(“) + ToString(pnt.x) + _T(“,”) + ToString(pnt.y) + _T(“)\t”) ;
CString rot_Str ;
CString skewStr ;
if (fabs(txH.GetIncX()) > 1e-7) {
rot_Str = _T(“rotate(“) + ToString(0-txH.GetIncX()) + _T(“,0,0)\t”) ;
}
if (fabs(txH.GetIncY()) > 1e-7) {
skewStr = _T(“skewX(“) + ToString(0+txH.GetIncY()) + _T(“)\t”) ;
}
th.AddAttribute (_T(“transform”), moveStr + rot_Str + skewStr ) ;
}
else {
th.AddAttribute (_T(“x”), ::ToString(pnt.x)) ;
th.AddAttribute (_T(“y”), ::ToString(pnt.y)) ;
}
g.AddChild(th) ;
}
translate で回転の位置に動かし,
rotate で文字列を回転
skewX で文字を傾ける
explorer /e,/select
Explorer.exe コマンドライン オプション
void CDropADlg::OnExecExplorer()
{
UpdateData(TRUE) ;
CString file = m_SelectFile ;
ShellExec se ;
if (::FileIsDirectory(file)) {
se.SetFile(file) ;
}
else {
se.SetNon2QMark(TRUE) ;
se.SetFile(_T(“explorer.exe”)) ;
se.SetParamaters(_T(“/e,/select,”)+file) ;
}
se.Execute() ;
}
XML の書出しテスト – 5
MSXML.dll を利用しない方法を用意.
//#include “Xml_MS_.hxx”
#include “XmlOut.hxx”
#include “SvgOut.hxx”
class Xml_Attribute {
public:
// …
protected:
CString Name ;
CString Value ;
} ;
class XmlOut_E {
public:
// …
protected:
CString Name ;
CString Text ;
CArray<Xml_Attribute,Xml_Attribute> Attribute ;
protected:
CArray<XmlOut_E,XmlOut_E> Child ;
} ;
inline
BOOL XmlOut::Export (const XmlOut_E& elements,LPCTSTR svgName)
{
#ifdef UseMSXML
return Xml_MS::Export(elements,svgName) ;
#endif
CStringArray strAry ;
{
#ifdef _UNICODE
CString xml_ver = _T(“<?xml version=\”1.0\” encoding=\”utf-16\”?>”) ;
#else
CString xml_ver = _T(“<?xml version=\”1.0\” encoding=\”Shift-JIS\”?>”) ;
#endif
strAry.Add( xml_ver) ;
}
{
CStringArray sa ;
CreateElement(elements,&sa,0) ;
strAry.Append(sa) ;
}
return ::SaveText(svgName,strAry,TRUE) ;
}
inline
BOOL XmlOut::CreateElement (const XmlOut_E& elements,CStringArray* sa,const int indent)
{
CString tab = _T(“\t\t\t\t\t\t\t\t\t\t\t\t\t”) ;
CStringArray strAry ;
int nowIndent = indent ;
if (elements.IsComment()) {
sa->Add(tab.Left(indent) + _T(“<!–“)+elements.GetText()+_T(“–>”)) ;
return TRUE ;
}
CString eleStr ;
{
eleStr = tab.Left(indent) + _T(“<“) + elements.GetName() + _T(” “) ;
CString attStr ;
for (int aIndex=0 ; aIndex<elements.GetAttributeCount() ; aIndex++) {
Xml_Attribute a = elements.GetAttribute(aIndex) ;
CString name = a.GetName () ;
CString value= a.GetValue() ;
attStr += name + _T(“=\””) + value + _T(“\”\t”) ;
}
if (!attStr.IsEmpty()) {
eleStr += attStr ;
}
CString nameOrChild ;
if (!elements.GetText().IsEmpty()) {
nameOrChild = elements.GetText() ;
eleStr += _T(” >”) + nameOrChild ;
}
else {
CStringArray saChild ;
for (int cIndex=0 ; cIndex<elements.GetChildCount() ; cIndex++) {
XmlOut_E c = elements.GetChild(cIndex) ;
CreateElement(c,&saChild,indent+1) ;
}
if (saChild.GetSize() > 0) {
::StringArrayToString(saChild,nameOrChild) ;
eleStr += _T(” >\r\n”) + nameOrChild ;
}
}
if (nameOrChild.IsEmpty()) {
eleStr += _T(“/>”) ;
}
else {
if (!elements.GetText().IsEmpty()) {
eleStr += _T(“</”) + elements.GetName() + _T(“>”) ;
}
else {
eleStr += tab.Left(indent+1) + _T(“</”) + elements.GetName() + _T(“>”) ;
}
}
strAry.Add(eleStr) ;
}
return sa->Append(strAry) ;
}