[戻る]

// EzFax_J sorce code programmed by Yutaka Kawasaki

// bcc32 -tW -tWM EzFax.cpp
// brc32 -iC:\borland\bcc55\include EzFax.rc EzFax.exe

#define VER_MAJ 1
#define VER_MIN 1
#define LICENSE_KEY "1359462"

#define USE_WINDOWS_DIRECTORY_FOR_INI_FILE
// #define RISTRICT_ONE_PAGE

// tapi を使わないで直接 COM を使うのは、AT+FCLASS .AT コマンドが使用できないからである。
// 古いwin98マシンで動かないバグ、相当時間かかったが、
// (AT+FTM 後の)CONNECT から、(MHデータ)先頭ライン送信までに、
// 10 秒ほど時間がかかっていた( bitdata を構成する処理 )から。
// こんなのすぐ気づけよ。まぁ暑いから・・・・。
// 対策: @タイムアウトにならないように、ダミー(w1728かなんか。)を送る。
// 又は、A送信の事前にビットマップを用意する。

// 出品時 訪問者 220 名 [http://hp.vector.co.jp/authors/VA029438/]
// 11/23 現在 438名、少な!
// xsl,xml,csv,xslt は、フォルダ「xsl実験」を参照。
// [↓同期・コールドリンク]
// 1.DdeInitialize関数でDDEを初期化します。
// 2.DdeConnect関数で通信開始。
// 3.DdeClientTransaction関数でトランザクションをサーバーに転送
// 4.DdeGetData関数などでデータを取得
// 5.DdeDisconnect関数で通信終了
// 6.DdeUninitialize関数でDDEアプリケーションではなくなったことを  サーバーに通知


//  #define MHCHECKINGMODE // 黒線または白線で確かめる。
//  #define TRIANGLECHECK64


#define _WIN32_WINNT 0x400
#define  WINVER      0x500
#define _WIN32_IE    0x0501
//#define WIN32_LEAN_AND_MEAN
#define STRICT

#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <commdlg.h>

#include <richedit.h>

#include <richole.h>
#include <tom.h>

#define DEFINE_GUIDXXX(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID CDECL name \
= { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
// GUIDTOM

DEFINE_GUIDXXX(IID_ITextDocument,0x8CC497C0,0xA1DF,0x11CE,0x80,0x98,
0x00,0xAA,0x00,0x47,0xBE,0x5D);


#include <assert.h>
#include <list>
#include <stack>
#include <map>

//  #include "C:\ProgramFolder\Practice\SDK(Written in C)\mymacros.h"
#include "mymacros.h"

#include "fax_engine.h"
#include "decoders.h"

#include <stdio.h>
#include <process.h>
#include <time.h>

// #define OBJECTOK // works well adding "ES_NOOLEDRAGDROP" !

#ifdef OBJECTOK
#include "CImage.h"
#endif

//Header_Insertion

LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ;
//CallBack_Insertion

BOOL InitApp( HINSTANCE ) ;
BOOL InitInstance( HINSTANCE, int ) ;
BOOL Pretranslate( MSG* ) ;
//FuncDecl_Insertion

HINSTANCE hAppInst ;
int nExecute ;

DWORD dwmode = 0L ;

#define MODE_CHECK_NUMBER_OF_PAGES 0x1 // Create1728DC 内。
#define NMAXPAGE_VALID 0x2
#define ORIGINALLY_WAS_NO_CHECK_MODE 0x4

#define CHARACTER_FIXED_MODE 0x8

#define LOG_IMAGE_TRANSMISSION 0x10000000
#define APPONCE1_EXAMPLE  0x20000000
#define APPONCE2_MENUITEM 0x40000000

// このほか、1/4 縮小分割モード、1/2 同モード、
// 薄字時間短縮モード、全ページ一括送信モード、など追加予定。


HWND hAppWnd ;
DWORD dwAppStatus ; // 0x1 FontSizeChange All/Part
// 0x2 ツールバー非表示中 / 表示中

HWND hToolbar ;


HINSTANCE hRt32 ;
HWND hEdit ;
WNDPROC EditProcOrg ;
LRESULT CALLBACK EditSubclassProc( HWND , UINT , WPARAM , LPARAM ) ; 

char *FileAllocateMemory( LPCTSTR lpFullPath ) ;

int logpixelsx , logpixelsy ;

HBITMAP Create1728DC( HWND hEdit , int istart, int npages ) ;
HBITMAP ReCreate1728DC( HWND hEdit , int istart, int npages ) ;
int beg_index ;

HBITMAP _hBitmap1728 = NULL ;
HBITMAP _hBitmap1728Captured = NULL ;
HBITMAP _hCurBmp = NULL ;
HBITMAP _hBitmap1728SEND = NULL ;


int nCurpage = 0 ;
int nMaxpage = 1 ;

std::list<std::pair<HBITMAP,int> > hbmp1728_list ;
#define PAIRHB_I std::pair<HBITMAP,int>


#define LOGICALPIXELSTOTWIPS( pixels , hdc ) \
MulDiv( (pixels) , 1440 , GetDeviceCaps( (hdc) , LOGPIXELSX ))
LPRECT MAKERECT( int l,int t,int r, int b )
{ static RECT rc ; rc.left = l , rc.top = t , rc.right = r , rc.bottom = b ; return &rc ; }

int linepos ;
RECT preview_area ;

int fax_pixel_sacrifice   = 32 ; // fax_pixel
int user_add_marginh = 64  ; // fax_pixel
int user_add_marginv = 64  ; // fax_pixel

int mmPaperWidth  = 257 ;
int mmPaperHeight = 297 ;
int partial_mm = 50 ;

LRESULT CALLBACK PrvDialogProc( HWND, UINT, WPARAM, LPARAM ) ;
HWND hCf1 = NULL ;
HWND hCombo ;
LRESULT CALLBACK Cf1DialogProc( HWND, UINT, WPARAM, LPARAM ) ;
LRESULT CALLBACK Cf2DialogProc( HWND, UINT, WPARAM, LPARAM ) ;
LRESULT CALLBACK Cf3DialogProc( HWND, UINT, WPARAM, LPARAM ) ;
LRESULT CALLBACK PaymentDialogProc( HWND, UINT, WPARAM, LPARAM );


BOOL AppChooseFont( HWND hEdit ) ;
BOOL AppChooseFontAllorWord = TRUE ;
std::map<std::string ,CHARFORMAT> font_list ;


#define CFM_FULLMASK \
( CFM_BOLD  | CFM_CHARSET   | CFM_OFFSET |\
CFM_COLOR | CFM_FACE      | CFM_ITALIC |\
CFM_SIZE  | CFM_STRIKEOUT | CFM_UNDERLINE )

HWND hPopEdit ;


//────────────────(ダッシュ)
//━━━━━━━━━━━━━━━━( ? )

#include <tapi.h>

#define TAPI_VER_HIGH 0x7FFFFFFF
#define TAPI_VER_LOW  0x00010004
BOOL tapi_ver_ge_2 = FALSE ;

HLINEAPP hLineApp ; HLINE hLine ;
HANDLE   hModem1  ;
BOOL WriteDropOperation( HANDLE hModem ) ;
BOOL DtrOff( HANDLE hModem ) ;
BOOL WriteAsync
( HANDLE hModem , char *command , DWORD nbytes , LPDWORD lpBytesWritten , DWORD timeout ) ;
void SetCommTimeoutProperties( HANDLE hAsync , int intto , int totto ) ;


char *GetBinaryArrayAsStringFromBitmap
( HBITMAP hbitmap ,
DWORD (*pfunc)( char *, DWORD , DWORD ) , void *pstop ) ;

DWORD SendOneLineProc( char *, DWORD , DWORD ) ;

int dwCap = 0x8 ;
#define CAP_CAPTURING 0x1
#define CAP_SELECTING 0x2
#define CAP_REGISTCLS 0x4

#define CAP_CAPTUREISMAIN 0x8
#define CAP_CAPUSEWITHOR 0x10
#define CAP_NOUSE 0x20

HWND hTransp ;
LRESULT CALLBACK CaptureWndProc( HWND, UINT, WPARAM, LPARAM ) ;

FILE *fp1 ;
DWORD dwLastSendTime ;


BOOL CommStat() ;
BOOL ModemStat() ;
void GetComPortByModelFromRegistry( char *ModemModelName , char *ret ) ;


BOOL WriteAsync
( HANDLE hModem , char *command , DWORD nbytes , LPDWORD lpBytesWritten , DWORD timeout )
{   // この関数自体は、
// タイムアウトまたは書き込みが終了するまで帰らないので、
// 同期関数のように振舞う。

static DWORD dwBytes ;
BOOL btimeout = FALSE ;

static OVERLAPPED ovlap ; ZeroMemory( &ovlap , sizeof( OVERLAPPED )) ;

ovlap.hEvent = CreateEvent( NULL , TRUE , FALSE , NULL ) ; 

DWORD endtime = GetTickCount() + timeout ;

if( nbytes == (DWORD)-1 ) nbytes = strlen( command ) ;

{
COMSTAT cs ; DWORD dwRet = 0 ;
ClearCommError( hModem , &dwRet , &cs ) ;
if( dwRet )
fprintf( fp1 , "WriteFile 時 ClearCommError non-zero ! : 0x%x \r\n" , dwRet ) ;

}

if( ! WriteFile( hModem , command , nbytes ,
&dwBytes , &ovlap ))
if( GetLastError() == ERROR_IO_PENDING )
{   dwBytes = 0L ;
while( !GetOverlappedResult( hModem , &ovlap , &dwBytes , FALSE )) 
if( GetTickCount() > endtime ) { btimeout = TRUE ; break ; }

if( ! dwBytes )
fprintf( fp1 , "write error ! \r\n" ) ;
}

ResetEvent( ovlap.hEvent ) ;
CloseHandle( ovlap.hEvent ) ;

if( lpBytesWritten ) *lpBytesWritten = dwBytes ;

FlushFileBuffers( hModem ) ;

return btimeout ;
}





DWORD phase_mask ;
DWORD threadstop ;

#define HLINEAPP_VALID  0x1
#define THREAD_ON       0x2
#define DIALING         0x4

// HCALL_OK


HLINEAPP EnumModems() ;

VOID FAR PASCAL tapi_lineCallback
( DWORD hDevice , DWORD dwMsg ,DWORD dwCallbackInstance ,
DWORD dwp1 ,DWORD dwp2 ,DWORD dwp3 ) ;

void StartLongFaxSession( void * ) ;

struct MDM_RESPONSE {
BOOL btrue   ; // モデム操作問題なし。
BOOL _ERROR_ ; // ERROR リザルトコードの場合。
BOOL timeout ; // タイムアウトの場合。
// その他の場合は上記2つが付かない。
const char *buf ;
int  ibufsize ;
int  nmsgs ;

} ;

MDM_RESPONSE *WaitForExpectedResponse
( HANDLE hAsync , char *szstr , DWORD total_timeout ,
void *stop ) ;

int connection_duration ;
int time_rest ;

HWND hTrack ; // 右端設定用トラックバー
RECT channel_rect , thumb_rect ;
BOOL draw_bar ; int draw_bar_pos = -1 , draw_bar_pos_org = -1 ;
HPEN hgrpen ;

std::string s ;

char GlobalSendbuf[4096 * 4*2] ; // 使ってない !?
char *lpadd ;
HWND hProgress1 , hProgress2 ;

//────────────────

struct _DIS {
int protocols_avail ; // 可能なものをフラグでセット。
char protocol_settled[64] ;
int speed_settled ; // bps
int FTM_number ;  // AT+FTM=... で指定する値。

long dcs_fif[4] ; // 一応多めに。WriteFile にこのまま乗せる。

long f7_7 : 1       ; // 副走査線 7.7本/mm   有/無
long fMR  : 1       ; // MR 符号化能力       有/無
long fECM : 1       ; // 誤り訂正方式 (ECM)
unsigned long fwidth_mode : 2 ; // 記録幅能力 0 標準, 1 標準+255/2048 , 2 標準+255/2048+303/2432
unsigned long fheight : 2 ; // szheight と同等の情報。0:A4, 1:A4B4, 2:制限無し
long fMMR : 1       ; // MMR 符号化能力      有/無

long fDum : 24      ; // ダミー

// ビットフィールドの扱いには注意せよ。

char szheight[16] ; // "A4" , "" ,"A4orB4" // 最大記録長
// A4 : 297mm ,B4 : 364mm
int min_tsm_fine   ; // minimal transimit time,duration (最小伝送時間)
int min_tsm_normal ; // 同上(ただし、上は fine mode 7.7 時、これは 標準 3.85 時 )


} dis ;
#define V27TF 0x1
#define V27T  0x2
#define V29   0x4
#define V33   0x8
#define V17   0x10

OSVERSIONINFO osi ;

struct ADDITIONAL_DISPATCH
{   char user_name[64] ;
char user_number[32] ;
char user_memo[160] ;
char sz_Country[64] ;
char sz_City[64] ;
} add_mes ;

char ini_file[MAX_PATH] ;
char ini_dir[MAX_PATH] ;
char app_name[MAX_PATH] ; // ディレクトリと、拡張子.exe を除いたもの。


DWORD CALLBACK EditStreamCallback( DWORD dwCookie ,
LPBYTE pbBuff, LONG cb, LONG FAR *pcb ) ;

FILE *fp_rtf = NULL ;
char *lp_rtf = NULL ;

int WINAPI WinMain( HINSTANCE hCurInst, HINSTANCE hPreInst,
LPSTR lpszCmdLine, int nCmdShow )
{
BOOL bErr ;
MSG msg ;

if ( ! hPreInst ) {
if ( ! InitApp( hCurInst ) ) return FALSE ; }
if ( ! InitInstance( hCurInst, nCmdShow) ) return FALSE ;
while ( FALSE != ( bErr = GetMessage( &msg, NULL, 0, 0 )))
{
if ( bErr != -1 ) {
if( Pretranslate( &msg ) ) {
TranslateMessage( &msg ) ;
DispatchMessage( &msg ) ;
}
}
}
return ( msg.wParam ) ;
}

BOOL Pretranslate( MSG* pmsg )
{
WPARAM wp ; LPARAM lp ; HWND hWnd ; UINT msg;

//    wp = pmsg ->wParam  ;
//    lp = pmsg ->lParam  ;
hWnd = pmsg ->hwnd    ;
msg = pmsg ->message ;

if( GetDlgCtrlID( hWnd ) == ID_CF1_POPEDIT &&
msg == WM_KEYDOWN && wp == VK_RETURN )
{
SendMessage( hCf1 , WM_COMMAND ,
MAKEWPARAM( IDM_ENTRY , 0 ) , (LPARAM)hWnd ) ;
return FALSE ; }


if( hCf1 && IsDialogMessage( hCf1, pmsg ) )
return FALSE ;

return TRUE ;
}



BOOL InitApp( HINSTANCE hInst )
{
WNDCLASS wc;
wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
wc.lpfnWndProc   = WndProc ;
wc.cbClsExtra    = 0 ;
wc.cbWndExtra    = 0 ;
wc.hInstance     = hInst ;
wc.hIcon   = ( HICON )LoadIcon( NULL, IDI_APPLICATION ) ;
wc.hCursor = ( HCURSOR )LoadCursor( NULL, IDC_ARROW ) ;
wc.hbrBackground = ( HBRUSH )GetStockObject( WHITE_BRUSH ) ;
wc.lpszMenuName  = "USERSMENU" ;
wc.lpszClassName = ( LPCTSTR )"EzFaxClass" ;
hAppInst = hInst ;
return( RegisterClass( &wc ) ) ;
}

BOOL InitInstance( HINSTANCE hInst, int nCmdShow )
{
HWND hWnd ;

{   char dbfile[ MAX_PATH ] ;

GetModuleFileName( hInst , dbfile , 256 ) ;

{   strcpy( ini_dir , dbfile ) ;
for( char *lp = ini_dir + strlen(ini_dir) ; lp != ini_dir ; lp -- )
if( *lp == '\\' ) { *lp = '\0' ; break ; }
else *lp = '\0' ;
}

std::string s(dbfile) ;

if( strrchr( dbfile , '\\' )) {
strncpy( app_name , strrchr( dbfile , '\\' ) +1 ,
strcspn( strrchr( dbfile , '\\' ) +1 , "." )) ;

strcpy( strrchr( dbfile , '\\' )  + 1 , "faxlog.txt" ) ;
fp1 = fopen( dbfile , "wb" ) ; }

strcpy( ini_file , s.c_str()) ;

if( strrchr( ini_file , '.' )) {
strcpy( strrchr( ini_file , '.' )  , ".ini" ) ;

#ifdef USE_WINDOWS_DIRECTORY_FOR_INI_FILE
ZeroMemory( ini_file , MAX_PATH ) ;
GetWindowsDirectory( ini_file , MAX_PATH ) ;
if( strlen(ini_file) && ini_file[strlen(ini_file)-1]=='\\' ) ini_file[strlen(ini_file)-1] = '\0' ; // ini_file が、"C:\\" の場合。
strncpy( ini_file + strlen( ini_file ) , "\\ezfax_j.ini" , strlen( "\\EzFax_J.ini" ) ) ;
#endif

if( 0xFFFFFFFF == GetFileAttributes( ini_file )) {
FILE *fp_ini = fopen( ini_file , "wb" ) ;
fprintf( fp_ini , "[SECTION1]\r\n" ) ;
fprintf( fp_ini , ":This is \"%s\"'s initialization file.\r\n" , s.c_str() ) ;
fprintf( fp_ini , "LastModemName=\"\"\r\n" ) ;
fprintf( fp_ini , "LastCallNumber=#*1\r\n" ) ;

fprintf( fp_ini , "SenderName=FAX 太郎\r\n" ) ;
fprintf( fp_ini , "SenderID=xxx-xxxx\r\n" ) ;
fprintf( fp_ini , "SenderMemo=\"\"\r\n" ) ;
fprintf( fp_ini , "PULSE=0\r\n" ) ;
fprintf( fp_ini , "Fine=1\r\n" ) ;
fprintf( fp_ini , "CountryCode=-1\r\n" ) ;
fprintf( fp_ini , "CityCode=-1\r\n" ) ;
fprintf( fp_ini , "AppOnce1=0\r\n"  ) ;
fprintf( fp_ini , "AppOnce2=0\r\n"  ) ;

fprintf( fp_ini , "Excute=0\r\n" ) ;
fprintf( fp_ini , "Payment=0\r\n" ) ;


fprintf( fp_ini , "\r\n" ) ;
fprintf( fp_ini , "[FONT]\r\n" ) ;
fprintf( fp_ini , "Face=MS 明朝\r\n" ) ;
fprintf( fp_ini , "PointSize=14\r\n" ) ;
fprintf( fp_ini , "Bold=1\r\n" ) ;
fprintf( fp_ini , "Italic=0\r\n" ) ;
fprintf( fp_ini , "CharSet=\r\n" ) ;
fprintf( fp_ini , "bPitchAndFamily=\r\n" ) ;
fprintf( fp_ini , "MenuItemFace=\r\n" ) ;

fprintf( fp_ini , "ChangeSize=Part\r\n" ) ;


fprintf( fp_ini , "\r\n" ) ;

fclose( fp_ini ) ; }

}

{   ZeroMemory( &add_mes , sizeof( ADDITIONAL_DISPATCH )) ;
GetPrivateProfileString( "SECTION1" , "SenderName" , "FAX 太郎" , add_mes.user_name , sizeof( add_mes.user_name ) , ini_file ) ;
GetPrivateProfileString( "SECTION1" , "SenderID" , "xxx-xxxx" , add_mes.user_number , sizeof( add_mes.user_number ) , ini_file ) ;

char szCountry[256] ;
tapiGetLocationInfo( szCountry , szCountry + 128 ) ;

strncpy( add_mes.sz_Country , szCountry , 63 ) ;
strncpy( add_mes.sz_City , szCountry + 128 , 63 ) ;


}
}


// シェアウェア
nExecute = GetPrivateProfileInt( "SECTION1" , "Execute" , 0 , ini_file ) ;
nExecute ++ ;
char sz_profile[256] ;
itoa( nExecute , sz_profile ,10 ) ;

WritePrivateProfileString( "SECTION1" , "Execute" , sz_profile , ini_file ) ;


if( nExecute > 50 || nExecute < 0 )
{ char payment[256] ;
GetPrivateProfileString( "SECTION1" , "Payment" , "0" , payment , 256 , ini_file ) ;
if( strcmp( payment , "True" ))
DialogBoxParam( hAppInst, "PAYMENTDIALOG",
hWnd, ( DLGPROC ) PaymentDialogProc ,0) ;
}
//--


hWnd = CreateWindow(
( LPCTSTR )"EzFaxClass" ,
( LPCTSTR ) fmt( "%s(%d.%d)" ,app_name , VER_MAJ , VER_MIN ) ,
WS_OVERLAPPEDWINDOW ,
CW_USEDEFAULT , //x座標 ; int
CW_USEDEFAULT , //y座標 ; int
CW_USEDEFAULT , //ウィンドウ横幅
CW_USEDEFAULT , //ウィンドウ高さ
NULL ,
NULL ,
hInst,
NULL
) ;

hAppWnd = hWnd ;
if ( ! hWnd ) return FALSE ;
ShowWindow( hWnd, nCmdShow ) ;
UpdateWindow( hWnd ) ;
SetFocus( hWnd ) ;

return TRUE ;
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{


#ifdef OBJECTOK
static IExtRichEditOleCallback  *pReOleCallback ;
#endif

switch( msg )
{
case WM_CREATE :

{   INITCOMMONCONTROLSEX ic ;
ic.dwSize = sizeof( INITCOMMONCONTROLSEX ) ;
ic.dwICC = ICC_WIN95_CLASSES |
ICC_DATE_CLASSES | ICC_USEREX_CLASSES |
ICC_COOL_CLASSES | ICC_INTERNET_CLASSES |
ICC_PAGESCROLLER_CLASS | ICC_NATIVEFNTCTL_CLASS ;
InitCommonControlsEx( &ic ) ;
}


{   HDC hdc = GetDC( hWnd ) ;
logpixelsx = GetDeviceCaps( hdc , LOGPIXELSX ) ;
logpixelsy = GetDeviceCaps( hdc , LOGPIXELSY ) ;

ReleaseDC( hWnd , hdc ) ;
}

if( NULL == (
hRt32 = LoadLibrary( // "RICHED32.DLL"
"RICHED20.DLL" )))
MessageBox( NULL , "RICHED20.DLL をロードできない。" , "エラー" , MB_OK | MB_SETFOREGROUND | MB_ICONASTERISK ) ;

#define INIT_EDIT_WIDTH ( ( 1728 - fax_pixel_sacrifice * 2) / 4 )
#define LRTP_MARGIN ( fax_pixel_sacrifice * 4 / 4 )

// 255 ? 216 

// 折り返すようにするには ES_AUTOHSCROLL , WS_HSCROLL をはずした。

hEdit = 
CreateWindowEx( NULL , // WS_EX_CLIENTEDGE ,
"RichEdit20A" , "" ,
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_MULTILINE | ES_AUTOVSCROLL |
ES_NOHIDESEL | ES_WANTRETURN  | ES_DISABLENOSCROLL
#ifdef OBJECTOK
| ES_NOOLEDRAGDROP 
#endif
, 4 , 4 , 0 , 0 , hWnd ,
(HMENU)ID_EDIT1 , hAppInst , NULL ) ;

{
RECT rc = *MAKERECT( 0 , 0 , INIT_EDIT_WIDTH ,
MulDiv( MulDiv( INIT_EDIT_WIDTH , logpixelsy , logpixelsx )
, 297 , 216 )) ;

#define WIDTHRC( rc )  ((rc).right  - (rc).left )
#define HEIGHTRC( rc ) ((rc).bottom - (rc).top  )

AdjustWindowRectEx( &rc ,
GetWindowStyle( hEdit ) /*& ~WS_VSCROLL*/ ,
GetMenu( hEdit ) ? TRUE : FALSE ,
GetWindowExStyle( hEdit ) ) ;

MoveWindow( hEdit ,  LRTP_MARGIN ,  LRTP_MARGIN , WIDTHRC(rc) /*+ 84*/ ,
HEIGHTRC(rc) , TRUE ) ;

{   // 親ウィンドウの再調整
RECT rcp ; RECT rce ;
GetClientRect( hWnd  , &rcp ) ;
GetWindowRect( hEdit , &rce ) ;

//              MapWindowRect( NULL , hWnd , &rce ) ;
{   POINT pt ;
pt.x = rce.left , pt.y = rce.top ;
ScreenToClient( hWnd , &pt ) ;
rce.left = pt.x , rce.top = pt.y ;
pt.x = rce.right , pt.y = rce.bottom ;
ScreenToClient( hWnd , &pt ) ;
rce.right = pt.x , rce.bottom = pt.y ;

}


BOOL bmod = FALSE ;
int newht , newwd ;

if( HEIGHTRC( rcp ) < rce.bottom )
bmod = TRUE , newht = rce.bottom + 32 ;
else newht = HEIGHTRC( rcp ) ;

if( WIDTHRC( rcp ) < rce.right )
bmod = TRUE ,
newwd = LRTP_MARGIN + WIDTHRC( rce ) + LRTP_MARGIN 
+ WIDTHRC( rce ) / 2 ;
else newwd = WIDTHRC( rcp ) ;

if( bmod ) {

RECT _rc = *MAKERECT( 0, 0, newwd, newht ) ;

AdjustWindowRectEx( &_rc , GetWindowStyle( hWnd ) ,
GetMenu( hWnd ) ? TRUE : FALSE , GetWindowExStyle( hWnd ) ) ;

newwd = _rc.right  - _rc.left ;
newht = _rc.bottom - _rc.top  ;

SetWindowPos( hWnd , NULL , 0, 0,
newwd , newht ,
SWP_NOMOVE | SWP_NOZORDER ) ;
}

}


// Edit_SetRect( hEdit , (const RECT *)MAKERECT( 0 , 0 , INIT_EDIT_WIDTH , HEIGHTRC( rc ) )) ;

GetWindowRect( hEdit , &rc ) ;

// SetDlgItemInt( hWnd , ID_EDIT1 , WIDTHRC( rc ) , TRUE ) ;

linepos = LRTP_MARGIN + WIDTHRC( rc ) + LRTP_MARGIN ;

GetClientRect( hWnd , &rc ) ;

preview_area =
*MAKERECT( linepos + 1 , 0 ,
WIDTHRC(rc), HEIGHTRC(rc) ) ;


}

SendMessage( hEdit, EM_EXLIMITTEXT, 0L, (LPARAM) 65535 * 4 );


{   // 重要 : リッチ 2.0 での特殊。2004/10/11
//          SendMessage( hEdit , EM_GETLANGOPTIONS , 0L ,0L ) ;

SendMessage( hEdit , EM_SETLANGOPTIONS , ECOOP_AND , ~( IMF_DUALFONT | IMF_AUTOFONT ) ) ;

}

{   // SetInitialFont == Initializing ...

CHARFORMAT cfm ;
ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;

cfm.crTextColor = RGB( 0 , 0 , 0 ) ;

if( GetPrivateProfileInt( "FONT" , "Bold" , 1 , ini_file ))
cfm.dwEffects |= CFE_BOLD ;

if( GetPrivateProfileInt( "FONT" , "Italic" , 0 , ini_file ))
cfm.dwEffects |= CFE_ITALIC ;

GetPrivateProfileString( "FONT" , "Face" , "MS 明朝" , cfm.szFaceName , sizeof( cfm.szFaceName ) , ini_file ) ;

cfm.bCharSet = GetPrivateProfileInt( "FONT" , "CharSet" , SHIFTJIS_CHARSET , ini_file ) ;
cfm.bPitchAndFamily = GetPrivateProfileInt( "FONT" , "bPitchAndFamily" , VARIABLE_PITCH | FF_MODERN , ini_file ) ;

//          cfm.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE ;
//          cfm.bPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE ;

cfm.dwMask
= CFM_BOLD | CFM_FACE | CFM_CHARSET | CFM_COLOR ;


{   int pointsize = GetPrivateProfileInt( "FONT" , "PointSize" , 14 , ini_file ) ;
cfm.dwMask |= CFM_SIZE ;
cfm.yHeight = pointsize * 20 ;
}

font_list.insert
( font_list.end(), std::pair<std::string,CHARFORMAT>( cfm.szFaceName ,cfm ) ) ;

if ( 0 == SendMessage( hEdit, EM_SETCHARFORMAT ,
SCF_ALL , ( LPARAM)&cfm ))
MessageBox( NULL , "フォントの初期設定に失敗しました。", "エラー" , MB_OK | MB_SETFOREGROUND ) ;
// SCF_SELECTION | SCF_WORD にすると違う。

SendMessage( hEdit , EM_SETMODIFY , FALSE , 0 ) ;
}

//      if( ! SendMessage( hEdit , EM_SETFONTSIZE , 24 , 0L ))
//      MessageBox( NULL , "しっぱい" , "" , MB_OK | MB_SETFOREGROUND ) ;
//      if( ! SendMessage( hEdit , EM_SETZOOM , 4 , 1L )) ;

{   char str[16] ; memset( str, 0, sizeof( str)) ;

GetPrivateProfileString( "FONT" , "ChangeSize" , "All" , str, sizeof( str ) , ini_file ) ;
if( stricmp( str , "Part" )) dwAppStatus &= ~0x1 ; else dwAppStatus |= 0x1 ;
}



//  ドラッグアンドドロップを有効にする
{   DWORD dwEvent ;
dwEvent = SendMessage( hEdit, EM_GETEVENTMASK , 0L , 0L ) ;

dwEvent |= ENM_MOUSEEVENTS | ENM_SELCHANGE | ENM_CHANGE | ENM_UPDATE | ENM_PROTECTED ;
dwEvent |= ENM_DROPFILES ;

SendMessage( hEdit , EM_SETEVENTMASK , 0L , (LPARAM) dwEvent ) ;
}

DragAcceptFiles( hEdit , TRUE ) ;

//      Edit_FmtLines( hEdit , TRUE ) ;

if( NULL == (    EditProcOrg = 
SubclassWindow( hEdit , EditSubclassProc )))
MessageBox( NULL , "リッチエディットコントロールのサブクラス化できない。(続行)" , "エラー" , MB_OK | MB_SETFOREGROUND | MB_ICONASTERISK ) ;



// 〇 "richedit.h" のインクルード
// 〇 LoadLibrary( , "RICHED32.DLL" ) ;
// @ CreateWindow 
// A フォント初期化
// ( リミットテキスト )
// ( イベントマスク 特に ドラッグ&ドロップを使用したい場合 = ENM_DROPFILES )
// ( DragAcceptFiles()) ;
// B サブクラス化 == windowsx.h 定義マクロ SubclassWindow が簡単。けじめとしてアプリケーション終了時にもとに戻す。
// 関数は LRESULT CALLBACK 型。返り値 : return CallWindowProc( EditProcOrg , hWnd, msg, wp, lp )) ;
// FreeLibrary と、DestroyWindow のタイミングに注意する。richedit コントロールが Destroy されないうちに FreeLibrary してはいけない !!

hCf1 = CreateDialog( hAppInst , "CONFIG1" ,
hWnd, ( DLGPROC )Cf1DialogProc ) ;

hLineApp = EnumModems() ;

{   int wx = WIDTHRC( preview_area )  , wy = 24 ;
int x , y ; x = preview_area.left , y = preview_area.bottom - wy ;

hTrack = CreateWindowEx( NULL , "msctls_trackbar32" , "" ,
WS_CHILD | WS_VISIBLE ,
x ,y , wx ,wy , hWnd , (HMENU)ID_TRACK , hAppInst , NULL ) ;

SendMessage( hTrack , TBM_GETCHANNELRECT , 0, (LPARAM)&channel_rect ) ;

int channel_len = WIDTHRC( channel_rect ) ;



SendMessage( hTrack , TBM_GETTHUMBRECT , 0, (LPARAM)&thumb_rect ) ;
int thumb_len = WIDTHRC( thumb_rect ) ;

SendMessage( hTrack , TBM_SETRANGE , TRUE ,
MAKELONG( thumb_len / 2 , channel_len - thumb_len / 2 ) ) ;
// SendMessage( hTrack , TBM_SETPOS , TRUE , ) ;

OffsetRect( &channel_rect , x, y ) ;

hgrpen  = CreatePen( PS_DOT , 1 , RGB( 0x7F ,0x7F, 0x7F )) ;

}

{   ZeroMemory( &osi , sizeof( osi )) ;
osi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ) ;
GetVersionEx( &osi ) ;
DWORD dw = osi.dwPlatformId ;

fprintf( fp1 , "Windows 3.1系 %s 95系 %s NT系 %s その他 %s  ver %d.%d\r\n"
, ( dw == VER_PLATFORM_WIN32s ) ? "(◎)" : "(-)"
, ( dw == VER_PLATFORM_WIN32_WINDOWS ) ? "(◎)" : "(-)"
, ( dw == VER_PLATFORM_WIN32_NT ) ? "(◎)" : "(-)"
, ( dw > 2 ) ? "(◎)" : "(-)" 
, osi.dwMajorVersion, osi.dwMinorVersion ) ;

}

#ifdef OBJECTOK
pReOleCallback = new IExtRichEditOleCallback  ; // "CImage.h"
SendMessage( hEdit , EM_SETOLECALLBACK , 0L , (LPARAM) pReOleCallback ) ;
#endif

// もとに戻す場合は...
// SendMessage( hEdit , EM_SETOLECALLBACK , 0L , 0L ) ;

// フォント変更用「ツールバー」を、本体画面の右上隅につくる。
{
TBADDBITMAP tbab ;
int nBTN = 8, nsep = 1 ; // ボタンの数とセパレータの数

TBBUTTON tbb[] = {

{ 0 , IDM_BOLD   , TBSTATE_ENABLED, BTNS_CHECK, "", 0,0 } ,
{ 1 , IDM_ITALIC , TBSTATE_ENABLED, BTNS_CHECK, "", 0,1 } ,
{ 2 , IDM_ULINE  , TBSTATE_ENABLED, BTNS_CHECK, "", 0,2 } ,

//  { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0 } ,

{ 3 , IDM_STRIKE , TBSTATE_ENABLED, BTNS_CHECK, "", 0,3 } ,
{ 4 , IDM_SUP    , TBSTATE_ENABLED, BTNS_CHECK, "", 0,4 } ,
{ 5 , IDM_SUB    , TBSTATE_ENABLED, BTNS_CHECK, "", 0,5 } ,

{ 0 , 0, TBSTATE_ENABLED, TBSTYLE_SEP, "", 0,0 } ,
{ 6 , IDM_UNDO , TBSTATE_ENABLED, TBSTYLE_BUTTON, "", 0,6 } ,
{ nBTN-1 , IDM_SEND , TBSTATE_ENABLED, TBSTYLE_BUTTON|TBSTYLE_DROPDOWN, "", 0,nBTN-1 }


//  { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0 } ,

//  { 8 , IDM_DESKTOPCAP , TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 8 } ,

} ;  // 並び : 絵の番号 , ID , ... , ツールチップ表示の 番号


RECT rc ; GetWindowRect( hEdit , &rc ) ;
MapWindowRect( NULL, hWnd , &rc ) ;


int wid = 16 * nBTN + 8 + 16 ;

hToolbar = CreateWindowEx( WS_EX_PALETTEWINDOW ,
TOOLBARCLASSNAME ,"" ,
WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_LIST | CCS_NODIVIDER | CCS_NORESIZE , // | CCS_ADJUSTABLE ,

rc.right - wid - 3, rc.top - 24, wid, 16, // Make it zero, Let owner resize it.
hWnd , (HMENU)ID_FONTTOOLBAR , hAppInst , NULL ) ;


ToolBar_SetExtendedStyle( hToolbar , TBSTYLE_EX_DRAWDDARROWS 
| TBSTYLE_EX_MIXEDBUTTONS | ToolBar_GetExtendedStyle( hToolbar )) ;

SendMessage( hToolbar , TB_BUTTONSTRUCTSIZE,
(WPARAM) sizeof(TBBUTTON) , 0 ) ;

tbab.hInst = NULL ;
tbab.nID   = (UINT) LoadBitmap( hAppInst, "FONTTOOLBARBITMAP" ) ;

SendMessage( hToolbar , TB_SETBITMAPSIZE , 0L , MAKELONG(8 ,7 )) ;

// SendMessage( hToolbar , TB_SETBUTTONSIZE , 0L , MAKELONG( 8 , 7)) ;

SendMessage( hToolbar , TB_AUTOSIZE , 0L , 0L ) ;

SendMessage( hToolbar , TB_ADDBITMAP , nBTN  , (LPARAM) &tbab ) ;

char *szTips =
"太字(BOLD)\0斜体(Italic)\0下線(Underline)\0中線(Strike out)\0"
"吊り上げ(Superscript)\0吊り下げ(Subscript)\0"
"やり直し(UNDO)\0" "送信\0" "\0" ;


SendMessage( hToolbar , TB_ADDSTRING , 0L , (LPARAM)szTips ) ;
SendMessage( hToolbar , TB_ADDBUTTONS , nBTN + nsep , (LPARAM) &tbb ) ;

if( ! GetPrivateProfileInt( "FONT" , "ShowToolbar" , -1 , ini_file ))
SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_HIDETOOLBAR ,0 ) ,0 ) ;


}


//      case_Insertion

break ;
case WM_PAINT :
{   RECT upd ;
if( ! GetUpdateRect( hWnd , &upd , FALSE )) break ;
PAINTSTRUCT ps ;
HDC hdc = BeginPaint( hWnd , &ps ) ;

// エディット部とプレビュー部の境界線
if( upd.left <= linepos && linepos <= upd.right )
{   HPEN penOrg = (HPEN)SelectObject( hdc , GetStockObject( BLACK_PEN )) ;
MoveToEx( hdc , linepos , upd.top , NULL ) ;
LineTo( hdc , linepos , upd.bottom ) ;
SelectObject( hdc , penOrg ) ;
}

if( ! _hCurBmp && _hBitmap1728 ) {
_hCurBmp = CreateCompatibleBitmap
( hdc , WIDTHRC(preview_area), HEIGHTRC(preview_area) ) ;

HDC hdc_mem = CreateCompatibleDC( hdc ) ;
HDC hdc_memmem = CreateCompatibleDC( hdc ) ;
SelectObject( hdc_memmem , _hBitmap1728 ) ;
SelectObject( hdc_mem , _hCurBmp ) ;

FillRect( hdc_mem , MAKERECT( 0,0,WIDTHRC(preview_area), HEIGHTRC(preview_area) )
,(HBRUSH)GetStockObject( GRAY_BRUSH )) ;


int offsetx =
MulDiv( WIDTHRC( preview_area ) , ( mmPaperWidth - 216 ) , mmPaperWidth )
/ 2 ;

int w = MulDiv( WIDTHRC( preview_area ) , 216 , mmPaperWidth ) ;

// int h = MulDiv( w , mmPaperHeight * logpixelsy , mmPaperWidth * logpixelsx ) ;
// w*(mmPaperHeight*logpixelsy)/(mmPaperWidth*logpixelsx)

int h = MulDiv( w , 1728 , 297 * 4 ) ;

int voffsetToshow = 25 ;

StretchBlt(
hdc_mem    , offsetx , voffsetToshow , w , h ,
hdc_memmem , 0, 0, 1728 , 297 * 4 * 2 , SRCCOPY ) ;

DeleteDC( hdc_memmem ) ;
DeleteDC( hdc_mem ) ;
}


if( _hCurBmp )
{   HDC hdc_mem = CreateCompatibleDC( hdc ) ;
SelectObject( hdc_mem , _hCurBmp ) ;

BitBlt( hdc , preview_area.left , preview_area.top ,
WIDTHRC(preview_area) , HEIGHTRC(preview_area) ,
hdc_mem , 0 , 0 , SRCCOPY ) ;

//              BitBlt( hdc , upd.left , upd., , , hdc_mem , 0 , 0 , SRCCOPY ) ;

DeleteDC( hdc_mem ) ;
}

if( upd.left <= draw_bar_pos && draw_bar_pos <= upd.right )
{
HPEN penOrg = (HPEN)SelectObject( hdc , hgrpen ) ;
MoveToEx( hdc , draw_bar_pos , preview_area.top  , NULL ) ;
LineTo( hdc , draw_bar_pos , preview_area.bottom ) ;
SelectObject( hdc , penOrg ) ;
}

EndPaint( hWnd , &ps ) ;

return 0L ;
}

break ;

case WM_TIMER :

#define TIMER_CONNECTDURATION 101

if( wParam == TIMER_CONNECTDURATION )
{   connection_duration ++ ;

SbarSetText( 2 , fmt( "接続時間 %02d:%02d:%02d (残%d秒)"
, connection_duration / 3600 , connection_duration / 60 , connection_duration % 60
, time_rest ) ) ;
}


break ;

//case WM_GETDLGCODE :
//break ;
//case WM_INITMENUPOPUP
//break ;



case WM_COMMAND :
switch( LOWORD( wParam ) )
{

case IDM_REDO :
SendMessage( hEdit , EM_REDO , 0 , 0 ) ;
break ;

case IDM_UNDO :
SendMessage( hEdit , EM_UNDO , 0 , 0 ) ;
break ;
case IDM_CUT :
SendMessage( hEdit , WM_CUT , 0 , 0 ) ;
break ;
case IDM_COPY :
SendMessage( hEdit , WM_COPY , 0 , 0 ) ;
break ;

case IDM_PASTE :

SendMessage( hEdit , WM_PASTE , 0 , 0 ) ;
{   CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_COLOR ;

SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (LPARAM)&cfm ) ;

cfm.dwMask = CFM_COLOR ;
SendMessage( hEdit , EM_SETCHARFORMAT , SCF_ALL , (LPARAM)&cfm ) ;
}


break ;
case IDM_CLEAR :
SendMessage( hEdit , WM_CLEAR , 0 , 0 ) ;
break ;
case IDM_SELECTALL :
{   CHARRANGE Pchr ; Pchr.cpMin = 0 , Pchr.cpMax = -1 ;
SendMessage( hEdit , EM_EXSETSEL , 0L ,(LPARAM)&Pchr ) ;
}

break ;

case IDM_ULINE  :
case IDM_BOLD   :
case IDM_ITALIC :
case IDM_STRIKE :
case IDM_SUP    :
case IDM_SUB    :

{
CHARFORMAT2 cfm ;
DWORD dwMask , dwEffects ;
switch( LOWORD( wParam )) { 
case IDM_ULINE  : dwMask = CFM_UNDERLINE , dwEffects = CFE_UNDERLINE ; break ;
case IDM_BOLD   : dwMask = CFM_BOLD      , dwEffects = CFE_BOLD ; break ;
case IDM_ITALIC : dwMask = CFM_ITALIC    , dwEffects = CFE_ITALIC ; break ;
case IDM_STRIKE : dwMask = CFM_STRIKEOUT , dwEffects = CFE_STRIKEOUT ; break ;
case IDM_SUP    : dwMask = CFM_SUPERSCRIPT , dwEffects = CFE_SUPERSCRIPT ; break ;
case IDM_SUB    : dwMask = CFM_SUBSCRIPT   , dwEffects = CFE_SUBSCRIPT   ; break ;

default : dwMask = CFM_ITALIC , dwEffects = CFE_ITALIC ; break ;

}

CHARRANGE Pchr ;
SendMessage( hEdit , EM_EXGETSEL , 0L , (LPARAM)&Pchr ) ;

LPRICHEDITOLE ppIRe = NULL ;
SendMessage( hEdit , EM_GETOLEINTERFACE , 0L ,(LPARAM)&ppIRe ) ;


// MessageBox( NULL , fmt( "%d こ" ,
// ppIRe->GetLinkCount() ) , "" , MB_OK ) ;


if( ! ppIRe )
fprintf( fp1 , "EM_GETOLEINTERFACE 失敗 \r\n" ) ;


if( ppIRe ) {
// ITextSelection *pTexSel ;
// ppIRe->GetSelection( &pTexSel ) ;

ITextDocument FAR *pTexDoc  ;
HRESULT res =
ppIRe->QueryInterface( IID_ITextDocument , (void **)&pTexDoc ) ;

if( res != S_OK )
fprintf( fp1 , "QueryInterface IID_ITextDocument 失敗 \r\n" ) ;

if( res == S_OK ) {
DWORD dw = Pchr.cpMin ;

ITextRange *pTexRange ;
res = pTexDoc->Range( dw , dw+1 , &pTexRange ) ;

if( res != S_OK )
fprintf( fp1 , "ITextRange->Range 失敗 \r\n" ) ;

ITextFont *pTexFont ;
pTexRange->GetFont( &pTexFont ) ;

if( res == S_OK && pTexFont ) {
for( ; dw < Pchr.cpMax ; dw ++ ) {

long lret = 0 ;
BOOL bstop = FALSE ;
switch( LOWORD(wParam))
{
case IDM_ULINE  : pTexFont->GetUnderline(&lret)     ; if( lret == tomNone ) bstop = TRUE ; break ;
case IDM_BOLD   : pTexFont->GetBold(&lret)          ; if( lret != tomTrue ) bstop = TRUE ; break ;
case IDM_ITALIC : pTexFont->GetItalic(&lret)        ; if( lret != tomTrue ) bstop = TRUE ; break ;
case IDM_STRIKE : pTexFont->GetStrikeThrough(&lret) ; if( lret != tomTrue ) bstop = TRUE ; break ;

case IDM_SUP : pTexFont->GetSuperscript(&lret )    ; if( lret != tomTrue ) bstop = TRUE ; break ;
case IDM_SUB : pTexFont->GetSubscript(&lret )      ; if( lret != tomTrue ) bstop = TRUE ; break ;
}

if( bstop ) break ;

// fprintf( fp1 , "比較しています。 %d〜%d \r\n" , dw , dw+1 ) ;

/*
long lChar ;
pTexRange->GetChar( &lChar ) ;

char cCheck[3] ; cCheck[2] = '\0' ;
WideCharToMultiByte( CP_ACP , WC_COMPOSITECHECK , (LPCWSTR)&lChar , 1 , cCheck , 3 , NULL , NULL ) ;

if( IsDBCSLeadByte( *cCheck ))
// fprintf( fp , "%c%c" , cCheck[0] , cCheck[1] ) ;
dw ++ ;
// else 
// fprintf( fp1 , "%c" , lChar ) ;
*/


pTexRange->MoveStart( tomCharacter, 1 , NULL) ;
pTexRange->MoveEnd( tomCharacter, 1 , NULL) ;
// 一文字ずつ調べている(原始的な方法)

}
pTexFont->Release() ;

pTexRange->Release() ;
}

pTexDoc->Release() ;
if( dw == Pchr.cpMax ) dwEffects = 0L ;

}
ppIRe->Release() ;
}

ZeroMemory( &cfm , sizeof( cfm )) ;
cfm.cbSize = sizeof( cfm ) ;
cfm.dwMask = dwMask , cfm.dwEffects = dwEffects ;
SendMessage( hEdit , EM_SETCHARFORMAT , SCF_SELECTION ,(LPARAM)&cfm ) ;
}

break ;
case IDM_FONT_PARTIAL :

AppChooseFontAllorWord = FALSE ;
SendMessage( hCf1 , WM_COMMAND , MAKEWPARAM( IDC_CF1_SELECTFONT ,0) , (LPARAM)hWnd ) ;

break ;


case IDM_SEND :
SendMessage( hCf1 , WM_COMMAND ,MAKEWPARAM(IDC_CF1_SEND ,0) ,0 ) ;
break ;


case IDM_SWITCHTOOLBAR :

dwAppStatus ^= 0x2 ;

SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( ((dwAppStatus & 0x2) ? IDM_HIDETOOLBAR : IDM_SHOWTOOLBAR) , 0 ) ,0 ) ;


break ;

case IDM_HIDETOOLBAR :
case IDM_SHOWTOOLBAR :

if( IsWindow( hToolbar )) {
BOOL fShow = ( LOWORD(wParam) == IDM_HIDETOOLBAR ) ? TRUE : FALSE ;

// 以下は、「^=」 にしてはいけない。(念のために フラグをセットしていうる。)
if( LOWORD(wParam) == IDM_HIDETOOLBAR ) dwAppStatus |= 0x2 ; else dwAppStatus &= ~0x2 ;

RECT itemrc1, itemrc2 ;
SendMessage( hToolbar, TB_GETITEMRECT, 6, (LPARAM)&itemrc1 ) ;

SendMessage( hToolbar , TB_HIDEBUTTON , IDM_ULINE  , MAKELONG( fShow , 0 )) ;
SendMessage( hToolbar , TB_HIDEBUTTON , IDM_BOLD   , MAKELONG( fShow , 0 )) ;
SendMessage( hToolbar , TB_HIDEBUTTON , IDM_ITALIC , MAKELONG( fShow , 0 )) ;
SendMessage( hToolbar , TB_HIDEBUTTON , IDM_STRIKE , MAKELONG( fShow , 0 )) ;
SendMessage( hToolbar , TB_HIDEBUTTON , IDM_SUP , MAKELONG( fShow , 0 )) ;
SendMessage( hToolbar , TB_HIDEBUTTON , IDM_SUB , MAKELONG( fShow , 0 )) ;

SendMessage( hToolbar, TB_GETITEMRECT, 6, (LPARAM)&itemrc2 ) ;

#define OffsetWindow( hwndCtrl, dx, dy, fRedraw ) \
{   RECT rc ; GetWindowRect( (hwndCtrl), &rc ) ; \
MapWindowPoints( NULL, GetParent((hwndCtrl)), (LPPOINT)&rc, 2 ) ; \
OffsetRect( &rc, (dx), (dy)) ; \
MoveWindow( (hwndCtrl), rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, (fRedraw)) ; \
}

#define ResizeWindowDelta( hwndCtrl, dx, dy ) \
{   RECT rc ; GetWindowRect( (hwndCtrl), &rc ) ; \
SetWindowPos( (hwndCtrl) , NULL , 0, 0, rc.right-rc.left+(dx), rc.bottom-rc.top+(dy) , SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED ) ; \
}

ResizeWindowDelta( hToolbar, itemrc2.left - itemrc1.left , 0 ) ;
OffsetWindow( hToolbar, itemrc1.left - itemrc2.left, 0 , TRUE ) ;


}



break ;

default :
return( DefWindowProc( hWnd, msg,
wParam, lParam ) ) ;
}
break ;

case WM_NOTIFY :

if( ( ( NMHDR * )lParam) -> idFrom == ID_EDIT1 )
switch ( ( ( NMHDR *) lParam )->code )
{
MSGFILTER *pmf ;

case EN_MSGFILTER :

pmf = ( MSGFILTER * )lParam ;
switch( pmf -> msg ) {
case WM_RBUTTONDOWN :
{       POINTS pts = MAKEPOINTS( pmf ->lParam ) ;

HMENU hMenu = LoadMenu( hAppInst, "EDITMENU" ) ;
HMENU hSub  = GetSubMenu( hMenu, 0 ) ;
POINT pt ;
pt.x = ( LONG )pts.x ;
pt.y = ( LONG )pts.y ;

ClientToScreen( ( ( NMHDR * ) lParam ) -> hwndFrom , &pt ) ;

if( ! SendMessage( hEdit , EM_CANUNDO , 0 , 0 ))
EnableMenuItem( hSub , IDM_UNDO , MF_BYCOMMAND | MF_DISABLED | MF_GRAYED ) ;

if( ! SendMessage( hEdit , EM_CANREDO , 0 , 0 ))
EnableMenuItem( hSub , IDM_REDO , MF_BYCOMMAND | MF_DISABLED | MF_GRAYED ) ;


{   CHARRANGE Pchr ;
SendMessage( hEdit , EM_EXGETSEL , 0L , (LPARAM)&Pchr ) ;
if( Pchr.cpMin == Pchr.cpMax ) {
// DeleteMenu( hSub , IDM_ULINE , MF_BYCOMMAND ) ;
// DeleteMenu( hSub , IDM_BOLD  , MF_BYCOMMAND ) ;
// DeleteMenu( hSub , IDM_ITALIC , MF_BYCOMMAND ) ;
// DeleteMenu( hSub , IDM_STRIKE , MF_BYCOMMAND ) ;

// DeleteMenu( hSub , IDM_FONT_PARTIAL , MF_BYCOMMAND ) ;
}
else {}


// 文字装飾の状況(BOLD,ITALIC...) に従ってポップアップ時 メニューにチェックを入れる。
// 2005/6/8 改良
// ( RICHEDITOLE に関して は手っ取り早く NV を参照 )

LPRICHEDITOLE ppIRe = NULL ;
HRESULT res ;
ITextDocument *pEDoc ;

SendMessage( hEdit , EM_GETOLEINTERFACE , 0L ,(LPARAM)&ppIRe ) ;

if( ppIRe )
res =
ppIRe->QueryInterface( IID_ITextDocument , (void **)&pEDoc ) ;


if( res == S_OK && pEDoc )
{

ITextSelection *pESel ; ITextFont *pEFont ;
pEDoc->GetSelection( &pESel ) ;
pESel->GetFont( &pEFont )     ;
LONG lattr ;

lattr = 0 ; pEFont->GetUnderline( &lattr) ;
if( lattr == tomSingle || lattr == tomTrue )
CheckMenuItem( hSub , IDM_ULINE  , MF_BYCOMMAND | MF_CHECKED ) ;

lattr = 0 ; pEFont->GetBold( &lattr) ; 
if( tomTrue == lattr )
CheckMenuItem( hSub , IDM_BOLD   , MF_BYCOMMAND | MF_CHECKED ) ;

lattr = 0 ;  pEFont->GetItalic( &lattr) ;
if( tomTrue == lattr )
CheckMenuItem( hSub , IDM_ITALIC , MF_BYCOMMAND | MF_CHECKED ) ;

lattr = 0 ; pEFont->GetStrikeThrough( &lattr) ;
if( tomTrue == lattr )
CheckMenuItem( hSub , IDM_STRIKE , MF_BYCOMMAND | MF_CHECKED ) ;

lattr = 0 ; pEFont->GetSuperscript( &lattr ) ;
if( tomTrue == lattr )
CheckMenuItem( hSub , IDM_SUP    , MF_BYCOMMAND | MF_CHECKED ) ;

lattr = 0 ; pEFont->GetSubscript( &lattr ) ;
if( tomTrue == lattr )
CheckMenuItem( hSub , IDM_SUB    , MF_BYCOMMAND | MF_CHECKED ) ;



}



}

TrackPopupMenu( hSub ,
TPM_LEFTALIGN ,
pt.x , pt.y , 0 , hAppWnd , NULL ) ;

DestroyMenu( hMenu ) ;
}

break;
default : break ;
}
break ; // EN_MSGFILTER

case EN_SELCHANGE :

{   CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_ALL ;
SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (LPARAM)&cfm );

if( font_list.end() == font_list.find( cfm.szFaceName ))
font_list.insert( font_list.end() , std::pair<std::string, CHARFORMAT>( cfm.szFaceName , cfm ) ) ;

}

SendMessage( hCf1 , WM_COMMAND , MAKEWPARAM( IDM_CF1_DISPLAYFONTINFO , 0), (LPARAM)hWnd ) ;

break ;
case EN_PROTECTED :

break ;


default : break ;

}
else
if( ( ( NMHDR * )lParam) -> idFrom == ID_TRACK )
{   if((( NMHDR *)lParam) ->code == NM_CUSTOMDRAW ) {
}
else
if((( NMHDR *)lParam)->code == NM_RELEASEDCAPTURE ) {

int tpos =
SendMessage( hTrack , TBM_GETPOS , 0,0) ;

draw_bar_pos_org = draw_bar_pos ;
draw_bar_pos     = channel_rect.left + tpos ;

draw_bar = TRUE ;

InvalidateRect( hWnd , &preview_area , TRUE ) ;
}

}
else
if( ((LPNMHDR)lParam )->idFrom == ID_FONTTOOLBAR
&& ((LPNMHDR)lParam )->code == TBN_DROPDOWN )
{
RECT rc ; TPMPARAMS tpm ;
SendMessage( ((LPNMHDR)lParam)->hwndFrom , TB_GETRECT , (WPARAM)(((LPNMTOOLBAR)lParam)->iItem ) , (LPARAM)&rc ) ;

MapWindowPoints( ((LPNMHDR)lParam)->hwndFrom , NULL , (LPPOINT)&rc , 2 ) ;
CopyRect( &tpm.rcExclude , &rc ) ;
tpm.cbSize = sizeof( TPMPARAMS ) ;

HMENU hSub = CreatePopupMenu() ;
AppendMenu( hSub ,MF_STRING, IDM_SWITCHTOOLBAR, "フォントツールバー" ) ;

if( !(dwAppStatus & 0x2 ))
CheckMenuItem( hSub , IDM_SWITCHTOOLBAR , MF_BYCOMMAND | MF_CHECKED ) ;



TrackPopupMenuEx( hSub ,
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL ,
rc.left, rc.bottom, hWnd , &tpm ) ; // hWnd は、どのウィンドウに、ポップアップの項目が選択された場合のメッセージが送られるか。

DestroyMenu( hSub ) ;


}

else ;


break ;

case WM_CLOSE :

{   char sz_profile[256] ;
ComboBox_GetText( hCombo , sz_profile, sizeof( sz_profile )) ;
WritePrivateProfileString( "SECTION1" , "LastModemName" , sz_profile , ini_file ) ;

GetDlgItemText( hCf1 ,IDC_CF1_DIALNUMBER , sz_profile , sizeof( sz_profile )) ;
WritePrivateProfileString( "SECTION1" , "LastCallNumber" , sz_profile , ini_file ) ;

WritePrivateProfileString( "SECTION1" , "SenderName" , add_mes.user_name , ini_file ) ;
WritePrivateProfileString( "SECTION1" , "SenderID" , add_mes.user_number , ini_file ) ;

// WritePrivateProfileString( "SECTION1" , "SenderMemo" , add_mes.user_memo , ini_file ) ;

WritePrivateProfileString( "SECTION1" , "PULSE" , fmt( "%d" , IsDlgButtonChecked( hCf1 , IDC_CF1_PULSE ) ? 1 : 0 ) , ini_file ) ;
WritePrivateProfileString( "SECTION1" , "Fine"  , fmt( "%d" , IsDlgButtonChecked( hCf1 , IDC_CF1_FINE_OR_NORMAL ) ? 1 : 0 ) , ini_file ) ;

WritePrivateProfileString( "SECTION1" , "CountryCode" , add_mes.sz_Country , ini_file ) ;
WritePrivateProfileString( "SECTION1" , "CityCode" , add_mes.sz_City , ini_file ) ;
WritePrivateProfileString( "SECTION1" , "AppOnce1" , fmt( "%d" , (dwmode & APPONCE1_EXAMPLE)?1:0 ) , ini_file ) ;
WritePrivateProfileString( "SECTION1" , "AppOnce2" , fmt( "%d" , (dwmode & APPONCE2_MENUITEM)?1:0 ) , ini_file ) ;

{   CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD | CFM_ITALIC | CFM_CHARSET ;
SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (LPARAM)&cfm ) ;
WritePrivateProfileString( "FONT" , "Face"  , cfm.szFaceName , ini_file ) ;
WritePrivateProfileString( "FONT" , "PointSize"  , fmt( "%d" , cfm.yHeight / 20 ) , ini_file ) ;
WritePrivateProfileString( "FONT" , "Bold"  , fmt( "%d" , ( cfm.dwEffects & CFE_BOLD ) ? 1 : 0 ) , ini_file ) ;
WritePrivateProfileString( "FONT" , "Italic"  , fmt( "%d" , ( cfm.dwEffects & CFE_ITALIC ) ? 1 : 0 ) , ini_file ) ;

WritePrivateProfileString( "FONT" , "CharSet" , fmt( "%d" , cfm.bCharSet ) , ini_file ) ;
WritePrivateProfileString( "FONT" , "bPitchAndFamily" , fmt( "%d" , cfm.bPitchAndFamily ) , ini_file ) ;

WritePrivateProfileString( "FONT" , "ChangeSize" , ( dwAppStatus & 0x1 ? "Part" : "All" ) , ini_file ) ;
WritePrivateProfileString( "FONT" , "ShowToolbar" , ( dwAppStatus & 0x2 ? "0" : "1" ) , ini_file ) ;

}
}

{       std::map<std::string,CHARFORMAT>::iterator p = font_list.begin() ;
for( int i = 1 ; p != font_list.end() ; i ++ , p ++ )
WritePrivateProfileStruct( "FONT" , fmt( "Entry%d" , i ) , &p->second , sizeof( CHARFORMAT ) , ini_file ) ;
}

if( EditSubclassProc != 
SubclassWindow( hEdit , EditProcOrg ))
MessageBox( NULL , "サブクラス化の解除に失敗しました。" , "エラー" , MB_ICONWARNING | MB_OK | MB_SETFOREGROUND ) ;

if( IsWindow( hEdit )) DestroyWindow( hEdit ) ;

DestroyWindow( hWnd ) ;

if( IsWindow( hCf1 ))       DestroyWindow( hCf1 ) ;

break ;

case WM_DESTROY :

if( hModem1 && ( phase_mask & THREAD_ON )
&& ( phase_mask & DIALING ) )
DtrOff( hModem1 ) ;

KillTimer( hWnd , TIMER_CONNECTDURATION ) ;

while( ! hbmp1728_list.empty() )
{   HBITMAP hbdel ;
if( NULL != ( hbdel = hbmp1728_list.back().first )) {
if( hbdel == _hBitmap1728 ) _hBitmap1728 = NULL ;
DeleteObject( hbdel ) ;
}
hbmp1728_list.pop_back() ;
}

if( _hBitmap1728 ) DeleteObject( _hBitmap1728 ) ;
if( _hBitmap1728Captured ) DeleteObject( _hBitmap1728Captured ) ;
if( _hBitmap1728SEND ) {
fprintf( fp1 , "エラー : 送信用ビットマップが残っていた。\r\n" ) ;
DeleteObject( _hBitmap1728SEND ) ;
}



if( _hCurBmp )
DeleteObject( _hCurBmp ) ;


if( ! FreeLibrary( hRt32 ))
MessageBox( NULL , "RICHED32.DLL の開放に失敗しました。" , "エラー" , MB_OK | MB_SETFOREGROUND | MB_ICONASTERISK ) ;

if( hLineApp ) 
lineShutdown( hLineApp ) ;


if( hModem1 ) { threadstop = 1 ;
Sleep( 2000 ) ;
if( hModem1 ) {
WriteDropOperation( hModem1 ) ; 
}
if( hModem1 ) {
CloseHandle( hModem1 ) ; hModem1 = NULL ; } }

if( hgrpen ) DeleteObject( hgrpen ) ;

if( fp1 ) fclose( fp1 ) ;

DestroyWindow( hEdit ) ;
#ifdef OBJECTOK
delete pReOleCallback ;
#endif
PostQuitMessage( 0 ) ;
break ;

default :
return( DefWindowProc( hWnd, msg,
wParam, lParam ) ) ;
}
return( 0L ) ;
}
//Following_Insertion

VOID CALLBACK mytmproc( HWND , UINT , UINT idEvent , DWORD )
{
KillTimer( NULL , idEvent ) ;

_hBitmap1728 = ReCreate1728DC( hEdit , 0 , 1 /* 8 */ ) ;

SetDlgItemInt( hCf1 , IDC_CF1_PAGENUMBER , 1 , FALSE ) ;

if( _hCurBmp ){ DeleteObject( _hCurBmp ) ;
_hCurBmp = NULL ; }

InvalidateRect( hAppWnd , NULL , TRUE ) ;

return ;
}

LRESULT CALLBACK EditSubclassProc
( HWND hWnd , UINT msg , WPARAM wp , LPARAM lp )
{
switch( msg )
{   case WM_DROPFILES :

{   HDROP h_Drop ; UINT uNumFiles ;
h_Drop = ( HDROP )wp ;
uNumFiles = DragQueryFile( h_Drop , 0xFFFFFFFF, NULL , 0 ) ;
char szfile[MAX_PATH] ;
DragQueryFile( h_Drop , 0 , szfile , MAX_PATH ) ;
DragFinish( h_Drop ) ;


if( strrchr( szfile, '.' ) &&
! stricmp( ".rtf", strrchr( szfile, '.' ) ) )
{
EDITSTREAM eStream ;
eStream.dwCookie = 1 ; eStream.dwError  = 0L ;
eStream.pfnCallback = EditStreamCallback ;
fp_rtf = fopen( szfile , "rb" ) ;

SendMessage( hEdit , EM_STREAMIN , SF_RTF ,
(LPARAM) (EDITSTREAM FAR *) &eStream ) ;

if( fp_rtf ) { fclose( fp_rtf ) ; fp_rtf = NULL ; }
}
else
{   char *buf = FileAllocateMemory( szfile ) ;

if( buf ) {
if( ! SendMessage( hEdit , WM_SETTEXT , 0, (LPARAM)buf ))
{
Edit_SetTextEx( hEdit , buf ) ;
fprintf( fp1 , "WM_SETTEXT が失敗したため、EM_SETTEXTEX を使用した。 \r\n" ) ;
}
free( buf ) ;    }
}
}

SetTimer( NULL , 0 , 500 , mytmproc ) ;

return 0L ;

default :


break ;
}

return CallWindowProc( EditProcOrg , hWnd, msg, wp, lp ) ;
}


char *FileAllocateMemory( LPCTSTR lpFullPath )
{
HANDLE hFile ;
DWORD dwAccBytes , dwSize ;
char *ret ;

if ( ! PathExists ( lpFullPath ) ) { return NULL ; }

hFile = CreateFile( lpFullPath, GENERIC_READ ,
0,0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) ;

if (    hFile == INVALID_HANDLE_VALUE ) {
char msg[512] ; wsprintf( msg , "Can't open file \"%s\" \r\n( GetLastError status : 0x%x ) " , lpFullPath , GetLastError() ) ;
MessageBox( NULL , msg , "エラー" , MB_OK | MB_SETFOREGROUND | MB_ICONHAND ) ;
return NULL ;  }

dwSize = GetFileSize( hFile , NULL ) ;

if( dwSize == 0xFFFFFFFF ) {
CloseHandle( hFile ) ;
char msg[512] ; wsprintf( msg , "Can't open file \"%s\" \r\nFILE SIZE ERROR \r\n( GetLastError status : 0x%x ) " , lpFullPath , GetLastError() ) ;
MessageBox( NULL , msg , "エラー", MB_OK | MB_SETFOREGROUND | MB_ICONHAND ) ;
return NULL ; }

ret = (char *)malloc( dwSize + 1 ) ;

SetFilePointer( hFile, 0, 0, FILE_BEGIN ) ;

if( ! ReadFile( hFile, ret, dwSize, &dwAccBytes, NULL )) {
char msg[512] ; wsprintf( msg , "読み込み中に失敗しました。\r\n( GetLastError status : 0x%x )" , GetLastError() ) ;

MessageBox( NULL , msg , "関数 ReadFile(...)" , MB_OK | MB_SETFOREGROUND | MB_ICONHAND ) ;

}

ret[dwAccBytes] = '\0';

CloseHandle( hFile ) ;
return ret ;
}


HBITMAP ReCreate1728DC( HWND hEdit , int istartpage , int npages )
{   HBITMAP ret ;

while( ! hbmp1728_list.empty() )
{   HBITMAP hbdel ;
if( NULL != ( hbdel = hbmp1728_list.back().first )) {
if( hbdel == _hBitmap1728 ) _hBitmap1728 = NULL ;
DeleteObject( hbdel ) ;
}
hbmp1728_list.pop_back() ;
}


ret = Create1728DC( hEdit , istartpage , npages ) ;
return ret ;
}

DWORD CALLBACK EditStreamCallback( DWORD dwCookie ,
LPBYTE pbBuff, LONG cb, LONG FAR *pcb )
{

static std::deque<char> deq_c ;

switch( dwCookie )
{   case 0 : // EM_STREAMOUT to file.

if( ! fp_rtf ) return 1 ;

for( *pcb = 0 ; *pcb < cb ; (*pcb) ++  )
fputc( *pbBuff ++ , fp_rtf  ) ;

// fprintf( fp1 , "cb = %d , *pcb = %d \r\n" , cb , *pcb ) ;
*pcb = cb ;

break ;
case 1 : // EM_STREAMIN file into Edit
if( ! fp_rtf ) return 1 ;

for( *pcb = 0 ; *pcb < cb ; (*pcb) ++ ) {
int c = fgetc( fp_rtf ) ;
if( c == EOF ) break ;
*pbBuff ++ = (char )c ;

// fprintf( fp1 , "%c" , c ) ;
}

break ;
case 2 : // EM_STREAMIN \fs?? を何倍かにする。


*pcb = 0 ;

if( ! deq_c.empty() )
for( ; ! deq_c.empty() && *pcb < cb ; (*pcb) ++ )
{ *pbBuff ++ = deq_c.front() ; deq_c.pop_front() ; }



if( ! lp_rtf ) return 1 ;

for( ; *pcb < cb && *lp_rtf ; (*pcb) ++ )
{   char c = *lp_rtf ++ ;

if( c == '\\' )
{   if( *lp_rtf == 'f' &&
*( lp_rtf + 1 ) == 's' &&
*( lp_rtf + 2 ) && strchr( "0123456789" , *( lp_rtf + 2 ))
){  lp_rtf += 2 ;
// \fs数字 が確定
int ipt ;
char sz[32] ; memset( sz , 0,sizeof( sz)) ;

for( int i = 0 ; *lp_rtf && strchr( "0123456789" , *lp_rtf ) && i < sizeof(sz) ;)
if( 15 <= i ) { while( *lp_rtf && strchr( "0123456789" , *lp_rtf )) lp_rtf ++ ; break ; } // この場合明らかにおかしい。
else { sz[i++] = *lp_rtf ++ ; }

ipt = strtol( sz, NULL , 10 ) ;

// ipt = MulDiv( ipt , , ) ;
ipt *= 4 ;
// \\fs?? が決定。
char szfs[64] ;
wsprintf( szfs , "\\fs%d" , ipt ) ;
fprintf( fp1 ,"\\fs%d \r\n" , ipt ) ;
int i = strlen( szfs ) , j = 0 ;
for( ; i && *pcb < cb ; i -- , j ++ )
*pbBuff ++ = *( szfs + j ) , (*pcb) ++ ;


if( *pcb == cb )
for( ; i ; i -- , j ++ )
deq_c.push_back( *(szfs + j )) ;

(*pcb)-- ;

}
else *pbBuff ++ = c ; // 「\\fs数字」 でない場合。
}
else *pbBuff ++ = c ;
}

break ;


default : return 1 ;

}


return 0 ;
}

HBITMAP Create1728DC
( HWND hEdit , int istartpage , int npages )
{
// npages :: 連続して送るページ、みたいなもの。

HDC hdc_mem ; // returned value.

#define EFFECTIVE_SCANRANGE1728 \
( 1728 - fax_pixel_sacrifice - /*2 **/ user_add_marginh )


int yHeightOrg ;
int yOffsetOrg ;
int yHeight ;
int cl_w ;
SIZE sz1 , sz2 ;

{   // RTF 形式で保存。
EDITSTREAM eStream ;
eStream.dwCookie = eStream.dwError  = 0L ;
eStream.pfnCallback = EditStreamCallback ;

fp_rtf = fopen( fmt( "%s\\%s.rtf" , ini_dir , app_name )
, "wb" ) ;

SendMessage( hEdit , EM_STREAMOUT , SF_RTF
// | SFF_PERSISTVIEWSCALE 
, (LPARAM) (EDITSTREAM FAR *) &eStream ) ;
if( fp_rtf ) { fclose( fp_rtf ) ; fp_rtf = NULL ; }
}

{   CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_ALL ;

SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (LPARAM)&cfm ) ;
yHeightOrg = cfm.yHeight ;
yOffsetOrg = cfm.yOffset ;
RECT rc ;

fprintf( fp1 , "---右端折り返し部分に関する細かい確認--- \r\n" ) ;
SendMessage( hEdit , EM_GETRECT , 0 , (LPARAM)&rc ) ;
fprintf( fp1 , "EM_GETRECT による。 %d,%d,%d,%d \r\n" , rc.left , rc.top , rc.right ,rc.bottom) ;
GetClientRect( hEdit , &rc ) ;
fprintf( fp1 , "クライアント領域は %d,%d,%d,%d \r\n" , rc.left , rc.top , rc.right ,rc.bottom) ;
cl_w = WIDTHRC( rc ) ;

yHeight = cfm.yHeight = MulDiv( cfm.yHeight , EFFECTIVE_SCANRANGE1728
, cl_w ) ;
cfm.yOffset = MulDiv( cfm.yOffset , EFFECTIVE_SCANRANGE1728
, cl_w ) ;

fprintf( fp1 , "org : %d to -> %d \r\n" , yHeightOrg , yHeight ) ;

/*
{ // 全フォント同サイズの場合
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_SIZE | CFM_OFFSET ;
SendMessage( hEdit , EM_SETCHARFORMAT , SCF_ALL , (LPARAM)&cfm ) ;
// 約4倍になる

cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_SIZE ;
SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (WPARAM)&cfm ) ;
// 正確を期すため改めて GETCHARFORMAT ;

fprintf( fp1 , "org : %d to -> %d ( confirmed ) \r\n" ,
yHeightOrg , cfm.yHeight ) ;
} // 全フォント同サイズの場合
*/

{   // 先に保存したものを利用。RTF 形式を読み込む。
EDITSTREAM eStream ;
eStream.dwCookie = 2 ; eStream.dwError  = 0L ;
eStream.pfnCallback = EditStreamCallback ;

fp_rtf = fopen( fmt( "%s\\%s.rtf" , ini_dir , app_name )
, "rb" ) ;

if( fp_rtf ) {
fseek( fp_rtf , 0, 2 ) ; // ファイル長取得
DWORD dwSize = ftell( fp_rtf ) ;
assert( dwSize != 0xFFFFFFFF ) ;
rewind( fp_rtf ) ;

char *sz_rtf = lp_rtf = (char *)malloc( dwSize + 1 ) ;
while( EOF != ( *lp_rtf ++ = (char )fgetc( fp_rtf ))) ;
sz_rtf[dwSize] = '\0' ;

lp_rtf = sz_rtf ;

SendMessage( hEdit , EM_STREAMIN , SF_RTF
, (LPARAM) (EDITSTREAM FAR *) &eStream ) ;

if( sz_rtf ) free( sz_rtf ) ; lp_rtf = NULL ;
if( fp_rtf ) { fclose( fp_rtf ) ; fp_rtf = NULL ; }
}
else
fprintf( fp1 , "重大なエラー : ファイル %s が開けない \r\n" 
, fmt( "%s\\%s.rtf" , ini_dir , app_name) ) ;
}




{   // より precise と思われる計算法。
LOGFONT lf ; ZeroMemory( &lf , sizeof( LOGFONT )) ;
HFONT hFont ;

hFont = GetWindowFont( hEdit ) ;
GetObject( hFont , sizeof( LOGFONT ) , &lf ) ;

HDC hdc = GetDC( hEdit ) ;


strcpy( lf.lfFaceName , cfm.szFaceName ) ;
lf.lfHeight = -MulDiv( yHeightOrg ,
GetDeviceCaps( hdc , LOGPIXELSY ) , 1440 ) ; // "twip" to "logical pixel"
lf.lfWidth = 0 ;
lf.lfWeight = ( cfm.dwEffects & CFE_BOLD ) ? 700 : 400 ; // FW_BOLD:700 , FW_NORMAL:400
lf.lfItalic = ( cfm.dwEffects & CFE_ITALIC ) ? (BYTE)1 : (BYTE)0 ;
lf.lfCharSet = cfm.bCharSet ;
lf.lfPitchAndFamily = cfm.bPitchAndFamily ;

hFont = CreateFontIndirect( &lf ) ;

HFONT hFontOrg = (HFONT)SelectObject( hdc , hFont ) ;

// TEXTMETRIC tmc ;
// GetTextMetrics( hdc , &tmc ) ;
// fprintf( fp1 , "d-aspect x : %d , d-aspect y : %d \r\n" , tmc.tmDigitizedAspectX , tmc.tmDigitizedAspectY ) ;


GetTextExtentPoint32( hdc , "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" , 52 , &sz1 ) ;
//   GetTextExtentPoint32( hdc , "あいうえお" , 10 , &sz1 ) ;

// TextOut( hdc ,0,0, "415" , 3 ) ;

// int iwid1 , iwid2 ;
// GetCharWidth32( hdc , iFirst , iLast , &iwid1 ) ;

// 上3つ、どの関数でやろうがあまり変わらない。

lf.lfHeight = -MulDiv( cfm.yHeight ,
GetDeviceCaps( hdc , LOGPIXELSY ) , 1440 ) ; // "twip" to "logical pixel"

hFont = CreateFontIndirect( &lf ) ;

DeleteObject( (HFONT)SelectObject( hdc , hFont )) ;

// GetTextMetrics( hdc , &tmc ) ;
// fprintf( fp1 , "d-aspect x : %d , d-aspect y : %d \r\n" , tmc.tmDigitizedAspectX , tmc.tmDigitizedAspectY ) ;


GetTextExtentPoint32( hdc , "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" , 52 , &sz2 ) ;

//   GetTextExtentPoint32( hdc , "あいうえお" , 10 , &sz2 ) ;


// TextOut( hdc ,cl_w,0, "415" , 3 ) ;

fprintf( fp1 , "org : %d to -> %d ( by width ) \r\n" ,
sz1.cx / 2 , sz2.cx / 2 ) ;

SelectObject( hdc , hFontOrg ) ;
DeleteObject( hFont ) ;

ReleaseDC( hEdit , hdc ) ;
}
}

Sleep( 150 ) ;

HDC hdc = GetDC( hEdit ) ;
if( ! hdc )
MessageBox( NULL , "リッチエディットの HDC が取得できない。" , "エラー" , MB_OK | MB_SETFOREGROUND ) ;

hdc_mem 
= CreateCompatibleDC( hdc ) ;

HBITMAP hBitmap
= CreateCompatibleBitmap( hdc , 1728 , 297 * 4 * 2 ) ;

ReleaseDC( hEdit , hdc ) ;

int count = 0 ;

if( ! hBitmap )
MessageBox( NULL , "ビットマップが作成できない。" , "エラー" , MB_OK | MB_SETFOREGROUND ) ;


SelectObject( hdc_mem , hBitmap ) ;

int ret = 0 ;
int ignore_pagedelm = 0 ;

nMaxpage = 1 ;

FORMATRANGE fr = 
{ hdc_mem , hdc_mem , NULL , NULL , NULL } ;

do { 

FillRect( hdc_mem , MAKERECT( 0,0, 1728, 297 * 4 * 2 ) ,
(HBRUSH)GetStockObject( WHITE_BRUSH )) ;

fr.rcPage = *MAKERECT( 0, 0, 1728 , 297 * 4 * 2 ) ;

fr.rcPage.right = MulDiv( 1728 , // GetDeviceCaps( hdc_mem , HORZRES ) ,
1440, GetDeviceCaps( hdc_mem , LOGPIXELSX )),
fr.rcPage.bottom = MulDiv( 297 * 4 * 2 , // GetDeviceCaps( hdc_mem , VERTRES )
1440, GetDeviceCaps( hdc_mem , LOGPIXELSY)) ;

/*
{   int mmd = GetMapMode( hdc_mem ) ;
SetMapMode( hdc_mem , MM_TWIPS ) ;

DPtoLP( hdc_mem , (LPPOINT)&fr.rcPage , 2 ) ;
fr.rcPage.top    *= -1 ;
//  fr.rcPage.bottom *= -1 ;
fr.rcPage.bottom = MulDiv( 297 * 4 * 2 ,
1440, GetDeviceCaps( hdc_mem , LOGPIXELSY)) ;

// fprintf( fp1, "%d,%d,%d,%d (rcPage) \r\n" , fr.rcPage.left , fr.rcPage.top , fr.rcPage.right , fr.rcPage.bottom ) ;

SetMapMode( hdc_mem , mmd ) ;
}
*/


int hmar = MulDiv( fax_pixel_sacrifice + user_add_marginh , 1440, GetDeviceCaps( hdc_mem , LOGPIXELSX )) ;

// 送信時ページ区画無視。
int umar = ( ignore_pagedelm && count != 0 ) ?
0 :
2 * MulDiv( user_add_marginv , 1440 , GetDeviceCaps( hdc_mem , LOGPIXELSY )) ;

int wdesir , wdesir_d ;

//wdesir = MulDiv ( MulDiv( cl_w , 1440 , GetDeviceCaps( hdc_mem , LOGPIXELSX )) , yHeight , yHeightOrg ) ;
//wdesir -= 1750 ;

{   int mmd = GetMapMode( hdc_mem ) ;
SetMapMode( hdc_mem , MM_TWIPS ) ;
POINT pt ;
/*
pt.x = MulDiv( cl_w , yHeight , yHeightOrg ) ;
pt.y = 0 ;
DPtoLP( hdc_mem , &pt , 1 ) ;

wdesir = pt.x ;
wdesir -= 440 ;

fprintf( fp1 , "ふるい計算法:その場しのぎの -440 twip による。: wdesir = %d \r\n" , wdesir ) ;
*/

pt.x = MulDiv( cl_w , sz2.cx , sz1.cx ) ;
pt.y = 0 ;
DPtoLP( hdc_mem , &pt , 1 ) ;

wdesir = pt.x ;
fprintf( fp1 , "新しい計算法: wdesir = %d \r\n" , wdesir ) ;

wdesir += 1440 ; // ?
/*
pt.x = wdesir , pt.y = 0 ;
LPtoDP( hdc_mem , &pt , 1 ) ;
wdesir_d = MulDiv( pt.x , yHeightOrg, yHeight ) ;
*/
SetMapMode( hdc_mem , mmd ) ;

}


int fr_rcPage_right_type1 = fr.rcPage.right - hmar - 350 ;
int fr_rcPage_right_type2 = hmar + wdesir ;

int fr_rcPage_right = fr_rcPage_right_type1 ;

fprintf( fp1 , "hmar %d, umar %d (twip) " , hmar , umar ) ;
fprintf( fp1 , "LOGPIXELSX %d, LOGPIXELSY %d " , GetDeviceCaps( hdc_mem , LOGPIXELSX ) , GetDeviceCaps( hdc_mem , LOGPIXELSY ) ) ;
fprintf( fp1 , "org %d to %d (twip) \r\n" ,
MulDiv( cl_w  , 1440 , GetDeviceCaps( hdc_mem , LOGPIXELSX )) , wdesir ) ;
fprintf( fp1 , "僅差 結果 - 理想 = %d (twip) 但し 1440 twip = 1 inch ( =2.54cm )\r\n" ,
fr_rcPage_right_type2 - fr_rcPage_right_type1 ) ;

fr.rc = *MAKERECT( hmar , umar ,
fr_rcPage_right , fr.rcPage.bottom - umar ) ;

{   draw_bar_pos =
preview_area.left 
+ ( fax_pixel_sacrifice + user_add_marginh )
+ wdesir_d ; }

fprintf( fp1 , "bar %d \r\n" , draw_bar_pos ) ;
fprintf( fp1 , "--- \r\n" ) ;


// 300 twip = 15 point , 

fr.chrg.cpMin = ret , fr.chrg.cpMax = -1 ;


int orgret = ret ;
ret =
SendMessage( hEdit , EM_FORMATRANGE , TRUE , (LPARAM)&fr ) ;

if( ret == 1 ) ;

if( istartpage <= count && count < istartpage + npages ) {
if( ! SendMessage( hEdit , EM_DISPLAYBAND , 0 , (LPARAM)&fr.rc ))
;
beg_index = orgret ;
}

SendMessage( hEdit , EM_FORMATRANGE , FALSE /* just measuring */ , (LPARAM)&fr ) ;

if( ! count && ret == 0 && orgret == ret ) ;
else
if( orgret == ret ) break ;

if( istartpage <= count && count < istartpage + npages )
{
hbmp1728_list.push_back( PAIRHB_I(
(HBITMAP)CopyImage( (HBITMAP)hBitmap , IMAGE_BITMAP , 0 , 0 , LR_COPYRETURNORG )
, count )
) ;
}
else ; // hbmp1728_list.push_back( NULL , -1 ) ;

if( hbmp1728_list.size() && ! hbmp1728_list.back().first ) {
SetDlgItemText( hCf1 , IDC_CF1_PAGENUMBER , "Er" ) ;
break ;
}

#define MAX_PAGES 64
} while( ret != -1 && ret < GetWindowTextLength( hEdit ) &&
++ count < MAX_PAGES &&
( dwmode & MODE_CHECK_NUMBER_OF_PAGES || count < istartpage + npages ) ) ;
// endof do-while

// TEST
SendMessage( hEdit , EM_FORMATRANGE , FALSE , NULL ) ;
// -- これを忘れるといけないらしい。

if( count == MAX_PAGES )
MessageBox( NULL , "安全のため 64 ページで処理を中止しました。" , "OK" , MB_OK | MB_SETFOREGROUND ) ;


DeleteObject( hBitmap ) ;
DeleteDC( hdc_mem ) ;

Sleep( 200 ) ;

{   // 先の RTF 形式を復帰。
EDITSTREAM eStream ;
eStream.dwCookie = 1 ; eStream.dwError  = 0L ;
eStream.pfnCallback = EditStreamCallback ;

fp_rtf = fopen( fmt( "%s\\%s.rtf" , ini_dir , app_name ) 
, "rb" ) ;
SendMessage( hEdit , EM_STREAMIN , SF_RTF ,
(LPARAM) (EDITSTREAM FAR *) &eStream ) ;
if( fp_rtf ) { fclose( fp_rtf ) ; fp_rtf = NULL ; }
}

{   // フォントも元に戻す。
CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.yHeight = yHeightOrg ;
cfm.yOffset = yOffsetOrg ;
cfm.dwMask = CFM_SIZE | CFM_OFFSET ;
SendMessage( hEdit , EM_SETCHARFORMAT , SCF_SELECTION , (LPARAM)&cfm ) ;
}

nCurpage = istartpage ;

nMaxpage = count + 1 ;

if( dwmode & MODE_CHECK_NUMBER_OF_PAGES )
dwmode |= NMAXPAGE_VALID ;
else
dwmode &= ~NMAXPAGE_VALID ;

SendDlgItemMessage( hCf1 , IDC_CF1_UPDOWN3 ,
UDM_SETRANGE , 0L , MAKELONG( max( 0,nMaxpage -1) , 0) ) ;

if( hbmp1728_list.empty()) return NULL ;

return hbmp1728_list.front().first ;
}



LRESULT CALLBACK Cf1DialogProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp )
{
static int yLinePos  ;
static int yLinePos2 ;

static int xLinePos[5] ;

static HFONT hfUpdateOrg ;
static HFONT hfUpdateBold ;



char sz_profile[256] ;
int i_profile ;

LPMEASUREITEMSTRUCT lpmi ;
LPDRAWITEMSTRUCT lpdi ;

switch( msg ) {

case WM_INITDIALOG :

hCombo = GetDlgItem( hWnd , IDC_CF1_SELECTMDM ) ;

SendDlgItemMessage( hWnd , IDC_CF1_UPDOWN3 ,
UDM_SETRANGE , 0L , MAKELONG( 1 , 0 ) ) ;

GetPrivateProfileString( "SECTION1" , "LastCallNumber" , "" , sz_profile , sizeof( sz_profile ) , ini_file ) ;

Edit_LimitText( GetDlgItem( hWnd , IDC_CF1_DIALNUMBER ) , 32 ) ;
SetDlgItemText( hWnd , IDC_CF1_DIALNUMBER , sz_profile ) ;



SetDlgItemInt( hWnd , IDC_CF1_MMWIDTH , mmPaperWidth , FALSE ) ;
SetDlgItemInt( hWnd , IDC_CF1_MMHEIGHT , mmPaperHeight , FALSE ) ;
SetDlgItemInt( hWnd , IDC_CF1_INVALPIXELS , fax_pixel_sacrifice , FALSE ) ;
SetDlgItemInt( hWnd , IDC_CF1_ZOOM , 100 , FALSE ) ;

SendDlgItemMessage( hWnd , IDC_CF1_TRACK_TESTMM , TBM_SETRANGE , FALSE , MAKELONG( 0 ,mmPaperHeight) ) ;
SendDlgItemMessage( hWnd , IDC_CF1_TRACK_TESTMM , TBM_SETPOS , TRUE , partial_mm ) ;

SetDlgItemInt( hWnd , IDC_CF1_TESTMM , (partial_mm == -1 ) ? mmPaperHeight : partial_mm , FALSE ) ;


CheckDlgButton( hWnd , IDC_CF1_SHOWSBAR , BST_CHECKED ) ;


SetDlgItemInt( hWnd , IDC_CF1_UPBLANK , user_add_marginv / 4 , FALSE  ) ;
SetDlgItemInt( hWnd , IDC_CF1_RLBLANK , ( user_add_marginh + fax_pixel_sacrifice ) / 8 , FALSE ) ;


{   RECT rc ; GetWindowRect( GetDlgItem( hWnd , IDC_CF1_NEW_STATIC1 ) , &rc ) ;
MapWindowRect( NULL , hWnd , &rc ) ;
yLinePos = rc.top - 5 ;

xLinePos[0] = rc.right + 1  ;

{   // Draw する線の位置決定
GetWindowRect( GetDlgItem( hWnd , IDC_CF1_MMHEIGHT ) , &rc ) ;
MapWindowRect( NULL , hWnd , &rc ) ;
xLinePos[1] = rc.right + 1 ;
GetWindowRect( GetDlgItem( hWnd , IDC_CF1_INVALPIXELS ) , &rc ) ;
MapWindowRect( NULL , hWnd , &rc ) ;
xLinePos[2] = rc.right + 1 ;
GetWindowRect( GetDlgItem( hWnd , IDC_CF1_RLBLANK ) , &rc ) ;
MapWindowRect( NULL , hWnd , &rc ) ;
xLinePos[3] = rc.right + 1 ;
GetWindowRect( GetDlgItem( hWnd , IDC_CF1_UPDOWN2 ) , &rc ) ;
MapWindowRect( NULL , hWnd , &rc ) ;
xLinePos[4] = rc.right + 1 ;
}

GetWindowRect( GetDlgItem( hWnd , IDC_CF1_SEND ) , &rc ) ;
MapWindowRect( NULL , hWnd , &rc ) ;


yLinePos2 = rc.top - 2 ;

}

{   HFONT hFont = GetWindowFont( GetDlgItem( hWnd , IDC_CF1_PAGENUMBER )) ;
LOGFONT lf ; ZeroMemory( &lf , sizeof( LOGFONT)) ;
GetObject( hFont , sizeof( LOGFONT ), &lf ) ;
RECT rc ; GetClientRect( GetDlgItem( hWnd , IDC_CF1_PAGENUMBER ) ,&rc ) ;
lf.lfHeight = ( lf.lfHeight < 0 ) ?
lf.lfHeight * ( - rc.bottom / lf.lfHeight ) :
lf.lfHeight * ( rc.bottom / lf.lfHeight ) ;
SetWindowFont( GetDlgItem( hWnd , IDC_CF1_PAGENUMBER ) ,
CreateFontIndirect( &lf ) , TRUE ) ;

SetDlgItemInt( hWnd , IDC_CF1_PAGENUMBER , 1 , FALSE ) ;
}


SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_CF1_DISPLAYFONTINFO , 0) , 0L ) ;

{   RECT rc ; GetClientRect( hWnd , &rc ) ;
int aw[3] ; aw[0] = rc.right / 2 , aw[1] = rc.right * 3 / 4 , aw[2] =  -1 ;
SendMessage( GetDlgItem( hWnd , IDC_CF1_STATUS1 ) , SB_SETPARTS ,
3 , (LPARAM)aw ) ;

}

{   hfUpdateOrg = GetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE )) ;
LOGFONT lf ; ZeroMemory( &lf , sizeof( LOGFONT )) ;
GetObject( hfUpdateOrg , sizeof( LOGFONT ), &lf ) ;
lf.lfWeight = FW_BOLD   ;
hfUpdateBold = CreateFontIndirect( &lf ) ;
SetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE ) , hfUpdateBold , TRUE ) ;
}


if( GetPrivateProfileInt( "SECTION1" , "PULSE" , 0 , ini_file )) {
CheckDlgButton( hWnd , IDC_CF1_PULSE , BST_CHECKED ) ;
// バグ 2005/6/6 ■ 正:IDC_CF1_PULSE 誤:IDC_CF1_FINE_OR_NORMAL を訂正 
}

if( GetPrivateProfileInt( "SECTION1" , "Fine" , 1 , ini_file ))
CheckDlgButton( hWnd , IDC_CF1_FINE_OR_NORMAL , BST_CHECKED ) ;
else {
SetDlgItemText( hWnd , IDC_CF1_FINE_OR_NORMAL ,
"ノーマルモード (時間節約)" ) ;
// バグ 2005/6/6 ■ 起動時、前回ノーマルモードで終わって今回ノーマルモードにチェックが入る場合、テキスト表示が「ノーマルモード・・・」にならず、「ファイン」のままだったバグ。
}


if( GetPrivateProfileInt( "SECTION1" , "AppOnce1" , 0 , ini_file ))
dwmode |= APPONCE1_EXAMPLE ;
if( GetPrivateProfileInt( "SECTION1" , "AppOnce2" , 0 , ini_file ))
dwmode |= APPONCE2_MENUITEM ;

{   CHARFORMAT cfm ;
for( int i = 1 ; GetPrivateProfileStruct( "FONT" , fmt( "Entry%d" , i ) , &cfm , sizeof(cfm) , ini_file )
&& i <= 64 ; i ++ )
font_list.insert
( font_list.end(), std::make_pair( cfm.szFaceName ,cfm ) ) ;
}

// シェアウェア
{  char payment[256];
GetPrivateProfileString( "SECTION1" , "Payment" , "0" , payment , 256 , ini_file ) ;
if( !strcmp( payment , "True"))
DestroyWindow( GetDlgItem( hWnd , IDC_CF1_PAYMENT )) ;
}
//--
return TRUE ;

case WM_LBUTTONDBLCLK :
{   POINT pt = {  LOWORD(lp) , HIWORD(lp)  } ;
HWND hchild = ChildWindowFromPoint( hWnd , pt ) ;
if(     hchild == GetDlgItem( hWnd , IDC_CF1_INVALPIXELS )
||  hchild == GetDlgItem( hWnd , IDC_CF1_UPBLANK )
||  hchild == GetDlgItem( hWnd , IDC_CF1_RLBLANK )
||  hchild == GetDlgItem( hWnd , IDC_CF1_ZOOM ))
; else break ;

int id = GetWindowID( hchild ) ;

RECT rc ; GetWindowRect( hchild , &rc ) ;
MapWindowRect( NULL , hWnd , &rc ) ;

if( IsWindow( hPopEdit ) ) DestroyWindow( hPopEdit ) ;
hPopEdit = CreateWindow( "EDIT" , "" ,
WS_CHILD | WS_BORDER | ES_NUMBER 
,rc.left , rc.top , WIDTHRC( rc ), HEIGHTRC( rc)
,hWnd , (HMENU)ID_CF1_POPEDIT , hAppInst , NULL ) ;

SetWindowLong( hPopEdit , GWL_USERDATA , (DWORD)id ) ;

AnimateWindow( hPopEdit , 200 ,
/*AW_SLIDE |*/ AW_CENTER | AW_ACTIVATE );

if( ! IsWindowVisible( hPopEdit )) ShowWindow( hPopEdit , SW_SHOW ) ;
BringWindowToTop( hPopEdit ) ;
SetFocus( hPopEdit ) ;

}


break ;

case WM_PAINT :
{   RECT rc ;
GetClientRect( hWnd , &rc ) ;
if( ! GetUpdateRect( hWnd , NULL , FALSE )) break ;
PAINTSTRUCT ps ;
HDC hdc = BeginPaint( hWnd , &ps ) ;

HPEN hpenOrg = (HPEN)SelectObject( hdc , GetStockObject( BLACK_BRUSH )) ;

//              MoveToEx( hdc , ps.rcPaint.left   , yLinePos , NULL ) ;
//              LineTo( hdc , ps.rcPaint.right  , yLinePos ) ;

//              MoveToEx( hdc , xLinePos[0] , yLinePos , NULL ) ;
//              LineTo( hdc , xLinePos[0] , yLinePos + 55 ) ;


DrawEdge( hdc , MAKERECT( 0 , 0 , rc.right , yLinePos )
,EDGE_ETCHED    , BF_BOTTOM ) ;

{
for( int i = 0 ; i < 5 ; i ++ )
DrawEdge( hdc , MAKERECT( 0 , yLinePos , xLinePos[i] + 2, yLinePos2 )
,EDGE_ETCHED    , BF_RIGHT ) ;
}


DrawEdge( hdc , MAKERECT( 0 , 0 , rc.right , yLinePos2 )
,EDGE_ETCHED    , BF_BOTTOM ) ;


SelectObject( hdc , hpenOrg ) ;

EndPaint( hWnd , &ps ) ;
return 0L ;
}

break ;

case WM_MEASUREITEM :

lpmi = (LPMEASUREITEMSTRUCT)lp ;

if( lpmi->CtlType == ODT_MENU ) {
if( IDM_CF1_FONTFACES_BEGIN <= lpmi->itemID 
&& lpmi->itemID < IDM_CF1_FONTFACES_BEGIN + NUMFACES )
{
std::map<std::string,CHARFORMAT >::iterator p 
= font_list.begin() ;
for( int i = lpmi->itemData ; i && p != font_list.end() ; i --, p ++ ) ;

HDC hdc = GetDC( hWnd ) ;
SIZE siz ;
if( p == font_list.end() )
siz.cx = 1 , siz.cy = GetSystemMetrics( SM_CYMENUSIZE ) ;
else
GetTextExtentPoint32( hdc,
p->first.c_str() ,
strlen( p->first.c_str()) , &siz ) ;

lpmi->itemWidth = siz.cx ; // 128 ;
lpmi->itemHeight = siz.cy ; // GetSystemMetrics( SM_CYMENUSIZE ) ;

ReleaseDC( hWnd , hdc ) ;
}

return TRUE ;
}

break ;

case WM_DRAWITEM :
lpdi = (LPDRAWITEMSTRUCT)lp ;

if( lpdi->CtlType == ODT_MENU )
{
std::map<std::string,CHARFORMAT >::iterator p 
= font_list.begin() ;
for( int i = lpdi->itemData ; i && p != font_list.end() ; i --, p ++ ) ;

if( p != font_list.end() ) {
HDC hdc = lpdi->hDC ;

if( ! ( dwmode & APPONCE2_MENUITEM ))
{
// dwmode |= APPONCE2_MENUITEM ;
}

HFONT h_old = (HFONT)SelectObject( hdc , GetStockObject(SYSTEM_FONT) ) ;

LOGFONT lf ; ZeroMemory( &lf , sizeof( LOGFONT )) ;
GetObject( h_old , sizeof( LOGFONT ) , &lf ) ;

lf.lfCharSet = p->second.bCharSet ;
lf.lfPitchAndFamily = p->second.bPitchAndFamily ;
strncpy( lf.lfFaceName , p->second.szFaceName , LF_FACESIZE - 1 ) ;

if( lpdi->itemState & ODS_CHECKED )
lf.lfUnderline = TRUE ;

HFONT h_new = CreateFontIndirect( &lf ) ;
SelectObject( hdc , h_new  ) ;

if( lpdi->itemState & ODS_SELECTED )
{
SetBkColor( hdc, RGB( 127,127,127 ) ) ;
SetTextColor( hdc, RGB(255,255,255) ) ;
}

TextOut( hdc , lpdi->rcItem.left + GetSystemMetrics( SM_CXMENUCHECK ) , lpdi->rcItem.top ,
p->first.c_str() , strlen( p->first.c_str() )) ;

SelectObject( hdc , h_old ) ;

DeleteObject( h_new ) ;

}
}

return TRUE ;

case WM_COMMAND :
switch( LOWORD( wp ) ) {

case IDC_CF1_PULSE :
if( IsDlgButtonChecked( hWnd , wp ))
MessageBox( NULL ,
"このチェックはお使いの電話回線が「パルス回線」であるときにチェックします。"
"現在、回線は「トーン回線」が一般的です。お使いの回線がトーン回線の場合にこのチェックがされている場合は送信に失敗します。"
"トーンかパルスかをよくご確認ください。\r\n\r\n"
"パルス回線の場合のみチェックしてください。"
, "注意" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;


break ;

case IDC_CF1_SHOWSBAR :

if( ! IsDlgButtonChecked( hWnd , wp ))
SetWindowLong( hEdit , GWL_STYLE , GetWindowStyle( hEdit ) &~WS_VSCROLL ) ;

ShowScrollBar( hEdit , SB_VERT  , 
IsDlgButtonChecked( hWnd , LOWORD(wp) ) ?
TRUE : FALSE ) ;


//SendMessage( hEdit , EM_SHOWSCROLLBAR , SB_VERT ,
//IsDlgButtonChecked( hWnd , LOWORD(wp) ) ? TRUE : FALSE ) ;

InvalidateRect( hAppWnd , NULL , TRUE ) ;


break ;

case IDC_CF1_FINE_OR_NORMAL :

SetDlgItemText( hWnd , IDC_CF1_FINE_OR_NORMAL ,
IsDlgButtonChecked( hWnd , IDC_CF1_FINE_OR_NORMAL )
? "ファインモード (高画質)" : "ノーマルモード (時間節約)" ) ;


break ;

case IDC_CF1_POPUPFACE : // FACE 一覧

{   RECT rc ;
GetWindowRect( GetDlgItem( hWnd , IDC_CF1_POPUPFACE ) , &rc ) ;
// (HWND)lp , LOWORD(wp) とか使おうと思ったが、他から呼ぶときおかしくなりそうなので、テクニカルなことはやめる。素直に IDC_CF1_POPUPFACE
CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ; cfm.dwMask = CFM_FACE | CFM_SIZE ;
SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (LPARAM)&cfm ) ;

HMENU hSub = CreatePopupMenu() ;

std::stack<std::pair<HBITMAP,HBITMAP> > bmp_stack ;

{
std::map<std::string,CHARFORMAT>::iterator p
= font_list.begin() ;

for( int i = 0 ; p != font_list.end() ; i ++ , p ++ )
{
AppendMenu( hSub , MF_OWNERDRAW, IDM_CF1_FONTFACES_BEGIN + i , (LPCTSTR)i ) ;

if( cfm.szFaceName == p->first )
CheckMenuItem( hSub , IDM_CF1_FONTFACES_BEGIN + i , MF_BYCOMMAND | MF_CHECKED ) ;
}
}

TrackPopupMenu( hSub , TPM_LEFTALIGN , rc.left , rc.bottom , 0 ,
hWnd , NULL ) ;

DestroyMenu( hSub ) ;

}

break ;
case IDC_CF1_SELECTFONT :

{   BOOL ret ;

ret = AppChooseFont( hEdit ) ;
SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_CF1_DISPLAYFONTINFO , 0) , 0L ) ;

if( ret && hfUpdateBold != GetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE )))
SetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE ) , hfUpdateBold , TRUE ) ;

if( ! AppChooseFontAllorWord ) AppChooseFontAllorWord = TRUE ;
}

break ;
case IDM_CF1_DISPLAYFONTINFO :
{

CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_FULLMASK ;

SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (LPARAM)&cfm ) ;

SetDlgItemText( hWnd , IDC_CF1_SELECTFONT , cfm.szFaceName ) ;
{
//  int pointsize = MulDiv( lf.lfHeight , 72 , GetDeviceCaps( hdc, LOGPIXELSY )) ;
int pointsize = cfm.yHeight / 20 ;

SetDlgItemInt( hWnd , IDC_CF1_FONTSIZE , pointsize , TRUE ) ;
}

}

// ツールバーの状態も変更する。(2005/6/10)
if( IsWindow( hToolbar ))
{
LPRICHEDITOLE ppIRe = NULL ;
HRESULT res ;
ITextDocument *pEDoc ;

SendMessage( hEdit , EM_GETOLEINTERFACE , 0L ,(LPARAM)&ppIRe ) ;

if( ppIRe )
res =
ppIRe->QueryInterface( IID_ITextDocument , (void **)&pEDoc ) ;

if( res == S_OK && pEDoc )
{

ITextSelection *pESel ; ITextFont *pEFont ;
pEDoc->GetSelection( &pESel ) ;
pESel->GetFont( &pEFont )     ;
LONG lattr ;

lattr = 0 ; pEFont->GetUnderline( &lattr) ;
CheckToolButton( hToolbar , IDM_ULINE  , 
( lattr == tomSingle || lattr == tomTrue ) ? TRUE : FALSE ) ;

lattr = 0 ; pEFont->GetBold( &lattr) ; 
CheckToolButton( hToolbar , IDM_BOLD  , ( tomTrue == lattr ) ? TRUE : FALSE ) ;

lattr = 0 ;  pEFont->GetItalic( &lattr) ;
CheckToolButton( hToolbar , IDM_ITALIC  , ( tomTrue == lattr ) ? TRUE : FALSE ) ;

lattr = 0 ; pEFont->GetStrikeThrough( &lattr) ;
CheckToolButton( hToolbar , IDM_STRIKE  , ( tomTrue == lattr ) ? TRUE : FALSE ) ;

lattr = 0 ; pEFont->GetSuperscript( &lattr ) ;
CheckToolButton( hToolbar , IDM_SUP  , ( tomTrue == lattr ) ? TRUE : FALSE ) ;

lattr = 0 ; pEFont->GetSubscript( &lattr ) ;
CheckToolButton( hToolbar , IDM_SUB  , ( tomTrue == lattr ) ? TRUE : FALSE ) ;

}


}



break ;

case IDM_ENTRY :

if( GetWindowID( (HWND)lp ) == ID_CF1_POPEDIT )
{   int val =
GetDlgItemInt( hWnd , ID_CF1_POPEDIT , NULL , TRUE ) ;

int id = GetWindowLong( (HWND)lp , GWL_USERDATA ) ;
DestroyWindow( (HWND)lp ) ; hPopEdit = NULL ;

if( val && 0 < val )
{
switch( id )
{   case IDC_CF1_INVALPIXELS :
fax_pixel_sacrifice = val ;

case IDC_CF1_UPBLANK :
user_add_marginv = val * 4 ;

case IDC_CF1_RLBLANK :
user_add_marginh = val * 8 - fax_pixel_sacrifice ;

case IDC_CF1_ZOOM :


break ;
default :
break ;
}
SendMessage( hWnd , WM_COMMAND ,
MAKEWPARAM( IDM_CF1_REFRESHPARAMS , 0 ) , 0L ) ;

_hBitmap1728 = ReCreate1728DC( hEdit , nCurpage , 1 ) ;

if( _hCurBmp ) {
DeleteObject( _hCurBmp ) ;
_hCurBmp = NULL ;
}
InvalidateRect( hAppWnd , &preview_area , TRUE ) ;


}

}


break ;

case IDM_CF1_REFRESHPARAMS :

SetDlgItemInt( hWnd , IDC_CF1_INVALPIXELS , fax_pixel_sacrifice , FALSE ) ;
//      SetDlgItemInt( hWnd , IDC_CF1_ZOOM , 100 , FALSE ) ;

SetDlgItemInt( hWnd , IDC_CF1_UPBLANK , user_add_marginv / 4 , FALSE  ) ;
SetDlgItemInt( hWnd , IDC_CF1_RLBLANK , ( user_add_marginh + fax_pixel_sacrifice ) / 8 , FALSE ) ;



break ;

case IDC_CF1_UPDOWN2 :
break ;

case IDC_CF1_ENDAPP :
SendMessage( hAppWnd , WM_CLOSE , 0L , 0L) ;
break ;

#ifdef RISTRICT_ONE_PAGE
case IDC_CF1_SENDALL :
MessageBox( NULL, "この機能はまだ動作しません。1ページずつの送信でお願いします。", "開発中" , MB_OK | MB_ICONASTERISK | MB_SETFOREGROUND | MB_TASKMODAL ) ;
CheckDlgButton( hWnd , IDC_CF1_SENDALL, BST_UNCHECKED ) ;
break ;
#endif

case IDC_CF1_SEND :

if( phase_mask & THREAD_ON ) break ;

if( ! GetWindowTextLength( GetDlgItem( hWnd , IDC_CF1_DIALNUMBER )))
{   MessageBox( NULL , "ダイアル番号がありません。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONQUESTION ) ;
break ;
}

partial_mm =
SendDlgItemMessage( hWnd , IDC_CF1_TRACK_TESTMM , TBM_GETPOS , 0,0) ;

if( partial_mm == -1 || ! IsDlgButtonChecked( hCf1 , IDC_CF1_CHECK_PARTIALMM )) ;
else {  if( partial_mm == 0 ) {
MessageBox( NULL , "送信する高さを 0mm 以上にしてください。" , "テスト送信" , MB_OK | MB_SETFOREGROUND ) ;
break ; }
}

// if( ! ( dwmode & MODE_CHECK_NUMBER_OF_PAGES ))
// dwmode |= ( ORIGINALLY_WAS_NO_CHECK_MODE | MODE_CHECK_NUMBER_OF_PAGES ;

#ifndef RISTRICT_ONE_PAGE
if( IsDlgButtonChecked( hWnd , IDC_CF1_SENDALL ))
{
SendMessage( hWnd , WM_COMMAND , 
MAKEWPARAM( IDC_CF1_CLEARCAPTURE ,0), 0L ) ;

SendDlgItemMessage( hWnd , IDC_CF1_UPDOWN3 ,
UDM_SETPOS , 0L , MAKELONG( 0, 0) ) ;
nCurpage = 0 ;
SetDlgItemInt( hWnd , IDC_CF1_PAGENUMBER , 1 , FALSE ) ;
}

#endif

SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDC_CF1_UPDATE ,0) , 0L ) ;

// if( dwmode & ORIGINALLY_WAS_NO_CHECK_MODE )
// dwmode &= ~ ( ORIGINALLY_WAS_NO_CHECK_MODE | MODE_CHECK_NUMBER_OF_PAGES ) ;

{
if( _hBitmap1728SEND ) {
fprintf( fp1 , "エラー : 送信用ビットマップが残っていた。\r\n" ) ;
DeleteObject( _hBitmap1728SEND ) ;
_hBitmap1728SEND = NULL ;
}
DWORD t = GetTickCount() ;
_hBitmap1728SEND = (HBITMAP)
CopyImage( (HBITMAP)_hBitmap1728 , IMAGE_BITMAP , 0 , 0 ,
LR_COPYRETURNORG ) ;
// ビット送信の直前に用意すると、10 秒とかかかってしまうことがあり、
// リモート FAX がタイムアウトしてしまい、送信エラーになってします。教訓。
fprintf( fp1 , "CopyImage に要した時間 %d msec. \r\n" , GetTickCount() - t ) ;

}

{   char msg[256] ; char sz[256] ;
GetDlgItemText( hWnd , IDC_CF1_DIALNUMBER , sz , sizeof( sz)) ;

wsprintf( msg , "送信します。 相手先 : %s" , sz ) ;
if( IDCANCEL == MessageBox( NULL , msg , "OK" , MB_OKCANCEL | MB_SETFOREGROUND | MB_TASKMODAL ))
break ;
else
SbarSetText( 2L , "" ) ; // 接続時間の表示をクリア。
}

time_rest = -1 ;

phase_mask |= THREAD_ON ;

if( hProgress1 ) { DestroyWindow( hProgress1 ) ; hProgress1 = NULL ; }

{   // スレッドの中でやると(↓)、不都合。( hCf1 のボタンが押せなくなる )
RECT rc , rcs ;
SendDlgItemMessage(
hCf1 , IDC_CF1_STATUS1 , SB_GETRECT , 1L , (LPARAM)&rc ) ;

GetWindowRect( GetDlgItem( hCf1 , IDC_CF1_STATUS1 ) , &rcs ) ;
POINT pt = { rcs.left , rcs.top } ;
ScreenToClient( hCf1 , &pt ) ;

OffsetRect( &rc , pt.x , pt.y ) ;

hProgress1 = CreateWindow( "msctls_progress32" , "" ,
WS_CHILD , rc.left , rc.top ,
WIDTHRC( rc ), HEIGHTRC( rc ) ,
hCf1 , (HMENU)ID_CF1_PROGRESS , hAppInst , NULL ) ;
}



_beginthread( StartLongFaxSession , 0 , (void *)&threadstop ) ;


break ;


case IDC_CF1_STOP :
if( phase_mask & THREAD_ON ) {
if( phase_mask & DIALING )
DtrOff( hModem1 ) ;
fprintf( fp1 , "中止ボタンが押されました。 \r\n" ) ;

threadstop = 1 ;
}


break ;

case IDC_CF1_UPDATE :

SbarSetText( 0L , "ページを構成しています。" ) ;
_hBitmap1728 = ReCreate1728DC( hEdit , nCurpage , 1 ) ;

if( nMaxpage <= nCurpage ) {
nCurpage = nMaxpage - 1 ;
}

SetDlgItemInt( hWnd , IDC_CF1_PAGENUMBER , nCurpage + 1 , TRUE ) ;

if( ! ( dwCap & CAP_NOUSE ) && _hBitmap1728Captured )
{   HDC hdc , hdc_mem , hdc_ ;

hdc = GetDC( hWnd ) ;
hdc_mem = CreateCompatibleDC( hdc ) ;
hdc_ = CreateCompatibleDC( hdc ) ;
ReleaseDC( hWnd , hdc ) ;
SelectObject( hdc_mem , _hBitmap1728Captured ) ;
SelectObject( hdc_ , _hBitmap1728 ) ;

SbarSetText( 0L , "キャプチャ画像のピクセルを修正しています。" ) ;

if( hProgress2 ) { DestroyWindow( hProgress2 ) ; hProgress2 = NULL ; }

{   RECT rc , rcs ;
// hWnd == hCf1 です。
SendDlgItemMessage(
hCf1 , IDC_CF1_STATUS1 , SB_GETRECT , 2L , (LPARAM)&rc ) ;
GetWindowRect( GetDlgItem( hCf1 , IDC_CF1_STATUS1 ) , &rcs ) ;
POINT pt = { rcs.left , rcs.top } ;
ScreenToClient( hCf1 , &pt ) ;

OffsetRect( &rc , pt.x , pt.y ) ;

hProgress2 = CreateWindow( "msctls_progress32" , "" ,
WS_CHILD | WS_VISIBLE , rc.left , rc.top ,
WIDTHRC( rc ), HEIGHTRC( rc ) ,
hWnd , (HMENU)ID_CF1_PROGRESS , hAppInst , NULL ) ;
SendMessage( hProgress2 , PBM_SETRANGE , 0 ,
MAKELPARAM( 1, 297 * 4 * 2 ) ) ;
}


{   COLORREF bkclr = GetBkColor( hdc_mem ) ;
for( int y = 0 ; y < 297 * 4 * 2 ; y ++ )
{
for( int x = 0 ; x < 1728 ; x ++ ) {
COLORREF clr = GetPixel( hdc_mem , x , y ) ;
if( clr != bkclr && clr != CLR_INVALID &&
( GetRValue( clr ) + GetGValue( clr ) + GetBValue( clr ) > /*127*/ 128 * 3 )

) SetPixelV( hdc_mem , x, y , bkclr ) ;
}
if( ! ( y % 8) )
SendMessage( hProgress2 , PBM_SETPOS , y + 1 , 0 ) ;

}
}






/*
{   HBRUSH hbOrg ;
hbOrg = (HBRUSH)SelectObject( hdc_mem , CreateSolidBrush( RGB( 128,128,128) ) ) ;
//          PatBlt( hdc_mem , 0, 0, 1728 , 297 * 4 *2 ,0xA000C9 ) ;

PatBlt( hdc_mem , 0, 0, 1728 , 297 * 4 *2 , DSTINVERT ) ;
PatBlt( hdc_mem , 0, 0, 1728 , 297 * 4 *2 , 0x5F00E9 ) ;

//          PatBlt( hdc_mem , 0, 0, 1728 , 297 * 4 *2 , 0xFA0089 ) ;

hbOrg = (HBRUSH)SelectObject( hdc_mem , GetStockObject( WHITE_BRUSH )) ;

ExtFloodFill( hdc_mem , 0,0 , RGB( 127,127,127) ,FLOODFILLBORDER );

hbOrg = (HBRUSH)SelectObject( hdc_mem , hbOrg ) ;

// ( ~( ~D & P )) | gray

hbOrg = (HBRUSH)SelectObject( hdc_mem , hbOrg ) ;
DeleteObject( hbOrg ) ;
}
*/
if( hProgress2 ) {
DestroyWindow( hProgress2 ) ;
hProgress2 = NULL ;
}

SbarSetText( 0L , "修正が終了しました。" ) ;

DWORD dwRop = SRCCOPY ;
if( dwCap & CAP_CAPUSEWITHOR )
dwRop = SRCPAINT ;

BitBlt( hdc_ , 0 , 0 , 1728 , 297 * 4 * 2 ,
hdc_mem , 0 , 0 ,
dwRop ) ;

DeleteDC( hdc_mem ) ;
DeleteDC( hdc_ ) ;
}

if( _hCurBmp ) {
DeleteObject( _hCurBmp ) ;
_hCurBmp = NULL ;
}
InvalidateRect( hAppWnd , &preview_area , TRUE ) ;

SetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE ) , hfUpdateOrg , TRUE ) ;

{   int line , offset ;
// beg_index ;
line = SendMessage( hEdit , EM_EXLINEFROMCHAR , 0 ,beg_index ) ;
offset = line - Edit_GetFirstVisibleLine( hEdit ) ;

CHARRANGE Pchr ;
Pchr.cpMin = Pchr.cpMax = beg_index ;
SendMessage( hEdit , EM_EXSETSEL , 0 , (LPARAM)&Pchr ) ;
Edit_Scroll( hEdit , offset , 0x80000001 ) ;
Edit_ScrollCaret( hEdit ) ;
}

SbarSetText( 0L , "ページを構成しました。OK " ) ;

break ;

/* // Gray にしたい・・・
case IDC_CF1_CHECK_PARTIALMM :
if( IsDlgButtonChecked( hWnd , LOWORD( wp )) )
EnableWindow( GetDlgItem( hWnd , IDC_CF1_TRACK_TESTMM ) , TRUE ) ;
else
EnableWindow( GetDlgItem( hWnd , IDC_CF1_TRACK_TESTMM ) , FALSE ) ;
break ;
*/
case IDC_CF1_STARTCAPTURE :


{
if( !( dwCap & CAP_REGISTCLS )) {
WNDCLASSEX wc ;

wc.cbSize = sizeof( WNDCLASSEX ) ;
wc.style = NULL ;
wc.lpfnWndProc = CaptureWndProc ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
wc.hInstance = hAppInst ;
wc.hIcon   = NULL ;
wc.hCursor = NULL ;
wc.hbrBackground = ( HBRUSH)GetStockObject( NULL_BRUSH ) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = "FE_TRANSPARENTWINDOW" ;
wc.hIconSm = NULL ;
if( RegisterClassEx( &wc ))
dwCap |= CAP_REGISTCLS ;
else break ;
}


dwCap &= ~CAP_NOUSE ; // CAPTURE 使わないモードを解除する。

hTransp = CreateWindow(
"FE_TRANSPARENTWINDOW" , "",
WS_POPUP , 0, 0 ,
GetSystemMetrics( SM_CXSCREEN ),
GetSystemMetrics( SM_CYSCREEN ),
NULL , NULL, hAppInst , NULL ) ;

if ( ! hTransp ) {
MessageBox( NULL ,
"透明ウィンドウ作成失敗しました" , "エラー", MB_OK | MB_SETFOREGROUND ) ;
break ;
}
}

Sleep( 300 ) ;
SbarSetText( 0L , "画面キャプチャスタート。画面から矩形(範囲)を切り取って下さい!" ) ;

ShowWindow( hTransp , SW_SHOWNORMAL ) ;

break ;

case IDC_CF1_CLEARCAPTURE :

if( dwCap & CAP_NOUSE || ! _hBitmap1728Captured ) break ;

dwCap |= CAP_NOUSE ;
SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDC_CF1_UPDATE ,0) , 0L ) ;

break ;

case IDC_CF1_CF2 :

DialogBox( hAppInst, "CONFIG2",
hWnd, ( DLGPROC ) Cf2DialogProc ) ;

break ;

case IDC_CF1_LOAD :
break ;
case IDC_CF1_SAVE :

{   EDITSTREAM eStream ;
eStream.dwCookie = eStream.dwError  = 0L ;
eStream.pfnCallback = EditStreamCallback ;

fp_rtf = fopen( fmt( "%s\\form.rtf" , ini_dir )
, "wb" ) ;

SendMessage( hEdit , EM_STREAMOUT , SF_RTF
, (LPARAM) (EDITSTREAM FAR *) &eStream ) ;
if( fp_rtf ) { fclose( fp_rtf ) ; fp_rtf = NULL ; }
}

break ;

case IDC_CF1_FIXFORMAT :

dwmode ^= CHARACTER_FIXED_MODE ;

{   long lSetProtect = IsDlgButtonChecked( hWnd , IDC_CF1_FIXFORMAT )
? tomTrue : tomFalse ;

LPRICHEDITOLE ppIRe = NULL ;
SendMessage( hEdit , EM_GETOLEINTERFACE , 0L ,(LPARAM)&ppIRe ) ;



if( ! ppIRe )
fprintf( fp1 , "EM_GETOLEINTERFACE 失敗 \r\n" ) ;

if( ppIRe ) {

ITextDocument FAR *pTexDoc  ;
HRESULT res =
ppIRe->QueryInterface( IID_ITextDocument , (void **)&pTexDoc ) ;

if( res != S_OK )
fprintf( fp1 , "QueryInterface IID_ITextDocument 失敗 \r\n" ) ;

if( res == S_OK ) {
DWORD dw = 0 ;

ITextRange *pTexRange ;
res = pTexDoc->Range( 0 , 1 , &pTexRange ) ;

if( res != S_OK )
fprintf( fp1 , "ITextRange->Range 失敗 \r\n" ) ;

ITextFont *pTexFont ;
pTexRange->GetFont( &pTexFont ) ;

long lDelta = 1 ;
if( res == S_OK && pTexFont ) {
for( ; lDelta ; dw ++ ) {

long lChar ;
pTexRange->GetChar( &lChar ) ;

char cCheck[3] ; cCheck[2] = '\0' ;
WideCharToMultiByte( CP_ACP , WC_COMPOSITECHECK , (LPCWSTR)&lChar , 1 , cCheck , 3 , NULL , NULL ) ;

if( ! strchr( " \r\n\t\v" , *cCheck ) ||
! strcmp( " " , cCheck ) )
pTexFont->SetProtected( lSetProtect ) ;

pTexRange->MoveStart( tomCharacter, 1 , NULL) ;
pTexRange->MoveEnd( tomCharacter, 1 , &lDelta ) ;

}
pTexFont->Release() ;

pTexRange->Release() ;
}

pTexDoc->Release() ;
int len = GetWindowTextLength(hEdit) ;
fprintf( fp1 , "dw = %d , GetTextWindowLength = %d , %s \r\n" , dw , len ,
((int)dw == len ) ? "同一" : "相違有り" ) ;

}
ppIRe->Release() ;
}




}
break ;
case IDC_CF1_PAYMENT :
DialogBoxParam( hAppInst, "PAYMENTDIALOG",
hWnd, ( DLGPROC ) PaymentDialogProc , 1) ;


break ;

case IDCANCEL :
break ;
default :

if( IDM_CF1_FONTFACES_BEGIN <= LOWORD(wp)
&& LOWORD(wp) < IDM_CF1_FONTFACES_BEGIN + NUMFACES )
{   CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_FACE ;
// map オブジェクトはその都度ソートされるので、今はいいけど、何かほかの事をする場合は注意。
std::map<std::string,CHARFORMAT>::iterator p 
= font_list.begin() ;
for( int i = LOWORD(wp) -  IDM_CF1_FONTFACES_BEGIN ;
i && p != font_list.end() ; i -- , p ++ ) ;

if( p != font_list.end() ) {
strncpy( cfm.szFaceName , p->first.c_str() , sizeof(cfm.szFaceName)-1 ) ;;
SendMessage( hEdit , EM_SETCHARFORMAT , SCF_SELECTION , (LPARAM)&cfm ) ;
}
}

break ;
}
break ;
case WM_NOTIFY :
if( ((NMHDR *)lp)->idFrom == IDC_CF1_UPDOWN3 ) {

if( ((NM_UPDOWN *)lp)->hdr.code == UDN_DELTAPOS ) {

int iPos = ((NMUPDOWN *)lp)->iPos ;

int lrg = SendDlgItemMessage( hWnd , IDC_CF1_UPDOWN3 , UDM_GETRANGE , 0 , 0 ) ;

if( iPos == HIWORD( lrg ) && ((NMUPDOWN *)lp)->iDelta < 0 )
{   MessageBeep(0) ; return FALSE ; }
if( LOWORD( lrg ) <= iPos && ((NMUPDOWN *)lp)->iDelta > 0 )
{   MessageBeep(0) ; return FALSE ; }

iPos += ((NMUPDOWN *)lp)->iDelta ;
if( iPos < 0 ) iPos = 0 ;
else
if( nMaxpage <= iPos ) iPos = max( 0 , nMaxpage - 1) ;

if( nCurpage == iPos ) break ;
else nCurpage = iPos ;

_hBitmap1728 = ReCreate1728DC( hEdit , iPos , 1 ) ;

if( _hBitmap1728 ) {
if( _hCurBmp ) { DeleteObject( _hCurBmp ) ;
_hCurBmp = NULL ; }}

SetDlgItemInt( hWnd , IDC_CF1_PAGENUMBER , iPos +1 , TRUE ) ;

/*
std::list<PAIRHB_I>::iterator p = hbmp1728_list.begin() ;
for( int i = nCurpage ; i && p != hbmp1728_list.end() ; i -- ) p ++ ;

_hBitmap1728 = ( p == hbmp1728_list.end() ) ? 
NULL : *p.first ;
*/

InvalidateRect( hAppWnd , &preview_area , TRUE ) ;

//-- 追加。IDC_CF1_UPDATE と 同じもの。

{   int line , offset ;
// beg_index ;
line = SendMessage( hEdit , EM_EXLINEFROMCHAR , 0 ,beg_index ) ;
offset = line - Edit_GetFirstVisibleLine( hEdit ) ;

CHARRANGE Pchr ;
Pchr.cpMin = Pchr.cpMax = beg_index ;
SendMessage( hEdit , EM_EXSETSEL , 0 , (LPARAM)&Pchr ) ;
Edit_Scroll( hEdit , offset , 0x80000001 ) ;
Edit_ScrollCaret( hEdit ) ;
}
//--

} else ;
}
else
if( ((NMHDR *)lp)->idFrom == IDC_CF1_UPDOWNFONT )
{
if( ((NM_UPDOWN *)lp)->hdr.code == UDN_DELTAPOS )
{   MessageBeep( 0 ) ;

// if( osi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
// MessageBox( NULL , "" , "OK" , MB_OK | MB_SETFOREGROUND ) ;

// if( ((NMUPDOWN *)lp->iPos == 0 ))
int iDelta = ((NMUPDOWN *)lp)->iDelta ;
{   CHARFORMAT cfm ; ZeroMemory( &cfm , sizeof( CHARFORMAT )) ;
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_SIZE ; // | CFM_OFFSET ?
SendMessage( hEdit , EM_GETCHARFORMAT , TRUE , (LPARAM)&cfm ) ;

( 0 > iDelta ) ? cfm.yHeight += 20 :
cfm.yHeight -= 20 ;

if( cfm.yHeight <= 0 ) cfm.yHeight = 1 ;

cfm.dwMask = CFM_SIZE ; cfm.cbSize = sizeof( CHARFORMAT ) ;


BOOL x ;
{   CHARRANGE Pchr ;
SendMessage( hEdit , EM_EXGETSEL , 0L , (LPARAM)&Pchr ) ;
if( Pchr.cpMin == Pchr.cpMax )
x = FALSE ; else x = TRUE ;
}


SendMessage( hEdit , EM_SETCHARFORMAT , 
(( dwAppStatus & 0x1 ) || x ) ? SCF_SELECTION : SCF_ALL , (LPARAM)&cfm ) ;

SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_CF1_DISPLAYFONTINFO , 0) , 0L ) ;

if( hfUpdateBold != GetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE )))
SetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE ) , hfUpdateBold , TRUE ) ;

if( !(dwAppStatus & 0x1 ))
SbarSetText( 0L, "[UNDO やり直し] で元に戻すことが出来ます。" ) ;


}
}
}
else
if( ((NMHDR *)lp)->idFrom == IDC_CF1_TRACK_TESTMM )
{
if( ((NMHDR *)lp)->code == NM_RELEASEDCAPTURE ||
((NMHDR *)lp)->code == NM_CUSTOMDRAW 
)
{
partial_mm =
SendDlgItemMessage( hWnd , IDC_CF1_TRACK_TESTMM , TBM_GETPOS , 0,0) ;

SetDlgItemInt( hWnd , IDC_CF1_TESTMM , partial_mm , FALSE ) ;

} // TB_LINEUP , TB_PAGEUP , TB_ENDTRACK ...
}


break ;

case WM_CLOSE : // IDC_CF1_ENDAPP と同じことをする。
SendMessage( hAppWnd , WM_CLOSE , 0L , 0L) ;

break ;

case WM_DESTROY :
{   HFONT hFont = GetWindowFont( GetDlgItem( hWnd , IDC_CF1_PAGENUMBER )) ;
SetWindowFont( GetDlgItem( hWnd ,IDC_CF1_PAGENUMBER ) , GetStockObject( SYSTEM_FONT ) , FALSE ) ;
DeleteObject( hFont ) ;
}

SetWindowFont( GetDlgItem( hWnd , IDC_CF1_UPDATE ) , hfUpdateOrg , FALSE ) ;
DeleteObject( hfUpdateBold ) ;

break ;


default :
break ;
}
return FALSE ;
}

LRESULT CALLBACK CaptureWndProc
( HWND hWnd , UINT msg , WPARAM wp , LPARAM lp )
{
static POINTS oldend , beg , end ;
static HCURSOR csorg ;
static HDC hdc ;
HDC hdc_mem , hdc_ ;
RECT BltRect ;
HPEN hpenOrg ;
int nROP2org ;

#define IDM_DRAWRECT_ERASE      257
#define IDM_DRAWRECT            258

switch( msg )
{
case WM_LBUTTONDOWN :
dwCap |= CAP_SELECTING ;
oldend = beg = MAKEPOINTS( lp ) ;

hdc = GetDC( hWnd ) ;
// draw new beg, oldend
SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_DRAWRECT_ERASE , 0), (LPARAM)hWnd ) ;
ReleaseDC( hWnd , hdc ) ;

csorg = SetCursor( LoadCursor( NULL , IDC_CROSS )) ;

break ;

case WM_MOUSEMOVE :
if( !(dwCap & CAP_SELECTING )) break ;
end = MAKEPOINTS( lp ) ;

hdc = GetDC( hWnd ) ;
// draw 消し    beg , oldend
SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_DRAWRECT_ERASE ,0 ), (LPARAM)hWnd ) ;

// draw new beg , end
SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_DRAWRECT ,0 ), (LPARAM)hWnd ) ;
ReleaseDC( hWnd , hdc ) ;

oldend = end ;

break ;


case WM_LBUTTONUP :
if( !( dwCap & CAP_SELECTING )) break ;

dwCap &= ~( CAP_SELECTING | CAP_CAPTURING ) ;

if( csorg ) {
SetCursor( csorg ) ; csorg = NULL ; }
else        SetCursor( LoadCursor( NULL, IDC_ARROW )) ;

end = MAKEPOINTS( lp ) ;

if( end.x == beg.x ) end.x += 8 ;
if( end.y == beg.y ) end.y += 8 ;

if( abs( end.x - beg.x ) < 8 ) end.x = beg.x + ((end.x - beg.x ) / abs( end.x - beg.x )) * 8 ;
if( abs( end.y - beg.y ) < 8 ) end.y = beg.y + ((end.y - beg.y ) / abs( end.y - beg.y )) * 8 ;

hdc = GetDC( hWnd ) ;

// draw 消し beg , oldend
SendMessage( hWnd , WM_COMMAND , MAKEWPARAM( IDM_DRAWRECT_ERASE ,0 ), (LPARAM)hWnd ) ;
// ↑をやらなければ、点線枠ののこった形となる。


hdc_mem = CreateCompatibleDC( hdc ) ;

if( ! _hBitmap1728Captured )
_hBitmap1728Captured = CreateCompatibleBitmap( hdc , 1728 , 297 * 4 * 2 ) ;

SelectObject( hdc_mem , _hBitmap1728Captured ) ;

FillRect( hdc_mem , MAKERECT( 0,0,1728,297 *4 *2 ) ,
(HBRUSH)GetStockObject( WHITE_BRUSH )) ;

BltRect = *MAKERECT
( fax_pixel_sacrifice + user_add_marginh ,
user_add_marginv * 2 ,
1728  , 297 * 4 * 2 ) ;



StretchBlt( hdc_mem , BltRect.left ,
BltRect.top , WIDTHRC( BltRect ) , HEIGHTRC( BltRect ) ,
hdc , beg.x , beg.y , end.x - beg.x , end.y - beg.y 
, SRCCOPY ) ;
// SRCPAINT ( S | D )

hdc_ = CreateCompatibleDC( hdc ) ;

if( ! _hBitmap1728 ) {
_hBitmap1728
= CreateCompatibleBitmap( hdc , 1728 , 297 * 4 * 2 ) ;
hbmp1728_list.push_back( PAIRHB_I( _hBitmap1728 , nCurpage )) ;
SelectObject( hdc_ , _hBitmap1728 ) ;
FillRect( hdc_ , MAKERECT( 0,0,1728, 297*4*2) ,
(HBRUSH)GetStockObject( WHITE_BRUSH )) ;
}
else        SelectObject( hdc_ , _hBitmap1728 ) ;

ReleaseDC( hWnd , hdc ) ;

//      if( ! ( dwCap & CAP_NOUSE )) // 要らないんでないの?
{   DWORD dwRop = SRCCOPY ;
if( dwCap & CAP_CAPUSEWITHOR )
dwRop = SRCPAINT ;

StretchBlt( hdc_ , 0 , 0 , 1728 , 297 * 4 * 2 ,
hdc_mem , 0 , 0 , 1728 , 297 * 4 * 2 ,
dwRop ) ;
}


DeleteDC( hdc_mem ) ;
DeleteDC( hdc_ ) ;

SbarSetText( 0L , "画面キャプチャ終了。" ) ;

if( _hCurBmp ) { DeleteObject( _hCurBmp ) ;
_hCurBmp = NULL ; }

DestroyWindow( hWnd ) ;

break ;

case WM_COMMAND :
switch( LOWORD( wp ))
{
case IDM_DRAWRECT_ERASE : // beg 〜 oldend

nROP2org = SetROP2( hdc , R2_XORPEN ) ;

hpenOrg = (HPEN)SelectObject( hdc , hgrpen ) ;

MoveToEx( hdc , beg.x , beg.y , NULL ) ;
LineTo( hdc , oldend.x , beg.y ) ;
LineTo( hdc , oldend.x , oldend.y ) ;
LineTo( hdc , beg.x , oldend.y ) ;
LineTo( hdc , beg.x , beg.y ) ;
SetROP2( hdc , nROP2org ) ;

SelectObject( hdc , hpenOrg ) ; // beg 〜 end
break ;

case IDM_DRAWRECT :
nROP2org = SetROP2( hdc , R2_XORPEN ) ;

hpenOrg = (HPEN)SelectObject( hdc , hgrpen ) ;

MoveToEx( hdc , beg.x , beg.y , NULL ) ;
LineTo( hdc , end.x , beg.y ) ;
LineTo( hdc , end.x , end.y ) ;
LineTo( hdc , beg.x , end.y ) ;
LineTo( hdc , beg.x , beg.y ) ;
SetROP2( hdc , nROP2org ) ;

SelectObject( hdc ,hpenOrg ) ;
break ;

}

break ;


default :
break ;
}


return DefWindowProc( hWnd , msg , wp , lp ) ;


BOOL AppChooseFont( HWND hEdit )
{

static BOOL ret ;
CHARFORMAT cfm ;
CHOOSEFONT cf  ;
LOGFONT    lf  ;

HDC hDC ;

memset( &cf,  0, sizeof(CHOOSEFONT)) ;
memset( &lf,  0, sizeof(LOGFONT)) ;
memset( &cfm, 0, sizeof(CHARFORMAT)) ;

cfm.cbSize = sizeof(CHARFORMAT) ;
cfm.dwMask = CFM_FULLMASK ;


SendMessage( hEdit, EM_GETCHARFORMAT ,
TRUE ,(LPARAM)&cfm ) ;

hDC = GetDC( hEdit ) ;

lf.lfHeight = MulDiv( cfm.yHeight ,
GetDeviceCaps( hDC, LOGPIXELSY ), -1440 ) ;

ReleaseDC( hEdit, hDC ) ;

cfm.dwMask = CFM_FULLMASK ;

if (cfm.dwEffects & CFE_BOLD)
lf.lfWeight = FW_BOLD ;
else
lf.lfWeight = FW_NORMAL;
if (cfm.dwEffects & CFE_ITALIC)
lf.lfItalic = TRUE ;
if (cfm.dwEffects & CFE_UNDERLINE)
lf.lfUnderline = TRUE ;
if (cfm.dwEffects & CFE_STRIKEOUT)
lf.lfStrikeOut = TRUE ;
lf.lfCharSet = cfm.bCharSet ;
lf.lfQuality = DEFAULT_QUALITY ;
lf.lfPitchAndFamily = cfm.bPitchAndFamily ;

strcpy( lf.lfFaceName, cfm.szFaceName ) ;
cf.rgbColors = cfm.crTextColor ;
cf.lStructSize = sizeof(CHOOSEFONT) ;
cf.hwndOwner = hEdit ;

cf.lpLogFont = &lf ;
cf.Flags = CF_SCREENFONTS | 
CF_EFFECTS     |
CF_INITTOLOGFONTSTRUCT ;


if ( FALSE != ( ret = ChooseFont( &cf ) ) )
{
cfm.cbSize = sizeof( CHARFORMAT ) ;
cfm.dwMask = CFM_FULLMASK & ~CFM_OFFSET ;
cfm.yHeight =  2 * cf.iPointSize ;
cfm.dwEffects = 0 ;
if (lf.lfWeight >= FW_BOLD)
cfm.dwEffects |= CFE_BOLD ;
if (lf.lfItalic)
cfm.dwEffects |= CFE_ITALIC ;
if (lf.lfUnderline)
cfm.dwEffects |= CFE_UNDERLINE ;
if (lf.lfStrikeOut)
cfm.dwEffects |= CFE_STRIKEOUT ;
cfm.crTextColor = (COLORREF)cf.rgbColors ;
cfm.bPitchAndFamily = lf.lfPitchAndFamily ;
cfm.bCharSet = lf.lfCharSet ;
strcpy( cfm.szFaceName, lf.lfFaceName ) ;

CHARRANGE Pchr ;
SendMessage( hEdit , EM_EXGETSEL , 0 , (LPARAM)&Pchr ) ;

CHARFORMAT cfm_before = cfm ;

if( SendMessage( hEdit, EM_SETCHARFORMAT , 
( Pchr.cpMax == Pchr.cpMin ) ?
( AppChooseFontAllorWord ? SCF_SELECTION /* SCF_ALL */ : SCF_SELECTION ) : SCF_SELECTION ,
(LPARAM)&cfm ) == 0 ) {
MessageBox( hEdit, "フォントの変更はできませんでした。", "Error", MB_OK | MB_SETFOREGROUND) ;
return FALSE ;
// テキスト全部のフォント変更はやめた。UNDO で復帰はできるが、結構間違えて全変更してしまうし、全選択してやれば問題ない。
}
SetFocus( hEdit ) ;

if( memcmp( &cfm , &cfm_before , sizeof(CHARFORMAT) ) )
MessageBox( NULL , "EM_SETCHARFORMAT の動きが予想に反しました。" , "" , MB_OK ) ;

if( font_list.end() ==
font_list.find( cfm_before.szFaceName ))
font_list.insert
( font_list.end(), std::pair<std::string,CHARFORMAT>( cfm.szFaceName ,cfm ) ) ;

// MessageBox( NULL , cfm.szFaceName ,"追加されました。" , MB_OK ) ;

if( !( dwmode & APPONCE1_EXAMPLE )) {
SendMessage( hCf1 , WM_COMMAND ,
MAKEWPARAM( IDC_CF1_POPUPFACE ,0) , (LPARAM)GetDlgItem( hCf1 , IDC_CF1_POPUPFACE )) ;
dwmode |= APPONCE1_EXAMPLE ;
}
}

return ret ;
}

char *tapiFormatMessage( LONG tapilResult ) ;
char *EzFormatMessage( DWORD dwError ) ;

char *tapiFormatMessage( LONG tapilResult )
{
char *pBuf = NULL ;
static char message[ 512 ] ;
ZeroMemory( message , sizeof( message )) ;

FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER ,
(LPCVOID) GetModuleHandle( "TAPIUI.DLL" ) , // TAPI32.DLL ?
TAPIERROR_FORMATMESSAGE( tapilResult ) ,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) ,
(LPTSTR)&pBuf , 0 , NULL ) ;

wsprintf( message , "tapi エラーコード 0x%x : %s \r\n" ,
tapilResult , pBuf ? pBuf : "メッセージ形式での取得は失敗" ) ;

if( pBuf ) LocalFree( pBuf ) ;


return message ;
}

char *EzFormatMessage( DWORD dwError )
{
char *pBuf = NULL ;
static char message[ 512 ] ;
memset( message , 0, sizeof( message ) ) ;

FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER ,
NULL , dwError ,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) ,
(LPTSTR)&pBuf , 0 , NULL ) ;

wsprintf( message , "GetLastError() エラーコード 0x%x : %s \r\n" , dwError ,
pBuf ? pBuf : "er" ) ;

// FORMAT_MESSAGE_ALLOCATE_BUFFER のときはLocalFree を使用せよ!

if( pBuf ) LocalFree( pBuf ) ; // free ではいけない! "LocalFree" を使う。
else fprintf( fp1 , "GetLastError() の エラーメッセージは正常に取得できなかった。" ) ;

return message ;
}


LPLINEDEVCAPS lineGetDevCapsX
( HLINEAPP hLineApp  , DWORD dwDeviceID ,
LPDWORD lpdwAPIVersion , DWORD dwExtVersion )
{
LONG lresult ;

LINEEXTENSIONID ExtensionID ;
memset( &ExtensionID , 0,sizeof( LINEEXTENSIONID )) ;

lresult = lineNegotiateAPIVersion
( hLineApp       ,
dwDeviceID     ,
TAPI_VER_LOW   ,
TAPI_VER_HIGH  ,
lpdwAPIVersion ,
&ExtensionID    // プロバイダ関係 ?
) ;

if( lresult ) {
fprintf( fp1 , "lineNegotiateAPIVersion() 関数が失敗。" ) ;
fprintf( fp1 , tapiFormatMessage( lresult ) ) ;

return NULL ; }


LPLINEDEVCAPS ret ;

LINEUSETOTALSIZE_SANDWICH( LINEDEVCAPS , ret , 0 )

lresult = 
lineGetDevCaps
(
hLineApp, dwDeviceID , *lpdwAPIVersion ,
dwExtVersion ,
ret )

LINEUSETOTALSIZE_SANDWICH_( LINEDEVCAPS , ret )

if( lresult )
{
fprintf( fp1 , "lineCetDevCaps() 関数が失敗。デバイスのプロファイルが取得できない。" ) ;
fprintf( fp1 , tapiFormatMessage( lresult )) ;

MessageBox( NULL , "エラー" , tapiFormatMessage( lresult ) , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
}

if( lresult ) { free( ret ) ; ret = NULL ; }

return ret ;
}

HLINEAPP EnumModems()
{
{
if( hLineApp ) {
fprintf( fp1 , "TAPI は初期化されているのに再び初期化しようとしている。 \r\n" ) ;
return hLineApp ;
}

LONG  retInit   ;
DWORD dwNumDevs = 0L ;

DWORD dwAPIVersion = TAPI_VER_HIGH ;

LINEINITIALIZEEXPARAMS lIEx =
{ sizeof( LINEINITIALIZEEXPARAMS ) ,
0LU , 0LU ,
LINEINITIALIZEEXOPTION_USEHIDDENWINDOW ,
NULL ,NULL ,
} ;

retInit = lineInitializeEx( &hLineApp , 
GetModuleHandle( NULL ) ,
(LINECALLBACK)tapi_lineCallback ,
NULL          , // lpszFriendlyAppName
&dwNumDevs    , // アプリケーションの使用できる 回線デバイスの数。
&dwAPIVersion ,
&lIEx           // set NULL if "use event handle" or "completion port"
) ;

if( retInit ) {
MessageBox( NULL , "ERROR" , "テレフォニー API の初期化に失敗。" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
fprintf( fp1 , "関数 lineInitializeEx() がエラー。 %s \r\n" , tapiFormatMessage( retInit ) ) ;

return NULL ;
}

int nComboItems = 0 ;

DWORD idw ;
int iCombo_maybedesirable = -1 ;
DWORD dwAPIVerOrg = dwAPIVersion ;

if( 2 <= HIWORD( dwAPIVersion ))
tapi_ver_ge_2 = TRUE ;

//      if( tapi_ver_ge_2 )

char szLastModem[256] ;
GetPrivateProfileString( "SECTION1" , "LastModemName" , "" , szLastModem , sizeof( szLastModem ) , ini_file ) ;

for
( idw = 0 ; idw < dwNumDevs ; idw ++ )
{   dwAPIVersion = dwAPIVerOrg ;

LPLINEDEVCAPS pdevc =
lineGetDevCapsX
( hLineApp , idw , &dwAPIVersion ,0LU ) ;

if( ! pdevc ) {
char msgbuf[256] ;
wsprintf( msgbuf , "デバイスCapability が取得できない [%d/%d] \r\n" , idw+1 , dwNumDevs ) ;
fprintf( fp1 , msgbuf ) ;
}
else
{
char modem_name_[256] ;

fprintf( fp1 , "%s [%d/%d] , API のバージョン : 0x%x \r\n" , (BYTE *)pdevc + pdevc->dwLineNameOffset ,
idw+1 , dwNumDevs , dwAPIVersion ) ;

strcpy( modem_name_ , (BYTE *)pdevc + pdevc->dwLineNameOffset ) ;

if( *szLastModem )
{   if( iCombo_maybedesirable == -1 
&& ! strcmp( modem_name_ , szLastModem ))
iCombo_maybedesirable = nComboItems ;
}
else
if( iCombo_maybedesirable == -1 
&& strstr( modem_name_ , "56" ))
iCombo_maybedesirable = nComboItems ;


ComboBox_AddString( hCombo   , modem_name_ ) ;
ComboBox_SetItemData( hCombo , nComboItems , idw ) ;
nComboItems ++ ;

}
if( pdevc ) { free( pdevc ) ; pdevc = NULL ; }
}
// else ;

DWORD dwDeviceIDModem ;

if( ! nComboItems ) {
MessageBox( NULL , "" , "使用できるモデムがひとつもありません。" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
fprintf( fp1 , "エラー : 使用可能モデムがない。 \r\n" ) ;
dwDeviceIDModem = (DWORD)-1 ;
return hLineApp ;
}
else ;


if( -1 != iCombo_maybedesirable ) {
ComboBox_SetCurSel( hCombo , iCombo_maybedesirable ) ;
dwDeviceIDModem = (DWORD)
ComboBox_GetItemData( hCombo , iCombo_maybedesirable ) ;
}
else {
ComboBox_SetCurSel( hCombo , 0 ) ;
dwDeviceIDModem = 0L ; }

char buf[256] ; *buf = '\0' ;

if( dwDeviceIDModem != (DWORD)-1 )
ComboBox_GetLBText( hCombo
,( iCombo_maybedesirable == -1 ) ? 0 : iCombo_maybedesirable
, buf ) ;

fprintf( fp1 , "TAPI初期化時選択モデム : %s [%d/%d] 0x%x \r\n" , ( *buf ? buf : "不可" )
, dwDeviceIDModem + 1 , dwNumDevs , dwAPIVersion ) ;

fprintf( fp1 , "有効デバイス数 %d ( リストに含まれるデバイスの数。) \r\n" , nComboItems ) ;

}

fprintf( fp1 , "TAPI の初期化と モデムのリストアップ終了 \r\n" ) ;

phase_mask |= HLINEAPP_VALID ;

return hLineApp ;
}

void StartLongFaxSession( void *param )
{
SbarSetText( 0 , "送信を開始します。" ) ;

DWORD *p_threadstop = (DWORD *)param ;

#define th_return { phase_mask &= ~( THREAD_ON | DIALING ) ; \
*p_threadstop = 0 ; \
KillTimer( hAppWnd , TIMER_CONNECTDURATION ) ; \
if( _hBitmap1728SEND ) { DeleteObject( _hBitmap1728SEND ) ; _hBitmap1728SEND = NULL ; } \
if( hProgress1 ) { ShowWindow( hProgress1 , SW_HIDE  ) ; DestroyWindow( hProgress1 ) ; hProgress1 = NULL ; } \
_endthread() ; \
return ; }


if( ! hLineApp ) {
MessageBox( NULL , "テレフォニー API の初期化が正常に行えなかったため送信手順を開始できません。" , "ok" , MB_OK | MB_SETFOREGROUND ) ;
th_return ; }

fprintf( fp1 , "\r\n ****** 送信手順開始 ****** \r\n\r\n" ) ;

DWORD dwDeviceID ;
DWORD dwAPIVersion ;

char modem_model[256] ;

{   {   int index = ComboBox_GetCurSel( hCombo ) ;
ComboBox_GetLBText( hCombo , index , modem_model ) ;
fprintf( fp1 , "使用するモデム %s \r\n" , modem_model ) ;
dwDeviceID = ComboBox_GetItemData( hCombo , index ) ;
}

LONG ret ;      LINEEXTENSIONID ExtensionID ;
ZeroMemory( &ExtensionID , sizeof( LINEEXTENSIONID )) ;

ret =   lineNegotiateAPIVersion(
hLineApp , dwDeviceID ,
TAPI_VER_LOW ,TAPI_VER_HIGH ,
&dwAPIVersion , &ExtensionID ) ;

if( ret ) {
MessageBox( NULL , "バージョンの整合に失敗しました。処理を中断します。" , "エラー" , MB_OK | MB_SETFOREGROUND | MB_ICONHAND ) ;
fprintf( fp1 , "lineNegotiateAPIVersion() 関数が失敗。( DeviceID = %d )" , dwDeviceID ) ;
fprintf( fp1 , tapiFormatMessage( ret ) ) ;
th_return ;
}
else
fprintf( fp1 , "システムとデバイス間で調整された TAPI のバージョン 0x%x \r\n" , dwAPIVersion ) ;

ret =   lineOpen(
hLineApp     ,
dwDeviceID   , // OK ( or, set LINEMAPPER and fill (LPLINECALLPARAMS const) lpCallParams
&hLine ,          // hLine is obtaind here. // OK
dwAPIVersion ,    // lineNegotiateAPIVersion() // temporalily OK
0LU ,
0x1 , // dwCallbackInstance , user-data to pass to callback func (多分) // OK
LINECALLPRIVILEGE_OWNER | LINECALLPRIVILEGE_MONITOR ,
// LINECALLPRIVILEGE_NONE ,  // 音が出る。OWNER だと聞こえない。
LINEMEDIAMODE_DATAMODEM   ,
NULL ) ;

if( ret ) {
MessageBox( NULL , "回線の準備に失敗しました。処理を中断します。" , "エラー" , MB_OK | MB_SETFOREGROUND | MB_ICONHAND ) ;
fprintf( fp1 , "回線が準備できない。 lineOpen() " ) ;
fprintf( fp1 , tapiFormatMessage( ret ) ) ;

th_return ;
}

fprintf( fp1 , "lineOpen() 関数による、回線の準備が完了 \r\n" ) ;

}

{
char szport[256] ; memset( szport , 0, 256 ) ;

if( tapi_ver_ge_2 ) {

// comm/datamodem/portname は、0x0002xxxx 以上でサポート。

LONG ret ;
VARSTRING *vs ;
LINEUSETOTALSIZE_SANDWICH( VARSTRING , vs , 0 ) 

ret = lineGetID( hLine ,0 , NULL, LINECALLSELECT_LINE,
vs, "comm/datamodem/portname" )

LINEUSETOTALSIZE_SANDWICH_( VARSTRING , vs ) 

strncpy( szport , (char *)vs + vs->dwStringOffset , 255 ) ;

if( *szport )
fprintf( fp1 , "コムポート : \"%s\" \r\n" , szport ) ;
else {
fprintf( fp1 , "TAPI により コムポートの名前を取得できなかった。 lineGetID の返した値 %d \r\n" ,
ret ) ;
}

free( vs ) ;
}

lineClose( hLine ) ; hLine = NULL ;

Sleep( 500 ) ;

if( ! tapi_ver_ge_2 || ! *szport )
{   // レジストリ
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96D-E325-11CE-BFC1-08002BE10318}\xxxx // xxxx は、0000,0001,0002... 
// をチェック : ↑ は NT の場合。キー AttachedTo を調べる。
// Win95/98 では、モデム名は、
// HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Class\\Modem\\"
// ポート名は、
// HKEY_LOCAL_MACHINE\\Enum 以下を「全部」調べて、キー DeviceDesc ( FRIENDLYNAME もあたるといい。)= モデムの名前 が一致したら、
// そこの キー PORTNAME を調べる。

if( *modem_model )
GetComPortByModelFromRegistry( modem_model , szport ) ;

if( *szport )
fprintf( fp1 , "COM ポート名の取得に成功 (%s) \r\n" , szport ) ;

}

char szdev[256] ; memset( szdev , 0, sizeof( szdev )) ;

if( *szport ) {
wsprintf( szdev , "\\\\.\\%s" , szport ) ;
hModem1 =
CreateFile( szdev , GENERIC_READ | GENERIC_WRITE ,
FILE_SHARE_READ | FILE_SHARE_WRITE , NULL ,
OPEN_EXISTING , FILE_FLAG_OVERLAPPED | FILE_FLAG_RANDOM_ACCESS , NULL ) ;
}
/*
else {  {   char sztapi_ver[256] ;
wsprintf( sztapi_ver , "TAPIのバージョンは %d.%d" , HIWORD( dwAPIVersion ) , LOWORD( dwAPIVersion )) ;

MessageBox( NULL , "TAPI のバージョンが 2.0 未満 、またはそのほかの理由により、「選択されたモデム」が接続されているポート名及びデバイスハンドルを取得できませんでした。\r\n"
"このソフトウェアはさらにポートを探しますが、特に、「選択されたモデム」と「似通った名前のモデム(ドライバ)が2つ以上」インストールされている場合や、その他特殊な場合は、ポートを検出できなかったり、正しく選択できない可能性があります。\r\n\r\n"
"その場合は、お手数ではありますが、このソフトウェアが改めてモデムの情報をリストアップしなおしますので、その中から、再度モデムを選択し直してください。既に「選択されたモデム」は無視されます。", sztapi_ver , 
MB_YESNOCANCEL | MB_SYSTEMMODAL | MB_SETFOREGROUND ) ;
}

fprintf( fp1 , "ポートネームを取得できないため特殊な処理を実行中。 \r\n" ) ;

std::list< std::pair< std::string , std::string> > comlist ;

for( int i = 1 ; i <= 10 ; i ++ )
{
wsprintf( szdev , "\\\\.\\COM%d" , i ) ;
fprintf( fp1 , "opening %s ....." , szdev ) ;

hModem1 =
CreateFile( szdev , GENERIC_READ | GENERIC_WRITE ,
FILE_SHARE_READ | FILE_SHARE_WRITE , NULL ,
OPEN_EXISTING , FILE_FLAG_OVERLAPPED | FILE_FLAG_RANDOM_ACCESS , NULL ) ;


// add ( "COM%d" , i )

comlist.push_back
( std::pair<std::string,std::string>
( strstr( szdev , "COM" ) , "" )) ;

strcpy( szport , comlist.back().first.c_str() ) ;

if( hModem1 == INVALID_HANDLE_VALUE ) {
fprintf( fp1 , "failed. \r\n" ) ;

comlist.back().second.assign( "×" ) ;

continue ; }
fprintf( fp1 , "opened. \r\n" ) ;

{   MDM_RESPONSE *pres ;

WriteAsync( hModem1 , "ATI4\r" , -1 , NULL , 50 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , NULL ) ;

char modemname[256] ;
ComboBox_GetLBText( hCombo ,
ComboBox_GetCurSel( hCombo ), modemname ) ;

fprintf( fp1 , "ATI4 on COM%d \r\n" , i ) ;
fprintf( fp1 , "response : %s \r\n" , pres->buf ) ;

// add( pres->buf , [ただし \r\n , \r\nOK\r\n を削除。] )
{   std::string s = pres->buf ; DWORD index ;
if(( index = s.find( "\r\nOK\r\n" )) != (DWORD)-1 &&
index == s.size() - 6 ) s.erase( index , 6 ) ;

if( 0 == s.find( "\r\n" )) s.erase( 0 , 2 ) ;

comlist.back().second.assign( s ) ;
}

fprintf( fp1 , "ポート:%s , ATI4 : %s \r\n" ,
comlist.back().first.c_str() ,comlist.back().second.c_str() ) ;

//MessageBox( NULL , comlist.back().second.c_str(),
//comlist.back().first.c_str() , MB_OK | MB_SETFOREGROUND ) ;

if( pres->btrue ) {
if( strstr( pres->buf , modemname ) ) {

char msg[256] ;
wsprintf( msg , "%s がヒットしました。" , comlist.back().second.c_str() ) ;
//MessageBox( NULL , msg , comlist.back().first.c_str() , MB_OK | MB_SETFOREGROUND ) ;
SbarSetText( 0L ,msg ) ;

fprintf( fp1 , "%s がマッチ。選択しました。 \r\n" , comlist.back().second.c_str() ) ;
Sleep( 500 ) ;

break ; }

}
}
CloseHandle( hModem1 ) ; hModem1 = NULL ;
}
} // end of LARGE else
*/

if( hModem1 == NULL || hModem1 == INVALID_HANDLE_VALUE )
{   if( *szport ) fprintf( fp1 , "CreateFile() で \"%s\" を指定して取得したハンドルは INVALID_HANDLE_VALUE または NULL 。原因:モデム使用中など。(%d) : 中断。\r\n" , szdev , hModem1 ) ;
else fprintf( fp1 , "COM ポート名が取得できなかった。 \r\n" ) ;

MessageBox( NULL , fmt( "%s が開けません。モデムを使用中かどうかなどを確認してください。処理を中断します。" , szport ) , "エラー" , MB_OK | MB_SETFOREGROUND | MB_ICONHAND ) ;
th_return ;
}

SbarSetText( 0 , fmt( "%s ポートをオープンしました。" , szport ) ) ;

COMMPROP cp ; ZeroMemory( &cp , sizeof( COMMPROP )) ;
cp.wPacketLength = sizeof( COMMPROP ) ;

{   BOOL ret ;
GetCommProperties( hModem1 , &cp ) ;
fprintf( fp1 , "cur/maxTxQ : %d,%d cur/maxRxQ : %d,%d settable/maxBaud : 0x%x,0x%x settalbe-params 0x%x \r\n"
, cp.dwCurrentTxQueue ,cp.dwMaxTxQueue , cp.dwCurrentRxQueue, cp.dwMaxRxQueue , cp.dwSettableBaud, cp.dwMaxBaud 
, cp.dwSettableParams ) ;


/*
fprintf( fp1 , "dwServiceMask 0x%x \r\n" , cp.dwServiceMask ) ;

if( cp.wPacketLength != sizeof( COMMPROP ))
fprintf( fp1 , "追加データ有り( サイズ : %d -> %d ) \r\n" 
, sizeof( COMMPROP ) , cp.wPacketLength ) ;
else
fprintf( fp1 , "追加データ無し \r\n" ) ; 


if( cp.wcProvChar[0] )
fprintf( fp1 , "モデムである。 \r\n" ) ; 

if( cp.dwProvSubType == PST_MODEM )
fprintf( fp1 , "※モデムとして認識 \r\n" ) ;
else if( cp.dwProvSubType == PST_RS232 )
fprintf( fp1 , "※RS232 として認識 \r\n" ) ;
else fprintf( fp1 , "※モデム、RS232 以外 (0x%x) \r\n" , cp.dwProvSubType ) ;
*/

ret = SetupComm( hModem1 ,
( cp.dwMaxRxQueue == 0 ) ? 4096 : min( 4096 , (int)cp.dwMaxTxQueue ) ,
( cp.dwMaxTxQueue == 0 ) ? 4096 : min( 4096 , (int)cp.dwMaxRxQueue ) ) ;

// TxQueue == dwOutQueue に対応
// RxQueue ==  dwInQueue に対応
// RxQueue = 0 だとエラーである。

fprintf( fp1 , "SetupComm 処理後 %s : \r\n" , ret ? "" : "(関数は失敗した。)" ) ;

ZeroMemory( &cp , sizeof( COMMPROP )) ;
cp.wPacketLength = sizeof( COMMPROP ) ;

GetCommProperties( hModem1 , &cp ) ;

fprintf( fp1 , "cur/maxTxQ : %d,%d cur/maxRxQ : %d,%d settable/maxBaud : 0x%x,0x%x settalbe-params 0x%x \r\n"
, cp.dwCurrentTxQueue ,cp.dwMaxTxQueue , cp.dwCurrentRxQueue, cp.dwMaxRxQueue , cp.dwSettableBaud, cp.dwMaxBaud 
, cp.dwSettableParams ) ;

}

// ○機種依存

/*
{   DCB dcb ; ZeroMemory( &dcb , sizeof( DCB )) ;
dcb.DCBlength= sizeof(DCB) ;

GetCommState( hModem1 , &dcb ) ;
fprintf( fp1 , "%d,%d,%d,%d \r\n" ,
dcb.BaudRate, dcb.StopBits ,dcb.ByteSize , dcb.Parity) ;

fprintf( fp1 , "%d \r\n" ,     dcb.fOutX ) ;

if( dcb.fNull )     fprintf( fp1 , "NULL 破棄 \r\n" ) ;

BOOL modifyDCB = TRUE ;
// if( ! dcb.BaudRate ) modifyDCB = TRUE ;

if( modifyDCB ) {

ZeroMemory( &dcb , sizeof( DCB )) ;
dcb.DCBlength= sizeof(DCB) ;

if( ! BuildCommDCB( "115200,N,8,P" , &dcb )) {
// "szport COM1: baud=19200 parity=N data=8 stop=0"
fprintf( fp1 , "DCB 構造体の構成に失敗しました。 ( %s ) \r\n" ,
EzFormatMessage( GetLastError()) ) ;
// パラメータが正しくありません。
// FORMAT_MESSAGE_ALLOCATE_BUFFER のときはLocalFree を使用せよ!

}
// dcb.fNull = FALSE ;

if( ! SetCommState( hModem1 , &dcb )) {
fprintf( fp1 , "COM ポートの構築 : SetCommState に失敗しました。 ( %s ) \r\n" ,
EzFormatMessage( GetLastError()) ) ;
// win98 ハンドルが無効 ? 
// xp では 例外エラー(EzFormatMessage 関数) 
// FORMAT_MESSAGE_ALLOCATE_BUFFER のときはLocalFree を使用せよ!

}

ZeroMemory( &dcb , sizeof( DCB )) ;
GetCommState( hModem1 , &dcb ) ;
fprintf( fp1 , "BaudRate = 0 のため、COMを設定 : %d,%d,%d,%d \r\n" ,
dcb.BaudRate, dcb.StopBits ,dcb.ByteSize , dcb.Parity) ;


DWORD dws ;
COMMCONFIG *lpCC 
= (COMMCONFIG *)calloc( sizeof( COMMCONFIG ),1) ;
lpCC->dwSize = sizeof( COMMCONFIG ) ;
while( GetCommConfig( hModem1 , lpCC , &dws )) {
if(  dws <= lpCC->dwSize ) break ;
else { free( lpCC ) ;
lpCC = (COMMCONFIG *)calloc( dws,1 ) ; lpCC->dwSize = dws ;
}
}

if( ! CommConfigDialog( // "COM1"
szport , NULL , lpCC )) {
fprintf( fp1 , "関数 CommConfigDialog(...) 変更なし。又は失敗。  ( %s ) \r\n" ,
EzFormatMessage( GetLastError() ) ) ;
} // 9600 , フロー制御なし。

lpCC->dcb.fAbortOnError = 1 ;

if( ! SetCommConfig( hModem1, lpCC, lpCC->dwSize ) )
{ fprintf( fp1 ,"%s のコンフィギュレーションに失敗。 ( %s ) \r\n" ,
szport , EzFormatMessage( GetLastError() )) ;
}

free( lpCC ) ;

}
} // DCB CommCommConfig 関係、ここまで。
*/


if( SetCommMask( hModem1 , EV_TXEMPTY | EV_RXCHAR ))
fprintf( fp1 , "イベントマスクを設定しました。 \r\n" ) ;
else
fprintf( fp1 , "イベントマスクの設定に失敗しました。\r\n" ) ;

// SetCommTimeoutProperties( hModem1 , 300 , 0 ) ;

SbarSetText( 1 ,
fmt( "%sポートを AT コマンドで初期化します。" , szport ) ) ;

MDM_RESPONSE *pres ;
int no_ok = 0 ;

WriteAsync( hModem1 , "AT\r" , -1   , NULL , 1000 ) ;
//pres =
WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 5000 , p_threadstop ) ;

WriteAsync( hModem1 , "ATZ\r" , -1 , NULL , 1000 ) ;
//pres =
WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 1000 , p_threadstop ) ;


WriteAsync( hModem1 , "ATE0\r" , -1 , NULL , 1000 ) ;
//pres =
WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 1000 , p_threadstop ) ;


// WriteAsync( hModem1 , "ATX?\r" , -1 , NULL , 1000 ) ;

/*
WriteAsync( hModem1 , "AT&V0\r" , -1 , NULL , 1000 ) ;
//pres =
WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 5000 , p_threadstop ) ;
*/



if( WriteAsync( hModem1 , "AT+FCLASS=?\r" ,
-1 , NULL , 1000 )) {
MessageBox( NULL , "モデムへの書き込みに失敗しました。( AT+FCLASS=? ) 処理を中断します。" , "エラー" , MB_OK | MB_SETFOREGROUND ) ;
fprintf( fp1 , "COM ポートに、FAX モデム確認コマンド AT+FCLASS=? を書き込めない。" ) ;

WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ;
th_return ;
}
else
fprintf( fp1 , "FAXモデム確認。 \r\n" ) ;

pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 5000 , p_threadstop ) ;

if( pres->btrue ) {
if( ! strstr( pres->buf , "1" )) no_ok |= 0x1 ;
}
else if( pres->_ERROR_ ) no_ok |= 0x2 ;
else no_ok |= 0x4 ;

if( no_ok ) {
if( no_ok & 0x1 )
MessageBox( NULL , "選択されたモデムでは FAX の送信をサポートしていません。" , "モデムを選択し直してください。SORRY" , MB_OK | MB_SETFOREGROUND ) ;
else if( no_ok & 0x2 )
MessageBox( NULL , "選択されたモデムでは FAX の送信をサポートしていないか、モデムの応答が不正です。" , "モデムを選択し直してください。" , MB_OK | MB_SETFOREGROUND ) ;
else if( no_ok & 0x4 )
MessageBox( NULL , "FAX 機能が使用可能か確認できませんでした。" , "SORRY" , MB_OK | MB_SETFOREGROUND ) ;

WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ;
th_return ;
}
else
fprintf( fp1 , "FAX CLASS 1 使用可能。 \r\n" ) ;

// Q0V1X3 // &K3

// WriteAsync( hModem1 , "AT&FE0&C1&D2&K3V1W3S0=0\r" ,    -1 , NULL , 1000 ) ;
// WriteAsync( hModem1 , "ATS7=60S30=0M1\N3%C3&K3B0N1X4\r" ,  -1 , NULL , 1000 ) ;
// WriteAsync( hModem1 , "AT%C0\r" ,  -1 , NULL , 1000 ) ;


//--
fprintf( fp1 , "AT&C0&D2\\r \r\n" ) ;
WriteAsync( hModem1 , "AT&C0\r" ,
-1 , NULL , 1000 ) ;
WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 1000 , p_threadstop ) ;
Sleep( 500 ) ;
fprintf( fp1 , "AT+FCLASS=1\\r \r\n" ) ;

WriteAsync( hModem1 , "AT+FCLASS=1\r" ,
-1 , NULL , 1000 ) ;
WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 1000 , p_threadstop ) ;

Sleep( 500 ) ;

fprintf( fp1 , "AT+FAE=1\\r \r\n" ) ;

WriteAsync( hModem1 , "AT+FAE=1\r" ,
-1 , NULL , 1000 ) ;

//    fprintf( fp1 , "AT+FAA=1\\r \r\n" ) ;
//    WriteAsync( hModem1 , "AT+FAA=1\r" ,
//    -1 , NULL , 1000 ) ;
//   藤井氏指摘により、オレが工夫して追加(2005/5/31)
//   ---------- 関係なかった!(2005/6/?) ------------

//--

/*
if( WriteAsync( hModem1 , "AT&C0;+FCLASS=1;+FAE=1\r" ,
-1 , NULL , 1000 )) {
MessageBox( NULL , "初期化コマンドの書き込みでタイムアウトが発生しました。処理を中断します。" , "エラー" , MB_OK | MB_SETFOREGROUND ) ;
fprintf( fp1 , "初期化コマンドの書き込みでタイムアウトが発生。処理中断。 \r\n" ) ;

WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ;
th_return ;
}
else
*/

fprintf( fp1 , "初期化コマンドの書き込み完了 \r\n" ) ;

pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 2500 , p_threadstop ) ;


if( pres->btrue ) {
fprintf( fp1 , "応答は正常 初期化完了 \r\n" ) ;
}
else {
if( pres->_ERROR_ )
MessageBox( NULL , "モデムの初期化に失敗しました。処理を中断します。" , "<ERROR>リザルトコードによる中断" , MB_OK | MB_SETFOREGROUND ) ;
if( pres->timeout )
MessageBox( NULL , "モデムの初期化に失敗しました。処理を中断します。" , "タイムアウト" , MB_OK | MB_SETFOREGROUND ) ;

WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ;
th_return ;
}

SbarSetText( 0 , "初期化 AT コマンドが完了しました。" ) ;
ModemStat() ;


{
fprintf( fp1 , "サポートされるデータ送信速度 : AT+FTM=? \r\n" ) ;
WriteAsync( hModem1 , "AT+FTM=?\r" ,
-1 , NULL , 1000 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 1000 , p_threadstop ) ;

fprintf( fp1 , "AT+FTM=? に対する応答 : \r\n%s \r\n" , pres->buf ) ;
// strtok( pres->buf , " ,\r\n\t\v" ) ;

fprintf( fp1 , "サポートされるHDLCフレームデータ送信速度 : AT+FTH=? \r\n" ) ;

WriteAsync( hModem1 , "AT+FTH=?\r" ,
-1 , NULL , 1000 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 1000 , p_threadstop ) ;

fprintf( fp1 , "AT+FTH=? に対する応答 : \r\n%s \r\n" , pres->buf ) ;


}



PurgeComm( hModem1 , PURGE_RXCLEAR ) ;
PurgeComm( hModem1 , PURGE_TXCLEAR ) ;

char dial[256] ; char dialnum[128] ;
GetDlgItemText( hCf1 , IDC_CF1_DIALNUMBER , dialnum , 128 ) ;
for( int i = 0 , j = 0 ; *( dialnum + i ) ; i ++ , j ++ ) {
if( strchr( "-()" , *( dialnum + i ))) j -- ;
else if( i != j )
*( dialnum + j ) = *( dialnum + i ) ;

if( i != j && ! *( dialnum + i + 1 )) *( dialnum + j + 1 ) = '\0' ;

}

wsprintf( dial , "ATD%c%s\r"  , IsDlgButtonChecked ( hCf1 ,IDC_CF1_PULSE ) ? 'P' : 'T' 
, dialnum ) ;

fprintf( fp1 , "ダイアリング %s\n ........\r\n" , dial ) ;
SbarSetText( 1 , fmt( "ダイアルしています。%s" , dialnum ) ) ;

phase_mask |= DIALING ;

WriteAsync( hModem1 , dial , -1 , NULL , 1000 ) ;

DWORD dwtime = GetTickCount() ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 60000 , p_threadstop ) ;


if( pres->timeout || *p_threadstop )
{   fprintf( fp1 , "リモートFAX から正常な応答がないか、又は全く応答がない。( 時間 : %d msec.) \r\n" , GetTickCount() - dwtime ) ;
SbarSetText( 1 , "リモートFAX との交信を開始できません。" ) ;

MessageBox( NULL , "リモートFAX から正常な応答を得られません。処理を中断します。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ; th_return ; }
else
fprintf( fp1 , "リモート FAX からの最初のリスポンス受信 ( took %d ms.) \r\n" , GetTickCount() - dwtime ) ;

if( pres->_ERROR_ )
fprintf( fp1 , "<ERROR>リザルトコードを受け取ったが続行する。 \r\n" ) ;

phase_mask &= ~DIALING ;

connection_duration = 0 ;

SetTimer( hAppWnd ,TIMER_CONNECTDURATION ,1000 , NULL ) ;

SbarSetText( 1 , "リモートとの交信を開始します。" ) ;


// pres->buf is expected to be the [NSF] frame !!

{   const unsigned char *lp = pres->buf ;
lp = strchr( (char *)lp , 0xFF ) ;
if( lp ) {
if( *lp == 0xFF ) lp ++ ; if( *lp == 0x3 ) lp ++ ;
if( *lp == 0x20 ) fprintf( fp1 , "[NSF] OK \r\n" ) ;
else fprintf( fp1 , "[NSF] が確認できない。 \r\n" ) ;
}
}

ModemStat() ;

SbarSetText( 0 , "NSF フレーム受信完了。" ) ;
SbarSetText( 1 , "CSI を要求。" ) ;


double_NSF :


fprintf( fp1 , "リモート FAX に CSI フレームを要求します。 \r\n" ) ;

////////////////////
//  RECEIVE CSI
////////////////////

WriteAsync( hModem1 , "AT+FRH=3\r" , -1 , NULL , 1000 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;

{   BOOL stop_ss = FALSE ;
if( pres->btrue )
{   const unsigned char *lp = pres->buf ;
lp = strchr( (char *)lp , 0xFF ) ;
if( lp ) { lp ++ ; if( *lp == 0x3 ) lp ++ ;

if( *lp != 0x40 ) {

// CSI を経ず直接 DIS を送ってくるような FAX に対応。
// CSI:0xFF,0x13,DIS(0x80)

// (exception)
if( *lp == 0x13
&& *(lp+1) == 0x80 ) {

SbarSetText( 0 , "DIS OK。(CSI omitted)" ) ;
SbarSetText( 1 , "例外1−1(エラーではありません)"  ) ;
fprintf( fp1 , "\r\n" ) ;
fprintf( fp1 , "★例外1−1: CSI フレームが省略され、DIS を受信。 \r\n" ) ;

goto direct_DIS ;

}
else if( *lp == 0x20 )
{   // 0xFF,0x3,NSF(0x20)

SbarSetText( 0 , "NSF(2) OK。(NSF doubled)" ) ;
SbarSetText( 1 , "例外1−2(エラーではありません)"  ) ;

fprintf( fp1 , "\r\n" ) ;
fprintf( fp1 , "★例外1−2: NSF フレームを2回受信した。CSI を「再」要求します。\r\n" ) ;

goto double_NSF ;

}
//


fprintf( fp1 , "[%s] の代わりに [%s] を受け取った。 \r\n" , visdig( 0x40 ) , visdig( *lp) ) ;
stop_ss = TRUE ; }

} else stop_ss = TRUE ;
}
else {
stop_ss = TRUE ; }

if( ! pres->btrue || stop_ss ) {

if( ! pres->btrue ) {
// 藤井氏指摘 2005/5/31 (LUCENT MODEM)
fprintf( fp1 , "モデムの反応が不正。_ERROR_ %d, timeout %d \r\n" , pres->_ERROR_, pres->timeout ) ;
char tempmsg[256] ;
wsprintf( tempmsg, "モデムが、標準的な AT コマンドに正常に応答しません。"
"詳細:ERROR %d, timeout %d \r\n\r\n" , pres->_ERROR_, pres->timeout ) ;
// AT+FRH=? をためしていただく。単に「3」と出れば OK.
MessageBox( NULL , tempmsg , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
}
else {
fprintf( fp1 , "%s が正常に受信できない。処理中断。 \r\n"
, "[CSI]" ) ;
MessageBox( NULL , "リモートファックスとの交渉に失敗しました。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
}

WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ; th_return ;

}
}

SbarSetText( 0 , "CSI OK。" ) ;
SbarSetText( 1 , "DIS を要求。" ) ;

fprintf( fp1 , "CSI フレーム受信。 OK \r\n" ) ;


fprintf( fp1 , "引き続き、リモート FAX に DIS フレームを要求します。 \r\n" ) ;

////////////////////
//  RECEIVE DIS
////////////////////

WriteAsync( hModem1 , "AT+FRH=3\r" , -1 , NULL , 1000 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;


direct_DIS :


{   BOOL stop_ss = FALSE ;
if( pres->btrue )
{   const unsigned char *lp = pres->buf ;
lp = strchr( (char *)lp , 0xFF ) ;
if( lp ) { lp ++ ; if( *lp == 0x13 ) lp ++ ;
if( *lp != 0x80 ) {
fprintf( fp1 , "[%s] の代わりに [%s] を受け取った。" , visdig( 0x80 ) , visdig( *lp) ) ;
stop_ss = TRUE ; }
// 0x13 : CTC1 ("11001000")
// 0x80 : DIS  ("00000001")
} else stop_ss = TRUE ;
}
else stop_ss = TRUE ;

if( ! pres->btrue || stop_ss ) {
fprintf( fp1 , "%s が正常に受信できない。処理中断。 \r\n"
, "[DIS]" ) ;

MessageBox( NULL , "リモートファックスとの交渉に失敗しました。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;

WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ; th_return ;

}
}

ZeroMemory( &dis , sizeof( _DIS )) ;

fprintf( fp1 , "DIS の FIF 情報 : " ) ;

// fprintf( fp1 , "test visdig(1) = %s \r\n" , visdig(1) ) ;

{
const unsigned char *lp = pres->buf ;
assert( NULL != ( lp = strchr( (char *)lp , 0xFF ))) ;
lp ++ ;                  // skip "11111111"
if( 0x13 == *lp ) lp ++ ;    // skip CTC
lp ++ ;                  // skip DIS

fprintf( fp1 , "No.1- %s %s %s %s -No.32 \r\n"
, visdig( *lp ) , visdig( *( lp+1) ) , visdig( *(lp+2) ) , visdig( *(lp+3) ) ) ;

lp ++ ; // skip first non-important data ( 1〜8 ) ;


int bits ;
// get 11〜14
bits = ( *lp & ( 4 + 8 + 16 + 32 )) >> 2 ;

{   switch( bits )
{   case 0 : // 0000
dis.protocols_avail |= V27TF ;

dis.dcs_fif[0] |= 0 << ( 11 - 1 ) ;

dis.speed_settled = 2400 ;
dis.FTM_number = 24 ;
s = "V.27ter (fallback mode)" ;
wsprintf( dis.protocol_settled , s.c_str() ) ;

break ;
case 2 : // 0100
dis.protocols_avail |= V27T ;

dis.dcs_fif[0] |= 2 << ( 11 - 1 ) ;

dis.speed_settled = 4800 ;
dis.FTM_number = 48 ;
s = "V.27ter" ;
wsprintf( dis.protocol_settled , s.c_str() ) ;

break ;
case 1 : // 1000
dis.protocols_avail |= V29 ;

dis.dcs_fif[0] |= 1 << ( 11 - 1 ) ;

dis.speed_settled = 9600 ;
dis.FTM_number = 96 ;
s = "V.29" ;
wsprintf( dis.protocol_settled , s.c_str() ) ;

break ;
// 以下では、複数モード選択可能。
case 3 : // 1100
dis.protocols_avail |=  V27T | V29  ;
dis.dcs_fif[0] |= 1 << ( 11 - 1 ) ;

dis.speed_settled = 9600 ;
dis.FTM_number = 96 ;
s = "V.27ter, V.29" ;
wsprintf( dis.protocol_settled , "V.29" ) ;

break ;
case 7 : // 1110
dis.protocols_avail |= V27T | V29 | V33 ;
// モデムの規格みると、V33 がないので、V29。V33 は、多分 class2 限定。

fprintf( fp1 , "※ リモートは V33 に対応していますが、V29を使用します。 \r\n" ) ;
dis.dcs_fif[0] |= 1 << ( 11 - 1 ) ;

dis.speed_settled = 9600 ; // 14400 ;

dis.FTM_number = 96 ; // 145 ; // V17 指定で V33 も使用可能の場合は 145 でよい。
s = "V.27ter, V.29, V.33" ;
wsprintf( dis.protocol_settled , "V.29" ) ;

break ;
case 11 : // 1101
dis.protocols_avail |= V27T | V29 | V33 | V17 ;

dis.dcs_fif[0] |= 8 << ( 11 - 1 ) ;

dis.speed_settled = 14400 ;
dis.FTM_number = 145 ; // == long train . ( 146 == short train )
s = "V.27ter, V.29, V.33, V.17" ;
wsprintf( dis.protocol_settled , "V.17" ) ;

break ;
default : // その他。予期しないビットパターン。

{   std::string s_temp ;
s_temp.assign( visdig( bits ), 4 ) ;
fprintf( fp1 , "DIS フレーム ( データ信号速度に関する部分 ) 予期しないビットパターン : (No.11) %s (No.14) \r\n" , s_temp.c_str() ) ;
}

dis.protocols_avail = V29 ;
dis.dcs_fif[0] |= 1 << 10 ;

dis.speed_settled = 9600 ;
dis.FTM_number = 96 ;
s = "不明" ;
wsprintf( dis.protocol_settled , "V.29" ) ;

break ;
}
}

fprintf( fp1 , "リモート FAX は、 ITU-T %s に対応しています。 \r\n" , s.c_str() ) ;


// get 15 , 副走査線
if( *lp & 64 ) dis.f7_7 = 1 ;
// get 16 , MR 符号化能力
if( *lp & 128 ) dis.fMR = 1 ;

// get 17-18 , 記録幅
bits = (*( lp + 1 ) & ( 1 + 2 ) ) ;

switch( bits )
{   case 0 :    case 2 :    case 1 : break ;
default : bits = 0 ;
fprintf( fp1 , "注意 : 記録幅能力に不正な値 \r\n" ) ;
break ;
}

dis.fwidth_mode = bits ;

// get 19-20 , 最大記録長
bits = (*( lp + 1 ) & ( 4 + 8 ) ) >> 2 ;

{   char *szheight = NULL ;
switch( bits )
{   case 0 : szheight = "A4" ; break ;
case 1 : szheight = "A4orB4" ; break ;
case 2 : break ;
default : bits = 0 ; break ;
}

if( szheight )
strcpy( dis.szheight , szheight ) ;
else *dis.szheight = '\0' ;

dis.fheight = bits ;
}


// get 21-23 , 最小伝送時間
bits = (*( lp + 1 ) & ( 16 + 32 + 64 )) >> 4 ;
switch( bits )
{   case 0 : dis.min_tsm_fine = dis.min_tsm_normal = 20 ; break ;// 000
case 4 : dis.min_tsm_fine = dis.min_tsm_normal = 40 ; break ;// 001
case 2 : dis.min_tsm_fine = dis.min_tsm_normal = 10 ; break ;// 010
case 1 : dis.min_tsm_fine = dis.min_tsm_normal = 5 ;  break ;// 100
case 7 : dis.min_tsm_fine = dis.min_tsm_normal = 0 ;  break ;// 111

case 3 : dis.min_tsm_fine = dis.min_tsm_normal = 20 ; // 110
dis.min_tsm_normal *= 2 ; break ;
case 5 : dis.min_tsm_fine = dis.min_tsm_normal = 40 ; // 101
dis.min_tsm_normal *= 2 ; break ;
case 6 : dis.min_tsm_fine = dis.min_tsm_normal = 10 ; // 011
dis.min_tsm_normal *= 2 ; break ;
default : break ;
}



fprintf( fp1 , "拡張フィールド%s \r\n" , 
(*(lp + 1) & 128 ) ? "があります。" : "はありません。" ) ;

if( *(lp + 1) & 128 )
{   if( *( lp + 2 ) & 4 ) dis.fECM = 1 ;
if( *( lp + 2 ) & 64 ) dis.fMMR = 1 ;

}



fprintf( fp1 , "プロトコルが決定しました。 : ITU-T %s \r\n" , dis.protocol_settled ) ;
fprintf( fp1 , "データ信号送信速度が決定しました。 : %d bps \r\n" , dis.speed_settled ) ;

if( ! dis.f7_7 ) fprintf( fp1 , "注意 : リモートfax が 7.7 本/mm モードをサポートしていない。 \r\n" ) ;
else fprintf( fp1 , "副走査線 7.7 本/mm モード あり \r\n" ) ;

fprintf( fp1 , "MR 符号化能力 %s \r\n" , dis.fMR ? "あり" : "なし" ) ;

fprintf( fp1 , "記録幅 : \r\n" ) ;
fprintf( fp1 , "215mm(±1%%) の走査線当り1728 画素のモード あり(標準:A4) \r\n" ) ;
fprintf( fp1 , "255mm(±1%%) の走査線当り2048 画素のモード %s(:B4) \r\n" , ( 1 <= (int)dis.fwidth_mode ) ? "あり" : "なし" ) ;
fprintf( fp1 , "303mm(±1%%) の走査線当り2432 画素のモード %s(:A3) \r\n" , ( 2 <= (int)dis.fwidth_mode ) ? "あり" : "なし" ) ;


fprintf( fp1 , "最大記録長 : %s \r\n" , *dis.szheight ? dis.szheight : "制限なし" ) ;

fprintf( fp1 , "1ライン最小伝送時間(ファインモード/標準モード) %d (%d) msec. \r\n" , dis.min_tsm_fine , dis.min_tsm_normal ) ;

fprintf( fp1 , "誤り訂正方式 (ECM) %s \r\n" , dis.fECM ? "あり" : "なし" ) ;
fprintf( fp1 , "MMR 符号化能力 %s \r\n" , dis.fMMR ? "あり" : "なし" ) ;

{   //  プロトコル&送信速度 の部分は構成済み。
//  それ以外の部位は、DCS の構成もれを防ぐために以下に於いて構築

BOOL use3_85 = IsDlgButtonChecked( hCf1 , IDC_CF1_FINE_OR_NORMAL )
? FALSE : TRUE ; // 7.7 ファイン : TRUE , 3.85 ノーマル : FALSE
BOOL use_MR  = FALSE ; // MR or MH
BOOL use_ECM = FALSE ;
BOOL use_MMR = FALSE ;
BOOL oct64   = FALSE ; // フレームサイズ 64oct or 256oct
// 初期化しなきゃエラーになるのは当たり前だよな。

//  受信機能有り:つねに1
dis.dcs_fif[0] |= 1 << ( 10 - 1 ) ;

//  副走査線
if( dis.f7_7 ) ;

if( use3_85 )
dis.dcs_fif[0] |= 0 << ( 15 - 1 ) ;
else
dis.dcs_fif[0] |= 1 << ( 15 - 1 ) ;

//  MR 符号化能力 : MR は使用しない(MHを使用する)ので、常に 1
if( use_MR )
dis.dcs_fif[0] |= 1 << ( 16 - 1 ) ;
else
dis.dcs_fif[0] |= 0 << ( 16 - 1 ) ;

//  記録幅
dis.dcs_fif[0] |= 0 << ( 17 - 1 ) ;
// dis.dcs_fif[0] |= 1 << ( 17 - 1 ) ; // 2048/255 の場合。

//  記録長
if( (unsigned)dis.fheight == 2 )
dis.dcs_fif[0] |= 2 << ( 19 - 1 ) ;
else if( (unsigned)dis.fheight == 1 ) // A4orB4
dis.dcs_fif[0] |= 1 << ( 19 - 1 ) ; // B4(364mm)
else
dis.dcs_fif[0] |= 0 << ( 19 - 1 ) ; // A4(297mm)

//  最小伝送時間
int Min_tsm ;
if( use3_85 )       Min_tsm = dis.min_tsm_normal ;
else                Min_tsm = dis.min_tsm_fine ;

switch( Min_tsm )
{   case 20 :
dis.dcs_fif[0] |= 0 << ( 21 - 1 ) ; break ;
case 40 :
dis.dcs_fif[0] |= 4 << ( 21 - 1 ) ; break ;
case 10 :
dis.dcs_fif[0] |= 2 << ( 21 - 1 ) ; break ;
case 5 :
dis.dcs_fif[0] |= 1 << ( 21 - 1 ) ; break ;
case 0 :
dis.dcs_fif[0] |= 7 << ( 21 - 1 ) ; break ;
default :
fprintf( fp1 , "内部エラー : 最小伝送時間の取得に失敗している。 normal %d ,fine %d \r\n" , dis.min_tsm_normal , dis.min_tsm_fine ) ;
break ;
}

//  拡張フィールド1 : 有り
dis.dcs_fif[0] |= 1 << ( 24 - 1 ) ;


if( use_ECM )
dis.dcs_fif[0] |= 1 << ( 27 - 1 ) ;

//  フレームサイズ 0:256 oct, 1:64 oct
if( oct64 )
dis.dcs_fif[0] |= 1 << ( 28 - 1 ) ;
else
dis.dcs_fif[0] |= 0 << ( 28 - 1 ) ;

if( use_MMR )
dis.dcs_fif[0] |= 1 << ( 31 - 1 ) ;

fprintf( fp1 , "DCS の FIF を構成しました : No.1- %s %s %s %s -No.32 \r\n" , 
visdig( dis.dcs_fif[0] & 0xFF ) , visdig( ( dis.dcs_fif[0] >> 8 ) & 0xFF ) ,
visdig( ( dis.dcs_fif[0] >> 16 ) & 0xFF ) , visdig( ( dis.dcs_fif[0] >> 24 ) & 0xFF ) ) ;


//  拡張フィールド2
dis.dcs_fif[0] |= 0 << ( 32 - 1 ) ;

}


// ファインモードと標準モードについて調べよ。
// V.17 は V.33 を兼ねるか? => V.33 は CLASS2 のみ ( よって使用しない )
fprintf( fp1 , "以上 \r\n" ) ;
}


SbarSetText( 0 , "DIS OK。" ) ;
SbarSetText( 1 , "TSI を送信..." ) ;

fprintf( fp1 , "DIS フレーム受信終了。 \r\n" ) ;

fprintf( fp1 ,  "TSI フレームの送信を開始します。\r\n" ) ;

////////////////////
//  SEND        TSI
////////////////////


WriteAsync( hModem1 , "AT+FTH=3\r" , -1 , NULL , 1000 ) ;

pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 3000 , p_threadstop ) ;

if( ! pres->btrue ) {
fprintf( fp1 , "TSI 送信準備の、AT+FTH=.. に失敗しました。処理中断 \r\n" ) ;

MessageBox( NULL , "リモートファックスとの交渉に失敗しました。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ; th_return ;
}
else
fprintf( fp1 ,  "TSI フレームの送信準備 OK 。送信 ... \r\n" ) ;


{   char sendbuf[64] ; ZeroMemory( sendbuf , sizeof( sendbuf )) ;
char *lpbuf = sendbuf ;
// @ TSI の IDENTIFIER ( 11111111 + CTC + TSI )
lpbuf =  stpcpy( lpbuf , digitstring_toint8( 
"11111111" "11000000" "X1000010" )) ;

{   char sz20[21] ; ZeroMemory( sz20 , sizeof( sz20 )) ;
char *lp = add_mes.user_number ; int i ;
lp += strlen( lp ) ; if( lp != add_mes.user_number ) lp -- ;
for( i = 0 ; add_mes.user_number <= lp && i < 20 ; lp -- , i ++ )
sz20[i] = ( strchr( "+#*0123456789" , *lp ) ) ? *lp : (unsigned char)0x20 ;

fprintf( fp1 , "ID reversed : %s ( length %d ) \r\n" , sz20 , strlen( sz20 ) ) ;

lpbuf = stpcpy( lpbuf , sz20 ) ;
memset( lpbuf , (unsigned char)0x20 , 20 - strlen( sz20 ) ) ;
lpbuf += 20 - strlen( sz20 ) ;
}

/*
// A TSI の内容
lpbuf =  stpcpy( lpbuf , "+2*#" ) ;
// B 残りを 0x20 で埋める。( 計 20 オクテット (キマリ) )
memset( lpbuf , (unsigned char)0x20 , 16 ) ;
lpbuf += 16 ;
*/


// C _DLE_  _ETX_
strcpy( lpbuf , digitstring_toint8( "00001000" "11000000" )) ;

WriteAsync( hModem1 , sendbuf , -1 , NULL , 1000 ) ;
}

pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 3000 , p_threadstop ) ;


if( ! pres->btrue ) {
fprintf( fp1 ,  "TSI フレームの送信が何らかの理由で失敗。処理中断 \r\n" ) ;

MessageBox( NULL , "リモートファックスとの交渉に失敗しました。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ; th_return ;
}


SbarSetText( 0 , "TSI 送信終了。" ) ;
SbarSetText( 1 , "DCS を送信..." ) ;

//////////////////
//  SEND        DCS
//////////////////

fprintf( fp1 ,  "DCS フレームの送信準備です。DCS フレームを構成します。\r\n" ) ;

{
/*
// 暫定的にうまくいく例↓
const char *lpsend = 
digitstring_toint8(
"11111111" "11001000" "X1000001" // frame identifier
"00000000" "01""1000""10" "00" "010001" "00000000" // 4 octets
"00001000" "11000000" // _DLE_ _ETX_
) ; // , 9
*/

char lpsend[64] ; ZeroMemory( lpsend , sizeof( lpsend )) ;

memcpy( lpsend ,
digitstring_toint8( "11111111" "11001000" "X1000001" ) , 3 ) ;
memcpy( lpsend + 3 , &dis.dcs_fif[0] , 4 ) ;
memcpy( lpsend + 3 + 4 , digitstring_toint8( "00001000" "11000000" ) , 2 ) ;


fprintf( fp1 ,  "DCS フレームを送信します。\r\n" ) ;

WriteAsync( hModem1 , (char *)lpsend , 9 , NULL , 1000 ) ;
}


pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;


if( ! pres->btrue ) {
fprintf( fp1 ,  "DCS フレームの送信が何らかの理由で失敗。処理中断 \r\n" ) ;

MessageBox( NULL , "リモートファックスとの交渉に失敗しました。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
WriteDropOperation( hModem1 ) ; 

CloseHandle( hModem1 ) ; hModem1 = NULL ; th_return ;
}


SbarSetText( 0 , "DCS 送信終了。" ) ;
SbarSetText( 1 , "モデムの Modulation Sheme を設定" ) ;

////////////////////////////////////
//  SEND        TCF トレーニングチェック
////////////////////////////////////
static char szzero[4096] ;

//static int iretry = 0 ;
//l555:

DWORD ttt ;

{
fprintf( fp1 ,  "モデムにモードを指定します。 \r\n" ) ;

WriteAsync( hModem1 , "AT+FTS=8\r"  , -1 , NULL , 20 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;

s = fmt( "AT+FTM=%d\r" , dis.FTM_number ) ;

WriteAsync( hModem1 , (char *)s.c_str() , -1 , NULL , 20 ) ;

pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 3000 , p_threadstop ) ;
//  ↑これがいらないんだな。むちゃくちゃシビアだな ! ざっけんなマジ !
//  というか、Wait.. 関数が 250 msec のタイムラグをとるからか...。
//  それは改良した。ので復活させても 動作確認 OK .

//  fprintf( fp1 ,  "AT+FTM=%d のリザルトコード CONNECT を確認したいが リザルトコードを待つと TCF が安定しないので確認しない。 \r\n" 
//  , dis.FTM_number ) ;

if( pres->btrue )
fprintf( fp1 ,  "AT+FTM=%d : CONNECT を確認 \r\n" , dis.FTM_number ) ;
else    fprintf( fp1 ,  "AT+FTM=%d : CONNECT が確認できません。 \r\n" , dis.FTM_number ) ;


SbarSetText( 1 , "1.5 秒間の トレーニングチェック..." ) ;

//...send 0 for 1.5 sec
fprintf( fp1 ,  "1.5 秒間に相当する 連続 '0' 信号を送信。\r\n" ) ;

{
ZeroMemory( szzero , 4096 ) ;

DWORD dwBytes = 0 ;

int nBytes_for_1_5 = ( dis.speed_settled * 3 / 8 ) / 2 ; // == / 8 * 3 / 2
fprintf( fp1 , "1.5 秒間に相当するバイト数が計算されました。: %d バイト \r\n" , nBytes_for_1_5 ) ;

for( int iwrite = nBytes_for_1_5 ;
0 < iwrite ; iwrite -= 1024 )
{
WriteAsync( hModem1 , szzero , min( iwrite , 1024 ) , &dwBytes , 100 ) ;
fprintf( fp1 , "書き込み %d バイト \r\n" , dwBytes ) ;

if( ! dwBytes ) {
fprintf( fp1 , "書き込みが0バイトでした。十分なウェイトをおくことが推奨されます。 [A]\r\n" ) ;
SbarSetText( 2 , " 書き込み 0 バイト [A]" ) ;
}

CommStat() ;

if( 1024 <= iwrite ) {
int isleep = 1000 * 1024 * 8 / dis.speed_settled ; // 1000 * 1024 / ( dis.speed_settled / 8 )
// isleep -= 100 ; // 9600 のときで、750 (msec)
isleep = isleep *  7 / 8 ; // 9600 のときで、747
isleep -= 50 ; // WriteFile にかかった時間分引いてみる。
// 4分の3が かぎ かな?
// isleep = 700 ; // オリジナル。

Sleep( isleep ) ; // 適切な時間でこれをおくと、write error がでなくなる。
fprintf( fp1 , "%d msec のウェイトをあけました。 \r\n" , isleep ) ;

// ○機種依存 ?
}
}

ttt = GetTickCount() ;

WriteAsync( hModem1 ,
digitstring_toint8( "00001000" "11000000" ) , -1 ,
&dwBytes , 1000 ) ;

fprintf( fp1 , "書き込み %d バイト \r\n" , dwBytes ) ;
if( ! dwBytes ) {
fprintf( fp1 , "書き込みが0バイトでした。十分なウェイトをおくことが推奨されます。 [B]\r\n" ) ;
SbarSetText( 2 , " 書き込み 0 バイト [B]" ) ;
}

pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 1500 + 3000 , p_threadstop ) ;
{   int t = GetTickCount() - ttt ;
fprintf( fp1 , "TCF 送信完了から OK を受け取るまでの時間 約 %d msec. \r\n" ,t ) ;
}

if( ! pres->btrue ) {
fprintf( fp1 ,  "トレーニングチェック TCF の送信が異常。処理中断 \r\n" ) ;

MessageBox( NULL , "リモートファックスとの交渉に失敗しました。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;

WriteDropOperation( hModem1 ) ; 
CloseHandle( hModem1 ) ; hModem1 = NULL ;

th_return ;
}
else
fprintf( fp1 ,  "トレーニングチェック 完了。\r\n" ) ;

}}

SbarSetText( 1 , "TCF を送信しました。" ) ;

////////////////////////////////////////////
//  RECEIVE CFR (すべての準備が完了の合図。)
////////////////////////////////////////////


WriteAsync( hModem1 , "AT+FRH=3\r" , -1 , NULL , 1000 ) ;

pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 4000 , p_threadstop ) ;
// 受け取ったバッファが CFR フレームなら OK !


{   BOOL stop_ss = FALSE ;
if( pres->btrue )
{   const unsigned char *lp = pres->buf ;
lp = strchr( (char *)lp , 0xFF ) ;
if( lp ) { lp ++ ; if( *lp == 0x13 ) lp ++ ;
if( *lp != 0x84 ) {
fprintf( fp1 , "[%s] の代わりに [%s] を受け取った。 \r\n" , visdig( 0x84 ) , visdig( *lp) ) ;
stop_ss = TRUE ; }

if( *lp == 0x44 /* FTT0 */ ) {
fprintf( fp1 , "リモートファックスは TCF の再送を要求しています。\r\n" ) ;

// if( iretry ++ < 1 ) goto l555 ;

// 11111111 (?      ) [ 255 0xff]
// 11001000 (CTC1   ) [ 19 0x13]
// 00100010 (FTT0   ) [D 68 0x44]
}
} else stop_ss = TRUE ;
}
else stop_ss = TRUE ;

if( ! pres->btrue || stop_ss ){

SbarSetText( 0 , "手順の途中で失敗しました。" ) ; // トレーニングチェックが失敗しました。" ) ;


// リモートに送信する DCS フレームが原因の場合あり。
// 種種の Wait のタイミングが原因(多くは間の空きすぎ)の場合あり。
// というか、ここでの失敗は、CFR が正常に取得できないのであって、
// トレーニングチェックの失敗に限らないとはいうものの、
// ここまで OK が続いた( DCS の後も OK だったわけだから。)
// のだから、トレーニングチェックと思いたいよな。
// (けど違う。)

fprintf( fp1 , "%s が正常に受信できない。処理中断。 \r\n"
, "[CFR]" ) ;

MessageBox( NULL , "リモートファックスとの交渉に失敗しました。" , "OK" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;

WriteDropOperation( hModem1 ) ;

CloseHandle( hModem1 ) ; hModem1 = NULL ; th_return ;

}
}


SbarSetText( 0 , "ビットデータ送信前の準備が全て完了しました。" ) ;

fprintf( fp1 , "MH : ビットデータ送信のための全ての準備が整いました。 \r\n" ) ;


// PHASE C !

#ifdef RISTRICT_ONE_PAGE
int nmx = 1 ;

#else
int nmx = IsDlgButtonChecked( hCf1 , IDC_CF1_SENDALL ) ? nMaxpage : 1 ;

#endif

for( int ctr = 0 ; ctr < nmx ; ctr ++ ) {

s = fmt( "AT+FTM=%d\r" , dis.FTM_number ) ;
WriteAsync( hModem1 , (char *)s.c_str() , -1 , NULL , 1000 ) ;

pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 3000 , p_threadstop ) ;

if( ! pres->btrue ) {
fprintf( fp1 , "! CONNECT リザルトコードが確認できないが、続行します。 \r\n" ) ;
SbarSetText( 1 , "! CONNECT リザルト未検出(強行)" ) ;
}


SbarSetText( 0 , "ビットデータを構成しています。..." ) ;
fprintf( fp1 , "ビットデータ を構成しています。 : MH \r\n" ) ;

ShowWindow( hProgress1 , SW_SHOW ) ;

dwLastSendTime = GetTickCount() ;

GetBinaryArrayAsStringFromBitmap( _hBitmap1728SEND , SendOneLineProc , p_threadstop ) ;

/*
{
memset( GlobalSendbuf ,0 , sizeof( GlobalSendbuf ) ) ;
lpadd = GlobalSendbuf ;
GetBinaryArrayAsStringFromBitmap( _hBitmap1728SEND , ConstructOneLineProc , p_threadstop ) ;

for( int cb = 0 ; cb < lpadd - GlobalSendbuf ; cb += 1024 )
WriteAsync( hModem1 , GlobalSendbuf + cb , min( 1024 , (lpadd - GlobalSendbuf - cb) ) , NULL , 1000 ) ;
}
*/

ShowWindow( hProgress1 , SW_HIDE  ) ;

if( hProgress1 )
{   DestroyWindow( hProgress1 ) ;   hProgress1 = NULL ; }


SbarSetText( 1 , "ビットデータの送信が完了しました..." ) ;
fprintf( fp1 , "書き込みは終了しました。 \r\n" ) ;

/*
{   DWORD dwBytes ;
fprintf( fp1 , "ページ終了の信号 RTC ( 6 * EOL ) (+ DLE ETX ) を送信します。 \r\n" ) ;

WriteAsync( hModem1 ,

digitstring_toint8( 
"00000000" "00010000" 
"00000001" "00000000" "00010000" "00000001"
"00000000" "00010000" "00000001"
"00001000" "11000000" ) , 11 , // EOL * 6 , nameed "RTC"
&dwBytes , 500 ) ;
}
*/

ttt = GetTickCount() ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 5500 , p_threadstop ) ;

if( ! pres->btrue )
fprintf( fp1 , "ページデータ送信後の OK リザルトコードが確認できない。(続行) %d msec.\r\n" , GetTickCount() - ttt ) ;
else
fprintf( fp1 , "OK (%d msec.) \r\n" , GetTickCount() - ttt ) ;

Sleep( 250 ) ;

/*
{   WriteAsync( hModem1 , "AT+FTS=8\r" , -1 , NULL , 20 ) ;
//      pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;
}
*/

fprintf( fp1 , "フェーズ C の終了の最終コマンド。 \r\n" ) ;

{
int iretry = 0 ;
while( iretry ++ < 10 &&
WriteAsync( hModem1 , "AT+FTH=3\r" , -1 , NULL , 20 )) {
for( DWORD endtime = GetTickCount() + 2000 ; GetTickCount() < endtime ; ) ;
fprintf( fp1 , fmt( "%d 回目の試行 \r\n" , iretry )) ;
}
}

pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 3000 , p_threadstop ) ;

// phase C ends...

#ifdef RISTRICT_ONE_PAGE
break ;

#else
if( ctr == nmx - 1 ) break ;
else {
SendDlgItemMessage( hCf1 , IDC_CF1_UPDOWN3 ,
UDM_SETPOS , 0L , MAKELONG( ctr +1, 0) ) ;

NM_UPDOWN nm_updown ;

nm_updown.hdr.hwndFrom = hCf1 ;
nm_updown.hdr.idFrom = IDC_CF1_UPDOWN3 ;

nm_updown.hdr.code = UDN_DELTAPOS ;
nm_updown.iPos = ctr + 1 ;
nm_updown.iDelta = 1 ;

SendMessage( hCf1 , WM_NOTIFY , IDC_CF1_UPDOWN3 , 
(LPARAM)&nm_updown );

DeleteObject( _hBitmap1728SEND ) ;

_hBitmap1728SEND = (HBITMAP)
CopyImage( (HBITMAP)_hBitmap1728 , IMAGE_BITMAP , 0 , 0 ,
LR_COPYRETURNORG ) ;
}

#endif

//-- マルチページの場合
//  EOM は モード変更ありのとき。(phase B へ戻る。)
//、MPS は モード変更なしのとき。(phase C へ戻る。)


/*
// SEND EOM
fprintf( fp1 , "EOM を送信しています。 \r\n" ) ;
WriteAsync( hModem1 , digitstring_toint8( 
"11111111" "11001000" "X1110001" // EOM
"00001000" "11000000"   // _DLE_ _ETX_
) , -1 , NULL , 20 ) ;

ttt = GetTickCount() ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;

if( ! pres->btrue )
fprintf( fp1 , "EOM に対する応答がありません。 \r\n" ) ;
else
fprintf( fp1 , "EOM OK (%d msec.) \r\n" , GetTickCount() - ttt ) ;

// SEND MPS
*/

fprintf( fp1 , "MPS を送信しています。 \r\n" ) ;
WriteAsync( hModem1 , digitstring_toint8( 
"11111111" "11001000" "X1110010" // MPS
"00001000" "11000000"   // _DLE_ _ETX_
) , -1 , NULL , 20 ) ;

ttt = GetTickCount() ;

pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 5000 , p_threadstop ) ;


// RECEIVE MCF
fprintf( fp1 , "MCF の要求を行います。\r\n" ) ;
WriteAsync( hModem1 , "AT+FRH=3\r" , -1 , NULL , 20 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3500 , p_threadstop ) ;


{   BOOL stop_ss = FALSE ;
if( pres->btrue )
{   const unsigned char *lp = pres->buf ;
lp = strchr( (char *)lp , 0xFF ) ;
if( lp ) { lp ++ ; if( *lp == 0x13 ) lp ++ ;
if( *lp != 0x8C ) {
fprintf( fp1 , "[%s] の代わりに [%s] を受け取った。%d msec. \r\n" , visdig( 0x8C ) , visdig( *lp) , GetTickCount() - ttt ) ;

if( *lp == 76 ) {
MessageBox( hAppWnd , "RTN を受信しました。本アプリケーションでは 再リトレーニング処理 を行いません。処理を中断します。" , "リトレーニング否定" , MB_OK | MB_SETFOREGROUND ) ;
}
stop_ss = TRUE ; }

} else stop_ss = TRUE ;
}
else stop_ss = TRUE ;

if( ! pres->btrue || stop_ss ){
fprintf( fp1 , "%s が正常に受信できない。 \r\n"
, "[MCF]" ) ;
//      Sleep( 250 ) ;
WriteAsync( hModem1 , "AT+FTH=3\r" , -1 , NULL , 20 ) ;
pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 1500 , p_threadstop ) ;

break ;
}
}



//

} // end multi pages ..

////////////////////////////////////////////
//  SEND        EOP
////////////////////////////////////////////

SbarSetText( 1 , "終了処理をしています..." ) ;

SbarSetText( 0 , "Send EOP" ) ;

/*
fprintf( fp1 , "EOP の送信準備です。 \r\n" ) ;
{
int iretry = 0 ;
while( iretry ++ < 10 &&
WriteAsync( hModem1 , "AT+FTH=3\r" , -1 , NULL , 20 )) {
for( DWORD endtime = GetTickCount() + 2000 ; GetTickCount() < endtime ; ) ;
fprintf( fp1 , fmt( "%d 回目の試行 \r\n" , iretry )) ;
SbarSetText( 0 , fmt( "Send EOP %d 回目" , iretry + 1 )) ;
}
}

pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 3000 , p_threadstop ) ;
*/

fprintf( fp1 , "EOP を送信しています。 \r\n" ) ;

WriteAsync( hModem1 , digitstring_toint8( 
"11111111" "11001000" "X1110100" // EOP
"00001000" "11000000"   // _DLE_ _ETX_
) , -1 , NULL , 20 ) ; 

ttt = GetTickCount() ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 5000 , p_threadstop ) ;
if( ! pres->btrue )
fprintf( fp1 , "EOP に対する応答がありません。 \r\n" ) ;
else
fprintf( fp1 , "EOP OK (%d msec.) \r\n" , GetTickCount() - ttt ) ;

SbarSetText( 0 , "Recieve MCF" ) ;
fprintf( fp1 , " \r\n" ) ;

// RECEIVE MCF .. 送信データが小さい場合は MCF をちゃんと返すが、
//                  少し大きいデータだと、RTN を返す...
// 結論。送信データの形式がおかしかった。
// EOL data EOL EOL data EOL  .... 誤り
// EOL data EOL data EOL data .... 正しい。

fprintf( fp1 , "MCF の要求を行います。\r\n" ) ;
WriteAsync( hModem1 , "AT+FRH=3\r" , -1 , NULL , 20 ) ;
ttt = GetTickCount() ;
pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;


{   BOOL stop_ss = FALSE ;
if( pres->btrue )
{   const unsigned char *lp = pres->buf ;
lp = strchr( (char *)lp , 0xFF ) ;
if( lp ) { lp ++ ; if( *lp == 0x13 ) lp ++ ;
if( *lp != 0x8C ) {
fprintf( fp1 , "[%s] の代わりに [%s] を受け取った。%d msec. \r\n" , visdig( 0x8C ) , visdig( *lp) , GetTickCount() - ttt ) ;
if( *lp != 76 )
stop_ss = TRUE ; }

} else stop_ss = TRUE ;
}
else stop_ss = TRUE ;

if( ! pres->btrue || stop_ss ){
fprintf( fp1 , "%s が正常に受信できない。 \r\n"
, "[MCF]" ) ;
}
}


SbarSetText( 0 , "Send DCN" ) ;
fprintf( fp1 , "DCN の送信準備です。 \r\n" ) ;

WriteAsync( hModem1 , "AT+FTH=3\r" , -1 , NULL , 20 ) ;

pres = WaitForExpectedResponse( hModem1 , "\r\nCONNECT\r\n" , 1000 , p_threadstop ) ;

fprintf( fp1 , "DCN を送信しています。 \r\n" ) ;

WriteAsync( hModem1 , digitstring_toint8( 
"11111111" "11001000" "X1011111" // DCN
"00001000" "11000000"   // _DLE_ _ETX_
) , -1 , NULL , 20 ) ; 

pres = WaitForExpectedResponse( hModem1 , "\r\nOK\r\n" , 3000 , p_threadstop ) ;


SbarSetText( 0 , "Hang up" ) ;
fprintf( fp1 , "手順を終了しました。 \r\n" ) ;

if( hModem1 && hModem1 != INVALID_HANDLE_VALUE ) {
WriteDropOperation( hModem1 ) ;
CloseHandle( hModem1 ) ; hModem1 = NULL ; }


SbarSetText( 1 , "手順終了" ) ;
}

th_return ;
}




VOID FAR PASCAL
tapi_lineCallback
( DWORD hDevice , DWORD dwMsg ,DWORD dwCallbackInstance ,
DWORD dwp1 ,DWORD dwp2 ,DWORD dwp3 )
{
LONG lret ;

// fprintf( fp1 ,"this is test \r\n" ) ;

switch( dwMsg )
{
case LINE_CREATE :

// dwp1 == dwDeviceID of newly established device

fprintf( fp1 , "LINE_CREATE \r\n" ) ;
break ;

case LINE_CLOSE : // forcibly closed

MessageBox( NULL , "line forcibly closed" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;
fprintf( fp1 , "ラインが強制的に切断されました。 \r\n" ) ;

WriteDropOperation( hModem1 ) ;

break ;

case LINE_GENERATE : // MessageBox( NULL , ( LINEGENERATETERM_CANCEL == dwp1 ) ?            "LINE_GENERATE 失敗" : "LINE_GENERATE" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;
break ;

case LINE_REPLY :

if( 0 == (LONG)dwp2 ) // (LONG) にキャストしなくてはいけないらしい。
fprintf( fp1 , "正常な LINE_REPLY ( ReqID : 0x%x ) " , dwp1 ) ;
else {

// call unavail 0x80000005 , allocated    0x80000001

MessageBox( NULL , "LINE_REPLY が エラーコードを返しました。" , tapiFormatMessage( dwp2 ) , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
fprintf( fp1 , "LINE_REPLY ( ReqID は 0x%x ) の受け取り時、エラー : %s " , dwp1 , tapiFormatMessage( dwp2 ) ) ;

WriteDropOperation( hModem1 ) ;

/*
pClassTAPI->Drop() ;
pClassTAPI->CallValidate( FALSE ) ;
*/
}

break ;

case LINE_ADDRESSSTATE :
fprintf( fp1 , "LINE_ADDRESSSTATE \r\n" ) ;
break ;
case LINE_CALLINFO :
// これも、他のアプリが使うとくる。// see LINECALLSTATE_UNKNOWN 
MessageBox( NULL , "LINE_CALLINFO" , "ok" , MB_OK | MB_SETFOREGROUND ) ;
break ;
case LINE_REMOVE :
MessageBox( NULL , "device removed ?" , "LINE_REMOVE を受け取った。" , MB_OK | MB_SETFOREGROUND | MB_ICONQUESTION ) ;
fprintf( fp1 , "TAPI コールバック関数より、LINE_REMOVE を受け取る。 \r\n" ) ;

if( hLine ) { lineClose( hLine ) ; hLine = NULL ; }

break ;

case LINE_LINEDEVSTATE :
MessageBox( NULL , "LINE_LINEDEVSTATE" , "ok" , MB_OK | MB_SETFOREGROUND ) ;
break ;

case LINE_REQUEST :
MessageBox( NULL , "LINE_REQUEST" , "ok" , MB_OK | MB_SETFOREGROUND ) ;
break ;

case LINE_GATHERDIGITS : break ;

case LINE_CALLSTATE :
switch( dwp1 )
{   case LINECALLSTATE_IDLE     :

fprintf( fp1 , "待機中 IDLE 状態です。 \r\n" ) ;
MessageBox( NULL , "status IDLING ..." , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;

break ;
case LINECALLSTATE_OFFERING :
MessageBox( NULL , "LINECALLSTATE_OFFERING" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;
break ;

case LINECALLSTATE_ACCEPTED :
MessageBox( NULL , "LINECALLSTATE_ACCEPTED" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;


break ;

case LINECALLSTATE_DIALTONE :

MessageBox( NULL , "ダイアルトーンを確認しました。 \r\n" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;

break ;

case LINECALLSTATE_DIALING  :

fprintf( fp1 , "LINECALLSTATE_DIALING \r\n" ) ;

//Edit_ReplaceSel( hLog , "ダイアルしてください。 \r\n" ) ;


break ;

case LINECALLSTATE_RINGBACK :
MessageBox( NULL , "RINGBACK" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;
break ;

case LINECALLSTATE_BUSY :
MessageBox( NULL , "BUSY です。" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;

WriteDropOperation( hModem1 ) ;

break ;

case LINECALLSTATE_CONNECTED :

fprintf( fp1 , "接続が確認された。 \r\n" ) ;
MessageBox( NULL , "connect caught !!" , "" , MB_OK | MB_SETFOREGROUND ) ;

break ;

case LINECALLSTATE_PROCEEDING :

fprintf( fp1 , "PROCEEDING... \r\n" ) ;

/*
{  char msgbuf[256] ;
wsprintf( msgbuf , "PROCEEDING...。( ReqID 0x%x ) \r\n" , dwp1 ) ;
Edit_ReplaceSel( hLog , msgbuf ) ;
}

lret = pClassTAPI->GetModemHandle( pClassTAPI->hCall ) ;

{  char msgbuf[256] ;
if( lret )
{
MessageBox( NULL , "コネクションが成立したがモデムのハンドルが取得できない。" , "エラー", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
wsprintf( msgbuf , ERR_FORMAT , lret , lret ) ;
}
else wsprintf( msgbuf , "MODEM HANDLE retrieved OK. \r\n" ) ;

Edit_ReplaceSel( hLog , msgbuf ) ;
}
*/

break ;

case LINECALLSTATE_ONHOLD :
case LINECALLSTATE_CONFERENCED :
case LINECALLSTATE_ONHOLDPENDCONF :
case LINECALLSTATE_ONHOLDPENDTRANSFER :
MessageBox( NULL , "?" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;
break ;


case LINECALLSTATE_DISCONNECTED :

fprintf( fp1 , "切断 \r\n" ) ;

WriteDropOperation( hModem1 ) ;

// The remote party has disconnected from the call. 
break ;

case LINECALLSTATE_UNKNOWN :

// 他のアプリが使うと、くる。 see LINE_CALLINFO
MessageBox( NULL , "LINECALLSTATE_UNKNOWN" , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;

break ;

default :
MessageBox( NULL , "予期しない LINECALLSTATE メッセージ" , "ok(?)" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
break ;

}

break ;

default :
MessageBox( NULL , "othre message." , "ok" , MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ) ;
break   ;
}

return ;
}


void SetCommTimeoutProperties( HANDLE hAsync , int intto , int totto )
{

COMMPROP commprop ; ZeroMemory( &commprop , sizeof( COMMPROP )) ;

if( ! GetCommProperties( hAsync , &commprop ))
fprintf( fp1 , "タイムアウト設定のために ポートのプロパーティを取得しようとしたが関数 GetCommProperty() が失敗した。 \r\n" ) ;

fprintf( fp1 , "トータルタイムアウトは %s \r\n" ,
( commprop.dwProvCapabilities & PCF_TOTALTIMEOUTS )
? "サポートされています。" : "サポートされていません。" ) ;

fprintf( fp1 , "インターバルタイムアウトは %s \r\n" ,
( commprop.dwProvCapabilities & PCF_INTTIMEOUTS )
? "サポートされています。" : "サポートされていません。" ) ;

COMMTIMEOUTS to_ ; ZeroMemory( &to_ , sizeof( to_ )) ;
if( commprop.dwProvCapabilities & PCF_INTTIMEOUTS )
to_.ReadIntervalTimeout = intto ; // 100 ;

if( commprop.dwProvCapabilities & PCF_TOTALTIMEOUTS )
to_.ReadTotalTimeoutMultiplier = totto ; // 一文字分の時間

if( commprop.dwProvCapabilities &
( PCF_INTTIMEOUTS | PCF_TOTALTIMEOUTS ))
SetCommTimeouts( hAsync , &to_ ) ;


return ;
}


MDM_RESPONSE *WaitForExpectedResponse
( HANDLE hAsync , char *szstr , DWORD total_timeout ,
void *stop )
{

int msg_interval = 50 ;

static MDM_RESPONSE res ;

ZeroMemory( &res , sizeof( MDM_RESPONSE ) ) ;

DWORD total_end ; // 終了予定時刻 ( バッファを受け取ることにより延長される。)
DWORD last_recv = 0L ; // 最後にバッファを受け取った時刻

// static std::string s ;
#define MAX_RETBUF 4096
static char retbuf[MAX_RETBUF] ; res.buf = retbuf ;

COMSTAT cs ;

fprintf( fp1 , "読み込みループの開始です。 \r\n" ) ;

total_end = GetTickCount() + total_timeout ;

// total_timeout とはしてみたが、inttimeout_message , 各メッセージ間のインターバル。


// s.clear() ;
memset( retbuf , 0 , MAX_RETBUF ) ;
char *lp_retbuf = retbuf ;

while( ( ! stop || ! ( *(int *)stop  ))
&& (( GetTickCount() < total_end ) ? TRUE : ( res.timeout = TRUE , FALSE )  )
&& res.ibufsize < MAX_RETBUF - 1 )
{
DWORD dwError = 0L ; ZeroMemory( &cs , sizeof( COMSTAT )) ;
ClearCommError( hAsync , &dwError , &cs ) ;

if( cs.cbInQue )
{
if( dwError ) fprintf( fp1 , "ポート の状態がエラー。 ERROR STATE 0x%x \r\n" , dwError ) ;

if( cs.cbInQue )
{
OVERLAPPED ovlap  ;
memset( &ovlap , 0,sizeof( ovlap)) ;
ovlap.hEvent = CreateEvent( NULL , TRUE , FALSE , NULL ) ;

DWORD dwBytes = 0 ;
char buffer[256] ;
memset( buffer , 0 , sizeof( buffer )) ;

if( 0 == ReadFile( hAsync , buffer ,
min( (unsigned int)cs.cbInQue , sizeof( buffer )) ,
&dwBytes  , &ovlap ))
{   dwBytes  = 0 ;

if( ERROR_IO_PENDING == GetLastError())
{   DWORD endtime = GetTickCount() + 500 ;
while( ! GetOverlappedResult
(  hAsync, &ovlap , &dwBytes  , FALSE ))
if( GetTickCount() > endtime ) break ;
}
else GetLastError() ;
}

if( dwBytes  )
{
unsigned char *lpbuffer = buffer ;
unsigned char cbu ;

while( dwBytes  -- ) {
char msgbuf[256] ; cbu = *lpbuffer ;

// s.append( (*lpbuffer) ? (char *)lpbuffer : "\\" , 1 ) ;
*lp_retbuf ++ = *lpbuffer ;
res.ibufsize ++ ;

char a1[2]     ; 
*(a1+1) = '\0' ; 
char *la1 = a1 ;

if( cbu == '\r' ) la1 = "<cr>" ;
else if( cbu == '\n' ) la1 = "<lf>" ;
else if( cbu == 0x7E ) la1 = "0x7E HDLC" ;
else la1 = G3digits( cbu ) ;


static std::string outbuf ;

wsprintf( msgbuf ,
"%s (%-7s) [%c %d 0x%x] \r\n" , visdig( cbu  ), la1 , cbu && cbu != '\r' && cbu != '\n' ? cbu : '\\' , cbu , cbu ) ; 
outbuf += msgbuf ;

fprintf( fp1 , msgbuf ) ;
fflush( fp1 ) ;


if( cbu == '\n' ) {

// Edit_ReplaceSel( hEdit ,  outbuf.c_str() ) ;

outbuf.clear() ;
}

lpbuffer ++ ;


total_end = ( last_recv = GetTickCount() ) + total_timeout ;
if( ! last_recv ) last_recv = 1 ; // 安全。

if( res.ibufsize == MAX_RETBUF - 1 ) {
if( dwBytes )
fprintf( fp1 , "受信サイズが大きいため情報の一部 %d bytes を取りこぼした。 \r\n" , dwBytes ) ;

break ;
}
// 読み込みが行われると、total_timeout を延長。
}
}
else
fprintf( fp1 , "キューの内容を読み込めなかった \r\n" ) ;

ResetEvent( ovlap.hEvent ) ;
}
else { // if( ! cbInQue...) 
}
} // 
if( last_recv != 0
&& last_recv + msg_interval < GetTickCount() )
{
res.nmsgs ++ ;
last_recv = 0 ;

if( strlen( szstr) <= (DWORD)res.ibufsize &&
//                  res.ibufsize - strlen( szstr ) == s.rfind( szstr , -1 ))
! strcmp( szstr , res.buf + res.ibufsize - strlen(szstr) ))
{
// s.clear() ;
res.btrue    = TRUE ; break ;
}
else if( strlen( "\r\nERROR\r\n" ) <= (DWORD)res.ibufsize &&
//                  s.size() - strlen( "\r\nERROR\r\n" ) == s.rfind( "\r\nERROR\r\n" , -1 ))
! strcmp( "\r\nERROR\r\n" , res.buf + res.ibufsize - strlen("\r\nERROR\r\n") ))
{
res._ERROR_ = TRUE ; break ;
}
}

}

PurgeComm( hAsync , PURGE_RXCLEAR ) ;

// res.ibufsize = s.size() ;

{   char *msgfmt = "読み込みループの終了です。 断続的に読んだ回数 %d %s" ;
char add_msg[256] ; char *lp_add_msg ;

if( res.timeout ) 
wsprintf( (lp_add_msg = add_msg) , "( タイムアウトによる終了 (%d ms.) ) \r\n" , total_timeout ) ;
else
if( res._ERROR_ )
wsprintf( (lp_add_msg = add_msg) , "( ERROR リザルトコードによる終了 ) \r\n"  ) ;
else
if( stop && *(int *)stop )
wsprintf( (lp_add_msg = add_msg) , "( 強制中断 ) \r\n"  ) ;
else lp_add_msg = "\r\n" ;

fprintf( fp1 , msgfmt , res.nmsgs , lp_add_msg ) ;


// fprintf( fp1 , s.c_str() ) ;
fflush( fp1 ) ;
}

// res.buf = s.c_str() ;

return &res ;
}

BOOL DtrOff( HANDLE hModem )
{   // DTR off によるハードウェア切断
BOOL ret ;
if( ! hModem ) return FALSE ;

fprintf( fp1 , "ダイアル中に中止ボタンが押されたため、DTR オフ によるハードウェア切断を行います。..." ) ;
if( FALSE ==
( ret = EscapeCommFunction( hModem1 , CLRDTR )))
fprintf( fp1 , "失敗 ! \r\n" ) ;
else {
KillTimer( hAppWnd , TIMER_CONNECTDURATION ) ; \
SbarSetText( 0 , "切断しました。" ) ;

fprintf( fp1 , "成功 \r\n" ) ;
}


return ret ;
}

BOOL WriteDropOperation( HANDLE hModem )
{   
char *disconnect_command = "ATH0\r" ;
DWORD dwBytes ;

if( ! hModem || hModem == INVALID_HANDLE_VALUE ) {
fprintf( fp1 , "モデムのハンドル == %d のため、切断コマンド ATH0 の書き込みは行いませんでした。 \r\n" , hModem ) ;
return TRUE ;
}

WriteAsync( hModem , disconnect_command , -1 , &dwBytes , 1000 ) ;

MDM_RESPONSE *res =
WaitForExpectedResponse
( hModem , "\r\nOK\r\n" , 5000 , NULL ) ;

if( res->timeout ) {
MessageBox( NULL , "切断コマンドに対してモデムの応答がありません。" , "失敗" , MB_OK | MB_SETFOREGROUND | MB_ICONSTOP ) ;
fprintf( fp1 , "切断コマンド %s に対してモデムの応答なし。 \r\n" , "ATH0" ) ;
}
Sleep( 500 ) ;

if( ! res->btrue ) return FALSE ;

return TRUE ;
}


DWORD SendOneLineProc
( char *plainbitstr , DWORD dwp1 , DWORD dwp2 )
{   // plainbitstr は 1 ライン分。
// dwp1 HIWORD = y , LOWORD = x
// dwp2 HIWROD = ymax , LOWORD = xmax

char bitstr_[2048] ; // 0と1 の文字列。
memset( bitstr_ , 0 , sizeof( bitstr_ )) ;
char *lp_bitstr_ ;

assert( sizeof( bitstr_ ) == 2048 ) ;

static char sendbuffer[2048] ; memset( sendbuffer , 0 , sizeof( sendbuffer )) ;

lp_bitstr_ = stpcpy( bitstr_ , "00000000" "0001" ) ; // BOL だが == EOL


#ifndef TRIANGLECHECK64
G3MHasBITSTR1728
( lp_bitstr_ , plainbitstr ,
sizeof( bitstr_ ) - strlen( bitstr_ )) ;
#else
{   int line = HIWORD(dwp1 ) ;
lp_bitstr_ = stpcpy( lp_bitstr_ , W_str(32) )  ;
lp_bitstr_ = stpcpy( lp_bitstr_ , B_str(line+1) ) ;
lp_bitstr_ = stpcpy( lp_bitstr_ , B_remainder(line+1) ) ;
lp_bitstr_ = stpcpy( lp_bitstr_ , W_str(1728-line-1-32) ) ;
lp_bitstr_ = stpcpy( lp_bitstr_ , W_remainder(1728-line-1-32) ) ;

}
#endif

//if( fp_mhbits ) { fprintf( fp_mhbits , "--" ) ;
//fprintf( fp_mhbits , bitstr_ ) ; }

// 面倒なので , 8 こ以上 0 をつける。( DLE の検出が正しく行われるために。)
lp_bitstr_ += strlen( lp_bitstr_ ) ;
lp_bitstr_ = stpcpy( lp_bitstr_ , "00000000" ) ;
while( (lp_bitstr_ - bitstr_ ) % 8) *lp_bitstr_ ++ = '0' ;


if( strstr( bitstr_ , "00001000" )) {
//if( fp_mhbits ) {
//fprintf( fp_mhbits , " [ cnt. <DLE> ]" ) ;
//Edit_ReplaceSel( hEditLog , "<DLE> detected \r\n" ) ; }

// doubles <DLE>
for( char *lpdle = strstr( bitstr_ , "00001000" ) ;
lpdle ; lpdle = strstr( lpdle , "00001000" ) )
{   if( (lpdle - bitstr_ ) % 8 ) { lpdle ++ ; continue ; }
memmove( lpdle + 8 , lpdle , strlen( lpdle ) ) ;
if( strncmp( lpdle , "00001000" , 8 ))
memcpy( lpdle , "00001000" , 8 ) ; lpdle += 16 ;
}
}

// if( fp_mhbits ) fprintf( fp_mhbits , "\r\n" ) ;



memcpy( sendbuffer  ,
digitstring_toint8( bitstr_ ) ,
strlen( bitstr_ ) / 8 + 1 ) ;

//int n_zeropad_bytes = 24 ; // 80 bytes = 9600 bps で、0.066 秒分。66 msec. > 20 msec .
// 24 bytes for 20 msec in 9600 bps.

int n_zeropad_bytes = 0 ;
if( ( dis.speed_settled * dis.min_tsm_fine ) % 8000 )
n_zeropad_bytes ++ ;

n_zeropad_bytes += dis.speed_settled * dis.min_tsm_fine / 8 / 1000 ;

n_zeropad_bytes -= ( strlen( bitstr_ ) / 8 + 1 ) ;
if( n_zeropad_bytes < 0 ) n_zeropad_bytes = 0 ;

if( n_zeropad_bytes )
memset( sendbuffer + strlen( bitstr_ ) / 8 + 1 ,
0 , n_zeropad_bytes )  ; // zero-padding している。

int nEol = 1 ;  // やっぱり 2 だとだめ。
// 1 だと、ひしゃげる。== それで OK !

if( HIWORD( dwp1) == HIWORD(dwp2 ) -1 ) nEol += 13 - nEol ; // RTC + DLE + ETX を付加する場合。

memcpy( sendbuffer + strlen( bitstr_ ) / 8 + 1 + n_zeropad_bytes ,
digitstring_toint8( 
"00000000" "00000001" "00000000" // nEol = 3 の場合はこの3つだけとなる。
"00010000" "00000001" "00000000" 
"00010000" "00000001" "00000000" "00010000"
"00000001"
"00001000" "11000000" // DLE ETX

) , nEol ) ;

int cbOneLine =
strlen( bitstr_ ) / 8 + 1 + n_zeropad_bytes + nEol ;

// EOL 付加。次の送信に備えるため、NULL も付加。
#ifdef MHCHECKINGMODE
// 黒1728 を利用する場合。
{   // this is test for black1728 (w0b1728) you can see the effect of 副走査線 (sub scan line)
memcpy( sendbuffer + cbOneLine ,
digitstring_toint8( "00000001" "00110101" "00000011" "00101000" "0110111" "0" ) , 5 ) ;
cbOneLine += 5 ;
}
/*  // 白1728 を利用する場合。
{ // this is for white1728
memcpy( sendbuffer + cbOneLine ,
digitstring_toint8( "00000001" "010011011" "00110101" "0000000" ) , 4 ) ;
cbOneLine += 4 ;
}*/

memset( sendbuffer + cbOneLine , 0 , n_zeropad_bytes ) ;
cbOneLine += n_zeropad_bytes ;
#endif


if( HIWORD(dwp1) == 0 )
fprintf( fp1 , "<CONNECT> から初回書き込みまで %d msec. " , GetTickCount() - dwLastSendTime ) ;
else {
if( dwmode & LOG_IMAGE_TRANSMISSION )
fprintf( fp1 , "前回書き込みから今回書き込みまで %d msec. " , GetTickCount() - dwLastSendTime ) ;
}

dwLastSendTime = GetTickCount() ;

// ClearCommBreak( hModem1 ) ;

DWORD dwBytes ;
WriteAsync( hModem1 , sendbuffer 
, cbOneLine
, &dwBytes , 1000 ) ;

if( dwmode & LOG_IMAGE_TRANSMISSION )
{ fprintf( fp1 , "書き込みに要した時間 %d msec.(%d/%d) \r\n" ,  GetTickCount() - dwLastSendTime , dwBytes ,cbOneLine ) ; }

//Sleep( 100) ; ←アウト。

dwLastSendTime = GetTickCount() ;


{   int lineno = HIWORD(dwp1) ;

int curpos = SendMessage( hProgress1 , PBM_GETPOS ,0 ,0 ) ;

//  if( ! ( (lineno +1)% 8 )) // ← lineno % 8 だったが、ノーマルモードのときは一行おきにくるので、奇数となるので、+1 を追加。
if( (lineno+1) - curpos > 8 )
SendMessage( hProgress1 , PBM_SETPOS , lineno+1 , 0L ) ;

}


//if( nEol == 2 )
// { fprintf( fp1 , "確認 ! \r\n" ) ;
//   if( *(sendbuffer + dwBytes -1 ))
//fprintf( fp1 , "OK です。確認 ! \r\n" ) ;
//else
//fprintf( fp1 , "エラー!! 確認 ! \r\n" ) ;
// }

return 1L ;
}



char *GetBinaryArrayAsStringFromBitmap
( HBITMAP hbitmap1728 , DWORD (*pfunc)( char *, DWORD , DWORD )
, void *pstop )
{
// 関数名の由来の役割は szret が果たす。
// 関数名と少し趣を異にするが、走査も行う。

/*
char path[256] ;
GetModuleFileName( NULL , path , 256 ) ;

Edit_ReplaceSel( hEditLog , path )  ; Edit_ReplaceSel( hEditLog , "\r\n" )  ;
char *lppath   = strrchr( path , '\\' ) + 1 ;
if( ! lppath ) {
Edit_ReplaceSel( hEditLog , "ファイル名が合成できない ! \r\n" )  ;
return NULL ;
}

*stpcpy( lppath , "bitstr.txt" ) = '\0' ;

fp_bits = fopen( path , "wb" ) ;

*stpcpy( lppath , "mhbitstr.txt" ) = '\0' ;
fp_mhbits = fopen( path , "wb" ) ;

if( ! fp_bits || ! fp_mhbits ) {
Edit_ReplaceSel( hEditLog , "ファイルが開けない ! \r\n" )  ;
return NULL ;
} else Edit_ReplaceSel( hEditLog , path )  ;
Edit_ReplaceSel( hEditLog , "\r\n" )  ;
*/

HDC hdc ;
static char szret[2048] ;
HDC     hdc_mem ;

/*

hbitmap1728 =
(HBITMAP)
CopyImage( (HBITMAP)hbitmap1728 , IMAGE_BITMAP , 0 , 0 ,
LR_COPYRETURNORG ) ;
*/

int error_skip_flag = 0 ;

int xpix = 1728 , ypix = 297 * 4 * 2 ;

// line counts per page !!


hdc = GetDC( hEdit  ) ;

hdc_mem  = CreateCompatibleDC( hdc ) ;

ReleaseDC( hEdit , hdc ) ;


// 幅 xpix , 高さ ypix のキャンバスビットマップを用意
// ( == G3Fax A4 サイズ : xpix = 1728 )


if( ! SelectObject( hdc_mem , hbitmap1728 )) {
#ifdef DEBUG
//Edit_ReplaceSel( hEditLog , "hdc_mem に SelectObject するのに失敗。\r\n" )  ;
#endif
error_skip_flag |= 0x2 ;
}

#ifdef MHCHECKINGMODE
{   StretchBlt( hdc_mem , 0 , 0 , 1728 , 297 * 4 ,

hdc_mem, 0 , 0 , 1728 , 297 * 4 * 2 , SRCCOPY ) ;
}
#endif


int xmax = xpix ;

#ifdef MHCHECKINGMODE
int ymax = ( partial_mm == -1 || ! IsDlgButtonChecked( hCf1 , IDC_CF1_CHECK_PARTIALMM ) )
? 297 * 4 : min( 297 , partial_mm ) * 4 ; // 4 /* *2 */; //128 ; // 走査 max ;
#else
int ymax = ( partial_mm == -1 || ! IsDlgButtonChecked( hCf1 , IDC_CF1_CHECK_PARTIALMM ) )
? 297 * 4 * 2 : min( 297 , partial_mm ) * 4 * 2 ;
#endif

#ifdef TRIANGLECHECK64
ymax = 64 ;
#endif


fprintf( fp1 , "幅:%d ピクセル 長さ:%d ピクセル で印刷します。 \r\n" , xmax, ymax ) ;

BOOL b_fine_mode = IsDlgButtonChecked( hCf1 , IDC_CF1_FINE_OR_NORMAL )
? TRUE : FALSE ;

fprintf( fp1 , "%s モードです。 \r\n" , b_fine_mode ? "ファイン(7.7本/mm)" : "ノーマル(3.85本/mm)" ) ;

{   char szface[256] ; // GetTextFace( hdc_mem , 256 , szface ) ; == "System"
GetDlgItemText( hCf1 , IDC_CF1_SELECTFONT , szface , 128 ) ;
int ipt = GetDlgItemInt( hCf1 , IDC_CF1_FONTSIZE , NULL , TRUE ) ;

time_t tim ; time( &tim ) ;
tm *pltim  ; pltim = localtime( &tim ) ;
char szout[512] ;

if( dwmode & NMAXPAGE_VALID )
wsprintf( szout , "%s ,%d : %s , page %d/%d" , szface , ipt , asctime( pltim ) , nCurpage+1 , nMaxpage ) ;
else
wsprintf( szout , "%s ,%d : %s , page %d/-" , szface , ipt , asctime( pltim ) , nCurpage+1 ) ;


TextOut( hdc_mem , 864 , 0 , szout , strlen( szout )) ;

if( nCurpage == 0 )
wsprintf( szout , "発信者番号:%s (※この番号は、発信者が本ソフトウェアを通じて任意に設定した番号です。"
"回線により提供される発信者番号通知等のサービスによるものではありません。) PERFORMED & PRINTED by %s" ,
add_mes.user_number , app_name ) ;

TEXTMETRIC txm ; ZeroMemory( &txm , sizeof( TEXTMETRIC )) ;
GetTextMetrics( hdc_mem , &txm ) ;
TextOut( hdc_mem , 64 , txm.tmHeight + txm.tmExternalLeading , szout , strlen( szout )) ;

wsprintf( szout , "発信者氏名 : %s       Note :%s" , add_mes.user_name , add_mes.user_memo ) ;
TextOut( hdc_mem , 64 , 2 * (txm.tmHeight + txm.tmExternalLeading) , szout , strlen( szout )) ;

}

COLORREF bkcolor = GetBkColor( hdc_mem ) ;

/*
#ifdef DEBUG
{   char msg[256] ; wsprintf( msg ,
"背景色は = R %x G %x B %x + %x" , GetRValue(bkcolor) , GetGValue(bkcolor) , GetBValue(bkcolor) , ((BYTE) ((bkcolor) >> 24 ))  ) ;
Edit_ReplaceSel( hEditLog , msg )  ;
Edit_ReplaceSel( hEditLog , "\r\n\r\n" )  ;
}
#endif
*/


SbarSetText( 0 , "ビットデータを送信しています。..." ) ;
fprintf( fp1 , "(MH) ビットデータ を送信しています。 \r\n" ) ;

SendMessage( hProgress1 , PBM_SETRANGE , 0 ,
MAKELPARAM( 1, ymax ) ) ;

int bits_start_time = connection_duration ;

// ループ始まり。
if( ! error_skip_flag )
for( int y = 0 ; y < ymax ; ( y < 65 || b_fine_mode || y == ymax - 2 ) ? y ++ : y += 2 ) {
char sz_line[2048] ; memset( sz_line , 0, sizeof( sz_line )) ;
char *lp_line = sz_line ;
int outofrgn = 0 ;

int x ; 
for( x = 0 ; x < xmax ; x ++ ) {

COLORREF clr = GetPixel( hdc_mem , x , y ) ;

/*
if( x < 64 )
fprintf( fp_bits , "( %x %x %x %x) " , GetRValue(clr) , GetGValue(clr) , GetBValue(clr) , ((BYTE) ((clr) >> 24 ))  ) ;
else if( clr != 0L && clr != CLR_INVALID )
fprintf( fp_bits , " _OK_ ! ( %x %x %x %x) " , GetRValue(clr) , GetGValue(clr) , GetBValue(clr) , ((BYTE) ((clr) >> 24 ))  ) ;

if( x == xmax -1 ) fprintf( fp_bits , "\r\n" ) ;
*/

if( clr == CLR_INVALID ) {

*lp_line ++ = 'x' ; outofrgn |= 0x1 ; break ; }
else
*lp_line ++ = ( clr == bkcolor ) ? '0' : '1' ;
}

if( pfunc ) {
// 一行毎の処理を pfunc で行う。
if( ! (*pfunc)( sz_line ,
MAKEWPARAM( x , y ) , MAKEWPARAM( xmax , ymax ) ))
break ;
}

if( *(int *)pstop ) {
fprintf( fp1 , "line %d(/%d) で中断しました。 \r\n" , y+1, ymax) ;

*(int *)pstop = 0 ;

WriteAsync( hModem1 , digitstring_toint8( 
"00000000" "00000001" "00000000"
"00010000" "00000001" "00000000" 
"00010000" "00000001" "00000000" "00010000"
"00000001"
"00001000" "11000000" )
, 13 , NULL , 500 ) ; // RTC( 6 * EOL ) + DLE ETX

// この後の read loop を最後まで完遂するため。
break ;
}

time_rest = ( connection_duration == bits_start_time ) ? -1 :
MulDiv( ( ymax - y - 1 ) , ( connection_duration - bits_start_time ) , ( y + 1 ) ) ;


}

DeleteDC( hdc_mem )  ;

// assert( hbitmap1728 == _hBitmap1728SEND ) ;
DeleteObject( _hBitmap1728SEND ) ;
_hBitmap1728SEND = NULL ; // ここはこれでいい。

#undef DEBUG

/*
fclose( fp_bits ) ; fp_bits = NULL ;
fclose( fp_mhbits ) ; fp_mhbits = NULL ;
*/

return szret ;
}

///////////////////////

BOOL CommStat()
{   DWORD dwError = 0L ; COMSTAT comstat ;
ZeroMemory( &comstat , sizeof( COMSTAT )) ;
BOOL ret = ClearCommError( hModem1 , &dwError , &comstat ) ;
fprintf( fp1 , "エラーフラグ 0x%x %s \r\n" , dwError ,
ret ? "" : "(関数は失敗している。)" ) ;
if( comstat.fCtsHold )
fprintf( fp1 , "送信が待機中。CTS(clear-to-send) 待ち \r\n" ) ;
if( comstat.fDsrHold )
fprintf( fp1 , "送信が待機中。DSR(data-set-ready) 待ち \r\n" ) ;
if( comstat.fRlsdHold )
fprintf( fp1 , "送信が待機中。RLSD 待ち \r\n" ) ;
fprintf( fp1 , "(0x%x) cbInQue : %d cbOutQue : %d \r\n"
, *(DWORD *)&comstat ,comstat.cbOutQue , comstat.cbInQue ) ;

return ret ;
}


void GetComPortByModelFromRegistry( char *ModemModelName , char *ret )
{
// WIN NT で、98 の互換モードのとき、GetVersionEx では , 98 を返すことがあるので、GetVersionEx は使わない。
// モデムのモデルネームから、接続されている COM ポートと得る。

*ret = '\0' ;

HKEY hkey ;

// char cType = 0 ;
std::string s_base ;

if( RegOpenKeyEx( HKEY_LOCAL_MACHINE ,
( s_base = "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96D-E325-11CE-BFC1-08002BE10318}"
).c_str(), 0, KEY_READ, &hkey ) == ERROR_SUCCESS ) // これがあると、NT 系ということ。NT で WIN98 互換で走らせると、osi...Id が、WIN98 になるので、osi での判別はやめる。
{   fprintf( fp1 , " レジストリ構成は WIN NT 系であると認識しました。 \r\n" ) ;
// cType = 1 ;
RegCloseKey( hkey ) ;
}
else
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE ,
( s_base = "SYSTEM\\CurrentControlSet\\Services\\Class\\Modem"
).c_str(), 0, KEY_READ, &hkey ) == ERROR_SUCCESS )
{   fprintf( fp1 , " レジストリ構成は WIN 95/98 系であると認識しました。 \r\n" ) ;
// cType = 2 ;
RegCloseKey( hkey ) ;
}
else {
fprintf( fp1 , " 予期しないレジストリ構成です。 COM ポート名を取得できません。 \r\n" ) ;
return ;
}

{   // ダミー中括弧
// まず、与えられた モデル名 が、000? のいくつ になるのかを得る。

hkey = NULL ; std::string s ;
int i_modem = -1 ;

for( int i = 0 ; i < 256 ; i ++ ) {
char sznum[16] ;
wsprintf( sznum , "\\%04d" , i ) ;
s = s_base + sznum ;

if( RegOpenKeyEx( HKEY_LOCAL_MACHINE ,
s.c_str(), 0, KEY_READ, &hkey ) == ERROR_SUCCESS )
{
char szData[256] ; ZeroMemory( szData , sizeof( szData )) ;
DWORD dwType = 0L , dwCount = sizeof( szData ) ;

RegQueryValueEx( hkey , "Model" , NULL , &dwType , szData , &dwCount ) ;
if( *szData && ! strcmp( szData , ModemModelName ))
{   i_modem = i ;
// ここで、AttachedTo は調べてしまう。
ZeroMemory( szData , sizeof( szData )) ;
dwType = 0L , dwCount = sizeof( szData ) ;

RegQueryValueEx( hkey , "AttachedTo" , NULL , &dwType , szData , &dwCount ) ;

if( *szData )
strcpy( ret , szData ) ;

// 慎重を期すなら PORTNAME も調べてしまってよいかもしれない。
// if( ! *szData ) ...

RegCloseKey( hkey ) ;   break ; }
RegCloseKey( hkey ) ;
}
} // end of "for"
if( i_modem == - 1 ) {
fprintf( fp1 , " 指定されたモデムの番号が取得できない。 \r\n" ) ;
return ;
}

if( *ret ) return ; // AttachedTo が発見され、COMx が得られた。

// 次に、その番号をもとに、キー AttachedTo 又は、PORTNAME を探す。
// @ Model が得られたレジストリ内で、AttachedTo を調べる。場合、i_modem はあまり関係ない。
// A 見つからない場合は、HKEY_LOCAL_MACHINE\\Enum 以下を全て調べ、キー Driver が、Modem\\000? になっているものと同じところに、キー PORTNAME を探し、値 (文字列)を得る。

// @ はもうやってしまった。

// A

std::string s_cmp( "Modem" ) ;
char _sznum[16] ;
wsprintf( _sznum , "\\%04d" , i_modem ) ;
s_cmp += _sznum ;

// すでに完成している s を利用しようと思ったが、
// NT の場合 Modem\\000? 形式でないからできない。注意せよ。

std::string relat_key_path( "Enum" ) ;

std::stack<std::pair<std::string, int > > stk1 ;
std::stack<HKEY> stk2 ;

int i1 =0 , i2 =0;

hkey = NULL ;
while( 1 ) {

int i_start = 0 ;

if( RegOpenKeyEx( HKEY_LOCAL_MACHINE , relat_key_path.c_str() , 0L, KEY_READ, &hkey )
== ERROR_SUCCESS ) {
i1 ++ ;
// fprintf( fp1 , " ○%s \r\n" , relat_key_path.c_str() ) ;

char szData[256] ; ZeroMemory( szData , sizeof( szData )) ;
DWORD dwType = 0L , dwCount = sizeof( szData ) ;

RegQueryValueEx( hkey , "Driver" , NULL , &dwType , szData , &dwCount ) ;
if( *szData && ! stricmp( szData , s_cmp.c_str() ) )
{   ZeroMemory( szData , sizeof( szData )) ;
dwType = 0L , dwCount = sizeof( szData ) ;

RegQueryValueEx( hkey , "PORTNAME" , NULL , &dwType , szData , &dwCount ) ;
if( *szData ) {
strcpy( ret , szData ) ;
break ;
}
}
} else          if( ! stk1.empty() ) {
// 通常はこの else の場合はない。なんらかの非常に稀な理由で、レジストリへのアクセスに失敗した場合。
fprintf( fp1 , " ×%s \r\n" , relat_key_path.c_str() ) ;

relat_key_path = stk1.top().first  ;
i_start   = stk1.top().second + 1 ;
stk1.pop() ;
hkey = stk2.top() ;
stk2.pop() ;
}
else break ;

for( int i = i_start ;; i ++ ) {
char szDest[256] ; 
DWORD dwSize = sizeof( szDest ) ; FILETIME f_time ;
if( RegEnumKeyEx( hkey , (DWORD)i , szDest , &dwSize , NULL , NULL , NULL , &f_time )
== ERROR_SUCCESS )
{   stk1.push( std::pair<std::string,int>( relat_key_path , i ) ) ;
stk2.push( hkey ) ;
relat_key_path += "\\" ;
relat_key_path += szDest ;
break ;
}
else // may be ERROR_NO_MORE_ITEMS
{
if( ! stk1.empty() ) { i2 ++ ;
// fprintf( fp1 , " ●%s 開放しました。 \r\n" , relat_key_path.c_str() ) ;
RegCloseKey( hkey ) ;

relat_key_path = stk1.top().first  ;
i = stk1.top().second ;
stk1.pop() ;
hkey = stk2.top() ;
stk2.pop() ;
}
else break ;
}
} // end of "for"

if( stk1.empty()) break ;
}

if( hkey ) { RegCloseKey( hkey ) ; i2 ++ ;
// fprintf( fp1 , " ◎%s 開放しました。 \r\n" , relat_key_path.c_str() ) ;
}

while( ! stk2.empty() )
{   RegCloseKey( stk2.top() ) ; stk2.pop() ;
// fprintf( fp1 , " ◎%s 開放しました。 \r\n" , stk1.top().first.c_str() ) ;
stk1.pop() ; i2 ++ ;
}

if( i1 - i2 )
fprintf( fp1 , " Open した回数 %d と 開放した回数 %d が異なっている ! \r\n" , i1 , i2 ) ;

}   // ダミー中括弧 終

return ;
}


BOOL ModemStat()
{   DWORD dwMdmStat = 0L ;
BOOL ret = GetCommModemStatus( hModem1 , &dwMdmStat ) ;
fprintf( fp1 , "モデムステータス : 0x%x %s \r\n" , dwMdmStat ,
ret ? "" : "(関数は失敗している。)" ) ;
// MS_CTS_ON  0x10 , MS_DSR_ON  0x20 ,
// MS_RING_ON 0x40 , MS_RLSD_ON 0x80 ,
// 0xb0 1+2+8 , 0x90 1+8 ?
return ret ;
}

LRESULT CALLBACK Cf2DialogProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp )
{
char org_text[sizeof(add_mes.user_number)] ;
static char international_prefix[64] ;

switch( msg ) {
case WM_INITDIALOG :

*international_prefix = '\0' ;

Edit_LimitText( GetDlgItem( hWnd , IDC_CFA_EDIT1 ), sizeof( add_mes.user_name ) ) ;
Edit_LimitText( GetDlgItem( hWnd , IDC_CFA_EDIT2 ), sizeof( add_mes.user_number ) ) ;
Edit_LimitText( GetDlgItem( hWnd , IDC_CFA_EDIT3 ), sizeof( add_mes.user_memo ) ) ;


SetDlgItemText( hWnd , IDC_CFA_EDIT1 , *add_mes.user_name ? add_mes.user_name : "FAX 太郎" ) ;
SetDlgItemText( hWnd , IDC_CFA_EDIT2 , *add_mes.user_number ? add_mes.user_number : "xxx-xxxx" ) ;
SetDlgItemText( hWnd , IDC_CFA_EDIT3 , add_mes.user_memo ) ;

return TRUE ;
case WM_COMMAND :
switch( LOWORD( wp ) ) {
case IDC_CFA_INTERNATIONAL :
{   char sz[64] ;
GetDlgItemText( hWnd , IDC_CFA_EDIT2 , sz , 32 ) ;
if( IsDlgButtonChecked( hWnd , wp ))
{   char sz_new[128] ;
char sz_new_City[16] ;

if( strcmp( "000" , add_mes.sz_City ))
{   char *lp_c = add_mes.sz_City ;
while( *lp_c == '0' ) lp_c ++ ;
strcpy( sz_new_City , *lp_c ? lp_c : add_mes.sz_City ) ;
} else strcpy( sz_new_City , add_mes.sz_City ) ;

wsprintf( international_prefix , "+%s-%s" ,add_mes.sz_Country , sz_new_City ) ;
wsprintf( sz_new , "%s-%s" , international_prefix , sz ) ;
SetDlgItemText( hWnd , IDC_CFA_EDIT2 , sz_new ) ;

}
else {
if( *international_prefix &&
! strncmp( sz , international_prefix , strlen( international_prefix )))
SetDlgItemText( hWnd , IDC_CFA_EDIT2 , sz + strlen( international_prefix )+1  ) ;
}

}
break ;

case IDC_CFA_EDIT3:
case IDC_CFA_STATIC4:
case IDC_CFA_STATIC3:
case IDC_CFA_EDIT2:
case IDC_CFA_STATIC2:
case IDC_CFA_EDIT1:
case IDC_CFA_STATIC1:
break ;

case IDOK :

strcpy( org_text , add_mes.user_number ) ;
GetDlgItemText( hWnd , IDC_CFA_EDIT2 , add_mes.user_number , sizeof(add_mes.user_number) ) ;

if( strcmp( add_mes.user_number , "xxx-xxxx" ))
{   char *lp = add_mes.user_number ;

BOOL break_flag = FALSE ;
while( *lp )
if( ! strchr( "0123456789+-#*" , *lp ))
{ break_flag = TRUE ; break ; }
else lp ++ ;

if( break_flag ) { 
strcpy( add_mes.user_number , org_text ) ;
MessageBox( NULL , "発信者番号に使用できるのは 数字及び記号(+-#*) のみです。", "0〜9,-+#*" , MB_OK | MB_SETFOREGROUND | MB_ICONWARNING ) ;
break ;
}
}

GetDlgItemText( hWnd , IDC_CFA_EDIT1 , add_mes.user_name , sizeof(add_mes.user_name) ) ;
GetDlgItemText( hWnd , IDC_CFA_EDIT3 , add_mes.user_memo  , sizeof(add_mes.user_memo) ) ;

EndDialog( hWnd , IDOK ) ;
break ;
case IDCANCEL :
EndDialog( hWnd , IDCANCEL ) ;
break ;
default :
break ;
}
break ;
case WM_NOTIFY :
break ;
case WM_CLOSE :
EndDialog( hWnd, IDCANCEL ) ;
//  DestroyWindow( hWnd ) ;
break ;
default :
break ;
}
return FALSE ;
}


//CreateDialog( hAppInst, "CONFIG3",
//              hWnd, ( DLGPROC )Cf3DialogProc );


LRESULT CALLBACK Cf3DialogProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp )
{
switch( msg ) {
case WM_INITDIALOG :
return TRUE ;
case WM_COMMAND :
switch( LOWORD( wp ) ) {
case IDC_CFB_CURPAGE :
case IDC_CFB_ALLPAGE :
case IDC_CFB_PAGESAFTER :
break ;

case IDCANCEL :
break ;
default :
break ;
}
break ;
case WM_NOTIFY :
break ;
case WM_CLOSE :
//EndDialog( hWnd, WM_CLOSE ) ;
DestroyWindow( hWnd ) ;
break ;
default :
break ;
}
return FALSE ;
}

// シェアウェア
LRESULT CALLBACK PaymentDialogProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp )
{
char payment[256] ;
static LPARAM init_lparam ;

switch( msg ) {
case WM_INITDIALOG :
init_lparam = lp ;
return TRUE ;
case WM_COMMAND :
switch( LOWORD( wp ) ) {

case IDC_PAYMENT_EDIT1:
case IDC_PAYMENT_STATIC2:
case IDC_PAYMENT_STATIC1:
break ;
case IDCANCEL :


break ;

case IDOK :
GetWindowText( GetDlgItem( hWnd , IDC_PAYMENT_EDIT1 ), payment , 255 ) ;
if( ! strcmp( payment , LICENSE_KEY )){
WritePrivateProfileString( "SECTION1" , "Payment" , "True" , ini_file ) ;
DestroyWindow( GetDlgItem( GetParent( hWnd ) , IDC_CF1_PAYMENT )) ;
}
SendMessage( hWnd , WM_CLOSE , wp , lp ) ;

break ;
default :
break ;
}
break ;
case WM_NOTIFY :
break ;
case WM_CLOSE :

if( init_lparam == 0 ) {
char payment[256] ;
GetPrivateProfileString( "SECTION1" , "Payment" , "0" , payment , 256 , ini_file ) ;
if( strcmp( payment , "True")) 
exit(0);
}

EndDialog( hWnd, WM_CLOSE ) ;
break ;
default :
break ;
}
return FALSE ;
}
//--