CEditView 雑記 |
Last Updated: Nov.24,2006 |
使用しているコンパイラは、Microsoft Visual C++ 6.0 です。これ以外のバージョンでは記述と食い違うことがあるかも知れません。 |
CEditView クラスは、シンボル _UNICODE を定義してビルドすると Shift-JIS ファイルの読み書きが出来なくなります。これが不都合な場合には自分で実装する必要があります。
■ 実装例1
まず、CEditView の派生クラスで次の 3 つのメンバ関数を宣言します。
public: #ifdef _UNICODE void ReadFromArchiveA(CArchive& ar); void WriteToArchiveA(CArchive& ar); void SerializeA(CArchive& ar); #endif
いろいろな実装法があると思いますが、以下の例では Win32 API の MultiByteToWideChar, WideCharToMultiByte 関数を使ってみました。この他、ATL マクロの A2W, W2A を使う方法もあります。
#ifdef _UNICODE void CMyView::ReadFromArchiveA(CArchive& ar) { ASSERT_VALID(this); CFile* pFile = ar.GetFile(); ASSERT(pFile->GetPosition() == 0); DWORD nFileSize = pFile->GetLength(); char *lpszA = new char[nFileSize+1]; if (lpszA == NULL) AfxThrowMemoryException(); if (ar.Read(lpszA, nFileSize) != nFileSize) { delete [] lpszA; AfxThrowArchiveException(CArchiveException::endOfFile); } lpszA[nFileSize] = '\0'; int nLen = ::MultiByteToWideChar(CP_ACP, 0, lpszA, -1, NULL, 0); if ((UINT)nLen > nMaxSize) { AfxMessageBox(AFX_IDP_FILE_TOO_LARGE); delete [] lpszA; AfxThrowUserException(); } LPWSTR lpszW = new WCHAR[nLen+1]; ::MultiByteToWideChar(CP_ACP, 0, lpszA, -1, lpszW, nLen); SetWindowText(lpszW); delete [] lpszW; delete [] lpszA; ASSERT_VALID(this); } void CMyView::WriteToArchiveA(CArchive& ar) { ASSERT_VALID(this); LPCWSTR lpszW = LockBuffer(); ASSERT(lpszW != NULL); int nLen = ::WideCharToMultiByte(CP_ACP, 0, lpszW, -1, NULL, 0, NULL, NULL); char *lpszA = new char[nLen+1]; ::WideCharToMultiByte(CP_ACP, 0, lpszW, -1, lpszA, nLen, NULL, NULL); TRY { ar.Write(lpszA, strlen(lpszA)); } CATCH_ALL(e) { UnlockBuffer(); delete [] lpszA; THROW_LAST(); } END_CATCH_ALL UnlockBuffer(); delete [] lpszA; ASSERT_VALID(this); } void CMyView::SerializeA(CArchive& ar) { ASSERT_VALID(this); if (ar.IsStoring()) { WriteToArchiveA(ar); } else { ReadFromArchiveA(ar); } ASSERT_VALID(this); } #endif
呼び出しは、CDocument の派生クラスの Serialize 関数を以下のように書き直します。
void CMyDoc::Serialize(CArchive& ar) { #ifdef _UNICODE ((CMyView*)m_viewList.GetHead())->SerializeA(ar); #else ((CEditView*)m_viewList.GetHead())->SerializeRaw(ar); #endif }
■ 実装例2
正攻法ではないのですが、CStdioFile クラスをロケールを切り替えて使うというちょっと面白い方法があります。CStdioFile クラスのソースをみると、ReadString, WriteString 関数はそれぞれ C ランタイムの fgetws, fputws 関数を使って実装されており、現在のロケールの LC_CTYPE カテゴリに依存して動作することが分かります。
BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName) { CStdioFile f; CFileException fe; CString sLine, sText; if (!f.Open(lpszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe)) { ReportSaveLoadException(lpszPathName, &fe, FALSE, AFX_IDP_FAILED_TO_OPEN_DOC); return FALSE; } DeleteContents(); SetModifiedFlag(); CWaitCursor wait; if (f.GetLength() != 0) { /* m_sLocale = _T(".932"); */ _tsetlocale(LC_CTYPE, m_sLocale); while (f.ReadString(sLine)) sText += sLine + _T("\r\n"); f.Close(); _tsetlocale(LC_CTYPE, _T("C")); } SetModifiedFlag(FALSE); ((CEditView*)m_viewList.GetHead())->SetWindowText(sText); return TRUE; } BOOL CMyDoc::OnSaveDocument(LPCTSTR lpszPathName) { CStdioFile f; CFileException fe; CString sText; if (!f.Open(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive, &fe)) { ReportSaveLoadException(lpszPathName, &fe, TRUE, AFX_IDP_INVALID_FILENAME); return FALSE; } CWaitCursor wait; /* m_sLocale = _T(".932"); */ _tsetlocale(LC_CTYPE, m_sLocale); ((CEditView*)m_viewList.GetHead())->GetWindowText(sText); sText.Replace(_T("\r\n"), _T("\n")); f.WriteString(sText); f.Close(); _tsetlocale(LC_CTYPE, _T("C")); SetModifiedFlag(FALSE); return TRUE; }
こちらは、CDocument の派生クラス CMyDoc に実装してみました。ファイルの末尾に勝手に改行を挿入してしまうなど、あまり厳密ではありません。なお、使用する場合には、<locale.h> をインクルードする必要があります。
【参考】 Microsoft Visual C++ 6.0 で Unicode アプリケーションを作成する場合の手順
|
Back | Copyright (c) 2006 AOK. All Rights Reserved. |