1 /*=============================================================================
\r
5 ===============================================================================
\r
6 / Copyright (C) 1997-2007 Sota. All rights reserved.
\r
8 / Redistribution and use in source and binary forms, with or without
\r
9 / modification, are permitted provided that the following conditions
\r
12 / 1. Redistributions of source code must retain the above copyright
\r
13 / notice, this list of conditions and the following disclaimer.
\r
14 / 2. Redistributions in binary form must reproduce the above copyright
\r
15 / notice, this list of conditions and the following disclaimer in the
\r
16 / documentation and/or other materials provided with the distribution.
\r
18 / THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
\r
19 / IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
\r
20 / OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
\r
21 / IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
22 / INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
\r
23 / BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
\r
24 / USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
\r
25 / ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
26 / (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
\r
27 / THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
28 /============================================================================*/
\r
35 #include <mbstring.h>
\r
37 //#include <winsock.h>
\r
38 #include <winsock2.h>
\r
39 #include <windowsx.h>
\r
40 #include <commctrl.h>
\r
45 #include "resource.h"
\r
47 #include <htmlhelp.h>
\r
51 #undef __MBSWRAPPER_H__
\r
52 #include "mbswrapper.h"
\r
56 /*===== 入力ダイアログデータのストラクチャ =====*/
\r
59 char Title[80]; /* ダイアログのタイトル */
\r
60 char Str[FMAX_PATH+1]; /* デフォルト文字列/入力された文字列(Output) */
\r
61 int MaxLen; /* 文字列の最長 */
\r
62 int Anonymous; /* Anonymousフラグ(Output) */
\r
65 /*===== プロトタイプ =====*/
\r
68 //static BOOL CALLBACK InputDialogCallBack(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);
\r
69 static INT_PTR CALLBACK InputDialogCallBack(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);
\r
71 /*===== 外部参照 =====*/
\r
73 extern HWND hHelpWin;
\r
75 /*===== ローカルなワーク =====*/
\r
77 static DIALOGDATA *DialogData; /* 入力ダイアログデータ */
\r
78 static int HelpPage;
\r
80 static int DisplayDPIX;
\r
81 static int DisplayDPIY;
\r
85 /*----- 入力ダイアログを表示 --------------------------------------------------
\r
88 * int Res : ダイアログボックスのID
\r
89 * HWND hWnd : 親ウインドウのウインドウハンドル
\r
90 * char *Title : ウインドウタイトル (NULL=設定しない)
\r
91 * char *Buf : エディットボックスの初期文字列/入力文字列を返すバッファ
\r
92 * int Max : バッファのサイズ (FMAX_PATH+1以下であること)
\r
93 * int *Flg : フラグの初期値/フラグを返すワーク
\r
94 * int Help : ヘルプのコンテキスト番号
\r
97 * int ステータス (YES/NO=取り消し)
\r
100 * ダイアログは1個のEditBoxと1個のButtonを持つものを使う
\r
101 *----------------------------------------------------------------------------*/
\r
103 int InputDialogBox(int Res, HWND hWnd, char *Title, char *Buf, int Max, int *Flg, int Help)
\r
108 dData.MaxLen = Max;
\r
109 memset(dData.Str, NUL, FMAX_PATH+1);
\r
110 strncpy(dData.Str, Buf, FMAX_PATH);
\r
111 strcpy(dData.Title, "");
\r
113 strcpy(dData.Title, Title);
\r
114 dData.Anonymous = *Flg;
\r
115 DialogData = &dData;
\r
118 Ret = DialogBox(GetFtpInst(), MAKEINTRESOURCE(Res), hWnd, InputDialogCallBack);
\r
122 memset(Buf, NUL, Max);
\r
123 strncpy(Buf, dData.Str, Max-1);
\r
124 *Flg = dData.Anonymous;
\r
130 /*----- 入力ダイアログのコールバック ------------------------------------------
\r
133 * HWND hDlg : ウインドウハンドル
\r
134 * UINT message : メッセージ番号
\r
135 * WPARAM wParam : メッセージの WPARAM 引数
\r
136 * LPARAM lParam : メッセージの LPARAM 引数
\r
140 *----------------------------------------------------------------------------*/
\r
143 //static BOOL CALLBACK InputDialogCallBack(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
\r
144 static INT_PTR CALLBACK InputDialogCallBack(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
\r
146 char Tmp[FMAX_PATH+1];
\r
150 case WM_INITDIALOG :
\r
152 ProtectAllEditControls(hDlg);
\r
153 if(strlen(DialogData->Title) != 0)
\r
154 SendMessage(hDlg, WM_SETTEXT, 0, (LPARAM)DialogData->Title);
\r
155 SendDlgItemMessage(hDlg, INP_INPSTR, EM_LIMITTEXT, DialogData->MaxLen-1, 0);
\r
156 SendDlgItemMessage(hDlg, INP_INPSTR, WM_SETTEXT, 0, (LPARAM)DialogData->Str);
\r
157 SendDlgItemMessage(hDlg, INP_ANONYMOUS, BM_SETCHECK, DialogData->Anonymous, 0);
\r
161 switch(GET_WM_COMMAND_ID(wParam, lParam))
\r
164 SendDlgItemMessage(hDlg, INP_INPSTR, WM_GETTEXT, DialogData->MaxLen, (LPARAM)DialogData->Str);
\r
165 DialogData->Anonymous = SendDlgItemMessage(hDlg, INP_ANONYMOUS, BM_GETCHECK, 0, 0);
\r
166 EndDialog(hDlg, YES);
\r
170 EndDialog(hDlg, NO);
\r
174 hHelpWin = HtmlHelp(NULL, AskHelpFilePath(), HH_HELP_CONTEXT, HelpPage);
\r
178 if(SelectDir(hDlg, Tmp, FMAX_PATH) == TRUE)
\r
179 SendDlgItemMessage(hDlg, INP_INPSTR, WM_SETTEXT, 0, (LPARAM)Tmp);
\r
188 /*----- [実行]と[取消]だけのダイアログの共通コールバック関数 --------------
\r
191 * HWND hDlg : ウインドウハンドル
\r
192 * UINT message : メッセージ番号
\r
193 * WPARAM wParam : メッセージの WPARAM 引数
\r
194 * LPARAM lParam : メッセージの LPARAM 引数
\r
198 *----------------------------------------------------------------------------*/
\r
201 //BOOL CALLBACK ExeEscDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
202 INT_PTR CALLBACK ExeEscDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
206 case WM_INITDIALOG :
\r
210 switch(GET_WM_COMMAND_ID(wParam, lParam))
\r
213 EndDialog(hDlg, YES);
\r
217 EndDialog(hDlg, NO);
\r
226 /*----- [実行]と[取消]だけのダイアログの共通コールバック関数(テキスト表示つき)
\r
229 * HWND hDlg : ウインドウハンドル
\r
230 * UINT message : メッセージ番号
\r
231 * WPARAM wParam : メッセージの WPARAM 引数
\r
232 * LPARAM lParam : メッセージの LPARAM 引数
\r
236 *----------------------------------------------------------------------------*/
\r
239 //BOOL CALLBACK ExeEscTextDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
240 INT_PTR CALLBACK ExeEscTextDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
244 case WM_INITDIALOG :
\r
245 SendDlgItemMessage(hDlg, COMMON_TEXT, WM_SETTEXT, 0, lParam);
\r
249 switch(GET_WM_COMMAND_ID(wParam, lParam))
\r
252 EndDialog(hDlg, YES);
\r
256 EndDialog(hDlg, NO);
\r
266 // 何らかのボタンが押されたときに終了
\r
267 INT_PTR CALLBACK AnyButtonDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
271 case WM_INITDIALOG :
\r
275 switch(GET_WM_COMMAND_CMD(wParam, lParam))
\r
278 EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
\r
286 /*----- 文字列の最後に "\" を付ける -------------------------------------------
\r
295 * オリジナルの文字列 char *Str が変更されます。
\r
296 *----------------------------------------------------------------------------*/
\r
298 void SetYenTail(char *Str)
\r
300 if(_mbscmp(_mbsninc(Str, _mbslen(Str) - 1), "\\") != 0)
\r
307 /*----- 文字列の最後の "\" を取り除く -----------------------------------------
\r
316 * オリジナルの文字列 char *Str が変更されます。
\r
317 *----------------------------------------------------------------------------*/
\r
319 void RemoveYenTail(char *Str)
\r
323 if(strlen(Str) > 0)
\r
325 Pos = _mbsninc(Str, _mbslen(Str) - 1);
\r
326 if(_mbscmp(Pos, "\\") == 0)
\r
333 /*----- 文字列の最後に "/" を付ける -------------------------------------------
\r
342 * オリジナルの文字列 char *Str が変更されます。
\r
343 *----------------------------------------------------------------------------*/
\r
345 void SetSlashTail(char *Str)
\r
347 #if defined(HAVE_TANDEM)
\r
348 /* Tandem では / の代わりに . を追加 */
\r
349 if(AskHostType() == HTYPE_TANDEM) {
\r
350 if(_mbscmp(_mbsninc(Str, _mbslen(Str) - 1), ".") != 0)
\r
354 if(_mbscmp(_mbsninc(Str, _mbslen(Str) - 1), "/") != 0)
\r
361 /*----- 文字列から改行コードを取り除く ----------------------------------------
\r
370 * オリジナルの文字列 char *Str が変更されます。
\r
371 *----------------------------------------------------------------------------*/
\r
373 void RemoveReturnCode(char *Str)
\r
377 if((Pos = strchr(Str, 0x0D)) != NULL)
\r
379 if((Pos = strchr(Str, 0x0A)) != NULL)
\r
385 /*----- 文字列内の特定の文字を全て置き換える ----------------------------------
\r
394 *----------------------------------------------------------------------------*/
\r
396 void ReplaceAll(char *Str, char Src, char Dst)
\r
400 /* Tandem ではノード名の変換を行わない */
\r
401 /* 最初の1文字が \ でもそのままにする */
\r
402 #if defined(HAVE_TANDEM)
\r
403 if (AskRealHostType() == HTYPE_TANDEM && strlen(Str) > 0)
\r
406 while((Pos = _mbschr(Str, Src)) != NULL)
\r
412 /*----- 数字もしくは特定の1文字かチェック ------------------------------------
\r
415 * int Ch : チェックする文字
\r
421 *----------------------------------------------------------------------------*/
\r
423 int IsDigitSym(int Ch, int Sym)
\r
427 if((Ret = IsDigit(Ch)) == 0)
\r
429 if((Sym != NUL) && (Sym == Ch))
\r
436 /*----- 文字列が全て同じ文字かチェック ----------------------------------------
\r
445 *----------------------------------------------------------------------------*/
\r
447 int StrAllSameChar(char *Str, char Ch)
\r
465 /*----- 文字列の末尾のスペースを削除 ------------------------------------------
\r
472 *----------------------------------------------------------------------------*/
\r
474 void RemoveTailingSpaces(char *Str)
\r
478 Pos = Str + strlen(Str);
\r
489 /*----- 大文字/小文字を区別しないstrstr --------------------------------------
\r
496 * char *文字列1中で文字列2が見つかった位置
\r
498 *----------------------------------------------------------------------------*/
\r
500 char *stristr(char *s1, char *s2)
\r
507 if((tolower(*s1) == tolower(*s2)) &&
\r
508 (_strnicmp(s1, s2, strlen(s2)) == 0))
\r
519 /*----- 文字列中のスペースで区切られた次のフィールドを返す --------------------
\r
527 *----------------------------------------------------------------------------*/
\r
529 char *GetNextField(char *Str)
\r
531 if((Str = strchr(Str, ' ')) != NULL)
\r
547 /*----- 現在のフィールドの文字列をコピーする ----------------------------------
\r
556 * FFFTP_SUCCESS/FFFTP_FAIL=長さが長すぎる
\r
557 *----------------------------------------------------------------------------*/
\r
559 int GetOneField(char *Str, char *Buf, int Max)
\r
565 if((Pos = strchr(Str, ' ')) == NULL)
\r
567 if((int)strlen(Str) <= Max)
\r
570 Sts = FFFTP_SUCCESS;
\r
575 if(Pos - Str <= Max)
\r
577 strncpy(Buf, Str, Pos - Str);
\r
578 *(Buf + (Pos - Str)) = NUL;
\r
579 Sts = FFFTP_SUCCESS;
\r
586 /*----- カンマを取り除く ------------------------------------------------------
\r
593 *----------------------------------------------------------------------------*/
\r
595 void RemoveComma(char *Str)
\r
614 /*----- パス名の中のファイル名の先頭を返す ------------------------------------
\r
623 * ディレクトリの区切り記号は "\" と "/" の両方が有効
\r
624 *----------------------------------------------------------------------------*/
\r
626 char *GetFileName(char *Path)
\r
630 if((Pos = _mbschr(Path, ':')) != NULL)
\r
633 if((Pos = _mbsrchr(Path, '\\')) != NULL)
\r
636 if((Pos = _mbsrchr(Path, '/')) != NULL)
\r
639 #if defined(HAVE_TANDEM)
\r
640 /* Tandem は . がデリミッタとなる */
\r
641 if((AskHostType() == HTYPE_TANDEM) && ((Pos = _mbsrchr(Path, '.')) != NULL))
\r
648 /*----- ツールの表示名を返す --------------------------------------------------
\r
655 *----------------------------------------------------------------------------*/
\r
657 char *GetToolName(char *Path)
\r
661 if((Pos = _mbschr(Path, ':')) != NULL)
\r
664 if((Pos = _mbsrchr(Path, '\\')) != NULL)
\r
671 /*----- パス名の中の拡張子の先頭を返す ----------------------------------------
\r
678 *----------------------------------------------------------------------------*/
\r
680 char *GetFileExt(char *Path)
\r
684 Ret = _mbschr(Path, NUL);
\r
685 if((_mbscmp(Path, ".") != 0) &&
\r
686 (_mbscmp(Path, "..") != 0))
\r
688 while((Path = _mbschr(Path, '.')) != NULL)
\r
698 /*----- パス名からファイル名を取り除く ----------------------------------------
\r
702 * char *Buf : ファイル名を除いたパス名のコピー先
\r
708 * ディレクトリの区切り記号は "\" と "/" の両方が有効
\r
709 *----------------------------------------------------------------------------*/
\r
711 void RemoveFileName(char *Path, char *Buf)
\r
717 if((Pos = _mbsrchr(Buf, '/')) != NULL)
\r
719 else if((Pos = _mbsrchr(Buf, '\\')) != NULL)
\r
721 if((Pos == Buf) ||
\r
722 ((Pos != Buf) && (*(Pos - 1) != ':')))
\r
729 /*----- 上位ディレクトリのパス名を取得 ----------------------------------------
\r
738 * ディレクトリの区切り記号は "\" と "/" の両方が有効
\r
740 * 例) "/pub" --> "/"
\r
741 * 例) "C:\DOS" --> "C:\"
\r
742 *----------------------------------------------------------------------------*/
\r
744 void GetUpperDir(char *Path)
\r
749 if(((Top = _mbschr(Path, '/')) != NULL) ||
\r
750 ((Top = _mbschr(Path, '\\')) != NULL))
\r
753 if(((Pos = _mbsrchr(Top, '/')) != NULL) ||
\r
754 ((Pos = _mbsrchr(Top, '\\')) != NULL))
\r
763 /*----- 上位ディレクトリのパス名を取得 ----------------------------------------
\r
772 * ディレクトリの区切り記号は "\" と "/" の両方が有効
\r
775 * 例) "C:\DOS" --> "C:"
\r
776 *----------------------------------------------------------------------------*/
\r
778 void GetUpperDirEraseTopSlash(char *Path)
\r
782 if(((Pos = _mbsrchr(Path, '/')) != NULL) ||
\r
783 ((Pos = _mbsrchr(Path, '\\')) != NULL))
\r
792 /*----- ディレクトリの階層数を返す --------------------------------------------
\r
801 * 単に '\' と '/'の数を返すだけ
\r
802 *----------------------------------------------------------------------------*/
\r
804 int AskDirLevel(char *Path)
\r
810 while(((Pos = _mbschr(Path, '/')) != NULL) ||
\r
811 ((Pos = _mbschr(Path, '\\')) != NULL))
\r
820 /*----- ファイルサイズを文字列に変換する --------------------------------------
\r
823 * double Size : ファイルサイズ
\r
824 * char *Buf : 文字列を返すバッファ
\r
828 *----------------------------------------------------------------------------*/
\r
830 void MakeSizeString(double Size, char *Buf)
\r
833 // if(Size >= (1024*1024))
\r
835 // Size /= (1024*1024);
\r
836 // sprintf(Buf, "%.2fM Bytes", Size);
\r
838 // else if (Size >= 1024)
\r
841 // sprintf(Buf, "%.2fK Bytes", Size);
\r
844 // sprintf(Buf, "%.0f Bytes", Size);
\r
857 sprintf(Buf, "%.2lfT Bytes", Size);
\r
860 sprintf(Buf, "%.2lfG Bytes", Size);
\r
863 sprintf(Buf, "%.2lfM Bytes", Size);
\r
866 sprintf(Buf, "%.2lfK Bytes", Size);
\r
869 sprintf(Buf, "%.0lf Bytes", Size);
\r
875 /*----- StaticTextの領域に収まるようにパス名を整形して表示 --------------------
\r
878 * HWND hWnd : ウインドウハンドル
\r
879 * char *Str : 文字列 (長さはFMAX_PATH以下)
\r
883 *----------------------------------------------------------------------------*/
\r
885 void DispStaticText(HWND hWnd, char *Str)
\r
887 char Buf[FMAX_PATH+1];
\r
895 GetClientRect(hWnd, &Rect);
\r
896 Rect.right -= Rect.left;
\r
904 GetTextExtentPoint32(hDC, Pos, strlen(Pos), &fSize);
\r
906 if(fSize.cx <= Rect.right)
\r
909 if(_mbslen(Pos) <= 4)
\r
913 Pos = _mbsninc(Pos, 4);
\r
914 if((Tmp = _mbschr(Pos, '\\')) == NULL)
\r
915 Tmp = _mbschr(Pos, '/');
\r
918 Tmp = _mbsninc(Pos, 4);
\r
921 memset(Pos, '.', 3);
\r
924 ReleaseDC(hWnd, hDC);
\r
926 SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)Pos);
\r
931 /*----- 文字列アレイの長さを求める --------------------------------------------
\r
934 * char *Str : 文字列アレイ (末尾はNUL2つ)
\r
940 * 終端の2つのNULのうちの最後の物は数えない
\r
941 * StrMultiLen("") = 0
\r
942 * StrMultiLen("abc\0xyz\0") = 8
\r
943 * StrMultiLen("abc") = 終端が2つのNULでないので求められない
\r
944 *----------------------------------------------------------------------------*/
\r
946 int StrMultiLen(char *Str)
\r
954 Tmp = strlen(Str) + 1;
\r
962 /*----- RECTをクライアント座標からスクリーン座標に変換 ------------------------
\r
965 * HWND hWnd : ウインドウハンドル
\r
966 * RECT *Rect : RECT
\r
970 *----------------------------------------------------------------------------*/
\r
972 void RectClientToScreen(HWND hWnd, RECT *Rect)
\r
976 Tmp.x = Rect->left;
\r
978 ClientToScreen(hWnd, &Tmp);
\r
979 Rect->left = Tmp.x;
\r
982 Tmp.x = Rect->right;
\r
983 Tmp.y = Rect->bottom;
\r
984 ClientToScreen(hWnd, &Tmp);
\r
985 Rect->right = Tmp.x;
\r
986 Rect->bottom = Tmp.y;
\r
992 /*----- 16進文字をバイナリに変換 ----------------------------------------------
\r
999 *----------------------------------------------------------------------------*/
\r
1001 int hex2bin(char Ch)
\r
1005 if((Ch >= '0') && (Ch <= '9'))
\r
1007 else if((Ch >= 'A') && (Ch <= 'F'))
\r
1008 Ret = Ch - 'A' + 10;
\r
1009 else if((Ch >= 'a') && (Ch <= 'f'))
\r
1010 Ret = Ch - 'a' + 10;
\r
1016 /*----- UNC文字列を分解する ------------------------------------------------
\r
1019 * char *unc : UNC文字列
\r
1020 * char *Host : ホスト名をコピーするバッファ (サイズは HOST_ADRS_LEN+1)
\r
1021 * char *Path : パス名をコピーするバッファ (サイズは FMAX_PATH+1)
\r
1022 * char *File : ファイル名をコピーするバッファ (サイズは FMAX_PATH+1)
\r
1023 * char *User : ユーザ名をコピーするバッファ (サイズは USER_NAME_LEN+1)
\r
1024 * char *Pass : パスワードをコピーするバッファ (サイズは PASSWORD_LEN+1)
\r
1025 * int *Port : ポート番号をコピーするバッファ
\r
1029 * FFFTP_SUCCESS/FFFTP_FAIL
\r
1032 *----------------------------------------------------------------------------*/
\r
1034 int SplitUNCpath(char *unc, char *Host, char *Path, char *File, char *User, char *Pass, int *Port)
\r
1039 char Tmp[FMAX_PATH+1];
\r
1041 memset(Host, NUL, HOST_ADRS_LEN+1);
\r
1042 memset(Path, NUL, FMAX_PATH+1);
\r
1043 memset(File, NUL, FMAX_PATH+1);
\r
1044 memset(User, NUL, USER_NAME_LEN+1);
\r
1045 memset(Pass, NUL, PASSWORD_LEN+1);
\r
1048 ReplaceAll(unc, '\\', '/');
\r
1050 if((Pos1 = _mbsstr(unc, "//")) != NULL)
\r
1055 if((Pos2 = _mbschr(Pos1, '@')) != NULL)
\r
1057 memset(Tmp, NUL, FMAX_PATH+1);
\r
1058 memcpy(Tmp, Pos1, Pos2-Pos1);
\r
1061 if((Pos2 = _mbschr(Tmp, ':')) != NULL)
\r
1063 memcpy(User, Tmp, min1(Pos2-Tmp, USER_NAME_LEN));
\r
1064 strncpy(Pass, Pos2+1, PASSWORD_LEN);
\r
1067 strncpy(User, Tmp, USER_NAME_LEN);
\r
1071 if((Pos2 = _mbschr(Pos1, '[')) != NULL && Pos2 < _mbschr(Pos1, ':'))
\r
1074 if((Pos2 = _mbschr(Pos2, ']')) != NULL)
\r
1076 memcpy(Host, Pos1, min1(Pos2-Pos1, HOST_ADRS_LEN));
\r
1081 if((Pos2 = _mbschr(Pos1, ':')) != NULL)
\r
1084 // memcpy(Host, Pos1, min1(Pos2-Pos1, HOST_ADRS_LEN));
\r
1085 if(strlen(Host) == 0)
\r
1086 memcpy(Host, Pos1, min1(Pos2-Pos1, HOST_ADRS_LEN));
\r
1088 if(IsDigit(*Pos2))
\r
1090 *Port = atoi(Pos2);
\r
1091 while(*Pos2 != NUL)
\r
1093 if(IsDigit(*Pos2) == 0)
\r
1098 RemoveFileName(Pos2, Path);
\r
1099 strncpy(File, GetFileName(Pos2), FMAX_PATH);
\r
1101 else if((Pos2 = _mbschr(Pos1, '/')) != NULL)
\r
1104 // memcpy(Host, Pos1, min1(Pos2-Pos1, HOST_ADRS_LEN));
\r
1105 if(strlen(Host) == 0)
\r
1106 memcpy(Host, Pos1, min1(Pos2-Pos1, HOST_ADRS_LEN));
\r
1107 RemoveFileName(Pos2, Path);
\r
1108 strncpy(File, GetFileName(Pos2), FMAX_PATH);
\r
1113 // strncpy(Host, Pos1, HOST_ADRS_LEN);
\r
1114 if(strlen(Host) == 0)
\r
1115 strncpy(Host, Pos1, HOST_ADRS_LEN);
\r
1119 if(strlen(Host) > 0)
\r
1120 Sts = FFFTP_SUCCESS;
\r
1126 /*----- 日付文字列(JST)をFILETIME(UTC)に変換 ----------------------------------
\r
1129 * char *Time : 日付文字列 ("yyyy/mm/dd hh:mm")
\r
1130 * FILETIME *Buf : ファイルタイムを返すワーク
\r
1134 * YES/NO=日付情報がなかった
\r
1135 *----------------------------------------------------------------------------*/
\r
1137 int TimeString2FileTime(char *Time, FILETIME *Buf)
\r
1144 Buf->dwLowDateTime = 0;
\r
1145 Buf->dwHighDateTime = 0;
\r
1147 if(strlen(Time) >= 16)
\r
1149 if(IsDigit(Time[0]) && IsDigit(Time[5]) && IsDigit(Time[8]) &&
\r
1150 IsDigit(Time[12]) && IsDigit(Time[14]))
\r
1155 sTime.wYear = atoi(Time);
\r
1156 sTime.wMonth = atoi(Time + 5);
\r
1157 sTime.wDay = atoi(Time + 8);
\r
1158 if(Time[11] != ' ')
\r
1159 sTime.wHour = atoi(Time + 11);
\r
1161 sTime.wHour = atoi(Time + 12);
\r
1162 sTime.wMinute = atoi(Time + 14);
\r
1164 // sTime.wSecond = 0;
\r
1165 if(strlen(Time) >= 19)
\r
1166 sTime.wSecond = atoi(Time + 17);
\r
1168 sTime.wSecond = 0;
\r
1169 sTime.wMilliseconds = 0;
\r
1171 SystemTimeToFileTime(&sTime, &fTime);
\r
1172 LocalFileTimeToFileTime(&fTime, Buf);
\r
1178 /*----- FILETIME(UTC)を日付文字列(JST)に変換 ----------------------------------
\r
1181 * FILETIME *Time : ファイルタイム
\r
1182 * char *Buf : 日付文字列を返すワーク
\r
1183 * int Mode : モード (DISPFORM_xxx)
\r
1184 * int InfoExist : 情報があるかどうか (FINFO_xxx)
\r
1188 *----------------------------------------------------------------------------*/
\r
1191 //void FileTime2TimeString(FILETIME *Time, char *Buf, int Mode, int InfoExist)
\r
1192 void FileTime2TimeString(FILETIME *Time, char *Buf, int Mode, int InfoExist, int ShowSeconds)
\r
1197 if(Mode == DISPFORM_LEGACY)
\r
1199 if((Time->dwLowDateTime == 0) && (Time->dwHighDateTime == 0))
\r
1203 // /* "yyyy/mm/dd hh:mm" */
\r
1204 /* "yyyy/mm/dd hh:mm:ss" */
\r
1205 FileTimeToLocalFileTime(Time, &fTime);
\r
1206 FileTimeToSystemTime(&fTime, &sTime);
\r
1209 // if(InfoExist & FINFO_DATE)
\r
1210 // sprintf(Buf, "%04d/%02d/%02d ", sTime.wYear, sTime.wMonth, sTime.wDay);
\r
1212 // sprintf(Buf, " ");
\r
1214 // if(InfoExist & FINFO_TIME)
\r
1215 // sprintf(Buf+11, "%2d:%02d", sTime.wHour, sTime.wMinute);
\r
1217 // sprintf(Buf+11, " ");
\r
1218 if(InfoExist & (FINFO_DATE | FINFO_TIME))
\r
1220 if(InfoExist & FINFO_DATE)
\r
1221 sprintf(Buf, "%04d/%02d/%02d ", sTime.wYear, sTime.wMonth, sTime.wDay);
\r
1223 sprintf(Buf, " ");
\r
1224 if(ShowSeconds == YES)
\r
1226 if(InfoExist & FINFO_TIME)
\r
1227 sprintf(Buf+11, "%2d:%02d:%02d", sTime.wHour, sTime.wMinute, sTime.wSecond);
\r
1229 sprintf(Buf+11, " ");
\r
1233 if(InfoExist & FINFO_TIME)
\r
1234 sprintf(Buf+11, "%2d:%02d", sTime.wHour, sTime.wMinute);
\r
1236 sprintf(Buf+11, " ");
\r
1244 // if (!strftime((char *)str, 100, "%c", (const struct tm *)thetime))
\r
1245 // SetTaskMsg("strftime が失敗しました!\n");
\r
1251 /*----- ファイルタイムを指定タイムゾーンのローカルタイムからGMTに変換 ---------
\r
1254 * FILETIME *Time : ファイルタイム
\r
1255 * int TimeZone : タイムゾーン
\r
1259 *----------------------------------------------------------------------------*/
\r
1261 void SpecificLocalFileTime2FileTime(FILETIME *Time, int TimeZone)
\r
1263 unsigned __int64 Tmp64;
\r
1265 Tmp64 = (unsigned __int64)Time->dwLowDateTime +
\r
1266 ((unsigned __int64)Time->dwHighDateTime << 32);
\r
1268 Tmp64 -= (__int64)TimeZone * (__int64)36000000000;
\r
1270 Time->dwHighDateTime = (DWORD)(Tmp64 >> 32);
\r
1271 Time->dwLowDateTime = (DWORD)(Tmp64 & 0xFFFFFFFF);
\r
1277 /*----- 属性文字列を値に変換 --------------------------------------------------
\r
1280 * char *Str : 属性文字列 ("rwxrwxrwx")
\r
1284 *----------------------------------------------------------------------------*/
\r
1286 int AttrString2Value(char *Str)
\r
1292 memset(Tmp, 0, 10);
\r
1294 // strncpy(Tmp, Str, 9);
\r
1296 // if(Tmp[0] != '-')
\r
1298 // if(Tmp[1] != '-')
\r
1300 // if(Tmp[2] != '-')
\r
1303 // if(Tmp[3] != '-')
\r
1305 // if(Tmp[4] != '-')
\r
1307 // if(Tmp[5] != '-')
\r
1310 // if(Tmp[6] != '-')
\r
1312 // if(Tmp[7] != '-')
\r
1314 // if(Tmp[8] != '-')
\r
1316 if(strlen(Str) >= 9)
\r
1318 strncpy(Tmp, Str, 9);
\r
1341 else if(strlen(Str) >= 3)
\r
1343 strncpy(Tmp, Str, 3);
\r
1344 Ret = strtol(Tmp, NULL, 16);
\r
1351 /*----- 属性の値を文字列に変換 ------------------------------------------------
\r
1355 * char *Buf : 属性文字列をセットするバッファ ("rwxrwxrwx")
\r
1359 *----------------------------------------------------------------------------*/
\r
1362 //void AttrValue2String(int Attr, char *Buf)
\r
1363 void AttrValue2String(int Attr, char *Buf, int ShowNumber)
\r
1366 // strcpy(Buf, "---------");
\r
1368 // if(Attr & 0x400)
\r
1370 // if(Attr & 0x200)
\r
1372 // if(Attr & 0x100)
\r
1375 // if(Attr & 0x40)
\r
1377 // if(Attr & 0x20)
\r
1379 // if(Attr & 0x10)
\r
1388 if(ShowNumber == YES)
\r
1390 sprintf(Buf, "%03x", Attr);
\r
1394 strcpy(Buf, "---------");
\r
1422 /*----- INIファイル文字列を整形 -----------------------------------------------
\r
1429 *----------------------------------------------------------------------------*/
\r
1431 void FormatIniString(char *Str)
\r
1436 while(*Str != NUL)
\r
1438 if((*Str != ' ') && (*Str != '\t') && (*Str != '\n'))
\r
1444 while(*Str != NUL)
\r
1446 if((*Str != '\"') && (*Str != '\n'))
\r
1456 /*----- ファイル選択 ----------------------------------------------------------
\r
1459 * HWND hWnd : ウインドウハンドル
\r
1460 * char *Fname : ファイル名を返すバッファ
\r
1461 * char *Title : タイトル
\r
1462 * char *Filters : フィルター文字列
\r
1463 * char *Ext : デフォルト拡張子
\r
1464 * int Flags : 追加するフラグ
\r
1465 * int Save : 「開く」か「保存」か (0=開く, 1=保存)
\r
1470 *----------------------------------------------------------------------------*/
\r
1472 int SelectFile(HWND hWnd, char *Fname, char *Title, char *Filters, char *Ext, int Flags, int Save)
\r
1474 OPENFILENAME OpenFile;
\r
1475 char Tmp[FMAX_PATH+1];
\r
1476 char Cur[FMAX_PATH+1];
\r
1479 GetCurrentDirectory(FMAX_PATH, Cur);
\r
1481 strcpy(Tmp, Fname);
\r
1483 memset(&OpenFile, 0, sizeof(OPENFILENAME));
\r
1484 OpenFile.lStructSize = sizeof(OPENFILENAME);
\r
1485 OpenFile.hwndOwner = hWnd;
\r
1486 OpenFile.hInstance = 0;
\r
1487 OpenFile.lpstrFilter = Filters;
\r
1488 OpenFile.lpstrCustomFilter = NULL;
\r
1489 OpenFile.nFilterIndex = 1;
\r
1490 OpenFile.lpstrFile = Tmp;
\r
1491 OpenFile.nMaxFile = FMAX_PATH;
\r
1492 OpenFile.lpstrFileTitle = NULL;
\r
1493 OpenFile.nMaxFileTitle = 0;
\r
1494 OpenFile.lpstrInitialDir = NULL;
\r
1495 OpenFile.lpstrTitle = Title;
\r
1496 OpenFile.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | Flags;
\r
1497 OpenFile.nFileOffset = 0;
\r
1498 OpenFile.nFileExtension = 0;
\r
1499 OpenFile.lpstrDefExt = Ext;
\r
1500 OpenFile.lCustData = 0;
\r
1501 OpenFile.lpfnHook = NULL;
\r
1502 OpenFile.lpTemplateName = NULL;
\r
1506 if((Sts = GetOpenFileName(&OpenFile)) == TRUE)
\r
1507 strcpy(Fname,Tmp);
\r
1511 if((Sts = GetSaveFileName(&OpenFile)) == TRUE)
\r
1512 strcpy(Fname,Tmp);
\r
1514 SetCurrentDirectory(Cur);
\r
1519 /*----- ディレクトリを選択 ----------------------------------------------------
\r
1522 * HWND hWnd : ウインドウハンドル
\r
1523 * char *Buf : ディレクトリ名を返すバッファ(初期ディレクトリ名)
\r
1524 * int MaxLen : バッファのサイズ
\r
1529 *----------------------------------------------------------------------------*/
\r
1531 int SelectDir(HWND hWnd, char *Buf, int MaxLen)
\r
1533 char Tmp[FMAX_PATH+1];
\r
1534 char Cur[FMAX_PATH+1];
\r
1536 LPITEMIDLIST lpIdll;
\r
1538 LPMALLOC lpMalloc;
\r
1541 GetCurrentDirectory(FMAX_PATH, Cur);
\r
1543 if(SHGetMalloc(&lpMalloc) == NOERROR)
\r
1545 Binfo.hwndOwner = hWnd;
\r
1546 Binfo.pidlRoot = NULL;
\r
1547 Binfo.pszDisplayName = Tmp;
\r
1548 Binfo.lpszTitle = MSGJPN185;
\r
1549 Binfo.ulFlags = BIF_RETURNONLYFSDIRS;
\r
1550 Binfo.lpfn = NULL;
\r
1553 if((lpIdll = SHBrowseForFolder(&Binfo)) != NULL)
\r
1555 SHGetPathFromIDList(lpIdll, Tmp);
\r
1556 memset(Buf, NUL, MaxLen);
\r
1557 strncpy(Buf, Tmp, MaxLen-1);
\r
1559 lpMalloc->lpVtbl->Free(lpMalloc, lpIdll);
\r
1561 lpMalloc->lpVtbl->Release(lpMalloc);
\r
1562 SetCurrentDirectory(Cur);
\r
1568 /*----- 値に関連付けられたラジオボタンをチェックする --------------------------
\r
1571 * HWND hDlg : ダイアログボックスのウインドウハンドル
\r
1573 * const RADIOBUTTON *Buttons : ラジオボタンと値の関連付けテーブル
\r
1580 * 値に関連付けられたボタンが無い時は、テーブルの最初に登録されているボタ
\r
1582 *----------------------------------------------------------------------------*/
\r
1584 void SetRadioButtonByValue(HWND hDlg, int Value, const RADIOBUTTON *Buttons, int Num)
\r
1589 Def = Buttons->ButID;
\r
1590 for(i = 0; i < Num; i++)
\r
1592 if(Value == Buttons->Value)
\r
1594 SendDlgItemMessage(hDlg, Buttons->ButID, BM_SETCHECK, 1, 0);
\r
1595 /* ラジオボタンを変更した時に他の項目のハイドなどを行なう事が */
\r
1596 /* あるので、そのために WM_COMMAND を送る */
\r
1597 SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(Buttons->ButID, 0), 0);
\r
1604 SendDlgItemMessage(hDlg, Def, BM_SETCHECK, 1, 0);
\r
1605 SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(Def, 0), 0);
\r
1611 /*----- チェックされているボタンに関連付けられた値を返す ----------------------
\r
1614 * HWND hDlg : ダイアログボックスのウインドウハンドル
\r
1615 * const RADIOBUTTON *Buttons : ラジオボタンと値の関連付けテーブル
\r
1622 * どのボタンもチェックされていない時は、テーブルの最初に登録されているボ
\r
1624 *----------------------------------------------------------------------------*/
\r
1626 int AskRadioButtonValue(HWND hDlg, const RADIOBUTTON *Buttons, int Num)
\r
1631 Ret = Buttons->Value;
\r
1632 for(i = 0; i < Num; i++)
\r
1634 if(SendDlgItemMessage(hDlg, Buttons->ButID, BM_GETCHECK, 0, 0) == 1)
\r
1636 Ret = Buttons->Value;
\r
1645 /*----- 16進文字列を数値に変換 ----------------------------------------------
\r
1652 *----------------------------------------------------------------------------*/
\r
1654 int xtoi(char *Str)
\r
1659 while(*Str != NUL)
\r
1662 if((*Str >= '0') && (*Str <= '9'))
\r
1663 Ret += *Str - '0';
\r
1664 else if((*Str >= 'A') && (*Str <= 'F'))
\r
1665 Ret += *Str - 'A' + 10;
\r
1666 else if((*Str >= 'a') && (*Str <= 'f'))
\r
1667 Ret += *Str - 'a' + 10;
\r
1677 /*----- ファイルが読み取り可能かどうかを返す ----------------------------------
\r
1680 * char *Fname : ファイル名
\r
1684 * FFFTP_SUCCESS/FFFTP_FAIL
\r
1685 *----------------------------------------------------------------------------*/
\r
1687 int CheckFileReadable(char *Fname)
\r
1690 HANDLE iFileHandle;
\r
1691 SECURITY_ATTRIBUTES Sec;
\r
1695 Sec.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
1696 Sec.lpSecurityDescriptor = NULL;
\r
1697 Sec.bInheritHandle = FALSE;
\r
1699 if((iFileHandle = CreateFile(Fname, GENERIC_READ,
\r
1700 FILE_SHARE_READ|FILE_SHARE_WRITE, &Sec, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
\r
1702 Sts = FFFTP_SUCCESS;
\r
1703 CloseHandle(iFileHandle);
\r
1712 int max1(int n, int m)
\r
1722 int min1(int n, int m)
\r
1731 void ExcEndianDWORD(DWORD *x)
\r
1738 *(Pos + 0) = *(Pos + 3);
\r
1741 *(Pos + 1) = *(Pos + 2);
\r
1749 /*----- int値の入れ替え -------------------------------------------------------
\r
1757 *----------------------------------------------------------------------------*/
\r
1759 void SwapInt(int *Num1, int *Num2)
\r
1770 /*----- 指定されたフォルダがあるかどうかチェック -------------------------------
\r
1776 * int ステータス (YES/NO)
\r
1777 *----------------------------------------------------------------------------*/
\r
1779 int IsFolderExist(char *Path)
\r
1782 char Tmp[FMAX_PATH+1];
\r
1786 if(strlen(Path) > 0)
\r
1788 strcpy(Tmp, Path);
\r
1789 if(_mbscmp(Tmp+1, ":\\") != 0)
\r
1790 RemoveYenTail(Tmp);
\r
1792 Attr = GetFileAttributes(Tmp);
\r
1793 if((Attr == 0xFFFFFFFF) || ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0))
\r
1800 /*----- テーブルにしたがって数値を登録 -----------------------------------------
\r
1805 * INTCONVTBL *Tbl : テーブル
\r
1806 * int Num : テーブルの数値の数
\r
1810 *----------------------------------------------------------------------------*/
\r
1812 int ConvertNum(int x, int Dir, const INTCONVTBL *Tbl, int Num)
\r
1818 for(i = 0; i < Num; i++)
\r
1820 if((Dir == 0) && (Tbl->Num1 == x))
\r
1825 else if((Dir == 1) && (Tbl->Num2 == x))
\r
1840 /*----- ファイルをゴミ箱に削除 ------------------------------------------------
\r
1843 * char *Path : ファイル名
\r
1846 * int ステータス (0=正常終了)
\r
1847 *----------------------------------------------------------------------------*/
\r
1849 int MoveFileToTrashCan(char *Path)
\r
1851 SHFILEOPSTRUCT FileOp;
\r
1852 char Tmp[FMAX_PATH+2];
\r
1854 memset(Tmp, 0, FMAX_PATH+2);
\r
1855 strcpy(Tmp, Path);
\r
1856 FileOp.hwnd = NULL;
\r
1857 FileOp.wFunc = FO_DELETE;
\r
1858 FileOp.pFrom = Tmp;
\r
1860 FileOp.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO;
\r
1861 FileOp.lpszProgressTitle = "";
\r
1862 return(SHFileOperation(&FileOp));
\r
1868 LONGLONG MakeLongLong(DWORD High, DWORD Low)
\r
1873 x1 = (LONGLONG)Low;
\r
1874 y1 = (LONGLONG)High;
\r
1875 z = x1 | (y1 << 32);
\r
1880 char *MakeNumString(LONGLONG Num, char *Buf, BOOL Comma)
\r
1891 *Pos++ = (char)(Num % 10) + '0';
\r
1893 if((Comma == TRUE) && ((i % 3) == 0) && (Num != 0))
\r
1905 // 異なるファイルが表示されるバグ修正
\r
1907 // ShellExecute等で使用されるファイル名を修正
\r
1908 // UNCでない場合に末尾の半角スペースは無視されるため拡張子が補完されなくなるまで半角スペースを追加
\r
1910 char* MakeDistinguishableFileName(char* Out, char* In)
\r
1913 char Tmp[FMAX_PATH+1];
\r
1914 char Tmp2[FMAX_PATH+3];
\r
1916 WIN32_FIND_DATA Find;
\r
1917 if(strlen(GetFileExt(GetFileName(In))) > 0)
\r
1921 Fname = GetFileName(In);
\r
1923 strcpy(Tmp2, Tmp);
\r
1924 strcat(Tmp2, ".*");
\r
1925 while(strlen(Tmp) < FMAX_PATH && (hFind = FindFirstFile(Tmp2, &Find)) != INVALID_HANDLE_VALUE)
\r
1929 if(strcmp(Find.cFileName, Fname) != 0)
\r
1932 while(FindNextFile(hFind, &Find));
\r
1934 if(strcmp(Find.cFileName, Fname) != 0)
\r
1937 strcpy(Tmp2, Tmp);
\r
1938 strcat(Tmp2, ".*");
\r
1949 char* GetAppTempPath(char* Buf)
\r
1952 GetTempPath(MAX_PATH, Buf);
\r
1954 sprintf(Temp, "ffftp%08x", GetCurrentProcessId());
\r
1955 strcat(Buf, Temp);
\r
1959 #if defined(HAVE_TANDEM)
\r
1960 /*----- ファイルサイズからEXTENTサイズの計算を行う ----------------------------
\r
1963 * LONGLONG Size : ファイルサイズ
\r
1967 *----------------------------------------------------------------------------*/
\r
1968 void CalcExtentSize(TRANSPACKET *Pkt, LONGLONG Size)
\r
1972 /* EXTENTS(4,28) MAXEXTENTS 978 */
\r
1973 if(Size < 56025088) {
\r
1974 Pkt->PriExt = DEF_PRIEXT;
\r
1975 Pkt->SecExt = DEF_SECEXT;
\r
1976 Pkt->MaxExt = DEF_MAXEXT;
\r
1978 /* 増加余地を残すため Used 75% 近辺になるように EXTENT サイズを調整) */
\r
1979 extent = (LONGLONG)(Size / ((DEF_MAXEXT * 0.75) * 2048LL));
\r
1980 /* 28未満にすると誤差でFile Fullになる可能性がある */
\r
1984 Pkt->PriExt = (int)extent;
\r
1985 Pkt->SecExt = (int)extent;
\r
1986 Pkt->MaxExt = DEF_MAXEXT;
\r
1992 void QueryDisplayDPI()
\r
1995 if(DisplayDPIX == 0)
\r
1997 if(hDC = GetDC(NULL))
\r
1999 DisplayDPIX = GetDeviceCaps(hDC, LOGPIXELSX);
\r
2000 DisplayDPIY = GetDeviceCaps(hDC, LOGPIXELSY);
\r
2001 ReleaseDC(NULL, hDC);
\r
2006 int CalcPixelX(int x)
\r
2008 QueryDisplayDPI();
\r
2009 return (x * DisplayDPIX + 96 / 2) / 96;
\r
2012 int CalcPixelY(int y)
\r
2014 QueryDisplayDPI();
\r
2015 return (y * DisplayDPIY + 96 / 2) / 96;
\r
2018 HBITMAP ResizeBitmap(HBITMAP hBitmap, int UnitSizeX, int UnitSizeY, int ScaleNumerator, int ScaleDenominator)
\r
2020 HBITMAP hDstBitmap;
\r
2029 hDstBitmap = NULL;
\r
2030 if(hDC = GetDC(NULL))
\r
2032 if(hSrcDC = CreateCompatibleDC(hDC))
\r
2034 if(hDstDC = CreateCompatibleDC(hDC))
\r
2036 if(GetObject(hBitmap, sizeof(BITMAP), &Bitmap) > 0)
\r
2038 if(UnitSizeX == 0)
\r
2039 UnitSizeX = Bitmap.bmWidth;
\r
2040 if(UnitSizeY == 0)
\r
2041 UnitSizeY = Bitmap.bmHeight;
\r
2042 Width = (Bitmap.bmWidth / UnitSizeX) * CalcPixelX((UnitSizeX * ScaleNumerator) / ScaleDenominator);
\r
2043 Height = (Bitmap.bmHeight / UnitSizeY) * CalcPixelY((UnitSizeY * ScaleNumerator) / ScaleDenominator);
\r
2044 if(hDstBitmap = CreateCompatibleBitmap(hDC, Width, Height))
\r
2046 hSrcOld = SelectObject(hSrcDC, hBitmap);
\r
2047 hDstOld = SelectObject(hDstDC, hDstBitmap);
\r
2048 SetStretchBltMode(hDstDC, COLORONCOLOR);
\r
2049 StretchBlt(hDstDC, 0, 0, Width, Height, hSrcDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, SRCCOPY);
\r
2050 SelectObject(hSrcDC, hSrcOld);
\r
2051 SelectObject(hDstDC, hDstOld);
\r
2058 ReleaseDC(NULL, hDC);
\r
2060 return hDstBitmap;
\r