クリップボードの監視


プログラマーやってた時に作った端末エミュレータ監視ソフトです。
これでログ取ったりしてました。

最終的には、最低でもこれくらいのプログラムまで行きたいと思います。
今回はサンプルと言うことで、ソースのみの公開です。
そのうち、回が進めば解説も入れていきます。(多分(^^;)
リッチテキストとクリップボードを使用してます。

まずは、リソースファイルです。
ここでは、メニューの宣言になります。
Rsrc.rc
#define IDM_EXIT    30009
#define IDM_CAPTER  30010
#define IDM_CLEAR   30011
#define IDM_OWARI   30012
#define IDM_OPTION  30013
#define IDM_SEARCH  30020

FirstMenu MENU
{
 POPUP "ファイル(&F)"	; 本当は半角カナ
        {
         MENUITEM "終了(&X)",IDM_EXIT
        }
 POPUP "ツール(&T)"	; 本当は半角カナ
        {
         MENUITEM "きゃぷた〜",IDM_CAPTER
         MENUITEM "くりあ〜",IDM_CLEAR
         MENUITEM "おわりぃ〜",IDM_OWARI
         MENUITEM SEPARATOR
         MENUITEM "おぷしょん",IDM_OPTION
        }
 POPUP "検索(&S)"
        {
         MENUITEM "けんさく",IDM_SEARCH
        }
}


プログラム本体です。
Capter.asm
; インクルードファイルの取り込み
include         .\windows.inc
include         .\inc\ComboBox.inc
include         .\inc\Font.inc
include         .\inc\ClipBoard.inc
include         .\inc\Kernel32.inc
include         .\inc\Dummy.inc
include         .\inc\masm32.inc
; ライブラリの取り込み
includelib      ..\lib\user32.lib
includelib      ..\lib\kernel32.lib
includelib      ..\lib\gdi32.lib
includelib      ..\lib\comctl32.lib         ; ステータスバーで使用
includelib      ..\lib\masm32.lib

; 定数領域の宣言
.const
; 各おぷじぇくとのID
Button0ID       equ     1       ; Button0のID
Button1ID       equ     2       ; Button1のID
Button2ID       equ     3       ; Button2のID
Edit0ID         equ     4       ; EditBox0のID
Rich0ID         equ     5       ; Rich0Box1のID
ComboBoxID      equ     6       ; ComboBoxのID
IDC_TIMER       equ     7       ; タイマー登録用ID
Edit1ID         equ     8
; リソースファイルの値と同一値に設定(メニュー用メッセージID)
IDM_EXIT        equ     30009   ; Exit用
IDM_CAPTER      equ     30010   ; きゃぷた〜用
IDM_CLEAR       equ     30011   ; くりや〜用
IDM_OWARI       equ     30012   ; きゃぷた〜終了用
IDM_OPTION      equ     30013   ; おぷしょん用
IDM_SEARCH      equ     30020   ; けんさく用

; 位置 & サイズ情報
WindowWidth     equ     500
WindowHight     equ     390
ComboXPos       equ     30
ComboYPos       equ     15
ComboHight      equ     100
ComboWidth      equ     150
Edit0XPos       equ     (ComboXPos + ComboWidth + 20)
Edit0YPos       equ     (ComboYPos)
Edit0Hight      equ     25
Edit0Width      equ     150
Rich0XPos       equ     (ComboXPos)
Rich0YPos       equ     (ComboYPos + 35)
Rich0Hight      equ     (WindowHight - 160)
Rich0Width      equ     (WindowWidth - 70)
Button0XPos     equ     (ComboXPos)
Button0YPos     equ     (Rich0YPos + Rich0Hight + 10)
Button0Hight    equ     25
Button0Width    equ     95
Button1XPos     equ     (Button0XPos + Button0Width + 5)
Button1YPos     equ     (Button0YPos)
Button1Hight    equ     (Button0Hight)
Button1Width    equ     (Button0Width)
Button2XPos     equ     (Button1XPos + Button1Width + 5)
Button2YPos     equ     (Button1YPos)
Button2Hight    equ     (Button0Hight)
Button2Width    equ     (Button0Width)
StatusBarHight  equ     200             ; 
TimerTime       equ     2000            ; 1000 = 1秒
EntryLength     equ     10              ; 検索文字列の文字列長
; ECS画面からクリップボードにコピーされるデータの保存領域サイズ
BuffSize        equ     2048
MaxSize         equ     0fffffh

; 変数領域の宣言(初期値あり)
.data
MenuName        db      "FirstMenu",0
AppName         db      "見張り番",0
ClassName       db      "SimpleWinClass",0
ButtonClassName db      "button",0
EditClassName   db      "edit",0
CmbBoxClassName db      "combobox",0
RichClassName   db      "richedit",0
ButtonText0     db      "きゃぷた〜",0
ButtonText1     db      "くりあ〜",0
ButtonText2     db      "おわりぃ〜",0
UserID0         db      "JKSC12",0
UserID1         db      "JKC160",0
JOBID           db      "JOB",0
MsgBoxText      db      "OKボタンを押して下さい",0
MsgCaption      db      "かくにん",0
EntryText       db      "検索文字列が10文字を超えています。",0
;### Font定義 ###
Font0           db      "Arial",0
Font1           db      "Arial Black",0
Font2           db      "Arial Bold",0
Font3           db      "Arial Bold Italic",0
Font4           db      "Arial Narrow",0
Font5           db      "Arial Narrow Bold",0
Font6           db      "Arial Narrow Bold Itaric",0
Font7           db      "Arial Narrow Italic",0
Font8           db      "Century",0
Font9           db      "Comic Sans MS",0
Font10          db      "MS ゴシック",0
Font11          db      "MS 明朝",0
; エディットボックス1に表示する文字用のフォントサイズ(横)
FontWidth       SDWORD  5               
FontHight       SDWORD  10
; エディットボックス1に表示する文字用のフォントサイズ(縦)
FlgOWARI        db      MF_GRAYED       ; メニュー制御用
FlgCAPTER       db      MF_ENABLED      ; 〃
DivStringLength dd      82              ; 1行は82バイト(改行コード込)
DispBuff        db      BuffSize * 2 dup(0) ; 表示用バッファ(新規追加用1画面,更新チェック用1画面)
ClipBuff        db      BuffSize * 2 dup(0) ; データ取得用バッファ領域(2画面分)
TmpBuff         db      BuffSize dup(0) ; クリップボードデータのコピー用
LibName         db      "RICHED32.DLL",0    ; リッチテキスト用DLL

; テスト用領域
template3 db "hMem[%lx],hGetData[%lx]",0
template2 db "%d",0
template0 db "%s",0
template db "%x",0
template1 db "ah[%x],al[%x],ecx[%x]",0
buffer db 128 dup(0)
buffer0 db 2048 dup(0)
buffer1 db 2048 dup(0)
buffer2 db 2048 dup(0)
tmpaaa db "abcdefg",0
SearchStatus db "UserID[ ],JOBID[ ]",0

; 変数領域の宣言(初期値なし)
.data?
hInstance       HINSTANCE       ?       ; インスタンスハンドル
CommandLine     LPSTR           ?       ; コマンドライン
hwndButton0     HWND            ?       ; Buttonのウィンドウハンドル
hwndButton1     HWND            ?       ; 〃
hwndButton2     HWND            ?       ; 〃
hwndEdit0       HWND            ?       ; EditBoxのウィンドウハンドル
hwndEdit1       HWND            ?
hwndRich0       HWND            ?       ; 
hwndCombo       HWND            ?       ; ComboBoxのウィンドウハンドル
hwndStatus      HWND            ?       ; StatusBarのウィンドウハンドル
hwndMenu        HWND            ?       ; MenuBarのウィンドウハンドル
hFont           dd              ?       ; Font用ハンドル
TimerID         dd              ?       ; タイマー用ID領域
UserIDBuff      db EntryLength + 1 dup(?) ; ユーザーIDの格納領域
JOBIDBuff       db EntryLength + 1 dup(?) ; ジョブIDの格納領域
p               CHARRANGE       <>      ; 挿入位置設定用構造体
hMem            HANDLE          ?       ; グローバルメモリデータのへハンドル
pMem            DWORD           ?       ; グローバルメモリデータのへポインタ
hClipboard      HANDLE          ?       ; クリップボードデータのへハンドル
pClip           DWORD           ?       ; クリップボードデータのへポインタ
RichRect        RECT            <>
ButtonRect      RECT            <>
StatusRect      RECT            <>

;**************プロトタイプ宣言(特に必要なし)
;WinMain PROTO :DWORD,:DWORD,:DWORD,:SDWORD
SearchString PROTO :DWORD,:DWORD        ; 検索データのアドレス,検索文字列のアドレス
DuplicateCut PROTO :DWORD,:DWORD,:DWORD ; 重複行削除
Strnequ PROTO :DWORD,:DWORD,:DWORD      ; n文字比較(同じ物かの判定のみ)

; プログラムコード
.code
start:
        invoke GetModuleHandle, NULL                                    ; モジュールハンドルの取得
        mov    hInstance,eax                                            ;
        invoke GetCommandLine                                           ; コマンドラインの取得
        mov    CommandLine,eax                                          ;
        invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT      ; WinMainの実行
        invoke ExitProcess,eax                                          ; 終了プロセス

; WinMain(メインプロセス)
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
        LOCAL  wc:WNDCLASSEX
        LOCAL  msg:MSG
        LOCAL  hwnd:HWND

        mov    wc.cbSize,SIZEOF WNDCLASSEX
        mov    wc.style, CS_HREDRAW or CS_VREDRAW
        mov    wc.lpfnWndProc, OFFSET WndProc
        mov    wc.cbClsExtra,NULL
        mov    wc.cbWndExtra,NULL
        push   hInstance
        pop    wc.hInstance
        mov    wc.hbrBackground,COLOR_BTNFACE+1
        mov    wc.lpszMenuName,OFFSET MenuName
        mov    wc.lpszClassName,OFFSET ClassName
        invoke LoadIcon,NULL,IDI_APPLICATION
        mov    wc.hIcon,eax
        mov    wc.hIconSm,0
        invoke LoadCursor,NULL,IDC_ARROW
        mov    wc.hCursor,eax
        invoke RegisterClassEx, addr wc
;        invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
;                              WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+ \
;                              WS_MINIMIZEBOX+WS_MAXIMIZE+WS_VISIBLE,\
;                              CW_USEDEFAULT,CW_USEDEFAULT,\
;                              WindowWidth,WindowHight,NULL,NULL,\
;                              hInst,NULL
;
        invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
                              WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+ \
                              WS_MINIMIZEBOX+WS_VISIBLE+ \
                              WS_SIZEBOX,\
                              CW_USEDEFAULT,CW_USEDEFAULT,\
                              WindowWidth,WindowHight,NULL,NULL,\
                              hInst,NULL
;
        mov    hwnd,eax
        invoke ShowWindow, hwnd,SW_SHOWNORMAL
        invoke UpdateWindow, hwnd
        invoke GetMenu, hwnd
        mov    hwndMenu,eax
        .WHILE TRUE                                     ; メッセージループ
               invoke GetMessage, ADDR msg,NULL,0,0     ; メッセージの取得
               .BREAK .IF (!eax)
               invoke TranslateMessage, ADDR msg        ; 
               invoke DispatchMessage, ADDR msg         ; 
        .ENDW
        mov    eax,msg.wParam
        ret
WinMain endp

; ウィンドウプロシージャ
WndProc proc uses ebx ecx edx hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
        LOCAL  RetCode:BOOL
        LOCAL  RichTop,RichLeft,RichWidth,RichHight:DWORD
        LOCAL  ButtonTop,ButtonLeft,ButtonWidth,ButtonHight:DWORD
        LOCAL  StatusTop,StatusLeft,StatusWidth,StatusHight:DWORD
        LOCAL  Orghwnd:HWND

        mov    eax,uMsg
        .IF eax == WM_DESTROY
                invoke PostQuitMessage,NULL      ; 終了メッセージの送信
                .IF TimerID != 0                 ; タイマー登録されていれば削除
                    invoke KillTimer,hWnd,TimerID
                .ENDIF
        .ELSEIF eax == WM_INITMENU               ; メニュー作成時にアイテムを初期化
                invoke EnableMenuItem,hwndMenu,IDM_CAPTER,FlgCAPTER
                invoke EnableMenuItem,hwndMenu,IDM_OWARI,FlgOWARI
        .ELSEIF eax == WM_CREATE
; ラベルテスト
;                invoke Static, ADDR Label0, hWnd, Label0_X, Label0_Y, Label0_Width, Label0_Hight, 
;
                ; エディットボックス0の作成
                invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
                                      WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or \
                                      ES_AUTOHSCROLL,\
                                      Edit0XPos,Edit0YPos,Edit0Width,Edit0Hight,\
                                      hWnd,Edit0ID,hInstance,NULL
                mov     hwndEdit0,eax           ; ハンドルの取得
                ; エディットボックス0へ初期値設定
                invoke SetWindowText,hwndEdit0,ADDR JOBID
                ; ボタン0の作成
                invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText0,\
                                      WS_CHILD or WS_VISIBLE or ES_DEFPUSHBUTTON,\
                                      Button0XPos,Button0YPos,Button0Width,Button0Hight,\
                                      hWnd,Button0ID,hInstance,NULL
                mov    hwndButton0,eax          ; ハンドルの取得
                ; ボタン1の作成
                invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText1,\
                                      WS_CHILD or WS_VISIBLE or ES_DEFPUSHBUTTON,\
                                      Button1XPos,Button1YPos,Button1Width,Button1Hight,\
                                      hWnd,Button1ID,hInstance,NULL
                mov    hwndButton1,eax          ; ハンドルの取得
                ; ボタン2の作成
                invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText2,\
                                      WS_CHILD or WS_VISIBLE or ES_DEFPUSHBUTTON,\
                                      Button2XPos,Button2YPos,Button2Width,Button2Hight,\
                                      hWnd,Button2ID,hInstance,NULL
                mov    hwndButton2,eax          ; ハンドルの取得
                ; エディットボタン2を入力不可にする
                invoke EnableWindow,hwndButton2,FALSE
                ; コンボボックスの作成
                invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR CmbBoxClassName,NULL,\
                                      WS_CHILD or WS_BORDER or WS_VISIBLE or \
                                      CBS_HASSTRINGS or CBS_DROPDOWNLIST or WS_VSCROLL,\
                                      ComboXPos,ComboYPos,ComboWidth,ComboHight,\
                                      hWnd,ComboBoxID,hInstance,NULL
                mov    hwndCombo,eax            ; ハンドルの取得
                ; コンボボックスへアイテムを追加
                invoke SendMessage,hwndCombo,CB_ADDSTRING,0,ADDR UserID0
                invoke SendMessage,hwndCombo,CB_ADDSTRING,0,ADDR UserID1
                ; アイテムの選択
                invoke SendMessage,hwndCombo,CB_SELECTSTRING,0,ADDR UserID0
                ; リッチテキスト1の作成
                invoke InitCommonControls
                invoke LoadLibrary, ADDR LibName
                invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR RichClassName,NULL,\
                                      WS_CHILD or WS_VISIBLE or WS_BORDER or \
                                      ES_AUTOHSCROLL or ES_AUTOVSCROLL or WS_VSCROLL or \
                                      WS_HSCROLL or ES_MULTILINE,\
                                      Rich0XPos,Rich0YPos,Rich0Width,Rich0Hight,\
                                      hWnd,Rich0ID,hInstance,NULL
                mov     hwndRich0,eax           ; ハンドルの取得
                invoke SendMessage, hwndRich0, EM_EXLIMITTEXT, NULL, MaxSize
                ; 使用フォントの作成
                invoke CreateFont,FontHight,FontWidth,0,0,500,0,0,0,\
                                  DEFAULT_CHARSET,0,0,0,\
                                  DEFAULT_PITCH,ADDR Font11
                mov hFont, eax
                ; エディットボックス1へのフォント指定
                invoke SendMessage,hwndRich0,WM_SETFONT,hFont,0
                ; ステータスバーの作成
                invoke CreateStatusWindow,WS_CHILD or WS_VISIBLE or \
                                  SBS_SIZEGRIP,0, hWnd, StatusBarHight
                mov hwndStatus, eax
        .ELSEIF eax == WM_COMMAND
                mov    eax,wParam
                ; メニューの項目が選択された場合
                .IF lParam == 0	
                    .IF ax == IDM_EXIT               ; 終了メッセージなら
                        invoke DestroyWindow,hWnd
                    .ELSEIF ax == IDM_CAPTER         ; きゃぷた〜なら
                        ; エディットボタン0を入力不可にする
                        invoke EnableWindow,hwndButton0,FALSE
                        mov    FlgCAPTER,MF_GRAYED
                        ; エディットボタン2を入力可にする
                        invoke EnableWindow,hwndButton2,TRUE
                        mov    FlgOWARI,MF_ENABLED
                        ; 新規タイマー登録
                        invoke SetTimer,hWnd,IDC_TIMER,TimerTime,NULL
                        mov   TimerID,eax
                    .ELSEIF ax == IDM_CLEAR          ; くりあ〜なら
                        ; 設定文字列のアドレスにNULLを設定し文字列をクリアする
                        invoke SendMessage,hwndRich0,WM_SETTEXT, NULL, NULL
                    .ELSEIF ax == IDM_OWARI          ; おわりぃ〜なら
                        .IF TimerID != 0        ; タイマー登録されていれば削除
                            invoke KillTimer,hWnd,TimerID
                            ; エディットボタン0を入力可にする
                            invoke EnableWindow,hwndButton0,TRUE
                            mov    FlgCAPTER,MF_ENABLED
                            ; エディットボタン2を入力不可にする
                            invoke EnableWindow,hwndButton2,FALSE
                            mov    FlgOWARI,MF_GRAYED
                        .ENDIF
                    .ELSEIF ax == IDM_OPTION         ; おぷしょんなら
;                        invoke wsprintf,addr buffer,addr template2,eax
;                        invoke MessageBox, NULL,addr buffer, addr MsgCaption, MB_OK
                        invoke MessageBox,NULL,ADDR MsgBoxText,ADDR AppName,MB_OK
                    .ELSEIF ax == IDM_SEARCH         ; けんさくなら
;検索処理を追加予定
                        invoke MessageBox,NULL,ADDR MsgBoxText,ADDR AppName,MB_OK
                    .ENDIF
                ; メニュー以外のイベントが発生した場合
                .ELSE
                    .IF ax == Button0ID              ; ボタン0に対するメッセージなら
                        shr eax,16
                        .IF ax == BN_CLICKED         ; クリックのメッセージなら
                            invoke SendMessage,hWnd,WM_COMMAND,IDM_CAPTER,0
                        .ENDIF
                    .ELSEIF ax == Button1ID          ; ボタン1に対するメッセージなら
                        shr eax,16
                        .IF ax == BN_CLICKED
                            invoke SendMessage,hWnd,WM_COMMAND,IDM_CLEAR,0
                        .ENDIF
                    .ELSEIF ax == Button2ID         ; ボタン2に対するメッセージなら
                        shr eax,16
                        .IF ax == BN_CLICKED
                            invoke SendMessage,hWnd,WM_COMMAND,IDM_OWARI,0
                        .ENDIF
                    .ENDIF
                .ENDIF
        .ELSEIF eax == WM_SIZE
                .IF wParam == SIZE_RESTORED          ; 最大化・最小化以外のウィンドウサイズ変更
                    mov    RichTop,Rich0YPos
                    mov    RichLeft,Rich0XPos
                    mov    eax,lParam
                    and    eax,0000ffffh
                    sub    eax,55
                    mov    RichWidth,eax
                    mov    eax,lParam
                    shr    eax,16
                    sub    eax,105
                    mov    RichHight,eax
                    invoke MoveWindow, hwndRich0, RichLeft, RichTop, \
                                                  RichWidth, RichHight, RetCode
                    mov    eax,RichTop
                    add    eax,RichHight
                    add    eax, 5
                    mov    ButtonTop,eax
                    mov    eax, Button0Hight
                    mov    ButtonHight,eax
                    mov    eax,RichLeft
                    mov    ButtonLeft,eax
                    mov    eax, Button0Width
                    mov    ButtonWidth,eax
                    invoke MoveWindow, hwndButton0, ButtonLeft, ButtonTop, \
                                                    ButtonWidth, ButtonHight, RetCode
                    mov    eax,ButtonLeft
                    add    eax,Button0Width
                    add    eax,5
                    mov    ButtonLeft,eax
                    invoke MoveWindow, hwndButton1, ButtonLeft, ButtonTop, \
                                                    ButtonWidth, ButtonHight, RetCode
                    mov    eax,ButtonLeft
                    add    eax,Button0Width
                    add    eax,5
                    mov    ButtonLeft,eax
                    invoke MoveWindow, hwndButton2, ButtonLeft, ButtonTop, \
                                                    ButtonWidth, ButtonHight, RetCode
                    mov    StatusLeft, 0
                    mov    eax,lParam
                    shr    eax,16
                    sub    eax,StatusBarHight
                    mov    StatusTop,eax
                    mov    StatusHight,StatusBarHight
                    mov    eax,lParam
                    and    eax,0000ffffh
                    mov    StatusWidth,eax
                    invoke MoveWindow, hwndStatus, StatusLeft, StatusTop, \
                                                   StatusWidth, StatusHight, RetCode
                .ENDIF
        .ELSEIF eax == WM_TIMER                      ; タイマー処理
                ; レングスチェック
                invoke GetWindowTextLength, hwndEdit0
                .IF eax > EntryLength
                    ; 先にメッセージを送らないと、タイマーが切れないので注意
                    invoke SendMessage,hWnd,WM_COMMAND,IDM_OWARI,0
                    invoke MessageBox,NULL,ADDR EntryText,ADDR AppName,MB_OK
                .ELSE
                    ; ジョブIDの取得
                    invoke GetWindowText, hwndEdit0, ADDR JOBIDBuff, EntryLength
                    ; ユーザIDの取得
                    invoke GetWindowText, hwndCombo, ADDR UserIDBuff, EntryLength
                    ; クリップボードはオープン後速やかに開放(クローズ)すること
                    invoke OpenClipboard,hWnd
                    invoke GetClipboardData,CF_TEXT
                    mov    hClipboard,eax
                    .IF eax != NULL
                        invoke GlobalLock,hClipboard
                        mov    pClip,eax
                        invoke lstrlen,pClip
                        push   eax
                        invoke MemCopy,pClip,ADDR TmpBuff, eax
                        pop    ebx
                        mov    byte ptr TmpBuff[ebx],NULL
                        invoke GlobalUnlock,hClipboard
                        invoke CloseClipboard
                        invoke lstrcmp, ADDR TmpBuff, ADDR DispBuff
                        .IF eax != 0 ; strcmp       ; 1回前のコピー内容と違ったら以下を実行
                            invoke MemCopy, ADDR ClipBuff,\
                                            ADDR ClipBuff + BuffSize, BuffSize - 2
                            invoke MemCopy, ADDR TmpBuff,\
                                            ADDR ClipBuff, BuffSize - 2
                            invoke DuplicateCut,ADDR ClipBuff + BuffSize,ADDR ClipBuff,\
                                            ADDR DispBuff
                            invoke lstrcmp, ADDR DispBuff, ADDR DispBuff + BuffSize
                            .IF eax != 0
                                invoke MemCopy, ADDR DispBuff, ADDR DispBuff + BuffSize,\
                                                BuffSize - 2
                                invoke lstrlen, ADDR DispBuff ; 追加文字列長の取得
                                push   eax                    ; 文字列長を退避(文字列コピー用)
                                push   eax                    ; 〃(NULL挿入用)
                                inc    eax                    ; NULL分追加
                                ; グローバルメモリを確保
                                invoke GlobalAlloc,GHND,eax
                                mov    hMem, eax              ; メモリハンドルの取得
                                invoke GlobalLock, hMem       ; メモリハンドルからアドレスを取得
                                mov    pMem, eax              ; 〃
                                pop    eax                    ; 文字列長復元
                                ; 追加分の文字列をグローバルメモリにコピー
                                invoke MemCopy, ADDR DispBuff, pMem, eax
                                pop    ebx                    ; 文字列長復元
                                mov    byte ptr pMem[ebx], NULL ; NULLの挿入
                                ; リッチテキストのサイズを取得
                                invoke GetWindowTextLength, hwndRich0
                                mov p.cpMin,eax               ; 選択文字の位置を設定
                                mov p.cpMax,eax               ; 選択文字の位置を設定
                                invoke SetFocus,hwndRich0
                                mov    Orghwnd, eax
                                ; 最終位置に位置付け
                                invoke SendMessage,hwndRich0,EM_EXSETSEL,NULL, ADDR p
                                invoke OpenClipboard,hWnd     ; クリップボードのオープン
                                invoke EmptyClipboard         ; クリップボードのクリア
                                ; クリップボードへ挿入文字列をコピー
                                             invoke SetClipboardData, CF_TEXT, hMem
                                invoke GlobalUnlock, hMem     ; メモリのアンロック
                                invoke CloseClipboard         ; クリップボードのクローズ
                                ; リッチテキスト領域にクリップボードの内容をペースト
                                invoke SendMessage,hwndRich0,EM_PASTESPECIAL, CF_TEXT,NULL
                                invoke SetFocus, Orghwnd
                                ; ユーザーIDの検索
                                invoke SearchString, ADDR ClipBuff, ADDR UserIDBuff
                                .IF eax == 1
                                    mov  SearchStatus[7],'1'
                                .ELSE
                                    mov  SearchStatus[7],'0'
                                .ENDIF
                                ; ジョブIDの検索
                                invoke SearchString, ADDR ClipBuff, ADDR JOBIDBuff
                               .IF eax == 1
                                   mov  SearchStatus[16],'1'
                               .ELSE
                                   mov  SearchStatus[16],'0'
                               .ENDIF
                               ; ステータスバーへ検索結果の表示
                               invoke SetWindowText, hwndStatus, ADDR SearchStatus
                            .ENDIF
                       .ELSE
                            invoke CloseClipboard
                       .ENDIF
                    .ENDIF     ; コピーバッファの内容チェック
                .ENDIF         ; レングスチェック
               .ELSE
                 invoke DefWindowProc,hWnd,uMsg,wParam,lParam
                 ret
        .ENDIF
        xor     eax,eax        ; リターンコードにゼロを設定
        ret
WndProc endp

; Return eax(-1):引数の文字列長エラー,eax(0):検索文字列なし,eax(1):検索文字列あり
;        検索文字列は1〜128Byte以外エラー
SearchString proc uses ebx ecx DataBuff:DWORD, SearchBuff:DWORD
        LOCAL tmpbuff[129]:BYTE
        LOCAL SearchLength:DWORD, DataLength:DWORD

        invoke lstrlen, SearchBuff
        mov SearchLength, eax
        invoke lstrlen, DataBuff
        mov DataLength, eax
        .IF SearchLength <= 128 && SearchLength <= eax && SearchLength > 0
            mov ebx, SearchLength
            mov byte ptr tmpbuff[ebx],NULL
            mov ecx, DataLength
            sub ecx, ebx
            inc ecx
            .WHILE ecx > 0
                push ecx
                ; 注意!!API呼び出し後は、ecxレジスタの内容は破壊される!!
                ; データのコピー(DataBuffにはアドレスが入っているので、そのまま渡す。)
                invoke MemCopy, DataBuff, ADDR tmpbuff, SearchLength
                ; データの比較(SearchBuffにはアドレスが入っているので、そのまま渡す。)
                invoke lstrcmp,ADDR tmpbuff, SearchBuff  ; =:0,<:1,>:-1
                pop ecx
                .IF eax == 0                 ; 検索対象が見つかった場合
                    mov eax,1
                    .BREAK
                .ENDIF
                xor eax,eax
                inc DataBuff
                dec ecx
            .ENDW
        .ELSE
            mov eax,-1                       ; 検索文字列長オーバー
        .ENDIF
        ret
SearchString endp

DuplicateCut proc uses ebx OldBuff:DWORD, NewBuff:DWORD, DspBuff:DWORD
        LOCAL OldIndex:DWORD
        LOCAL NewIndex:DWORD
        LOCAL DspIndex:DWORD
        LOCAL EndAddress:DWORD

        invoke lstrlen, NewBuff
        .IF eax == 1640
            invoke lstrlen, OldBuff
            .IF eax == 1640
                mov   eax,DspBuff
                mov   DspIndex,eax
                mov   eax,NewBuff
                mov   NewIndex,eax
                push  eax
                add   eax,1558
                mov   EndAddress,eax
                pop   eax
                .WHILE eax <= EndAddress
                   mov    eax,OldBuff
                   add    eax,1558     ; 82 * ( 20 - 1 )
                   mov    OldIndex,eax
                   .WHILE eax >= OldBuff
                      invoke Strnequ, OldIndex, NewIndex, 82
                      .BREAK .IF eax == 0
                      sub OldIndex, 82
                      mov eax, OldIndex
                   .ENDW
                   .IF eax != 0
                       invoke MemCopy, NewIndex, DspIndex, 82
                       mov    ebx,DspIndex
                       mov    byte ptr [ebx + 82],NULL
                       add    DspIndex,82
                   .ENDIF
                   add    NewIndex,82
                   mov    eax, NewIndex
                .ENDW
            .ELSEIF eax == 0
                invoke MemCopy, NewBuff, DspBuff, 1640
                mov    byte ptr DspBuff[1640],NULL
            .ENDIF
        .ELSE
            mov  byte ptr DspBuff[0], NULL
        .ENDIF
        ret
DuplicateCut endp

; str1 == str2 : 0, str1 != str2 : 1
; 
Strnequ proc uses ebx esi ecx str1:DWORD, str2:DWORD, n:DWORD
        mov   ecx, n
        mov   esi, str1
        mov   ebx, str2
        mov   al, byte ptr[ebx]
        mov   ah, byte ptr[esi]
        .WHILE ( al != NULL && ah != NULL ) && ecx != 0
              .BREAK .IF al != ah
              inc   ebx
              inc   esi
              mov   al, byte ptr[ebx]
              mov   ah, byte ptr[esi]
              dec   ecx
        .ENDW
        .IF   ecx == 0
              mov  eax, 0
        .ELSE
              mov  eax, 1
        .ENDIF
        ret
Strnequ endp

        end     start


実行するこんな感じのウィンドウが表示されます。
実行画面
今回の実行形式ファイルのサイズは、23,552Byteでした。

次回は何だろう?