特になし

とりとめもなくダラダラ書いてみようという感じ・・・

全体表示

[ リスト | 詳細 ]

記事検索
検索

全5ページ

[1] [2] [3] [4] [5]

[ 次のページ ]

矢印キーで現在位置が移動しないのは何故か?
ウィンドウプロシージャが対応していないから?
親ウィンドウを変えてみよう。
 
ということで、CreateWindowEx の第9引数 HWND hWndParent に Me.Handle を渡していたのを、Me.ParentForm.Handle に変えてみた。
が、ビルドするとエラーとなった。Me.ParentForm はデザインモードでは Nothing になっているようだ。
仕方がないので、MyRichText の Public Sub New を
 
    Public Sub New(ByVal hwndParent As IntPtr, ByVal left As Integer, ByVal top As Integer, ByVal width As Integer, ByVal height As Integer)
 
        InitializeComponent()
 
        Me.Left = left
        Me.Top = top
        Me.Width = width
        Me.Height = height
 
        Dim errorNo As Integer
        Dim hmRichEd20 As IntPtr = LoadLibrary("Msftedit.dll")
        If hmRichEd20 <> IntPtr.Zero Then
            hwndRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RICHEDIT50W", "", WS_CHILD + WS_VISIBLE + ES_MULTILINE, Me.Left, Me.Top, Me.Width, Me.Height, hwndParent, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)
            If hwndRichEdit = IntPtr.Zero Then
                errorNo = Marshal.GetLastWin32Error()
                Debug.WriteLine(errorNo)
            Else
                SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_OR, ES_VERTICAL)
            End If
        End If
 
    End Sub
 
に変更し、Form 側では
 
Imports System.Data
 
Public Class Form1
 
    Private rt As MyRichText
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        rt = New MyRichText(Me.Handle, Me.ClientRectangle.Left, Me.ClientRectangle.Top, Me.ClientRectangle.Width, Me.ClientRectangle.Height)
    End Sub
 
End Class
 
としてみた。
 
イメージ 1
図1 親ウィンドウを変更版
 
これで実行してみたところ、←キーで上に移動し、↑キーで右に、→キーで下に、↓キーに左に移動するようになった。要は横書きの場合の位置関係と同じ位置に移動する。まぁ、仕方がないのかもしれないが、それにしても使いにくい・・・。
Visual Basic で縦書き入力コントロールを使用する方法・その6 のソースコードを C# に書き換えてみた。
 
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
 
namespace WindowsApplication1
{
    public partial class MyRichText : UserControl
    {
        [DllImport("kernel32.dll", SetLastError=true)]
        static extern IntPtr LoadLibrary(string lpFileName);
 
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr CreateWindowEx(
           int dwExStyle,
           string lpClassName,
           string lpWindowName,
           int dwStyle,
           int x,
           int y,
           int nWidth,
           int nHeight,
           IntPtr hWndParent,
           IntPtr hMenu,
           IntPtr hInstance,
           IntPtr lpParam);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
 
        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError=true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool DestroyWindow(IntPtr hwnd);
 
        private const int WS_EX_CLIENTEDGE = 0x200;
        private const int WS_CHILD = 0x40000000;
        private const int WS_VISIBLE = 0x10000000;
        private const int ES_MULTILINE = 4;
        private const int ES_VERTICAL = 0x400000;
        private const int EM_SETOPTIONS = 1101;
        private const int ECOOP_OR = 2;
 
        private IntPtr hwndRichEdit;
 
        public MyRichText()
        {
            InitializeComponent();
 
            IntPtr hmRichEd = LoadLibrary( "Msftedit.dll" );
            if( hmRichEd != IntPtr.Zero ) {
                hwndRichEdit = CreateWindowEx( WS_EX_CLIENTEDGE, "RICHEDIT50W", "", WS_CHILD + WS_VISIBLE + ES_MULTILINE, this.Left, this.Top, this.Width, this.Height, this.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
                if( hwndRichEdit != IntPtr.Zero ) {
                    SendMessage( hwndRichEdit, EM_SETOPTIONS, ECOOP_OR, ES_VERTICAL );
                }
            }
        }
        ~MyRichText()
        {
            DestroyWindow( hwndRichEdit );
        }
    }
}
 
LoadLibrary が失敗したときの処理を省いてみたが、それ以外は同じだ。
 
しかし、Visual Basic 版も同じなんだけど、動かしてみると、どういうワケか、矢印キーで現在位置が動かないんだよね・・・。なんでかなぁ・・・。
とりあえず、Rich Edit 2.0、3.0 では縦書きにできないことがわかったので、Rich Edit 4.1 を使用するコードに書き換えてみる。
Imports System.Runtime.InteropServices
Imports System.Text
 
Public Class MyRichText
 
    <DllImport("kernel32.dll", SetLastError:=True)> _
    Public Shared Function LoadLibrary(ByVal lpFileName As String) As IntPtr
    End Function
 
    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function CreateWindowEx( _
        ByVal dwExStyle As Integer, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String, _
        ByVal dwStyle As Integer, _
        ByVal x As Integer, _
        ByVal y As Integer, _
        ByVal nWidth As Integer, _
        ByVal nHeight As Integer, _
        ByVal hWndParent As IntPtr, _
        ByVal hMenu As IntPtr, _
        ByVal hInstance As IntPtr, _
        ByVal lpParam As IntPtr) As IntPtr
    End Function
 
    Private Const WS_EX_CLIENTEDGE As Integer = &H200
    Private Const WS_CHILD As Integer = &H40000000
    Private Const WS_VISIBLE As Integer = &H10000000
    Private Const ES_MULTILINE As Integer = 4
    Private Const ES_VERTICAL As Integer = &H400000
 
    Dim hwndRichEdit As IntPtr
 
    Public Sub New()
        InitializeComponent()
 
        Dim errorNo As Integer
        Dim hmRichEd20 As IntPtr = LoadLibrary("Msftedit.dll")
        If hmRichEd20 = IntPtr.Zero Then
            errorNo = Marshal.GetLastWin32Error()
            Debug.WriteLine(errorNo)
        Else
            hwndRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RICHEDIT50W", "", WS_CHILD + WS_VISIBLE + ES_MULTILINE + ES_VERTICAL, Me.Left, Me.Top, Me.Width, Me.Height, Me.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)
            If hwndRichEdit = IntPtr.Zero Then
                errorNo = Marshal.GetLastWin32Error()
                Debug.WriteLine(errorNo)
            End If
        End If
 
    End Sub
 
End Class
 
ところで、RICHEDIT50W というクラス名だが、Rich Edit のバージョンは 4.1 なのに、どうして RICHEDIT50W なのだろうか・・・。
 
さて、これを実行すると

 
イメージ 1
図1 縦書き Rich Edit
 
のようになった。ようやく縦書きになった。っていうか、WS_DLGFRAME になってるし・・・。
調べてみると、
 
 
というものがあった。これを使ってスタイルを指定できるようだ。CreateWindowEx で ES_VERTICAL を指定するのではなく EM_SETOPTIONS で ES_VERTICAL を指定してみることにした。
あと、MyRichEdit が破棄されるときに、Rich Edit を破棄するようにしてみた。
 
Imports System.Runtime.InteropServices
Imports System.Text
 
Public Class MyRichText
 
    <DllImport("kernel32.dll", SetLastError:=True)> _
    Public Shared Function LoadLibrary(ByVal lpFileName As String) As IntPtr
    End Function
 
    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function CreateWindowEx( _
        ByVal dwExStyle As Integer, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String, _
        ByVal dwStyle As Integer, _
        ByVal x As Integer, _
        ByVal y As Integer, _
        ByVal nWidth As Integer, _
        ByVal nHeight As Integer, _
        ByVal hWndParent As IntPtr, _
        ByVal hMenu As IntPtr, _
        ByVal hInstance As IntPtr, _
        ByVal lpParam As IntPtr) As IntPtr
    End Function
 
    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    End Function
 
    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function DestroyWindow(ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.U1)> Boolean
    End Function
 
    Private Const WS_EX_CLIENTEDGE As Integer = &H200
    Private Const WS_CHILD As Integer = &H40000000
    Private Const WS_VISIBLE As Integer = &H10000000
    Private Const ES_MULTILINE As Integer = 4
    Private Const ES_VERTICAL As Integer = &H400000
    Private Const EM_SETOPTIONS As Integer = 1101
    Private Const ECOOP_OR As Integer = 2
 
    Dim hwndRichEdit As IntPtr
 
    Public Sub New()
        InitializeComponent()
 
        Dim errorNo As Integer
        Dim hmRichEd20 As IntPtr = LoadLibrary("Msftedit.dll")
 
        If hmRichEd20 = IntPtr.Zero Then
            errorNo = Marshal.GetLastWin32Error()
            Debug.WriteLine(errorNo)
        Else
            hwndRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RICHEDIT50W", "", WS_CHILD + WS_VISIBLE + ES_MULTILINE, Me.Left, Me.Top, Me.Width, Me.Height, Me.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)
            If hwndRichEdit = IntPtr.Zero Then
                errorNo = Marshal.GetLastWin32Error()
                Debug.WriteLine(errorNo)
            Else
                SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_OR, ES_VERTICAL)
            End If
        End If
 
    End Sub
 
    Protected Overrides Sub Finalize()
        DestroyWindow(hwndRichEdit)
        MyBase.Finalize()
    End Sub
 
End Class
 
これを実行すると
 
イメージ 2
図2 縦書き Rich Edit 改良版
 
のようになった。ふぅー、やれやれ・・・。
 
CreateWindowEx でクラス名として "RICHEDIT_CLASS" を指定しても CreateWindowEx がエラーとなっていたが、
 
 
を見ると
 
HWND CreateRichEdit(HWND hwndOwner,       // Dialog box handle.
                             int x, int y,                  // Location.
                             int width, int height,      // Dimensions.
                             HINSTANCE hinst)       // Application or DLL instance.
{
    LoadLibrary(TEXT("Msftedit.dll"));
   
    HWND hwndEdit= CreateWindowEx(0, MSFTEDIT_CLASS, TEXT("Type here"),
        ES_MULTILINE | WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
        x, y, width, height,
        hwndOwner, NULL, hinst, NULL);
       
    return hwndEdit;
}
 
というサンプルが載っていた。MSFTEDIT_CLASS はバージョン 4.1 の Rich Edit コントロールのクラス名なのだが、"MSFTEDIT_CLASS" ではなく MSFTEDIT_CLASS となっている!?
どういうことかと思い Windows SDK に含まれている Richedit.h の中を検索してみると、MSFTEDIT_CLASS は
 
#define MSFTEDIT_CLASS  L"RICHEDIT50W"
 
で、RICHEDIT_CLASS は
 
#define CERICHEDIT_CLASSA "RichEditCEA"
#define CERICHEDIT_CLASSW L"RichEditCEW"
#define RICHEDIT_CLASSA  "RichEdit20A"
#define RICHEDIT_CLASS10A "RICHEDIT"   // Richedit 1.0
#ifndef MACPORT
#define RICHEDIT_CLASSW  L"RichEdit20W"
#else //----------------------MACPORT
#define RICHEDIT_CLASSW  TEXT("RichEdit20W") // MACPORT change
#endif // MACPORT 
#if (_RICHEDIT_VER >= 0x0200 )
#ifdef UNICODE
#define RICHEDIT_CLASS  RICHEDIT_CLASSW
#else
#define RICHEDIT_CLASS  RICHEDIT_CLASSA
#endif // UNICODE
#else
#define RICHEDIT_CLASS  RICHEDIT_CLASS10A
#endif // _RICHEDIT_VER >= 0x0200
 
となっていた。なんだ、そういうことかよ・・・。
それにしても、
 
 
では、何の説明も無く BUTTON、や COMBOBOX、EDIT と同列で並べてあるけど、こんなのでわかるワケないね。全く、恐れ入るよ。
しかし、よく考えてみれば、"RICHEDIT50W" は「Visual Basic で縦書き入力コントロールを使用する方法」で、確認した、ワードパッドの Rich Edit コントロールのクラス名である。何かおかしいような気はしていたのだが、もっと早く気がつくべきだった。
 
さて、いったん、"RICHEDIT20W" で試してみよう。
 
Imports System.Runtime.InteropServices
Imports System.Text
 
Public Class MyRichText
 
    <DllImport("kernel32.dll", SetLastError:=True)> _
    Public Shared Function LoadLibrary(ByVal lpFileName As String) As IntPtr
    End Function
 
    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function CreateWindowEx( _
        ByVal dwExStyle As Integer, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String, _
        ByVal dwStyle As Integer, _
        ByVal x As Integer, _
        ByVal y As Integer, _
        ByVal nWidth As Integer, _
        ByVal nHeight As Integer, _
        ByVal hWndParent As IntPtr, _
        ByVal hMenu As IntPtr, _
        ByVal hInstance As IntPtr, _
        ByVal lpParam As IntPtr) As IntPtr
    End Function
 
    Private Const WS_EX_CLIENTEDGE As Integer = &H200
    Private Const WS_CHILD As Integer = &H40000000
    Private Const WS_VISIBLE As Integer = &H10000000
    Private Const ES_MULTILINE As Integer = 4
    Private Const ES_VERTICAL As Integer = &H400000
 
    Dim hwndRichEdit As IntPtr
 
    Public Sub New()
        InitializeComponent()
 
        Dim errorNo As Integer
        Dim hmRichEd20 As IntPtr = LoadLibrary("Riched20.dll")
        If hmRichEd20 = IntPtr.Zero Then
            errorNo = Marshal.GetLastWin32Error()
            Debug.WriteLine(errorNo)
        Else
            hwndRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RichEdit20W", "", WS_CHILD + WS_VISIBLE + ES_MULTILINE, Me.Left, Me.Top, Me.Width, Me.Height, Me.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)
            If hwndRichEdit = IntPtr.Zero Then
                errorNo = Marshal.GetLastWin32Error()
                Debug.WriteLine(errorNo)
            End If
        End If
 
    End Sub
 
End Class

これで実行した結果、
 
イメージ 1
図1 Rich Edit コントロールを作成
 
 
のようになった。やれやれである。

ようやく最初の本題、縦書きについてであるが、

 
 
のページを見ると、Rich Edit の 4.0 では ES_VERTICAL をサポートしていると書かれているが、2.0、3.0 には Vertical の記載がない。つまり、2.0、3.0 では縦書きはサポートされていないということなのだろうが、試しに "RichEdit20W" ( おそらく 3.0 ) で ES_VERTICAL を指定してみたところ、
 
イメージ 2
図2 "RichEdit20W" で ES_VERTICAL を指定
 
のようになった。縦書きにならないのは、まぁ、そうだろうと思うが、よく見ると Rich Edit のフレームの形状が変わっている。Spy++ で調べてみると WS_DLGFRAME ( ダイアログ・フレーム ) スタイルが付加されていた。何だそれ、と思いながら調べてみると、WS_DLGFRAME は WinUser.h の中で

 
#define WS_DLGFRAME         0x00400000L
 
と定義されていた。そう、ES_VERTICAL と同じ値だ・・・。
非常に嫌な予感がする・・・。
( つづく・・・ )
MSDN のアメリカ本国のページを見るには、.NET Framework のページであれば、右上の「 日本 - 日本語 」をクリックして「 United States - English 」をクリックすればよいのだが(Visual Basic で縦書き入力コントロールを使用する方法・その2 を参照)、API のページでは「 Page Not Found 」となってしまうので、Google で検索することにする。
Google の検索オプションで「言語」を英語にして検索してもよいのだが、通常の日本語ページの検索結果の一番下に表示される「 Google.com in English 」( 図1 ) をクリックするのが手っ取り早い。
 
イメージ 1
図1
 
これをクリックすると検索結果は図2 のようになる。
 
イメージ 2
図2
 
この検索結果の 1番目が目的のページだ。
1番目のリンクをクリックすると
 
 
のページに移動する。こちらのページは .NET Framework のページとは趣 ( おもむき ) が変わっている。おそらく、アメリカ本国のページは .NET Framework のページより API のページの方が新しのだろうが、日本語ページからの関連付けが古いページのままになっているので、日本語版の CreateWindowEx のページからアメリカ本国のページに飛ぼうとしたときに「 Page Not Found 」となってしまうのだろう。
さて、そんなことは実はどうでもよくて、「 RichEdit 」、または「 RICHEDIT_CLASS 」の説明欄の「 See Rich Edit Controls 」から
 
に飛び、さらにそのページの「 Overview 」の「 About Rich Edit Controls 」をクリックして
 
 
にたどり着いた。
このページを見てみると、どうやら、CreateWindowEx で Rich Edit コントロールを作成するには、その前に LoadLibrary で DLL を読み込んでおかなければならないようである。
Rich Edit のバージョンと DLL、クラス名は次のようになっている。
 
イメージ 3
図3 Rich Edit のバージョンと DLL、クラス名
 
「 バージョン 2.0 と 3.0 は同じ DLL 名だが、これにより、既存のバージョン 2.0 用のコードを破棄することなくバージョン 3.0 を使用することが可能となる。」
 
のようなことが書かれているが、それならばどうしてバージョン 4.1 で DLL 名を変えているんだよ!しかも、クラス名まで!
 
とツッコミを入れずにはいられない。それに、CreateWindowEx のページに書かれていたクラス名 "RichEdit" はどこにも見当たらない。一体、何だんだか・・・。
 
さて、Rich Edit のどのバージョンにするか、であるが、4.1 は XP の SP1 以降でないとインストールされていないようだ。今更 XP の SP なしの環境というのも考えにくいが、とりあえず、Rich Edit 3.0 を試してみよう。
LoadLibrary の宣言も追加して次のようなコードを記述した。
 
Imports System.Runtime.InteropServices
Imports System.Text
 
Public Class MyRichText
 
    <DllImport("kernel32.dll", SetLastError:=True)> _
    Public Shared Function LoadLibrary(ByVal lpFileName As String) As IntPtr
    End Function
 
    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function CreateWindowEx( _
        ByVal dwExStyle As Integer, _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String, _
        ByVal dwStyle As Integer, _
        ByVal x As Integer, _
        ByVal y As Integer, _
        ByVal nWidth As Integer, _
        ByVal nHeight As Integer, _
        ByVal hWndParent As IntPtr, _
        ByVal hMenu As IntPtr, _
        ByVal hInstance As IntPtr, _
        ByVal lpParam As IntPtr) As IntPtr
    End Function
 
    Private Const WS_EX_CLIENTEDGE As Integer = &H200
    Private Const WS_CHILD As Integer = &H40000000
    Private Const WS_VISIBLE As Integer = &H10000000
    Private Const ES_MULTILINE As Integer = 4
    Private Const ES_VERTICAL As Integer = &H400000
 
    Dim hwndRichEdit As IntPtr
 
    Public Sub New()
        InitializeComponent()
        Dim errorNo As Integer
        Dim hmRichEd20 As IntPtr = LoadLibrary("Riched20.dll")
        If hmRichEd20 = IntPtr.Zero Then
            errorNo = Marshal.GetLastWin32Error()
            Debug.WriteLine(errorNo)
        Else
            hwndRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RICHEDIT_CLASS", "", WS_CHILD + WS_VISIBLE + ES_MULTILINE, Me.Left, Me.Top, Me.Width, Me.Height, Me.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)
            If hwndRichEdit = IntPtr.Zero Then
                errorNo = Marshal.GetLastWin32Error()
                Debug.WriteLine(errorNo)
            End If
        End If
 
    End Sub
 
End Class
 
デバッグ実行してみると、LoadLibrary は成功しているものの CreateWindowEx は失敗し、エラーコード = 1407 となった・・・。一筋縄ではいかないものだ・・・。
( つづく・・・ )

全5ページ

[1] [2] [3] [4] [5]

[ 次のページ ]


.


プライバシー -  利用規約 -  メディアステートメント -  ガイドライン -  順守事項 -  ご意見・ご要望 -  ヘルプ・お問い合わせ

Copyright (C) 2019 Yahoo Japan Corporation. All Rights Reserved.

みんなの更新記事