source: lab.git/Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinUi.c

Last change on this file was a1bae3e, checked in by mitty <mitty@…>, 12 years ago
  • copy vendor drop to trunk

git-svn-id: https://lab.mitty.jp/svn/lab/trunk@147 7d2118f6-f56c-43e7-95a2-4bb3031d96e7

  • Property mode set to 100644
File size: 187.9 KB
Line 
1// SoftEther UT-VPN SourceCode
2//
3// Copyright (C) 2004-2010 SoftEther Corporation.
4// Copyright (C) 2004-2010 University of Tsukuba, Japan.
5// Copyright (C) 2003-2010 Daiyuu Nobori.
6// All Rights Reserved.
7//
8// http://utvpn.tsukuba.ac.jp/
9//
10// This program is free software; you can redistribute it and/or
11// modify it under the terms of the GNU General Public License
12// version 2 as published by the Free Software Foundation.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License version 2
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22//
23// このファイルは GPL バージョン 2 ライセンスで公開されています。
24// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
25// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
26// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
27// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
28//
29// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
30// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
31// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
32// ホストされています。
33// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
34// および、試験または研究のために利用が行われることを想定して配布
35// しています。
36// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
37// あります。
38// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
39// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
40// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
41// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
42// に組み込みさせていただきます。
43//
44// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
45// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
46//
47// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
48// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
49// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
50// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
51// ください。
52//
53// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
54// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
55// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
56// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
57// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
58// 公益保護にご協力いただきますようお願い申し上げます。
59//
60// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
61// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
62// を保護するための努力を行います。
63//
64// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
65// 日本国内の脆弱性情報届出受付公的機関:
66//         独立行政法人 情報処理推進機構
67//         http://www.ipa.go.jp/security/vuln/report/
68//
69// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
70// 連絡先: http://www.softether.co.jp/jp/contact/
71
72// -----------------------------------------------
73// [ChangeLog]
74// 2010.05.20
75//  新規リリース by SoftEther
76// -----------------------------------------------
77
78// WinUi.c
79// Win32 用ユーザーインターフェースコード
80
81#ifdef  WIN32
82
83#define WINUI_C
84
85#define _WIN32_WINNT        0x0502
86#define WINVER              0x0502
87#include <winsock2.h>
88#include <windows.h>
89#include <wincrypt.h>
90#include <wininet.h>
91#include <Iphlpapi.h>
92#include <shlobj.h>
93#include <commctrl.h>
94#include <Dbghelp.h>
95#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <wchar.h>
99#include <stdarg.h>
100#include <time.h>
101#include <errno.h>
102#include <Mayaqua/Mayaqua.h>
103#include <Cedar/Cedar.h>
104#include "../PenCore/resource.h"
105
106char cached_pin_code[MAX_SIZE] = {0};
107UINT64 cached_pin_code_expires = 0;
108
109static HINSTANCE hDll = NULL;
110static wchar_t *title_bar = NULL;
111static char *font_name = NULL;
112static UINT font_size = 9;
113static HIMAGELIST large_image_list = NULL, small_image_list = NULL;
114static LIST *icon_list = NULL;
115static HINSTANCE hMsHtml = NULL;
116static UINT init_winui_counter = 0;
117static bool new_style_mode = false;
118
119bool UseAlpha = false;
120UINT AlphaValue = 100;
121
122static THREAD *led_thread = NULL;
123static bool thread_stop = false;
124static bool g_led_special = false;
125static bool g_tcpip_topmost = false;
126
127typedef struct GDI_CACHE
128{
129    bool IsInited;
130    COLORREF BackgroundColor;
131    COLORREF ForegroundColor;
132    COLORREF TextBoxBackgroundColor;
133    HBRUSH BlackBrush;
134    HBRUSH WhiteBrush;
135    HBRUSH BackgroundColorBrush;
136    HBRUSH ForegroundColorBrush;
137    HBRUSH TextBoxBackgroundColorBrush;
138} GDI_CACHE;
139
140static GDI_CACHE gdi_cache = { false, };
141
142// スプラッシュウインドウデータ
143typedef struct SPLASH
144{
145    HWND hWnd;
146    HWND hWndParent;
147    WINBMP *Bmp;
148    void *Param;
149    UINT64 Ticks;
150    UINT64 StartTick;
151    char *Title;
152    wchar_t *Caption;
153    HPEN LinePen;
154    WINMEMDC *BackDC;
155} SPLASH;
156
157// 画面がフルカラーモードかどうか取得
158bool IsFullColor()
159{
160    bool ret = false;
161    HDC hDC = CreateCompatibleDC(0);
162
163    if (GetDeviceCaps(hDC, BITSPIXEL) >= 16)
164    {
165        ret = true;
166    }
167
168    DeleteDC(hDC);
169
170    return ret;
171}
172
173// リストビューの背景に画像を表示する
174void LvSetBkImage(HWND hWnd, UINT id, char *bmp_file_name)
175{
176    LVBKIMAGE t;
177    char *tmp;
178    // 引数チェック
179    if (hWnd == NULL || bmp_file_name == NULL)
180    {
181        return;
182    }
183    if (IsFullColor() == false)
184    {
185        // 256 色モードの場合は表示しない
186        return;
187    }
188
189    Zero(&t, sizeof(t));
190
191    tmp = MsCreateTempFileNameByExt(".bmp");
192
193    FileCopy(bmp_file_name, tmp);
194
195    t.ulFlags = LVBKIF_SOURCE_URL | LVBKIF_STYLE_NORMAL;
196    t.pszImage = tmp;
197    t.xOffsetPercent = 100;
198    t.yOffsetPercent = 100;
199
200    ListView_SetBkImage(DlgItem(hWnd, id), &t);
201
202    Free(tmp);
203}
204
205// メモリ DC を解放する
206void FreeMemDC(WINMEMDC *m)
207{
208    // 引数チェック
209    if (m == NULL)
210    {
211        return;
212    }
213
214    DeleteDC(m->hDC);
215    DeleteObject(m->hBitmap);
216
217    Free(m);
218}
219
220// メモリ DC を作成する
221WINMEMDC *NewMemDC(UINT width, UINT height)
222{
223    WINMEMDC *m = ZeroMalloc(sizeof(WINMEMDC));
224    BITMAPINFOHEADER h;
225    BITMAPINFO bi;
226
227    m->Width = width;
228    m->Height = height;
229
230    m->hDC = CreateCompatibleDC(0);
231
232    Zero(&h, sizeof(h));
233    h.biSize = sizeof(h);
234    h.biWidth = width;
235    h.biHeight = height;
236    h.biPlanes = 1;
237    h.biBitCount = 24;
238    h.biXPelsPerMeter = 2834;
239    h.biYPelsPerMeter = 2834;
240
241    Zero(&bi, sizeof(bi));
242    Copy(&bi.bmiHeader, &h, sizeof(BITMAPINFOHEADER));
243
244    m->hBitmap = CreateDIBSection(m->hDC, &bi, DIB_RGB_COLORS,
245        &m->Data, NULL, 0);
246
247    SelectObject(m->hDC, m->hBitmap);
248
249    return m;
250}
251
252// スプラッシュ画面を表示する (毎回絵が変わる)
253void ShowSplashEx(HWND hWndParent, char *software_name, UINT ticks, UINT line_color)
254{
255    wchar_t tmp[MAX_SIZE];
256    wchar_t caption[MAX_SIZE];
257    UINT id = MsRegReadInt(REG_CURRENT_USER, SPLASH_BMP_REGKEY, SPLASH_BMP_REGVALUE);
258    id++;
259    if (id > 20)
260    {
261        id = 1;
262    }
263    MsRegWriteInt(REG_CURRENT_USER, SPLASH_BMP_REGKEY, SPLASH_BMP_REGVALUE, id);
264
265    UniFormat(tmp, sizeof(tmp), L"|Splash%02u.bmp", id);
266
267    StrToUni(caption, sizeof(caption), software_name);
268
269    ShowSplash(hWndParent, tmp, software_name, caption, ticks, line_color, NULL);
270}
271
272// フォント描画
273void DrawFont(HDC hDC, wchar_t *text, UINT x, UINT y, HFONT font, UINT fore_color,
274              UINT back_color, UINT back_width)
275{
276    int i, j;
277
278    SelectObject(hDC, font);
279    SetBkMode(hDC, TRANSPARENT);
280
281    // 背景の描画
282    SetTextColor(hDC, back_color);
283    for (i = -((int)back_width);i <= (int)back_width;i++)
284    {
285        for (j = -((int)back_width); j <= (int)back_width;j++)
286        {
287            if (i != 0 || j != 0)
288            {
289                TextOutW(hDC, (int)x + i, (int)y + j, text, UniStrLen(text));
290            }
291        }
292    }
293
294    // 文字の描画
295    SetTextColor(hDC, fore_color);
296    TextOutW(hDC, x, y, text, UniStrLen(text));
297}
298
299// スプラッシュウインドウを開く
300LRESULT CALLBACK SplashProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
301{
302    SPLASH *splash;
303    CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
304    UINT64 now = Tick64();
305    UINT64 current_span = 0;
306    UINT a;
307    UINT fade = 8;
308
309    if (msg == WM_CREATE)
310    {
311        splash = (SPLASH *)cs->lpCreateParams;
312        current_span = 0;
313    }
314    else
315    {
316        splash = (SPLASH *)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
317        if (splash != NULL)
318        {
319            current_span = now - splash->StartTick;
320        }
321    }
322
323    switch (msg)
324    {
325    case WM_CREATE:
326        SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)splash);
327
328        CenterParent(hWnd);
329
330        if (splash->Ticks != 0)
331        {
332            SetTimer(hWnd, 1, 1, NULL);
333
334            splash->StartTick = now;
335
336            SetAplha(hWnd, 0);
337
338            Top(hWnd);
339        }
340
341        break;
342
343    case WM_TIMER:
344        switch (wParam)
345        {
346        case 1:
347            KillTimer(hWnd, 1);
348
349            a = 0;
350
351            if (current_span < (splash->Ticks / fade))
352            {
353                // フェードイン
354                a = (UINT)((double)current_span * 255.0 / (double)(splash->Ticks / fade));
355            }
356            else if (current_span < (splash->Ticks * (fade - 1) / fade))
357            {
358                // 通常表示
359                a = 255;
360            }
361            else if (current_span < splash->Ticks)
362            {
363                // フェードアウト
364                a = 255 - (UINT)(((double)(current_span - (splash->Ticks * (fade - 1) / fade))) * 255.0 / (double)(splash->Ticks / fade));
365            }
366            else
367            {
368                // 閉じる
369                goto LABEL_CLOSE;
370            }
371
372            SetAplha(hWnd, a);
373
374            SetTimer(hWnd, 1, 1, NULL);
375            break;
376        }
377        break;
378
379    case WM_PAINT:
380        if (true)
381        {
382            PAINTSTRUCT ps;
383            HDC hDC, hWndDC;
384
385            Zero(&ps, sizeof(ps));
386            hWndDC = BeginPaint(hWnd, &ps);
387            if (hWndDC != NULL)
388            {
389                POINT points[5];
390                wchar_t tmp[MAX_SIZE];
391
392                hDC = splash->BackDC->hDC;
393
394                // ビットマップ画像
395                BitBlt(hDC, 0, 0, splash->Bmp->Width, splash->Bmp->Height,
396                    splash->Bmp->hDC, 0, 0, SRCCOPY);
397
398                // 線
399                Zero(points, sizeof(points));
400                points[0].x = 0; points[0].y = 0;
401                points[1].x = splash->Bmp->Width - 1; points[1].y = 0;
402                points[2].x = splash->Bmp->Width - 1; points[2].y = splash->Bmp->Height - 1;
403                points[3].x = 0; points[3].y = splash->Bmp->Height - 1;
404                points[4].x = 0; points[4].y = 0;
405
406                SelectObject(hDC, splash->LinePen);
407                Polyline(hDC, points, 5);
408
409                // ソフトウェアのタイトルの描画
410                DrawFont(hDC, splash->Caption, 114, 136,
411                    GetFont("Arial", 36, true, false, false, false),
412                    RGB(0, 0, 0),
413                    RGB(255, 255, 255),
414                    3);
415
416                // ソフトウェアのバージョン情報の描画
417                UniFormat(tmp, sizeof(tmp),
418                    L"Version %u.%02u Build %u, Compiled in %04u/%02u/%02u.",
419                    CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100,
420                    CEDAR_BUILD, BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D);
421                DrawFont(hDC, tmp, 200, 202,
422                    GetFont("Arial", 8, true, false, false, false),
423                    RGB(0, 0, 0),
424                    RGB(255, 255, 255),
425                    1);
426
427                // 画面に描画
428                BitBlt(hWndDC, 0, 0, splash->Bmp->Width, splash->Bmp->Height,
429                    hDC, 0, 0, SRCCOPY);
430
431                EndPaint(hWnd, &ps);
432            }
433        }
434        break;
435
436    case WM_CLOSE:
437        if (splash->Ticks != 0)
438        {
439            return 0;
440        }
441LABEL_CLOSE:
442        if (splash->hWndParent != NULL)
443        {
444            Enable(splash->hWndParent, 0);
445        }
446        DestroyWindow(hWnd);
447        return 0;
448
449    case WM_KEYDOWN:
450        switch (wParam)
451        {
452        case VK_ESCAPE:
453        case VK_RETURN:
454        case VK_SPACE:
455            Close(hWnd);
456            break;
457        }
458        break;
459
460    case WM_LBUTTONUP:
461    case WM_RBUTTONUP:
462    case WM_MBUTTONUP:
463        Close(hWnd);
464        break;
465
466    case WM_DESTROY:
467        if (splash->hWndParent != NULL)
468        {
469            Enable(splash->hWndParent, 0);
470        }
471        PostQuitMessage(0);
472        return 0;
473    }
474
475    return DefWindowProc(hWnd, msg, wParam, lParam);
476}
477
478// スプラッシュウインドウ
479void ShowSplash(HWND hWndParent, wchar_t *bmp_file_name, char *title, wchar_t *caption, UINT ticks, UINT line_color, void *param)
480{
481    SPLASH *p;
482    WNDCLASSA wc;
483    char wndclass_name[MAX_SIZE];
484    // 引数チェック
485    if (bmp_file_name == NULL)
486    {
487        return;
488    }
489    if (IsEmptyStr(title))
490    {
491        title = "Splash Window";
492    }
493
494    p = ZeroMalloc(sizeof(SPLASH));
495
496    p->Bmp = LoadBmpFromFileW(bmp_file_name);
497    if (p->Bmp == NULL)
498    {
499        Free(p);
500        return;
501    }
502
503    p->BackDC = NewMemDC(p->Bmp->Width, p->Bmp->Height);
504
505    p->LinePen = CreatePen(PS_SOLID, 1, line_color);
506
507    p->hWndParent = hWndParent;
508
509    p->Title = title;
510    p->Caption = caption;
511    p->Ticks = ticks;
512
513    p->Param = param;
514
515    Zero(&wc, sizeof(wc));
516    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
517    wc.hCursor = LoadCursor(NULL, ticks == 0 ? IDC_ARROW : IDC_APPSTARTING);
518    wc.hInstance = GetModuleHandleA(NULL);
519    wc.lpfnWndProc = SplashProc;
520
521    Format(wndclass_name, sizeof(wndclass_name), "WINUI_SPLASH_CLASS_%I64u", Rand64());
522    wc.lpszClassName = wndclass_name;
523
524    RegisterClassA(&wc);
525
526    p->hWnd = CreateWindowA(wndclass_name, title,
527        WS_POPUP, 0, 0,
528        p->Bmp->Width, p->Bmp->Height,
529        hWndParent, NULL, GetModuleHandleA(NULL), p);
530    if (p->hWnd == NULL)
531    {
532        Debug("CreateWindowA Error: %u\n", GetLastError());
533    }
534
535    if (hWndParent != NULL)
536    {
537        Disable(hWndParent, 0);
538    }
539
540    ShowWindow(p->hWnd, SW_SHOW);
541
542    if (p->hWnd != NULL)
543    {
544        MSG msg;
545
546        while (true)
547        {
548            Zero(&msg, sizeof(msg));
549
550            if (GetMessageA(&msg, NULL, 0, 0) == 0)
551            {
552                break;
553            }
554
555            TranslateMessage(&msg);
556            DispatchMessageA(&msg);
557        }
558    }
559
560    if (hWndParent != NULL)
561    {
562        Enable(hWndParent, 0);
563        SetActiveWindow(hWndParent);
564        BringWindowToTop(hWndParent);
565    }
566
567    UnregisterClassA(wndclass_name, GetModuleHandleA(NULL));
568
569    FreeMemDC(p->BackDC);
570
571    FreeBmp(p->Bmp);
572
573    DeleteObject(p->LinePen);
574
575    Free(p);
576}
577
578// GDI オブジェクトのキャッシュがまだ作成されていない場合は作成する
579void InitGdiCache()
580{
581    if (gdi_cache.IsInited)
582    {
583        return;
584    }
585
586    gdi_cache.BlackBrush = GetStockObject(BLACK_BRUSH);
587    gdi_cache.WhiteBrush = GetStockObject(WHITE_BRUSH);
588
589    gdi_cache.BackgroundColor = RGB(247, 238, 255);
590    gdi_cache.BackgroundColorBrush = CreateSolidBrush(gdi_cache.BackgroundColor);
591
592    gdi_cache.ForegroundColor = RGB(0, 0, 0);
593    gdi_cache.ForegroundColorBrush = CreateSolidBrush(gdi_cache.ForegroundColor);
594
595    gdi_cache.TextBoxBackgroundColor = RGB(255, 255, 255);
596    gdi_cache.TextBoxBackgroundColorBrush = CreateSolidBrush(gdi_cache.TextBoxBackgroundColor);
597
598    gdi_cache.IsInited = true;
599}
600
601// ビットマップをリソースから読む
602WINBMP *LoadBmpFromResource(UINT id)
603{
604    HANDLE h;
605    // 引数チェック
606    if (id == 0)
607    {
608        return NULL;
609    }
610
611    h = LoadImageA(hDll, MAKEINTRESOURCEA(id), IMAGE_BITMAP, 0, 0,
612        LR_CREATEDIBSECTION | LR_VGACOLOR);
613
614    if (h == NULL)
615    {
616        return NULL;
617    }
618
619    return LoadBmpMain(h);
620}
621
622// ビットマップをファイルから読む
623WINBMP *LoadBmpFromFileW(wchar_t *filename)
624{
625    wchar_t tmp[MAX_SIZE];
626    char *tmpa;
627    // 引数チェック
628    if (filename == NULL)
629    {
630        return NULL;
631    }
632
633    // 一時ファイルにコピー
634    tmpa = MsCreateTempFileNameByExt("bmp");
635
636    StrToUni(tmp, sizeof(tmp), tmpa);
637
638    Free(tmpa);
639
640    if (FileCopyW(filename, tmp) == false)
641    {
642        return NULL;
643    }
644
645    return LoadBmpFromFileInnerW(tmp);
646}
647WINBMP *LoadBmpFromFileInnerW(wchar_t *filename)
648{
649    HANDLE h;
650    // 引数チェック
651    if (filename == NULL)
652    {
653        return NULL;
654    }
655
656    if (MsIsNt())
657    {
658        h = LoadImageW(NULL, filename, IMAGE_BITMAP, 0, 0,
659            LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_VGACOLOR);
660    }
661    else
662    {
663        char tmp[MAX_SIZE];
664
665        UniToStr(tmp, sizeof(tmp), filename);
666
667        h = LoadImageA(NULL, tmp, IMAGE_BITMAP, 0, 0,
668            LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_VGACOLOR);
669    }
670
671    if (h == NULL)
672    {
673        return NULL;
674    }
675
676    return LoadBmpMain(h);
677}
678WINBMP *LoadBmpFromFileA(char *filename)
679{
680    wchar_t tmp[MAX_SIZE];
681    // 引数チェック
682    if (filename == NULL)
683    {
684        return NULL;
685    }
686
687    StrToUni(tmp, sizeof(tmp), filename);
688
689    return LoadBmpFromFileW(tmp);
690}
691
692// ビットマップ読み込みメイン
693WINBMP *LoadBmpMain(void *hBitmap)
694{
695    WINBMP *b;
696    BITMAP d;
697    HDC hDC;
698    // 引数チェック
699    if (hBitmap == NULL)
700    {
701        return NULL;
702    }
703
704    Zero(&d, sizeof(d));
705
706    if (GetObject((HANDLE)hBitmap, sizeof(d), &d) == 0)
707    {
708        DeleteObject((HANDLE)hBitmap);
709        return NULL;
710    }
711
712    b = ZeroMalloc(sizeof(WINBMP));
713    b->Bits = d.bmBitsPixel;
714    b->hBitmap = hBitmap;
715    b->Height = d.bmHeight;
716    b->Width = d.bmWidth;
717
718    hDC = CreateCompatibleDC(0);
719
720    SelectObject(hDC, hBitmap);
721
722    b->hDC = hDC;
723
724    return b;
725}
726
727// ビットマップを解放する
728void FreeBmp(WINBMP *b)
729{
730    // 引数チェック
731    if (b == NULL)
732    {
733        return;
734    }
735
736    DeleteDC(b->hDC);
737    DeleteObject(b->hBitmap);
738
739    Free(b);
740}
741
742// 新しいスタイルを開始
743void EnableNewStyleMode()
744{
745    InitGdiCache();
746
747    new_style_mode = true;
748}
749
750// 新しいスタイルを終了
751void DisableNewStyleMode()
752{
753    new_style_mode = false;
754}
755
756// 新しいスタイルが有効になっているかどうかチェック
757bool IsNewStyleModeEnabled()
758{
759    return new_style_mode;
760}
761
762// NIC 情報ダイアログプロシージャ
763UINT NicInfoProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
764{
765    UI_NICINFO *info = (UI_NICINFO *)param;
766
767    switch (msg)
768    {
769    case WM_INITDIALOG:
770        NicInfoInit(hWnd, info);
771
772        SetTimer(hWnd, 1, 50, NULL);
773        break;
774
775    case WM_TIMER:
776        switch (wParam)
777        {
778        case 1:
779            KillTimer(hWnd, 1);
780
781            NicInfoOnTimer(hWnd, info);
782
783            SetTimer(hWnd, 1, 50, NULL);
784            break;
785
786        case 2:
787            KillTimer(hWnd, 2);
788            Close(hWnd);
789            break;
790        }
791        break;
792
793    case WM_COMMAND:
794        switch (wParam)
795        {
796        case IDOK:
797        case IDCANCEL:
798            Close(hWnd);
799            break;
800        }
801        break;
802
803    case WM_CLOSE:
804        KillTimer(hWnd, 1);
805        KillTimer(hWnd, 2);
806        EndDialog(hWnd, 0);
807        break;
808    }
809
810    return 0;
811}
812void NicInfoCloseAfterTime(HWND hWnd, UI_NICINFO *info, UINT tick)
813{
814    UINT64 now;
815    UINT64 closetime;
816    // 引数チェック
817    if (hWnd == NULL || info == NULL)
818    {
819        return;
820    }
821
822    now = Tick64();
823    closetime = now + (UINT64)tick;
824
825    if (info->CloseAfterTime == 0 || info->CloseAfterTime >= closetime)
826    {
827        info->CloseAfterTime = closetime;
828        KillTimer(hWnd, 2);
829        SetTimer(hWnd, 2, tick, NULL);
830    }
831}
832void NicInfoShowStatus(HWND hWnd, UI_NICINFO *info, wchar_t *msg1, wchar_t *msg2, UINT icon, bool animate)
833{
834    // 引数チェック
835    if (hWnd == NULL || info == NULL)
836    {
837        return;
838    }
839    if (icon == 0)
840    {
841        icon = ICO_TEST;
842    }
843    if (msg1 == NULL)
844    {
845        msg1 = L"";
846    }
847    if (msg2 == NULL)
848    {
849        msg2 = L"";
850    }
851
852    if (info->CurrentIcon != icon)
853    {
854        SetIcon(hWnd, S_ICON, icon);
855        info->CurrentIcon = icon;
856    }
857
858    SetText(hWnd, S_STATUS1, msg1);
859    SetText(hWnd, S_STATUS2, msg2);
860
861    SetShow(hWnd, P_BAR, animate && MsIsWinXPOrWinVista());
862}
863void NicInfoRefresh(HWND hWnd, UI_NICINFO *info)
864{
865    MS_ADAPTER *a;
866    IP ip;
867    char ip_str[MAX_SIZE];
868    char title[MAX_SIZE];
869    UINT i;
870    wchar_t tmp[MAX_SIZE];
871    bool has_ip = false;
872    // 引数チェック
873    if (hWnd == NULL || info == NULL)
874    {
875        return;
876    }
877
878    Format(title, sizeof(title), VLAN_ADAPTER_NAME_TAG, info->NicName);
879
880    a = MsGetAdapter(title);
881    if (a == NULL)
882    {
883        Close(hWnd);
884        return;
885    }
886
887    // IP アドレスが割り当てら割れているかどうかチェック
888    Zero(&ip, sizeof(ip));
889    for (i = 0;i < MAX_MS_ADAPTER_IP_ADDRESS;i++)
890    {
891        if (IsZeroIP(&a->IpAddresses[i]) == false)
892        {
893            Copy(&ip, &a->IpAddresses[i], sizeof(IP));
894
895            if (!(ip.addr[0] == 169 && ip.addr[1] == 254))
896            {
897                has_ip = true;
898            }
899        }
900    }
901    IPToStr(ip_str, sizeof(ip_str), &ip);
902
903    if (has_ip == false)
904    {
905        if (a->UseDhcp)
906        {
907            NicInfoShowStatus(hWnd, info, _UU("NICINFO_1"), _UU("NICINFO_1_1"), ICO_NIC_OFFLINE, true);
908        }
909        else
910        {
911            NicInfoShowStatus(hWnd, info, _UU("NICINFO_1"), _UU("NICINFO_1_2"), ICO_NIC_OFFLINE, true);
912        }
913    }
914    else
915    {
916        if (a->UseDhcp)
917        {
918            UniFormat(tmp, sizeof(tmp), _UU("NICINFO_2_1"), ip_str);
919            NicInfoShowStatus(hWnd, info, _UU("NICINFO_2"), tmp, ICO_NIC_ONLINE, false);
920        }
921        else
922        {
923            UniFormat(tmp, sizeof(tmp), _UU("NICINFO_3_1"), ip_str);
924            NicInfoShowStatus(hWnd, info, _UU("NICINFO_3"), tmp, ICO_NIC_ONLINE, false);
925        }
926
927        NicInfoCloseAfterTime(hWnd, info, NICINFO_AUTOCLOSE_TIME_2);
928    }
929
930    MsFreeAdapter(a);
931}
932void NicInfoInit(HWND hWnd, UI_NICINFO *info)
933{
934    // 引数チェック
935    if (hWnd == NULL || info == NULL)
936    {
937        return;
938    }
939
940    if (MsIsWinXPOrWinVista())
941    {
942        // Windows XP 以降の場合はプログレスバーを表示する
943        SendMsg(hWnd, P_BAR, PBM_SETMARQUEE, TRUE, 150);
944        SetStyle(hWnd, P_BAR, PBS_MARQUEE);
945    }
946
947    DlgFont(hWnd, S_STATUS1, 9, false);
948    DlgFont(hWnd, S_STATUS2, 11, false);
949
950    SetIcon(hWnd, 0, ICO_NIC_ONLINE);
951
952    FormatText(hWnd, 0, info->NicName);
953
954    NicInfoRefresh(hWnd, info);
955
956    NicInfoCloseAfterTime(hWnd, info, NICINFO_AUTOCLOSE_TIME_1);
957}
958void NicInfoOnTimer(HWND hWnd, UI_NICINFO *info)
959{
960    // 引数チェック
961    if (hWnd == NULL || info == NULL)
962    {
963        return;
964    }
965
966    if (info->Halt)
967    {
968        Close(hWnd);
969        return;
970    }
971
972    if (info->RouteChange != NULL &&
973        IsRouteChanged(info->RouteChange) == false)
974    {
975        return;
976    }
977
978    NicInfoRefresh(hWnd, info);
979}
980
981// NIC 情報ダイアログの表示
982void NicInfo(UI_NICINFO *info)
983{
984    // 引数チェック
985    if (info == NULL)
986    {
987        return;
988    }
989
990    info->RouteChange = NewRouteChange();
991
992    DialogEx2(NULL, D_NICINFO, NicInfoProc, info, true, true);
993
994    FreeRouteChange(info->RouteChange);
995    info->RouteChange = NULL;
996}
997
998// TCP 接続スレッド
999void WinConnectDlgThread(THREAD *thread, void *param)
1000{
1001    SOCK *s;
1002    WINCONNECT_DLG_DATA *d = (WINCONNECT_DLG_DATA *)param;
1003    // 引数チェック
1004    if (d == NULL || thread == NULL)
1005    {
1006        return;
1007    }
1008
1009    // ソケット接続
1010    s = ConnectEx2(d->hostname, d->port, d->timeout, &d->cancel);
1011
1012    d->ret_sock = s;
1013
1014    PostMessageA(d->hWnd, WM_APP + 68, 0, 0);
1015}
1016
1017// TCP 接続ダイアログプロシージャ
1018UINT WinConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
1019{
1020    WINCONNECT_DLG_DATA *d = (WINCONNECT_DLG_DATA *)param;
1021    // 引数チェック
1022    if (hWnd == NULL || d == NULL)
1023    {
1024        return 0;
1025    }
1026
1027    switch (msg)
1028    {
1029    case WM_INITDIALOG:
1030        // UI 設定
1031        CenterParent(hWnd);
1032        SetText(hWnd, 0, d->caption);
1033        SetText(hWnd, S_INFO, d->info);
1034        SetIcon(hWnd, S_ICON, d->icon_id);
1035        d->hWnd = hWnd;
1036
1037        if (MsIsWinXPOrWinVista())
1038        {
1039            // Windows XP 以降の場合はプログレスバーを表示する
1040            SendMsg(hWnd, IDC_PROGRESS1, PBM_SETMARQUEE, TRUE, 100);
1041            SetStyle(hWnd, IDC_PROGRESS1, PBS_MARQUEE);
1042        }
1043        else
1044        {
1045            // Windows 2000 以前の場合はプログレスバーを非表示にする
1046            Hide(hWnd, IDC_PROGRESS1);
1047        }
1048
1049        // スレッドの作成
1050        d->thread = NewThread(WinConnectDlgThread, d);
1051        break;
1052
1053    case WM_COMMAND:
1054        switch (wParam)
1055        {
1056        case IDCANCEL:
1057            Close(hWnd);
1058            break;
1059        }
1060        break;
1061
1062    case WM_APP + 68:
1063    case WM_CLOSE:
1064        if (d->cancel == false)
1065        {
1066            d->cancel = true;
1067            Disable(hWnd, IDCANCEL);
1068            if (d->ret_sock == NULL)
1069            {
1070                SetText(hWnd, S_INFO, _UU("CONNECTDLG_CANCELING"));
1071            }
1072            DoEvents(hWnd);
1073            Refresh(hWnd);
1074            WaitThread(d->thread, INFINITE);
1075            ReleaseThread(d->thread);
1076            EndDialog(hWnd, 0);
1077        }
1078        break;
1079    }
1080
1081    return 0;
1082}
1083
1084// TCP 接続を UI を表示しながら実施
1085SOCK *WinConnectEx2(HWND hWnd, char *server, UINT port, UINT timeout, UINT icon_id, wchar_t *caption, wchar_t *info)
1086{
1087    wchar_t tmp[MAX_SIZE];
1088    wchar_t tmp2[MAX_SIZE];
1089    WINCONNECT_DLG_DATA d;
1090    // 引数チェック
1091    if (server == NULL || port == 0)
1092    {
1093        return NULL;
1094    }
1095    if (icon_id == 0)
1096    {
1097        icon_id = ICO_USER_ADMIN;
1098    }
1099    if (caption == NULL)
1100    {
1101        if (hWnd == NULL)
1102        {
1103            caption = _UU("CONNECTDLG_CAPTION");
1104        }
1105        else
1106        {
1107            GetTxt(hWnd, 0, tmp2, sizeof(tmp2));
1108            caption = tmp2;
1109        }
1110    }
1111    if (info == NULL)
1112    {
1113        UniFormat(tmp, sizeof(tmp), _UU("CONNECTDLG_MESSAGE"), server, port);
1114
1115        info = tmp;
1116    }
1117
1118    Zero(&d, sizeof(d));
1119
1120    d.cancel = false;
1121    d.caption = caption;
1122    d.icon_id = icon_id;
1123    d.info = info;
1124    d.timeout = timeout;
1125    d.hostname = server;
1126    d.port = port;
1127
1128    Dialog(hWnd, D_CONNECT, WinConnectDlgProc, &d);
1129
1130    return d.ret_sock;
1131}
1132
1133// Windows ネットワーク設定画面の表示
1134bool ShowWindowsNetworkConnectionDialog()
1135{
1136    wchar_t exe_name[MAX_SIZE];
1137    void *proc;
1138
1139    CombinePathW(exe_name, sizeof(exe_name), MsGetSystem32DirW(), L"control.exe");
1140
1141    proc = Win32RunEx2W(exe_name, L"netconnections", false, NULL);
1142
1143    if (proc == NULL)
1144    {
1145        return false;
1146    }
1147
1148    Win32CloseProcess(proc);
1149
1150    return true;
1151}
1152
1153// メイリオフォントの取得
1154HFONT GetMeiryoFont()
1155{
1156    return GetMeiryoFontEx(0);
1157}
1158HFONT GetMeiryoFontEx(UINT font_size)
1159{
1160    // 少し適当な処理。日本語版では Meiryo, 中文版では Microsoft YaHei を使用する。
1161    if (_GETLANG() == 0)
1162    {
1163        return GetFont("Meiryo", font_size, false, false, false, false);
1164    }
1165    else if (_GETLANG() == 2)
1166    {
1167        return GetFont("Microsoft YaHei", font_size, false, false, false, false);
1168    }
1169    else
1170    {
1171        return GetFont(NULL, font_size, false, false, false, false);
1172    }
1173}
1174
1175// メイリオフォントに設定
1176void SetFontMeiryo(HWND hWnd, UINT id)
1177{
1178    SetFont(hWnd, id, GetMeiryoFont());
1179}
1180
1181// デフォルトフォントに設定
1182void SetFontDefault(HWND hWnd, UINT id)
1183{
1184    SetFont(hWnd, id, GetDialogDefaultFont());
1185}
1186
1187// 悪いプロセスに関する警告メッセージの表示
1188void ShowBadProcessWarning(HWND hWnd, BAD_PROCESS *bad)
1189{
1190    wchar_t title[MAX_SIZE];
1191    wchar_t message[8192];
1192    // 引数チェック
1193    if (bad == NULL)
1194    {
1195        return;
1196    }
1197
1198    UniFormat(title, sizeof(title), _UU("BAD_PROCESS_TITLE"), bad->Title);
1199    UniFormat(message, sizeof(message), _UU("BAD_PROCESS_MESSAGE"),
1200        bad->Title, bad->Title, bad->Title, bad->Title);
1201
1202    OnceMsg(hWnd, title, message, true, ICO_WARNING);
1203}
1204
1205// 競合するアンチウイルスソフトの一覧を検索し、該当するものがあれば表示する
1206bool CheckBadProcesses(HWND hWnd)
1207{
1208    bool ret = true;
1209    UINT i;
1210    LIST *o;
1211
1212    o = MsGetProcessList();
1213
1214    for (i = 0;i < LIST_NUM(o);i++)
1215    {
1216        MS_PROCESS *p = LIST_DATA(o, i);
1217        char exe[MAX_PATH];
1218        BAD_PROCESS *bad;
1219
1220        GetFileNameFromFilePath(exe, sizeof(exe), p->ExeFilename);
1221
1222        bad = IsBadProcess(exe);
1223
1224        if (bad != NULL)
1225        {
1226            // 悪いプロセスを発見したのでメッセージを表示する
1227            ret = false;
1228
1229            ShowBadProcessWarning(hWnd, bad);
1230        }
1231    }
1232
1233    MsFreeProcessList(o);
1234
1235    return ret;
1236}
1237
1238// 指定したプロセス名が悪いプロセスに該当するかどうか検索する
1239BAD_PROCESS *IsBadProcess(char *exe)
1240{
1241    UINT i;
1242    // 引数チェック
1243    if (exe == NULL)
1244    {
1245        return NULL;
1246    }
1247
1248    for (i = 0;i < num_bad_processes;i++)
1249    {
1250        BAD_PROCESS *bad = &bad_processes[i];
1251
1252        if (StrCmpi(bad->ExeName, exe) == 0)
1253        {
1254            return bad;
1255        }
1256    }
1257
1258    return NULL;
1259}
1260
1261// メッセージ表示プロシージャ
1262UINT OnceMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
1263{
1264    ONCEMSG_DLG *d = (ONCEMSG_DLG *)param;
1265    // 引数チェック
1266    if (hWnd == NULL)
1267    {
1268        return 0;
1269    }
1270
1271    switch (msg)
1272    {
1273    case WM_INITDIALOG:
1274        SetText(hWnd, 0, d->Title);
1275        SetText(hWnd, E_TEXT, d->Message);
1276        SetShow(hWnd, C_DONTSHOWAGAIN, d->ShowCheckbox);
1277        //DisableClose(hWnd);
1278        Focus(hWnd, IDCANCEL);
1279        if (d->Icon != 0)
1280        {
1281            SetIcon(hWnd, 0, d->Icon);
1282        }
1283
1284        if (MsIsVista())
1285        {
1286            SetFont(hWnd, E_TEXT, GetMeiryoFont());
1287        }
1288        else
1289        {
1290            DlgFont(hWnd, E_TEXT, 11, false);
1291        }
1292
1293        SetTimer(hWnd, 1, 50, NULL);
1294        break;
1295
1296    case WM_TIMER:
1297        switch (wParam)
1298        {
1299        case 1:
1300            if (*d->halt)
1301            {
1302                Close(hWnd);
1303            }
1304            break;
1305        }
1306        break;
1307
1308    case WM_COMMAND:
1309        switch (wParam)
1310        {
1311        case IDOK:
1312        case IDCANCEL:
1313            Close(hWnd);
1314            break;
1315        }
1316        break;
1317
1318    case WM_CLOSE:
1319        KillTimer(hWnd, 1);
1320        d->Checked = IsChecked(hWnd, C_DONTSHOWAGAIN);
1321        EndDialog(hWnd, 0);
1322        break;
1323    }
1324
1325    return 0;
1326}
1327
1328// メッセージを表示する
1329void OnceMsg(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon)
1330{
1331    OnceMsgEx(hWnd, title, message, show_checkbox, icon, NULL);
1332}
1333void OnceMsgEx(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon, bool *halt)
1334{
1335    ONCEMSG_DLG d;
1336    UINT hash;
1337    char valuename[MAX_PATH];
1338    bool b_dummy = false;
1339    // 引数チェック
1340    if (title == NULL)
1341    {
1342        title = title_bar;
1343    }
1344    if (message == NULL)
1345    {
1346        message = L"message";
1347    }
1348    if (halt == NULL)
1349    {
1350        halt = &b_dummy;
1351    }
1352
1353    Zero(&d, sizeof(d));
1354    d.Message = message;
1355    d.Title = title;
1356    d.ShowCheckbox = show_checkbox;
1357    d.Icon = icon;
1358    d.halt = halt;
1359
1360    hash = GetOnceMsgHash(title, message);
1361    Format(valuename, sizeof(valuename), ONCE_MSG_REGVALUE, hash);
1362
1363    if (MsRegReadInt(REG_CURRENT_USER, ONCE_MSG_REGKEY, valuename) == 0)
1364    {
1365        switch (icon)
1366        {
1367        case ICO_WARNING:
1368            MessageBeep(MB_ICONEXCLAMATION);
1369            break;
1370
1371        case ICO_INFORMATION:
1372            MessageBeep(MB_ICONASTERISK);
1373            break;
1374        }
1375
1376        Dialog(hWnd, D_ONCEMSG, OnceMsgProc, &d);
1377
1378        if (show_checkbox)
1379        {
1380            if (d.Checked)
1381            {
1382                MsRegWriteInt(REG_CURRENT_USER, ONCE_MSG_REGKEY, valuename, 1);
1383            }
1384        }
1385    }
1386}
1387
1388// メッセージハッシュの取得
1389UINT GetOnceMsgHash(wchar_t *title, wchar_t *message)
1390{
1391    BUF *b;
1392    UCHAR hash[SHA1_SIZE];
1393    UINT ret;
1394    // 引数チェック
1395    if (title == NULL)
1396    {
1397        title = title_bar;
1398    }
1399    if (message == NULL)
1400    {
1401        message = L"message";
1402    }
1403
1404    b = NewBuf();
1405    WriteBuf(b, title, UniStrSize(title));
1406    WriteBuf(b, message, UniStrSize(message));
1407    HashSha1(hash, b->Buf, b->Size);
1408    FreeBuf(b);
1409
1410    Copy(&ret, hash, sizeof(UINT));
1411
1412    return ret;
1413}
1414
1415// Windows Vista のテーマを設定する
1416void InitVistaWindowTheme(HWND hWnd)
1417{
1418    static HINSTANCE hInstDll = NULL;
1419    HRESULT (WINAPI *_SetWindowTheme)(HWND, LPCWSTR, LPCWSTR) = NULL;
1420
1421    if (MsIsVista() == false)
1422    {
1423        return;
1424    }
1425
1426    if (hInstDll == NULL)
1427    {
1428        hInstDll = LoadLibraryA("uxtheme.dll");
1429    }
1430
1431    if (hInstDll == NULL)
1432    {
1433        return;
1434    }
1435
1436    if (_SetWindowTheme == NULL)
1437    {
1438        _SetWindowTheme = (HRESULT (WINAPI *)(HWND,LPCWSTR,LPCWSTR))GetProcAddress(hInstDll, "SetWindowTheme");
1439    }
1440
1441    if (_SetWindowTheme == NULL)
1442    {
1443        return;
1444    }
1445
1446    _SetWindowTheme(hWnd, L"explorer", NULL);
1447}
1448
1449// 現在のディレクトリに存在する可能性のある Windows ファイアウォールに登録すべき
1450// すべてのアプリケーションを登録する
1451// Q. 行儀が悪いのではないか?
1452// A. 確かに行儀が悪いが、Windows Firewall でブロックされていることが原因で
1453//    VPN ソフトウェアが使用できないという苦情メールがよく来ていたので
1454//    やむを得ずこのように行うことにした。
1455//    なお、Microsoft 純正のサーバーソフトや他社のサーバーソフト等もこのように
1456//    して対応しているようであるから、良いのではないか。
1457void RegistWindowsFirewallAll()
1458{
1459    MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "utvpnclient.exe");
1460    MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "utvpnclient_x64.exe");
1461    MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "utvpnclient_ia64.exe");
1462
1463    MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "utvpncmgr.exe");
1464    MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "utvpncmgr_x64.exe");
1465    MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "utvpncmgr_ia64.exe");
1466
1467    MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "utvpnserver.exe");
1468    MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "utvpnserver_x64.exe");
1469    MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "utvpnserver_ia64.exe");
1470
1471    MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "utvpncmd.exe");
1472    MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "utvpncmd_x64.exe");
1473    MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "utvpncmd_ia64.exe");
1474
1475    MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham.exe");
1476    MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham_x64.exe");
1477    MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham_ia64.exe");
1478}
1479
1480// すでに通知サービスが動作しているかどうかチェックする
1481bool Win32CnCheckAlreadyExists(bool lock)
1482{
1483    char tmp[MAX_SIZE];
1484    HANDLE hMutex;
1485
1486    HashInstanceNameLocal(tmp, sizeof(tmp), CLIENT_NOTIFY_SERVICE_INSTANCENAME);
1487
1488    hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, tmp);
1489    if (hMutex != NULL)
1490    {
1491        CloseHandle(hMutex);
1492        return true;
1493    }
1494
1495    if (lock == false)
1496    {
1497        return false;
1498    }
1499
1500    hMutex = CreateMutex(NULL, FALSE, tmp);
1501    if (hMutex == NULL)
1502    {
1503        CloseHandle(hMutex);
1504        return true;
1505    }
1506
1507    return false;
1508}
1509
1510// hamcore 内の EXE の実行
1511bool ExecuteHamcoreExe(char *name)
1512{
1513    BUF *b;
1514    wchar_t tmp[MAX_PATH];
1515    char tmp2[MAX_PATH];
1516    UCHAR hash[MD5_SIZE];
1517    // 引数チェック
1518    if (name == NULL)
1519    {
1520        return false;
1521    }
1522
1523    b = ReadDump(name);
1524    if (b == NULL)
1525    {
1526        return false;
1527    }
1528
1529    Hash(hash, name, StrLen(name), false);
1530    BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
1531    UniFormat(tmp, sizeof(tmp), L"%s\\tmp_%S.exe", MsGetMyTempDirW(), tmp2);
1532    SeekBuf(b, 0, 0);
1533    DumpBufW(b, tmp);
1534
1535    FreeBuf(b);
1536
1537    return RunW(tmp, NULL, false, false);
1538}
1539
1540// イースターエッグの表示
1541void ShowEasterEgg(HWND hWnd)
1542{
1543}
1544
1545void KakushiThread(THREAD *thread, void *param)
1546{
1547    KAKUSHI *k;
1548    // 引数チェック
1549    if (thread == NULL || param == NULL)
1550    {
1551        return;
1552    }
1553
1554    k = (KAKUSHI *)param;
1555
1556    k->Thread = thread;
1557    AddRef(k->Thread->ref);
1558    NoticeThreadInit(thread);
1559
1560    Dialog(NULL, D_CM_KAKUSHI, KakushiDlgProc, k);
1561    k->hWnd = NULL;
1562}
1563
1564KAKUSHI *InitKakushi()
1565{
1566    THREAD *t;
1567    KAKUSHI *k = ZeroMalloc(sizeof(KAKUSHI));
1568
1569    t = NewThread(KakushiThread, k);
1570
1571    WaitThreadInit(t);
1572    ReleaseThread(t);
1573
1574    return k;
1575}
1576
1577UINT KakushiDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
1578{
1579    KAKUSHI *k = (KAKUSHI *)param;
1580    UINT64 now;
1581    bool b;
1582    if (hWnd == NULL)
1583    {
1584        return 0;
1585    }
1586
1587    switch (msg)
1588    {
1589    case WM_INITDIALOG:
1590        SetText(hWnd, S_INFO, _UU("CM_VLAN_CREATING"));
1591
1592        b = false;
1593
1594        if (MsIsVista())
1595        {
1596            if (_GETLANG() == 0)
1597            {
1598                SetFont(hWnd, S_INFO, GetFont("Meiryo", 11, false, false, false, false));
1599                b = true;
1600            }
1601            else if (_GETLANG() == 2)
1602            {
1603                SetFont(hWnd, S_INFO, GetFont("Microsoft YaHei", 11, false, false, false, false));
1604                b = true;
1605            }
1606        }
1607
1608        if (b == false)
1609        {
1610            DlgFont(hWnd, S_INFO, 11, false);
1611        }
1612
1613        SetTimer(hWnd, 1, 50, NULL);
1614        k->hWnd = hWnd;
1615
1616        k->Span = 20 * 1000;
1617        k->StartTick = Tick64();
1618
1619        SetRange(hWnd, P_PROGRESS, 0, (UINT)k->Span);
1620
1621    case WM_APP + 9821:
1622        now = Tick64();
1623
1624        if (((k->StartTick + k->Span) <= now) || k->Halt)
1625        {
1626            EndDialog(hWnd, 0);
1627            break;
1628        }
1629
1630        SetPos(hWnd, P_PROGRESS, (UINT)(now - k->StartTick));
1631        break;
1632
1633    case WM_TIMER:
1634        switch (wParam)
1635        {
1636        case 1:
1637            AllowSetForegroundWindow(ASFW_ANY);
1638            SetForegroundWindow(hWnd);
1639            SetActiveWindow(hWnd);
1640
1641            now = Tick64();
1642
1643            if (((k->StartTick + k->Span) <= now) || k->Halt)
1644            {
1645                EndDialog(hWnd, 0);
1646                break;
1647            }
1648
1649            SetPos(hWnd, P_PROGRESS, (UINT)(now - k->StartTick));
1650            break;
1651        }
1652        break;
1653
1654    case WM_CLOSE:
1655        return 1;
1656    }
1657
1658    return 0;
1659}
1660
1661// 隠し画面解放
1662void FreeKakushi(KAKUSHI *k)
1663{
1664    // 引数チェック
1665    if (k == NULL)
1666    {
1667        return;
1668    }
1669
1670    k->Halt = true;
1671
1672    if (k->hWnd != NULL)
1673    {
1674        PostMessage(k->hWnd, WM_APP + 9821, 0, 0);
1675    }
1676
1677    WaitThread(k->Thread, INFINITE);
1678    ReleaseThread(k->Thread);
1679
1680    Free(k);
1681}
1682
1683// TCP/IP 最適化選択ダイアログプロシージャ
1684UINT TcpMsgDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
1685{
1686    UINT ret;
1687    // 引数チェック
1688    if (hWnd == NULL)
1689    {
1690        return 0;
1691    }
1692
1693    switch (msg)
1694    {
1695    case WM_INITDIALOG:
1696        SetIcon(hWnd, 0, ICO_SETUP);
1697        //DlgFont(hWnd, R_OPTIMIZE, 0, true);
1698
1699        Check(hWnd, R_NO, true);
1700
1701        if (g_tcpip_topmost)
1702        {
1703            Top(hWnd);
1704        }
1705
1706        break;
1707
1708    case WM_COMMAND:
1709        switch (wParam)
1710        {
1711        case IDOK:
1712            ret = 1;
1713            if (IsChecked(hWnd, R_MANUAL))
1714            {
1715                ret = 2;
1716            }
1717            else if (IsChecked(hWnd, R_NO))
1718            {
1719                ret = 0;
1720            }
1721
1722            EndDialog(hWnd, ret);
1723            break;
1724        }
1725        break;
1726
1727    case WM_CLOSE:
1728        return 1;
1729    }
1730
1731    return 0;
1732}
1733
1734// ダイアログ初期化
1735void TcpIpDlgInit(HWND hWnd)
1736{
1737    MS_TCP tcp;
1738
1739    SetIcon(hWnd, 0, ICO_SETUP);
1740
1741    MsGetTcpConfig(&tcp);
1742
1743    Check(hWnd, R_RECV_DISABLE, tcp.RecvWindowSize == 0);
1744    Check(hWnd, R_RECV_ENABLE, tcp.RecvWindowSize != 0);
1745    SetInt(hWnd, E_RECV, tcp.RecvWindowSize != 0 ? tcp.RecvWindowSize : DEFAULT_TCP_MAX_WINDOW_SIZE_RECV);
1746
1747    Check(hWnd, R_SEND_DISABLE, tcp.SendWindowSize == 0);
1748    Check(hWnd, R_SEND_ENABLE, tcp.SendWindowSize != 0);
1749    SetInt(hWnd, E_SEND, tcp.SendWindowSize != 0 ? tcp.SendWindowSize : DEFAULT_TCP_MAX_WINDOW_SIZE_SEND);
1750
1751    TcpIpDlgUpdate(hWnd);
1752}
1753
1754// ダイアログ更新
1755void TcpIpDlgUpdate(HWND hWnd)
1756{
1757    bool ok = true;
1758
1759    SetEnable(hWnd, E_RECV, IsChecked(hWnd, R_RECV_ENABLE));
1760    SetEnable(hWnd, S_RECV, IsChecked(hWnd, R_RECV_ENABLE));
1761    SetEnable(hWnd, E_SEND, IsChecked(hWnd, R_SEND_ENABLE));
1762    SetEnable(hWnd, S_SEND, IsChecked(hWnd, R_SEND_ENABLE));
1763
1764    if (IsChecked(hWnd, R_RECV_ENABLE) && GetInt(hWnd, E_RECV) < 1454)
1765    {
1766        ok = false;
1767    }
1768
1769    if (IsChecked(hWnd, R_SEND_ENABLE) && GetInt(hWnd, E_SEND) < 1454)
1770    {
1771        ok = false;
1772    }
1773
1774    SetEnable(hWnd, IDOK, ok);
1775}
1776
1777// TCP/IP ダイアログプロシージャ
1778UINT TcpIpDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
1779{
1780    MS_TCP tcp, old;
1781    // 引数チェック
1782    if (hWnd == NULL)
1783    {
1784        return 0;
1785    }
1786
1787    switch (msg)
1788    {
1789    case WM_INITDIALOG:
1790        TcpIpDlgInit(hWnd);
1791
1792        if (g_tcpip_topmost)
1793        {
1794            Top(hWnd);
1795        }
1796
1797        break;
1798
1799    case WM_COMMAND:
1800        switch (LOWORD(wParam))
1801        {
1802        case R_RECV_DISABLE:
1803        case R_RECV_ENABLE:
1804        case R_SEND_DISABLE:
1805        case R_SEND_ENABLE:
1806        case E_RECV:
1807        case E_SEND:
1808            TcpIpDlgUpdate(hWnd);
1809            break;
1810        }
1811
1812        switch (wParam)
1813        {
1814        case IDOK:
1815            Zero(&tcp, sizeof(tcp));
1816
1817            if (IsChecked(hWnd, R_RECV_ENABLE))
1818            {
1819                tcp.RecvWindowSize = GetInt(hWnd, E_RECV);
1820            }
1821
1822            if (IsChecked(hWnd, R_SEND_ENABLE))
1823            {
1824                tcp.SendWindowSize = GetInt(hWnd, E_SEND);
1825            }
1826
1827            MsGetTcpConfig(&old);
1828
1829            MsSetTcpConfig(&tcp);
1830            MsSaveTcpConfigReg(&tcp);
1831
1832            EndDialog(hWnd, true);
1833            break;
1834
1835        case IDCANCEL:
1836            Close(hWnd);
1837            break;
1838
1839        case R_RECV_ENABLE:
1840            FocusEx(hWnd, E_RECV);
1841            break;
1842
1843        case R_SEND_ENABLE:
1844            FocusEx(hWnd, E_SEND);
1845            break;
1846
1847        case B_RECV:
1848            SetInt(hWnd, E_RECV, DEFAULT_TCP_MAX_WINDOW_SIZE_RECV);
1849            Check(hWnd, R_RECV_DISABLE, false);
1850            Check(hWnd, R_RECV_ENABLE, true);
1851            TcpIpDlgUpdate(hWnd);
1852            FocusEx(hWnd, E_RECV);
1853            break;
1854
1855        case B_SEND:
1856            SetInt(hWnd, E_SEND, DEFAULT_TCP_MAX_WINDOW_SIZE_SEND);
1857            Check(hWnd, R_SEND_DISABLE, false);
1858            Check(hWnd, R_SEND_ENABLE, true);
1859            TcpIpDlgUpdate(hWnd);
1860            FocusEx(hWnd, E_SEND);
1861            break;
1862
1863        case B_DELETE:
1864            Zero(&tcp, sizeof(tcp));
1865            MsSetTcpConfig(&tcp);
1866            MsDeleteTcpConfigReg();
1867            EndDialog(hWnd, 0);
1868            break;
1869        }
1870        break;
1871
1872    case WM_CLOSE:
1873        EndDialog(hWnd, false);
1874        break;
1875    }
1876
1877    return 0;
1878}
1879
1880// 64 bit に関する警告ダイアログ
1881UINT Cpu64DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
1882{
1883    switch (msg)
1884    {
1885    case WM_INITDIALOG:
1886        SetIcon(hWnd, 0, ICO_WARNING);
1887        DlgFont(hWnd, S_BOLD, 9, true);
1888        SetTimer(hWnd, 1, 30 * 1000, NULL);
1889        break;
1890
1891    case WM_TIMER:
1892        switch (wParam)
1893        {
1894        case 1:
1895            KillTimer(hWnd, 1);
1896            Command(hWnd, IDOK);
1897            break;
1898        }
1899
1900        break;
1901
1902    case WM_COMMAND:
1903        switch (wParam)
1904        {
1905        case IDOK:
1906        case IDCANCEL:
1907            Close(hWnd);
1908            break;
1909        }
1910        break;
1911
1912    case WM_CLOSE:
1913        EndDialog(hWnd, 0);
1914        break;
1915    }
1916
1917    return 0;
1918}
1919
1920// 64 bit に関する警告ダイアログの表示
1921void ShowCpu64Warning()
1922{
1923    Dialog(NULL, D_CPU64_WARNING, Cpu64DlgProc, NULL);
1924}
1925
1926// TCP/IP 設定ユーティリティの表示
1927void ShowTcpIpConfigUtil(HWND hWnd, bool util_mode)
1928{
1929    if (MsIsTcpConfigSupported() == false)
1930    {
1931        if (util_mode)
1932        {
1933            // 現在の OS ではサポートされていない旨のメッセージを表示
1934            if (MsIsAdmin() == false)
1935            {
1936                MsgBox(hWnd, MB_ICONINFORMATION, _UU("TCPOPT_NOT_ADMIN"));
1937            }
1938            else
1939            {
1940                MsgBox(hWnd, MB_ICONINFORMATION, _UU("TCPOPT_NOT_SUPPORTED"));
1941            }
1942        }
1943        return;
1944    }
1945
1946    if (util_mode == false)
1947    {
1948        // utvpncmd を起動してすぐに終了する
1949        wchar_t tmp[MAX_PATH];
1950        wchar_t exedir[MAX_PATH];
1951        HANDLE h;
1952
1953        GetExeDirW(exedir, sizeof(exedir));
1954
1955        if (IsX64())
1956        {
1957            UniFormat(tmp, sizeof(tmp), L"%s\\utvpncmd_x64.exe", exedir);
1958        }
1959        else if (IsIA64())
1960        {
1961            UniFormat(tmp, sizeof(tmp), L"%s\\utvpncmd_ia64.exe", exedir);
1962        }
1963        else
1964        {
1965            UniFormat(tmp, sizeof(tmp), L"%s\\utvpncmd.exe", exedir);
1966        }
1967
1968        if (IsFileW(tmp))
1969        {
1970            RunW(tmp, L"/tool /cmd:exit", true, false);
1971        }
1972
1973        // netsh によるタスクオフローディングの無効化
1974        if (MsIsVista())
1975        {
1976            char netsh_exe[MAX_SIZE];
1977            DIRLIST *dl;
1978            UINT i;
1979            bool b = false;
1980
1981            dl = EnumDirW(exedir);
1982
1983            for (i = 0;i < dl->NumFiles;i++)
1984            {
1985                if (UniInStr(dl->File[i]->FileNameW, L"utvpnbridge") || 
1986                    UniInStr(dl->File[i]->FileNameW, L"utvpnserver"))
1987                {
1988                    b = true;
1989                }
1990            }
1991
1992            FreeDir(dl);
1993
1994            if (b)
1995            {
1996                CombinePath(netsh_exe, sizeof(netsh_exe), MsGetSystem32Dir(), "netsh.exe");
1997
1998                Run(netsh_exe, "netsh int ipv6 set global taskoffload=disabled", true, false);
1999                Run(netsh_exe, "netsh int ipv4 set global taskoffload=disabled", true, false);
2000            }
2001        }
2002
2003        // Windows Firewall 登録
2004        RegistWindowsFirewallAll();
2005
2006        SleepThread(1000);
2007
2008        // utvpnclient.exe /uihelp の起動
2009        h = CmExecUiHelperMain();
2010        if (h != NULL)
2011        {
2012            CloseHandle(h);
2013        }
2014
2015        if (Is64() == false)
2016        {
2017            if (MsIs64BitWindows())
2018            {
2019                // 32 bit 版を 64 bit Windows 上で使用している場合は
2020                // 警告メッセージを表示する
2021                ShowCpu64Warning();
2022            }
2023        }
2024
2025        if (MsIsAdmin())
2026        {
2027            if (MsIsVista())
2028            {
2029                // Windows Vista でインストールする場合は
2030                // MMCSS のネットワーク制限を解除する
2031                if (MsIsMMCSSNetworkThrottlingEnabled())
2032                {
2033                    MsSetMMCSSNetworkThrottlingEnable(false);
2034                }
2035            }
2036        }
2037    }
2038
2039    if (util_mode == false && MsIsShouldShowTcpConfigApp() == false)
2040    {
2041        return;
2042    }
2043
2044    if (util_mode == false)
2045    {
2046        // 2006.07.04 nobori
2047        // インストーラ上では TCP/IP 最適化ユーティリティは表示しないことにした
2048        return;
2049    }
2050
2051    g_tcpip_topmost = util_mode ? false : true;
2052
2053    if (util_mode == false)
2054    {
2055        UINT ret = Dialog(hWnd, D_TCP_MSG, TcpMsgDlgProc, NULL);
2056
2057        if (ret == 0)
2058        {
2059            MS_TCP tcp;
2060
2061            Zero(&tcp, sizeof(tcp));
2062            MsGetTcpConfig(&tcp);
2063            MsSaveTcpConfigReg(&tcp);
2064            return;
2065        }
2066        else if (ret == 1)
2067        {
2068            MS_TCP tcp;
2069
2070            Zero(&tcp, sizeof(tcp));
2071
2072            tcp.RecvWindowSize = DEFAULT_TCP_MAX_WINDOW_SIZE_RECV;
2073            tcp.SendWindowSize = DEFAULT_TCP_MAX_WINDOW_SIZE_SEND;
2074            MsSetTcpConfig(&tcp);
2075            MsSaveTcpConfigReg(&tcp);
2076
2077            return;
2078        }
2079    }
2080
2081    Dialog(hWnd, D_TCP, TcpIpDlgProc, NULL);
2082}
2083
2084// メニューの国際化対応処理を行う (Unicode)
2085void InitMenuInternationalUni(HMENU hMenu, char *prefix)
2086{
2087    UINT i, num;
2088    // 引数チェック
2089    if (hMenu == NULL || prefix == NULL)
2090    {
2091        return;
2092    }
2093
2094    // メニューの項目数を取得する
2095    num = GetMenuItemCount(hMenu);
2096
2097    // メニューを列挙する
2098    for (i = 0;i < num;i++)
2099    {
2100        HMENU hSubMenu = GetSubMenu(hMenu, i);
2101        MENUITEMINFOW info;
2102        wchar_t tmp[MAX_SIZE];
2103
2104        if (hSubMenu != NULL)
2105        {
2106            // サブメニューがある場合再帰呼び出しする
2107            InitMenuInternational(hSubMenu, prefix);
2108        }
2109
2110        // メニュー項目を取得する
2111        Zero(&info, sizeof(info));
2112        info.cbSize = sizeof(info);
2113        info.cch = sizeof(tmp);
2114        info.dwTypeData = tmp;
2115        info.fMask = MIIM_STRING;
2116        Zero(tmp, sizeof(tmp));
2117
2118        if (GetMenuItemInfoW(hMenu, i, true, &info))
2119        {
2120            if (tmp[0] == L'@')
2121            {
2122                char name[256];
2123                wchar_t *ret;
2124
2125                Format(name, sizeof(name), "%s@%S", prefix, &tmp[1]);
2126
2127                ret = _UU(name);
2128                if (UniIsEmptyStr(ret) == false)
2129                {
2130                    UniStrCpy(tmp, sizeof(tmp), ret);
2131                    info.cch = UniStrLen(tmp);
2132
2133                    SetMenuItemInfoW(hMenu, i, true, &info);
2134                }
2135            }
2136        }
2137    }
2138}
2139
2140// メニューの国際化対応処理を行う
2141void InitMenuInternational(HMENU hMenu, char *prefix)
2142{
2143    UINT i, num;
2144    // 引数チェック
2145    if (hMenu == NULL || prefix == NULL)
2146    {
2147        return;
2148    }
2149
2150    if (MsIsNt())
2151    {
2152        InitMenuInternationalUni(hMenu, prefix);
2153        return;
2154    }
2155
2156    // メニューの項目数を取得する
2157    num = GetMenuItemCount(hMenu);
2158
2159    // メニューを列挙する
2160    for (i = 0;i < num;i++)
2161    {
2162        HMENU hSubMenu = GetSubMenu(hMenu, i);
2163        MENUITEMINFO info;
2164        char tmp[MAX_SIZE];
2165
2166        if (hSubMenu != NULL)
2167        {
2168            // サブメニューがある場合再帰呼び出しする
2169            InitMenuInternational(hSubMenu, prefix);
2170        }
2171
2172        // メニュー項目を取得する
2173        Zero(&info, sizeof(info));
2174        info.cbSize = sizeof(info);
2175        info.cch = sizeof(tmp);
2176        info.dwTypeData = tmp;
2177        info.fMask = MIIM_STRING;
2178        Zero(tmp, sizeof(tmp));
2179
2180        if (GetMenuItemInfo(hMenu, i, true, &info))
2181        {
2182            if (tmp[0] == '@')
2183            {
2184                char name[256];
2185                char *ret;
2186
2187                Format(name, sizeof(name), "%s@%s", prefix, &tmp[1]);
2188
2189                ret = _SS(name);
2190                if (IsEmptyStr(ret) == false)
2191                {
2192                    StrCpy(tmp, sizeof(tmp), ret);
2193                    info.cch = StrLen(tmp);
2194
2195                    SetMenuItemInfo(hMenu, i, true, &info);
2196                }
2197            }
2198        }
2199    }
2200}
2201
2202// ダイアログボックス用のデフォルトのフォントを取得する
2203HFONT GetDialogDefaultFont()
2204{
2205    return GetDialogDefaultFontEx(false);
2206}
2207HFONT GetDialogDefaultFontEx(bool meiryo)
2208{
2209    char *default_font_name = _SS("DEFAULT_FONT");
2210    UINT default_font_size = _II("DEFAULT_FONT_SIZE");
2211
2212    if (meiryo)
2213    {
2214        if (_GETLANG() == 2)
2215        {
2216            default_font_name = "Microsoft YaHei";
2217        }
2218        else
2219        {
2220            default_font_name = "Meiryo";
2221        }
2222    }
2223
2224    if (IsEmptyStr(default_font_name))
2225    {
2226        default_font_name = font_name;
2227    }
2228
2229    if (default_font_size == 0)
2230    {
2231        default_font_size = 9;
2232    }
2233
2234    return GetFont(default_font_name, default_font_size, false, false, false, false);
2235}
2236
2237// ウインドウサイズとコントロールサイズを調整する
2238void AdjustWindowAndControlSize(HWND hWnd)
2239{
2240    HFONT hDlgFont;
2241    UINT dlgfont_x, dlgfont_y;
2242    RECT rect, rect2;
2243    LIST *o;
2244    UINT i;
2245    // 引数チェック
2246    if (hWnd == NULL)
2247    {
2248        return;
2249    }
2250
2251    // 現在のウインドウのフォントを取得する
2252    hDlgFont = (HFONT)SendMsg(hWnd, 0, WM_GETFONT, 0, 0);
2253
2254    // 現在のウインドウのフォントの幅と高さを取得する
2255    CalcFontSize(hDlgFont, &dlgfont_x, &dlgfont_y);
2256
2257    if ((dlgfont_x == WINUI_DEFAULT_DIALOG_UNIT_X) &&
2258        (dlgfont_y == WINUI_DEFAULT_DIALOG_UNIT_Y))
2259    {
2260        // 調整する必要が無い
2261        return;
2262    }
2263
2264    // ウインドウのサイズを調整する
2265    if (GetWindowRect(hWnd, &rect))
2266    {
2267        if (GetClientRect(hWnd, &rect2))
2268        {
2269            UINT width = rect2.right - rect2.left;
2270            UINT height = rect2.bottom - rect2.top;
2271
2272            AdjustDialogXY(&width, &height, dlgfont_x, dlgfont_y);
2273
2274            width += (rect.right - rect.left) - (rect2.right - rect2.left);
2275            height += (rect.bottom - rect.top) - (rect2.bottom - rect2.top);
2276
2277            if (true)
2278            {
2279                HWND hParent = GetParent(hWnd);
2280
2281                if (hParent != NULL)
2282                {
2283                    RECT r;
2284
2285                    Zero(&r, sizeof(r));
2286
2287                    if (GetWindowRect(hParent, &r))
2288                    {
2289                        RECT r2;
2290
2291                        rect.top = r.top + GetSystemMetrics(SM_CYCAPTION);
2292
2293                        Zero(&r2, sizeof(r2));
2294                        if (SystemParametersInfo(SPI_GETWORKAREA, 0, &r2, 0))
2295                        {
2296                            if (r2.bottom < (rect.top + (int)height))
2297                            {
2298                                rect.top -= (rect.top + (int)height) - r2.bottom;
2299
2300                                if (rect.top < 0)
2301                                {
2302                                    rect.top = 0;
2303                                }
2304                            }
2305                        }
2306                    }
2307                }
2308            }
2309
2310            MoveWindow(hWnd, rect.left, rect.top, width, height, false);
2311        }
2312    }
2313
2314    // 子ウインドウを列挙する
2315    o = EnumAllChildWindowEx(hWnd, false, true, true);
2316
2317    for (i = 0;i < LIST_NUM(o);i++)
2318    {
2319        // 子ウインドウのサイズを調整する
2320        HWND h = *((HWND *)LIST_DATA(o, i));
2321        HWND hWndParent = GetParent(h);
2322        RECT current_rect;
2323        char class_name[MAX_PATH];
2324        bool is_image = false;
2325
2326        // クラス名を取得
2327        Zero(class_name, sizeof(class_name));
2328        GetClassNameA(h, class_name, sizeof(class_name));
2329
2330        if (StrCmpi(class_name, "static") == 0)
2331        {
2332            if (SendMsg(h, 0, STM_GETIMAGE, IMAGE_BITMAP, 0) != 0 ||
2333                SendMsg(h, 0, STM_GETIMAGE, IMAGE_ICON, 0) != 0 ||
2334                SendMsg(h, 0, STM_GETICON, 0, 0) != 0)
2335            {
2336                is_image = true;
2337            }
2338        }
2339
2340        // 位置を取得
2341        if (GetWindowRect(h, &current_rect))
2342        {
2343            // クライアント座標に変換
2344            POINT p1, p2;
2345
2346            p1.x = current_rect.left;
2347            p1.y = current_rect.top;
2348
2349            p2.x = current_rect.right;
2350            p2.y = current_rect.bottom;
2351
2352            ScreenToClient(hWndParent, &p1);
2353            ScreenToClient(hWndParent, &p2);
2354
2355            // 位置を調整
2356            AdjustDialogXY(&p1.x, &p1.y, dlgfont_x, dlgfont_y);
2357            AdjustDialogXY(&p2.x, &p2.y, dlgfont_x, dlgfont_y);
2358
2359            if (is_image)
2360            {
2361                p2.x = p1.x + (current_rect.right - current_rect.left);
2362                p2.y = p1.y + (current_rect.bottom - current_rect.top);
2363            }
2364
2365            // 移動
2366            MoveWindow(h, p1.x, p1.y, p2.x - p1.x, p2.y - p1.y, false);
2367        }
2368    }
2369
2370    FreeWindowList(o);
2371}
2372
2373// x と y の値をフォントに応じて調整する
2374void AdjustDialogXY(UINT *x, UINT *y, UINT dlgfont_x, UINT dlgfont_y)
2375{
2376    if (x != NULL)
2377    {
2378        *x = (UINT)(((double)*x) * (double)WINUI_DEFAULT_DIALOG_UNIT_X / (double)dlgfont_x);
2379    }
2380
2381    if (y != NULL)
2382    {
2383        *y = (UINT)(((double)*y) * (double)WINUI_DEFAULT_DIALOG_UNIT_Y / (double)dlgfont_y);
2384    }
2385}
2386
2387// ダイアログボックスの国際化対応処理を行う
2388void InitDialogInternational(HWND hWnd, void *param)
2389{
2390    LIST *o;
2391    UINT i;
2392    bool is_managed_dialog = false;
2393    char caption[MAX_PATH];
2394    char *dialog_name;
2395    // 引数チェック
2396    if (hWnd == NULL)
2397    {
2398        return;
2399    }
2400
2401    AdjustWindowAndControlSize(hWnd);
2402
2403    GetTxtA(hWnd, 0, caption, sizeof(caption));
2404    if (caption[0] == '@')
2405    {
2406        dialog_name = &caption[1];
2407
2408        is_managed_dialog = true;
2409    }
2410
2411    // すべてのウインドウハンドルを列挙する
2412    o = EnumAllChildWindow(hWnd);
2413
2414    for (i = 0;i < LIST_NUM(o);i++)
2415    {
2416        HWND hControl = *((HWND *)LIST_DATA(o, i));
2417
2418        if (hControl != NULL)
2419        {
2420            HFONT hFont = GetDialogDefaultFontEx(param && ((DIALOG_PARAM *)param)->meiryo);
2421
2422            SetFont(hControl, 0, hFont);
2423
2424            if (MsIsVista())
2425            {
2426                char classname[MAX_PATH];
2427                GetClassNameA(hControl, classname, sizeof(classname));
2428
2429                if (StrCmpi(classname, "syslistview32") == 0)
2430                {
2431                    InitVistaWindowTheme(hControl);
2432                }
2433            }
2434
2435            if (is_managed_dialog)
2436            {
2437                char str[MAX_PATH];
2438
2439                GetTxtA(hControl, 0, str, sizeof(str));
2440                if (str[0] == '@')
2441                {
2442                    char *control_name = &str[1];
2443                    char tmp[MAX_PATH];
2444                    wchar_t *ret;
2445
2446                    StrCpy(tmp, sizeof(tmp), dialog_name);
2447                    StrCat(tmp, sizeof(tmp), "@");
2448
2449                    if (hWnd == hControl)
2450                    {
2451                        StrCat(tmp, sizeof(tmp), "CAPTION");
2452                    }
2453                    else
2454                    {
2455                        StrCat(tmp, sizeof(tmp), control_name);
2456                    }
2457
2458                    ret = _UU(tmp);
2459
2460                    if (ret != NULL && UniIsEmptyStr(ret) == false)
2461                    {
2462                        SetText(hControl, 0, ret);
2463                    }
2464                }
2465            }
2466        }
2467    }
2468
2469    FreeWindowList(o);
2470}
2471
2472// 子ウインドウ列挙プロシージャ
2473// ダイアログ初期化
2474void StringDlgInit(HWND hWnd, STRING_DLG *s)
2475{
2476    // 引数チェック
2477    if (hWnd == NULL || s == NULL)
2478    {
2479        return;
2480    }
2481
2482    SetText(hWnd, E_STRING, s->String);
2483
2484    SetIcon(hWnd, S_ICON, s->Icon);
2485    SetText(hWnd, S_INFO, s->Info);
2486    SetText(hWnd, 0, s->Title);
2487
2488    FocusEx(hWnd, E_STRING);
2489
2490    StringDlgUpdate(hWnd, s);
2491}
2492
2493// ダイアログコントロール更新
2494void StringDlgUpdate(HWND hWnd, STRING_DLG *s)
2495{
2496    wchar_t *tmp;
2497    bool b = true;
2498    // 引数チェック
2499    if (hWnd == NULL || s == NULL)
2500    {
2501        return;
2502    }
2503
2504    tmp = GetText(hWnd, E_STRING);
2505
2506    if (tmp != NULL)
2507    {
2508        if (s->AllowEmpty == false)
2509        {
2510            if (UniIsEmptyStr(tmp))
2511            {
2512                b = false;
2513            }
2514        }
2515
2516        if (s->AllowUnsafe == false)
2517        {
2518            if (IsSafeUniStr(tmp) == false)
2519            {
2520                b = false;
2521            }
2522        }
2523
2524        Free(tmp);
2525    }
2526
2527    SetEnable(hWnd, IDOK, b);
2528}
2529
2530// 文字列ダイアログプロシージャ
2531UINT StringDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
2532{
2533    STRING_DLG *s = (STRING_DLG *)param;
2534    // 引数チェック
2535    if (hWnd == NULL)
2536    {
2537        return 0;
2538    }
2539
2540    switch (msg)
2541    {
2542    case WM_INITDIALOG:
2543        StringDlgInit(hWnd, s);
2544        break;
2545
2546    case WM_COMMAND:
2547        switch (LOWORD(wParam))
2548        {
2549        case E_STRING:
2550            StringDlgUpdate(hWnd, s);
2551            break;
2552        }
2553
2554        switch (wParam)
2555        {
2556        case IDOK:
2557            GetTxt(hWnd, E_STRING, s->String, sizeof(s->String));
2558            EndDialog(hWnd, true);
2559            break;
2560
2561        case IDCANCEL:
2562            Close(hWnd);
2563            break;
2564        }
2565        break;
2566
2567    case WM_CLOSE:
2568        EndDialog(hWnd, false);
2569        break;
2570    }
2571
2572    return 0;
2573}
2574
2575// 文字列ダイアログを表示する
2576wchar_t *StringDlg(HWND hWnd, wchar_t *title, wchar_t *info, wchar_t *def, UINT icon, bool allow_empty, bool allow_unsafe)
2577{
2578    STRING_DLG s;
2579    // 引数チェック
2580    if (title == NULL)
2581    {
2582        title = _UU("DLG_STRING_DEFTITLE");
2583    }
2584    if (info == NULL)
2585    {
2586        info = _UU("DLG_STRING_DEFINFO");
2587    }
2588    if (def == NULL)
2589    {
2590        def = L"";
2591    }
2592    if (icon == 0)
2593    {
2594        icon = ICO_NULL;
2595    }
2596
2597    Zero(&s, sizeof(s));
2598    s.Icon = icon;
2599    s.Info = info;
2600    s.Title = title;
2601    s.Icon = icon;
2602    UniStrCpy(s.String, sizeof(s.String), def);
2603    s.AllowEmpty = allow_empty;
2604    s.AllowUnsafe = allow_unsafe;
2605
2606    if (Dialog(hWnd, D_STRING, StringDlgProc, &s) == false)
2607    {
2608        return NULL;
2609    }
2610    else
2611    {
2612        return CopyUniStr(s.String);
2613    }
2614}
2615char *StringDlgA(HWND hWnd, wchar_t *title, wchar_t *info, char *def, UINT icon, bool allow_empty, bool allow_unsafe)
2616{
2617    wchar_t unidef[MAX_SIZE];
2618    wchar_t *tmp;
2619    char *ret;
2620    if (def == NULL)
2621    {
2622        def = "";
2623    }
2624
2625    StrToUni(unidef, sizeof(unidef), def);
2626
2627    tmp = StringDlg(hWnd, title, info, unidef, icon, allow_empty, allow_unsafe);
2628    if (tmp == NULL)
2629    {
2630        return NULL;
2631    }
2632
2633    ret = CopyUniToStr(tmp);
2634    Free(tmp);
2635
2636    return ret;
2637}
2638
2639// 再起動ダイアログ
2640UINT Win9xRebootDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
2641{
2642    WIN9X_REBOOT_DLG *d = (WIN9X_REBOOT_DLG *)param;
2643    UINT64 now;
2644    wchar_t tmp[MAX_PATH];
2645    // 引数チェック
2646    if (hWnd == NULL)
2647    {
2648        return 0;
2649    }
2650
2651    switch (msg)
2652    {
2653    case WM_INITDIALOG:
2654        d->StartTime = Tick64();
2655        SetRange(hWnd, P_PROGRESS, 0, d->TotalTime);
2656        SetTimer(hWnd, 1, 100, NULL);
2657        goto UPDATE;
2658
2659    case WM_TIMER:
2660        switch (wParam)
2661        {
2662        case 1:
2663UPDATE:
2664            now = Tick64();
2665            if ((d->StartTime + (UINT64)d->TotalTime) <= now)
2666            {
2667                KillTimer(hWnd, 1);
2668                UniStrCpy(tmp, sizeof(tmp), _UU("DLG_REBOOT_INFO_2"));
2669                SetText(hWnd, S_INFO, tmp);
2670                if (MsShutdown(true, false) == false)
2671                {
2672                    MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_REBOOT_ERROR"));
2673                }
2674                EndDialog(hWnd, 0);
2675            }
2676            else
2677            {
2678                SetPos(hWnd, P_PROGRESS, (UINT)(now - d->StartTime));
2679                UniFormat(tmp, sizeof(tmp), _UU("DLG_REBOOT_INFO"),
2680                    (UINT)((UINT64)d->TotalTime - (now - d->StartTime)) / 1000 + 1);
2681                SetText(hWnd, S_INFO, tmp);
2682            }
2683
2684            break;
2685        }
2686        break;
2687    }
2688    return 0;
2689}
2690
2691// 再起動用スレッド
2692void Win9xRebootThread(THREAD *t, void *p)
2693{
2694    // 引数チェック
2695    if (t == NULL)
2696    {
2697        return;
2698    }
2699
2700    Win9xReboot(NULL);
2701}
2702
2703// 自動的に再起動する
2704void Win9xReboot(HWND hWnd)
2705{
2706    WIN9X_REBOOT_DLG d;
2707
2708    Zero(&d, sizeof(d));
2709    d.TotalTime = 10 * 1000;
2710
2711    Dialog(hWnd, D_WIN9X_REBOOT, Win9xRebootDlgProc, &d);
2712}
2713
2714// バージョン情報の初期化
2715void AboutDlgInit(HWND hWnd, WINUI_ABOUT *a)
2716{
2717    wchar_t tmp[MAX_SIZE];
2718    // 引数チェック
2719    if (hWnd == NULL || a == NULL)
2720    {
2721        return;
2722    }
2723
2724    UniFormat(tmp, sizeof(tmp), _UU("ABOUT_CAPTION"), a->ProductName);
2725    SetText(hWnd, 0, tmp);
2726
2727    SetFont(hWnd, S_VERSION, GetFont(NULL, 15, true, false, false, false));
2728
2729    SetTextA(hWnd, S_VERSION, a->ProductName);
2730
2731    SetFont(hWnd, S_VERSION2, GetFont("Verdana", 13, false, false, false, false));
2732    UniFormat(tmp, sizeof(tmp),
2733        L"Version %u.%02u Build %u ",
2734        a->Cedar->Version / 100, a->Cedar->Version % 100,
2735        a->Cedar->Build);
2736    SetText(hWnd, S_VERSION2, tmp);
2737
2738    SetFont(hWnd, S_BUILD, GetFont("Verdana", 11, false, false, true, false));
2739    SetTextA(hWnd, S_BUILD, a->Cedar->BuildInfo);
2740
2741    SendMsg(hWnd, S_LOGO, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)LoadBitmap(hDll, MAKEINTRESOURCE(a->Bitmap)));
2742}
2743
2744// バージョン情報プロシージャ
2745UINT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
2746{
2747    WINUI_ABOUT *a = (WINUI_ABOUT *)param;
2748    // 引数チェック
2749    if (hWnd == NULL)
2750    {
2751        return 0;
2752    }
2753
2754    switch (msg)
2755    {
2756    case WM_INITDIALOG:
2757        AboutDlgInit(hWnd, a);
2758        break;
2759
2760    case WM_COMMAND:
2761        switch (wParam)
2762        {
2763        case IDOK:
2764        case IDCANCEL:
2765            if ((GetKeyState(VK_SHIFT) & 0x8000) &&
2766                (GetKeyState(VK_CONTROL) & 0x8000) &&
2767                (GetKeyState(VK_MENU) & 0x8000))
2768            {
2769                ShowEasterEgg(hWnd);
2770            }
2771            EndDialog(hWnd, true);
2772            break;
2773        case B_WEB:
2774            ShellExecute(hWnd, "open", _SS("SE_COMPANY_URL"), NULL, NULL, SW_SHOW);
2775            break;
2776        }
2777        break;
2778
2779    case WM_CLOSE:
2780        EndDialog(hWnd, false);
2781        break;
2782    }
2783
2784    return 0;
2785}
2786
2787// バージョン情報 (古い形式)
2788void About(HWND hWnd, CEDAR *cedar, char *product_name, UINT bitmap)
2789{
2790    WINUI_ABOUT a;
2791    // 引数チェック
2792    if (cedar == NULL || product_name == NULL || bitmap == 0)
2793    {
2794        return;
2795    }
2796
2797    Zero(&a, sizeof(a));
2798    a.Bitmap = bitmap;
2799    a.Cedar = cedar;
2800    a.ProductName = product_name;
2801
2802    Dialog(hWnd, D_ABOUT, AboutDlgProc, &a);
2803}
2804
2805// テスト
2806void UiTest()
2807{
2808}
2809
2810// IP アドレスが入力されているフィルード数を調べる
2811UINT IpGetFilledNum(HWND hWnd, UINT id)
2812{
2813    UINT ret;
2814    DWORD value;
2815    // 引数チェック
2816    if (hWnd == NULL)
2817    {
2818        return 0;
2819    }
2820
2821    ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
2822
2823    return ret;
2824}
2825
2826// IP アドレスが入力されているかどうか調べる
2827bool IpIsFilled(HWND hWnd, UINT id)
2828{
2829    UINT ret;
2830    DWORD value;
2831    // 引数チェック
2832    if (hWnd == NULL)
2833    {
2834        return 0;
2835    }
2836
2837    ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
2838
2839    if (ret != 4)
2840    {
2841        return false;
2842    }
2843    else
2844    {
2845        return true;
2846    }
2847}
2848
2849// IP アドレスのクリア
2850void IpClear(HWND hWnd, UINT id)
2851{
2852    // 引数チェック
2853    if (hWnd == NULL)
2854    {
2855        return;
2856    }
2857
2858    SendMsg(hWnd, id, IPM_CLEARADDRESS, 0, 0);
2859}
2860
2861// IP アドレスの取得
2862UINT IpGet(HWND hWnd, UINT id)
2863{
2864    UINT ret;
2865    DWORD value;
2866    // 引数チェック
2867    if (hWnd == NULL)
2868    {
2869        return 0;
2870    }
2871
2872    ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
2873
2874    if (ret != 4)
2875    {
2876        return 0;
2877    }
2878    else
2879    {
2880        return Endian32((UINT)value);
2881    }
2882}
2883
2884// IP アドレスのセット
2885void IpSet(HWND hWnd, UINT id, UINT ip)
2886{
2887    // 引数チェック
2888    if (hWnd == NULL)
2889    {
2890        return;
2891    }
2892
2893    SendMsg(hWnd, id, IPM_SETADDRESS, 0, Endian32(ip));
2894}
2895
2896// レジストリに候補を書き込む
2897void WriteCandidateToReg(UINT root, char *key, LIST *o, char *name)
2898{
2899    BUF *b;
2900    // 引数チェック
2901    if (key == NULL || o == NULL || name == NULL)
2902    {
2903        return;
2904    }
2905
2906    b = CandidateToBuf(o);
2907    if (b == NULL)
2908    {
2909        return;
2910    }
2911
2912    MsRegWriteBin(root, key, name, b->Buf, b->Size);
2913
2914    FreeBuf(b);
2915}
2916
2917// レジストリから候補を読み込む
2918LIST *ReadCandidateFromReg(UINT root, char *key, char *name)
2919{
2920    BUF *b;
2921    // 引数チェック
2922    if (key == NULL || name == NULL)
2923    {
2924        return NULL;
2925    }
2926
2927    b = MsRegReadBin(root, key, name);
2928    if (b == NULL)
2929    {
2930        return NewCandidateList();
2931    }
2932    else
2933    {
2934        LIST *o = BufToCandidate(b);
2935        FreeBuf(b);
2936
2937        return o;
2938    }
2939}
2940
2941// リモート接続ダイアログ初期化
2942void RemoteDlgInit(HWND hWnd, WINUI_REMOTE *r)
2943{
2944    LIST *o;
2945    UINT i;
2946    // 引数チェック
2947    if (hWnd == NULL || r == NULL)
2948    {
2949        return;
2950    }
2951
2952    SetIcon(hWnd, 0, r->Icon);
2953
2954    SetText(hWnd, 0, r->Caption);
2955    SetText(hWnd, S_TITLE, r->Title);
2956    SetIcon(hWnd, S_ICON, r->Icon);
2957
2958    // 候補を読み込む
2959    o = ReadCandidateFromReg(REG_CURRENT_USER, r->RegKeyName, "RemoteHostCandidate");
2960    r->CandidateList = o;
2961
2962    // 候補を表示する
2963    for (i = 0;i < LIST_NUM(o);i++)
2964    {
2965        CANDIDATE *c = LIST_DATA(o, i);
2966        CbAddStr(hWnd, C_HOSTNAME, c->Str, 0);
2967    }
2968
2969    if (r->DefaultHostname != NULL)
2970    {
2971        SetTextA(hWnd, C_HOSTNAME, r->DefaultHostname);
2972    }
2973
2974    FocusEx(hWnd, C_HOSTNAME);
2975
2976    RemoteDlgRefresh(hWnd, r);
2977}
2978
2979// リモート接続ダイアログ更新
2980void RemoteDlgRefresh(HWND hWnd, WINUI_REMOTE *r)
2981{
2982    char *s;
2983    bool ok = true;
2984    bool localhost_mode = false;
2985    // 引数チェック
2986    if (hWnd == NULL || r == NULL)
2987    {
2988        return;
2989    }
2990
2991    s = GetTextA(hWnd, C_HOSTNAME);
2992    if (s != NULL)
2993    {
2994        Trim(s);
2995        if (StrCmpi(s, "localhost") == 0 || StartWith(s, "127."))
2996        {
2997            localhost_mode = true;
2998        }
2999        Free(s);
3000    }
3001
3002    if (localhost_mode == false)
3003    {
3004        Enable(hWnd, C_HOSTNAME);
3005        Enable(hWnd, S_HOSTNAME);
3006        Check(hWnd, R_LOCAL, false);
3007    }
3008    else
3009    {
3010        if (r->Title != _UU("NM_CONNECT_TITLE"))
3011        {
3012            Disable(hWnd, C_HOSTNAME);
3013            Disable(hWnd, S_HOSTNAME);
3014        }
3015        Check(hWnd, R_LOCAL, true);
3016        SetTextA(hWnd, C_HOSTNAME, "localhost");
3017
3018        if (r->flag1 == false)
3019        {
3020            Focus(hWnd, IDOK);
3021        }
3022    }
3023
3024    if (IsEmpty(hWnd, C_HOSTNAME))
3025    {
3026        ok = false;
3027    }
3028
3029    SetEnable(hWnd, IDOK, ok);
3030
3031    r->flag1 = true;
3032}
3033
3034// リモート接続ダイアログ OK ボタン
3035void RemoteDlgOnOk(HWND hWnd, WINUI_REMOTE *r)
3036{
3037    char *hostname;
3038    wchar_t *s;
3039    LIST *o;
3040    // 引数チェック
3041    if (hWnd == NULL || r == NULL)
3042    {
3043        return;
3044    }
3045
3046    // 入力されているホスト名を取得
3047    hostname = GetTextA(hWnd, C_HOSTNAME);
3048    if (hostname == NULL)
3049    {
3050        return;
3051    }
3052    Trim(hostname);
3053
3054    // 候補を追加
3055    o = r->CandidateList;
3056    s = CopyStrToUni(hostname);
3057    AddCandidate(o, s, 64);
3058    Free(s);
3059
3060    // 候補を書き込む
3061    WriteCandidateToReg(REG_CURRENT_USER, r->RegKeyName, o, "RemoteHostCandidate");
3062    FreeCandidateList(o);
3063
3064    r->Hostname = hostname;
3065
3066    EndDialog(hWnd, true);
3067}
3068
3069// リモート接続ダイアログプロシージャ
3070UINT RemoteDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
3071{
3072    WINUI_REMOTE *r = (WINUI_REMOTE *)param;
3073    // 引数チェック
3074    if (hWnd == NULL)
3075    {
3076        return 0;
3077    }
3078
3079    switch (msg)
3080    {
3081    case WM_INITDIALOG:
3082        RemoteDlgInit(hWnd, r);
3083        SetTimer(hWnd, 1, 100, NULL);
3084        break;
3085    case WM_TIMER:
3086        switch (wParam)
3087        {
3088        case 1:
3089            KillTimer(hWnd, 1);
3090            RemoteDlgRefresh(hWnd, r);
3091            SetTimer(hWnd, 1, 100, NULL);
3092            break;
3093        }
3094        break;
3095    case WM_COMMAND:
3096        switch (wParam)
3097        {
3098        case R_LOCAL:
3099            if (IsChecked(hWnd, R_LOCAL) == false)
3100            {
3101                SetTextA(hWnd, C_HOSTNAME, "");
3102                RemoteDlgRefresh(hWnd, r);
3103                FocusEx(hWnd, C_HOSTNAME);
3104            }
3105            else
3106            {
3107                SetTextA(hWnd, C_HOSTNAME, "localhost");
3108                RemoteDlgRefresh(hWnd, r);
3109                Focus(hWnd, IDOK);
3110            }
3111            break;
3112        case IDCANCEL:
3113            Close(hWnd);
3114            break;
3115        case IDOK:
3116            RemoteDlgOnOk(hWnd, r);
3117            break;
3118        }
3119        switch (LOWORD(wParam))
3120        {
3121        case R_LOCAL:
3122        case C_HOSTNAME:
3123            RemoteDlgRefresh(hWnd, r);
3124            break;
3125        }
3126        break;
3127    case WM_CLOSE:
3128        FreeCandidateList(r->CandidateList);
3129        EndDialog(hWnd, false);
3130        break;
3131    }
3132
3133    return 0;
3134}
3135
3136// リモート接続ダイアログ
3137char *RemoteDlg(HWND hWnd, char *regkey, UINT icon, wchar_t *caption, wchar_t *title, char *default_host)
3138{
3139    WINUI_REMOTE r;
3140    // 引数チェック
3141    if (regkey == NULL)
3142    {
3143        regkey = "Software\\SoftEther Corporation\\SoftEther UT-VPN\\WinUI Common Module";
3144    }
3145    if (caption == NULL)
3146    {
3147        caption = _UU("REMOTE_DEF_CAPTION");
3148    }
3149    if (title == NULL)
3150    {
3151        title = _UU("REMOTE_DEF_TITLE");
3152    }
3153    if (icon == 0)
3154    {
3155        icon = ICO_INTERNET;
3156    }
3157
3158    Zero(&r, sizeof(r));
3159    r.RegKeyName = regkey;
3160    r.Caption = caption;
3161    r.Title = title;
3162    r.Icon = icon;
3163    r.DefaultHostname = default_host;
3164
3165    if (Dialog(hWnd, D_REMOTE, RemoteDlgProc, &r) == false)
3166    {
3167        return NULL;
3168    }
3169
3170    return r.Hostname;
3171}
3172
3173// ウインドウの検索プロシージャ
3174bool CALLBACK SearchWindowEnumProc(HWND hWnd, LPARAM lParam)
3175{
3176    if (hWnd != NULL && lParam != 0)
3177    {
3178        wchar_t *s = GetText(hWnd, 0);
3179        SEARCH_WINDOW_PARAM *p = (SEARCH_WINDOW_PARAM *)lParam;
3180        if (s != NULL)
3181        {
3182            if (UniStrCmpi(p->caption, s) == 0)
3183            {
3184                p->hWndFound = hWnd;
3185            }
3186            Free(s);
3187        }
3188    }
3189    return true;
3190}
3191
3192// ウインドウの検索
3193HWND SearchWindow(wchar_t *caption)
3194{
3195    SEARCH_WINDOW_PARAM p;
3196    // 引数チェック
3197    if (caption == NULL)
3198    {
3199        return NULL;
3200    }
3201
3202    Zero(&p, sizeof(p));
3203    p.caption = caption;
3204    p.hWndFound = NULL;
3205
3206    EnumWindows(SearchWindowEnumProc, (LPARAM)&p);
3207
3208    return p.hWndFound;
3209}
3210
3211// 指定したプロセスにフォアグラウンドウインドウになることを許可
3212void AllowFGWindow(UINT process_id)
3213{
3214    if (process_id == 0)
3215    {
3216        return;
3217    }
3218
3219    if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) &&
3220        GET_KETA(GetOsInfo()->OsType, 100) >= 2)
3221    {
3222        AllowSetForegroundWindow(process_id);
3223    }
3224}
3225
3226// アイテムのリネーム
3227void LvRename(HWND hWnd, UINT id, UINT pos)
3228{
3229    // 引数チェック
3230    if (hWnd == NULL || pos == INFINITE)
3231    {
3232        return;
3233    }
3234
3235    ListView_EditLabel(DlgItem(hWnd, id), pos);
3236}
3237
3238// メニューを表示する
3239void PrintMenu(HWND hWnd, HMENU hMenu)
3240{
3241    POINT p;
3242    // 引数チェック
3243    if (hMenu == NULL || hWnd == NULL)
3244    {
3245        return;
3246    }
3247
3248    GetCursorPos(&p);
3249
3250    TrackPopupMenu(hMenu, TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
3251}
3252
3253// メニューからショートカット文字列を削除する
3254void RemoveShortcutKeyStrFromMenu(HMENU hMenu)
3255{
3256    UINT i, num;
3257    // 引数チェック
3258    if (hMenu == NULL)
3259    {
3260        return;
3261    }
3262
3263    num = GetMenuNum(hMenu);
3264    for (i = 0;i < num;i++)
3265    {
3266        wchar_t *str = GetMenuStr(hMenu, i);
3267        if (str != NULL)
3268        {
3269            UINT j, len;
3270            len = UniStrLen(str);
3271            for (j = 0;j < len;j++)
3272            {
3273                if (str[j] == L'\t')
3274                {
3275                    str[j] = 0;
3276                }
3277            }
3278            SetMenuStr(hMenu, i, str);
3279            Free(str);
3280        }
3281    }
3282}
3283
3284// メニュー内の項目数を取得する
3285UINT GetMenuNum(HMENU hMenu)
3286{
3287    UINT ret;
3288    // 引数チェック
3289    if (hMenu == NULL)
3290    {
3291        return 0;
3292    }
3293
3294    ret = GetMenuItemCount(hMenu);
3295    if (ret == INFINITE)
3296    {
3297        return 0;
3298    }
3299    else
3300    {
3301        return ret;
3302    }
3303}
3304
3305// メニュー内の文字列を設定する
3306void SetMenuStr(HMENU hMenu, UINT pos, wchar_t *str)
3307{
3308    MENUITEMINFOW info;
3309    // 引数チェック
3310    if (hMenu == NULL || pos == INFINITE || str == NULL)
3311    {
3312        return;
3313    }
3314
3315    if (MsIsNt() == false)
3316    {
3317        char *s = CopyUniToStr(str);
3318        SetMenuStrA(hMenu, pos, s);
3319        Free(s);
3320        return;
3321    }
3322
3323    Zero(&info, sizeof(info));
3324    info.cbSize = sizeof(info);
3325    info.fMask = MIIM_STRING;
3326    info.dwTypeData = str;
3327    SetMenuItemInfoW(hMenu, pos, true, &info);
3328}
3329void SetMenuStrA(HMENU hMenu, UINT pos, char *str)
3330{
3331    MENUITEMINFOA info;
3332    // 引数チェック
3333    if (hMenu == NULL || pos == INFINITE || str == NULL)
3334    {
3335        return;
3336    }
3337
3338    Zero(&info, sizeof(info));
3339    info.cbSize = sizeof(info);
3340    info.fMask = MIIM_STRING;
3341    info.dwTypeData = str;
3342    SetMenuItemInfoA(hMenu, pos, true, &info);
3343}
3344
3345// メニュー内の文字列を取得する
3346wchar_t *GetMenuStr(HMENU hMenu, UINT pos)
3347{
3348    wchar_t tmp[MAX_SIZE];
3349    // 引数チェック
3350    if (hMenu == NULL || pos == INFINITE)
3351    {
3352        return NULL;
3353    }
3354    if (MsIsNt() == false)
3355    {
3356        char *s = GetMenuStrA(hMenu, pos);
3357        if (s == NULL)
3358        {
3359            return NULL;
3360        }
3361        else
3362        {
3363            wchar_t *ret = CopyStrToUni(s);
3364            Free(s);
3365            return ret;
3366        }
3367    }
3368
3369    if (GetMenuStringW(hMenu, pos, tmp, sizeof(tmp), MF_BYPOSITION) == 0)
3370    {
3371        return NULL;
3372    }
3373
3374    return UniCopyStr(tmp);
3375}
3376char *GetMenuStrA(HMENU hMenu, UINT pos)
3377{
3378    char tmp[MAX_SIZE];
3379    // 引数チェック
3380    if (hMenu == NULL || pos == INFINITE)
3381    {
3382        return NULL;
3383    }
3384
3385    if (GetMenuString(hMenu, pos, tmp, sizeof(tmp), MF_BYPOSITION) == 0)
3386    {
3387        return NULL;
3388    }
3389
3390    return CopyStr(tmp);
3391}
3392
3393// メニュー項目を太字にする
3394void SetMenuItemBold(HMENU hMenu, UINT pos, bool bold)
3395{
3396    MENUITEMINFO info;
3397    // 引数チェック
3398    if (hMenu == NULL || pos == INFINITE)
3399    {
3400        return;
3401    }
3402
3403    Zero(&info, sizeof(info));
3404    info.cbSize = sizeof(info);
3405    info.fMask = MIIM_STATE;
3406
3407    if (GetMenuItemInfo(hMenu, pos, true, &info) == false)
3408    {
3409        return;
3410    }
3411
3412    if (bold)
3413    {
3414        info.fState |= MFS_DEFAULT;
3415    }
3416    else
3417    {
3418        info.fState = info.fState & ~MFS_DEFAULT;
3419    }
3420
3421    SetMenuItemInfo(hMenu, pos, true, &info);
3422}
3423
3424// メニュー項目を有効 / 無効にする
3425void SetMenuItemEnable(HMENU hMenu, UINT pos, bool enable)
3426{
3427    MENUITEMINFO info;
3428    // 引数チェック
3429    if (hMenu == NULL || pos == INFINITE)
3430    {
3431        return;
3432    }
3433
3434    Zero(&info, sizeof(info));
3435    info.cbSize = sizeof(info);
3436    info.fMask = MIIM_STATE;
3437
3438    if (GetMenuItemInfo(hMenu, pos, true, &info) == false)
3439    {
3440        return;
3441    }
3442
3443    if (enable)
3444    {
3445        info.fState |= MFS_ENABLED;
3446        info.fState = info.fState & ~MFS_DISABLED;
3447    }
3448    else
3449    {
3450        info.fState |= MFS_DISABLED;
3451        info.fState = info.fState & ~MFS_ENABLED;
3452    }
3453
3454    SetMenuItemInfo(hMenu, pos, true, &info);
3455}
3456
3457// メニュー項目を削除する
3458void DeleteMenuItem(HMENU hMenu, UINT pos)
3459{
3460    // 引数チェック
3461    if (hMenu == NULL || pos == INFINITE)
3462    {
3463        return;
3464    }
3465
3466    DeleteMenu(hMenu, pos, MF_BYPOSITION);
3467}
3468
3469// メニュー内の ID から位置を取得する
3470UINT GetMenuItemPos(HMENU hMenu, UINT id)
3471{
3472    UINT num, i;
3473    // 引数チェック
3474    if (hMenu == NULL)
3475    {
3476        return INFINITE;
3477    }
3478
3479    num = GetMenuItemCount(hMenu);
3480    if (num == INFINITE)
3481    {
3482        return INFINITE;
3483    }
3484
3485    for (i = 0;i < num;i++)
3486    {
3487        if (GetMenuItemID(hMenu, i) == id)
3488        {
3489            return i;
3490        }
3491    }
3492
3493    return INFINITE;
3494}
3495
3496// サブメニューを取得
3497HMENU LoadSubMenu(UINT menu_id, UINT pos, HMENU *parent_menu)
3498{
3499    HMENU h = LoadMenu(hDll, MAKEINTRESOURCE(menu_id));
3500    HMENU ret;
3501    if (h == NULL)
3502    {
3503        return NULL;
3504    }
3505
3506    ret = GetSubMenu(h, pos);
3507
3508    if (parent_menu != NULL)
3509    {
3510        *parent_menu = h;
3511    }
3512
3513    return ret;
3514}
3515
3516// ユーザーインターフェイスの DLL を取得
3517HINSTANCE GetUiDll()
3518{
3519    return hDll;
3520}
3521
3522// 接続エラーダイアログプロシージャ
3523UINT ConnectErrorDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
3524{
3525    UI_CONNECTERROR_DLG *p = (UI_CONNECTERROR_DLG *)param;
3526    wchar_t tmp[1024];
3527    // 引数チェック
3528    if (hWnd == NULL)
3529    {
3530        return 0;
3531    }
3532
3533    switch (msg)
3534    {
3535    case WM_INITDIALOG:
3536        if (p->Err == ERR_DISCONNECTED || p->Err == ERR_SESSION_TIMEOUT)
3537        {
3538            // 接続が切断された旨のメッセージ
3539            SetText(hWnd, S_TITLE, _UU("ERRDLG_DISCONNECTED_MSG"));
3540        }
3541        if (p->HideWindow)
3542        {
3543            Hide(hWnd, R_HIDE);
3544        }
3545        FormatText(hWnd, 0, p->AccountName);
3546        FormatText(hWnd, S_TITLE, p->ServerName);
3547        UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_ERRMSG"), p->Err, _E(p->Err));
3548        SetText(hWnd, E_ERROR, tmp);
3549
3550        SetIcon(hWnd, 0, ICO_SERVER_OFFLINE);
3551
3552        if (p->RetryIntervalSec == 0)
3553        {
3554            SetText(hWnd, S_COUNTDOWN, _UU("ERRDLG_INFORMATION"));
3555            Hide(hWnd, P_PROGRESS);
3556            Hide(hWnd, S_RETRYINFO);
3557        }
3558        else
3559        {
3560            if (p->RetryLimit != INFINITE)
3561            {
3562                UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRY_INFO_1"), p->CurrentRetryCount, p->RetryLimit);
3563            }
3564            else
3565            {
3566                UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRY_INFO_2"), p->CurrentRetryCount);
3567            }
3568            SetText(hWnd, S_RETRYINFO, tmp);
3569            SetRange(hWnd, P_PROGRESS, 0, p->RetryIntervalSec);
3570            SetPos(hWnd, P_PROGRESS, 0);
3571            SetTimer(hWnd, 1, 10, NULL);
3572            p->StartTick = Tick64();
3573        }
3574        SetTimer(hWnd, 2, 10, NULL);
3575        Focus(hWnd, IDOK);
3576        break;
3577    case WM_TIMER:
3578        switch (wParam)
3579        {
3580        case 1:
3581            if (p->RetryIntervalSec != 0)
3582            {
3583                UINT64 start, end, now;
3584                now = Tick64();
3585                start = p->StartTick;
3586                end = start + (UINT64)p->RetryIntervalSec;
3587
3588                if (end > now)
3589                {
3590                    SetPos(hWnd, P_PROGRESS, (UINT)(now - start));
3591                    UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRYCOUNT"), ((UINT)(end - now)) / 1000);
3592                    SetText(hWnd, S_COUNTDOWN, tmp);
3593                }
3594                else
3595                {
3596                    Command(hWnd, IDOK);
3597                }
3598            }
3599            break;
3600        case 2:
3601            if (p->CancelEvent != NULL)
3602            {
3603                if (WaitForSingleObject((HANDLE)p->CancelEvent->pData, 0) != WAIT_TIMEOUT)
3604                {
3605                    // 強制キャンセル
3606                    Close(hWnd);
3607                }
3608            }
3609            break;
3610        }
3611        break;
3612    case WM_COMMAND:
3613        switch (LOWORD(wParam))
3614        {
3615        case R_HIDE:
3616            p->HideWindow = IsChecked(hWnd, R_HIDE);
3617            break;
3618        }
3619        switch (wParam)
3620        {
3621        case IDOK:
3622            EndDialog(hWnd, true);
3623            break;
3624        case IDCANCEL:
3625            Close(hWnd);
3626            break;
3627        }
3628        break;
3629    case WM_CLOSE:
3630        EndDialog(hWnd, false);
3631        break;
3632    }
3633
3634    return 0;
3635}
3636
3637// 接続エラーダイアログを表示
3638bool ConnectErrorDlg(UI_CONNECTERROR_DLG *p)
3639{
3640    // 引数チェック
3641    if (p == NULL)
3642    {
3643        return false;
3644    }
3645
3646    return DialogEx2(NULL, D_CONNECTERROR, ConnectErrorDlgProc, p, true, true);
3647}
3648
3649// 証明書の内容を表示する
3650void PrintCheckCertInfo(HWND hWnd, UI_CHECKCERT *p)
3651{
3652    wchar_t tmp[MAX_SIZE];
3653    char tmp2[MAX_SIZE];
3654    UCHAR md5[MD5_SIZE];
3655    UCHAR sha1[SHA1_SIZE];
3656    X *x;
3657    // 引数チェック
3658    if (hWnd == NULL || p == NULL)
3659    {
3660        return;
3661    }
3662
3663    x = p->x;
3664
3665    GetAllNameFromNameEx(tmp, sizeof(tmp), x->subject_name);
3666    SetText(hWnd, E_SUBJECT, tmp);
3667
3668    GetAllNameFromNameEx(tmp, sizeof(tmp), x->issuer_name);
3669    SetText(hWnd, E_ISSUER, tmp);
3670
3671    GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
3672    SetText(hWnd, E_EXPIRES, tmp);
3673
3674    GetXDigest(x, md5, false);
3675    BinToStr(tmp2, sizeof(tmp2), md5, sizeof(md5));
3676    SetTextA(hWnd, E_MD5, tmp2);
3677
3678    GetXDigest(x, sha1, true);
3679    BinToStr(tmp2, sizeof(tmp2), sha1, sizeof(sha1));
3680    SetTextA(hWnd, E_SHA1, tmp2);
3681
3682    SetFont(hWnd, E_MD5, GetFont("Arial", 8, false, false, false, false));
3683    SetFont(hWnd, E_SHA1, GetFont("Arial", 8, false, false, false, false));
3684}
3685
3686// 証明書が相違する旨を警告する
3687void ShowDlgDiffWarning(HWND hWnd, UI_CHECKCERT *p)
3688{
3689    UCHAR sha1_new[SHA1_SIZE], sha1_old[SHA1_SIZE];
3690    UCHAR md5_new[MD5_SIZE], md5_old[MD5_SIZE];
3691    char sha1_new_str[MAX_SIZE], sha1_old_str[MAX_SIZE];
3692    char md5_new_str[MAX_SIZE], md5_old_str[MAX_SIZE];
3693    // 引数チェック
3694    if (hWnd == NULL || p == NULL || p->x == NULL || p->old_x == NULL)
3695    {
3696        return;
3697    }
3698
3699    GetXDigest(p->x, sha1_new, true);
3700    GetXDigest(p->x, md5_new, false);
3701
3702    GetXDigest(p->old_x, sha1_old, true);
3703    GetXDigest(p->old_x, md5_old, false);
3704
3705    BinToStrEx(sha1_new_str, sizeof(sha1_new_str), sha1_new, sizeof(sha1_new));
3706    BinToStrEx(md5_new_str, sizeof(md5_new_str), md5_new, sizeof(md5_new));
3707    BinToStrEx(sha1_old_str, sizeof(sha1_old_str), sha1_old, sizeof(sha1_old));
3708    BinToStrEx(md5_old_str, sizeof(md5_old_str), md5_old, sizeof(md5_old));
3709
3710    MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("CC_DANGEROUS_MSG"),
3711        p->ServerName, md5_old_str, sha1_old_str, md5_new_str, sha1_new_str);
3712}
3713
3714// [OK] ボタンが押された
3715void CheckCertDialogOnOk(HWND hWnd, UI_CHECKCERT *p)
3716{
3717    UCHAR sha1_new[SHA1_SIZE];
3718    UCHAR md5_new[MD5_SIZE];
3719    char sha1_new_str[MAX_SIZE];
3720    char md5_new_str[MAX_SIZE];
3721    UINT ret;
3722    // 引数チェック
3723    if (hWnd == NULL || p == NULL)
3724    {
3725        return;
3726    }
3727
3728    GetXDigest(p->x, sha1_new, true);
3729    GetXDigest(p->x, md5_new, false);
3730    BinToStrEx(sha1_new_str, sizeof(sha1_new_str), sha1_new, sizeof(sha1_new));
3731    BinToStrEx(md5_new_str, sizeof(md5_new_str), md5_new, sizeof(md5_new));
3732
3733    ret = MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON2,
3734        _UU("CC_WARNING_MSG"),
3735        p->AccountName, sha1_new_str, md5_new_str);
3736
3737    if (ret == IDYES)
3738    {
3739        p->SaveServerCert = true;
3740    }
3741
3742    if (ret == IDCANCEL)
3743    {
3744        return;
3745    }
3746
3747    p->Ok = true;
3748    EndDialog(hWnd, true);
3749}
3750
3751// 証明書ダイアログプロシージャ
3752UINT CheckCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
3753{
3754    UI_CHECKCERT *p = (UI_CHECKCERT *)param;
3755    // 引数チェック
3756    if (hWnd == NULL || param == NULL)
3757    {
3758        return 0;
3759    }
3760
3761    switch (msg)
3762    {
3763    case WM_INITDIALOG:
3764        FormatText(hWnd, 0, p->AccountName);
3765        FormatText(hWnd, S_TITLE, p->ServerName);
3766        FormatText(hWnd, S_MSG1, p->ServerName);
3767
3768        PrintCheckCertInfo(hWnd, p);
3769
3770        Focus(hWnd, IDCANCEL);
3771
3772        SetIcon(hWnd, 0, ICO_WARNING);
3773
3774        if (p->DiffWarning)
3775        {
3776            SetTimer(hWnd, 1, 1, NULL);
3777        }
3778
3779        SetTimer(hWnd, 2, 100, NULL);
3780
3781        break;
3782    case WM_TIMER:
3783        switch (wParam)
3784        {
3785        case 1:
3786            KillTimer(hWnd, 1);
3787            ShowDlgDiffWarning(hWnd, p);
3788            break;
3789        case 2:
3790            if ((p->Session != NULL && p->Session->Halt) ||
3791                (p->Halt))
3792            {
3793                p->Ok = false;
3794                EndDialog(hWnd, false);
3795            }
3796            break;
3797        }
3798        break;
3799    case WM_COMMAND:
3800        switch (wParam)
3801        {
3802        case B_SHOW:
3803            CertDlg(hWnd, p->x, p->parent_x, false);
3804            break;
3805        case IDOK:
3806            CheckCertDialogOnOk(hWnd, p);
3807            break;
3808        case IDCANCEL:
3809            Close(hWnd);
3810            break;
3811        }
3812        break;
3813    case WM_CLOSE:
3814        p->Ok = false;
3815        EndDialog(hWnd, false);
3816        break;
3817    }
3818
3819    return 0;
3820}
3821
3822// 証明書のチェックダイアログ
3823void CheckCertDlg(UI_CHECKCERT *p)
3824{
3825    // 引数チェック
3826    if (p == NULL)
3827    {
3828        return;
3829    }
3830
3831    Dialog(NULL, D_CHECKCERT, CheckCertDlgProc, p);
3832}
3833
3834// アイコン ID からイメージリスト ID を取得する
3835UINT GetIcon(UINT icon_id)
3836{
3837    IMAGELIST_ICON *c, t;
3838    t.id = icon_id;
3839
3840    c = Search(icon_list, &t);
3841    if (c == NULL)
3842    {
3843        if (icon_id != ICO_NULL)
3844        {
3845            return GetIcon(ICO_NULL);
3846        }
3847        else
3848        {
3849            return INFINITE;
3850        }
3851    }
3852    else
3853    {
3854        return c->Index;
3855    }
3856}
3857
3858// イメージリスト用にアイコンをロードする
3859IMAGELIST_ICON *LoadIconForImageList(UINT id)
3860{
3861    IMAGELIST_ICON *ret = ZeroMalloc(sizeof(IMAGELIST_ICON));
3862    HICON small_icon, large_icon;
3863
3864    ret->id = id;
3865
3866    large_icon = LoadLargeIcon(id);
3867    if (large_icon == NULL)
3868    {
3869        large_icon = LoadSmallIcon(id);
3870    }
3871
3872    small_icon = LoadSmallIcon(id);
3873    if (small_icon == NULL)
3874    {
3875        small_icon = LoadLargeIcon(id);
3876    }
3877
3878    ret->hSmallImage = small_icon;
3879    ret->hLargeImage = large_icon;
3880    ret->Index = ImageList_AddIcon(large_image_list, large_icon);
3881    ImageList_AddIcon(small_image_list, small_icon);
3882
3883    return ret;
3884}
3885
3886// イメージリストアイコンの比較
3887int CompareImageListIcon(void *p1, void *p2)
3888{
3889    IMAGELIST_ICON *c1, *c2;
3890    if (p1 == NULL || p2 == NULL)
3891    {
3892        return 0;
3893    }
3894    c1 = *(IMAGELIST_ICON **)p1;
3895    c2 = *(IMAGELIST_ICON **)p2;
3896    if (c1 == NULL || c2 == NULL)
3897    {
3898        return 0;
3899    }
3900
3901    if (c1->id > c2->id)
3902    {
3903        return 1;
3904    }
3905    else if (c1->id < c2->id)
3906    {
3907        return -1;
3908    }
3909    else
3910    {
3911        return 0;
3912    }
3913}
3914
3915// イメージリストの初期化
3916void InitImageList()
3917{
3918    large_image_list = ImageList_Create(32, 32, ILC_COLOR32 | ILC_MASK, 1, 0);
3919    ImageList_SetBkColor(large_image_list, RGB(255, 255, 255));
3920    small_image_list = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 1, 0);
3921    ImageList_SetBkColor(small_image_list, RGB(255, 255, 255));
3922    icon_list = NewList(CompareImageListIcon);
3923
3924    // 列挙
3925    EnumResourceNames(hDll, RT_GROUP_ICON, EnumResNameProc, 0);
3926}
3927
3928// アイコンリソース列挙プロシージャ
3929BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
3930{
3931    if (IS_INTRESOURCE(lpszName))
3932    {
3933        UINT icon_id = (UINT)lpszName;
3934        IMAGELIST_ICON *img = LoadIconForImageList(icon_id);
3935
3936        Add(icon_list, img);
3937    }
3938
3939    return TRUE;
3940}
3941
3942// イメージリストの解放
3943void FreeImageList()
3944{
3945    UINT i;
3946    ImageList_Destroy(large_image_list);
3947    ImageList_Destroy(small_image_list);
3948    large_image_list = small_image_list = NULL;
3949
3950    for (i = 0;i < LIST_NUM(icon_list);i++)
3951    {
3952        IMAGELIST_ICON *c = LIST_DATA(icon_list, i);
3953        Free(c);
3954    }
3955
3956    ReleaseList(icon_list);
3957    icon_list = NULL;
3958}
3959
3960// カラムの横幅の取得
3961UINT LvGetColumnWidth(HWND hWnd, UINT id, UINT index)
3962{
3963    return ListView_GetColumnWidth(DlgItem(hWnd, id), index);
3964}
3965
3966// カラムの挿入
3967void LvInsertColumn(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT width)
3968{
3969    LVCOLUMNW c;
3970    // 引数チェック
3971    if (hWnd == NULL || str == NULL)
3972    {
3973        return;
3974    }
3975
3976    Zero(&c, sizeof(c));
3977    c.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
3978
3979    c.pszText = str;
3980    c.iSubItem = index;
3981    c.cx = width;
3982
3983    SendMsg(hWnd, id, LVM_INSERTCOLUMNW, index, (LPARAM)&c);
3984}
3985
3986// すべてのアイテムを削除
3987void LvReset(HWND hWnd, UINT id)
3988{
3989    // 引数チェック
3990    if (hWnd == NULL)
3991    {
3992        return;
3993    }
3994
3995    ListView_DeleteAllItems(DlgItem(hWnd, id));
3996}
3997
3998// リストビューを初期化
3999void LvInitEx(HWND hWnd, UINT id, bool no_image)
4000{
4001    LvInitEx2(hWnd, id, no_image, false);
4002}
4003void LvInitEx2(HWND hWnd, UINT id, bool no_image, bool large_icon)
4004{
4005    // 引数チェック
4006    if (hWnd == NULL)
4007    {
4008        return;
4009    }
4010
4011    ListView_SetUnicodeFormat(DlgItem(hWnd, id), true);
4012
4013    if (no_image == false)
4014    {
4015        ListView_SetImageList(DlgItem(hWnd, id), large_image_list, LVSIL_NORMAL);
4016        ListView_SetImageList(DlgItem(hWnd, id), large_icon ? large_image_list : small_image_list, LVSIL_SMALL);
4017    }
4018
4019    ListView_SetExtendedListViewStyle(DlgItem(hWnd, id), LVS_EX_FULLROWSELECT);
4020
4021    if (MsIsVista())
4022    {
4023        LvSetStyle(hWnd, id, LVS_EX_DOUBLEBUFFER);
4024    }
4025}
4026void LvInit(HWND hWnd, UINT id)
4027{
4028    LvInitEx(hWnd, id, false);
4029}
4030
4031// バッチ追加処理完了 (高速)
4032void LvInsertEnd(LVB *b, HWND hWnd, UINT id)
4033{
4034    LvInsertEndEx(b, hWnd, id, false);
4035}
4036void LvInsertEndEx(LVB *b, HWND hWnd, UINT id, bool force_reset)
4037{
4038    UINT i, num;
4039    LIST *new_list, *exist_list;
4040    wchar_t *last_selected = NULL;
4041    // 引数チェック
4042    if (b == NULL || hWnd == NULL)
4043    {
4044        return;
4045    }
4046
4047    new_list = NewListFast(CompareUniStr);
4048
4049    for (i = 0;i < LIST_NUM(b->ItemList);i++)
4050    {
4051        LVB_ITEM *t = LIST_DATA(b->ItemList, i);
4052        Add(new_list, t->Strings[0]);
4053    }
4054
4055    Sort(new_list);
4056
4057    if ((LIST_NUM(b->ItemList) >= LV_INSERT_RESET_ALL_ITEM_MIN) || force_reset)
4058    {
4059        last_selected = LvGetFocusedStr(hWnd, id, 0);
4060        LvReset(hWnd, id);
4061    }
4062
4063    exist_list = NewListFast(CompareUniStr);
4064
4065    num = LvNum(hWnd, id);
4066
4067    // 既存項目のうちバッチリスト内に存在していない項目を削除する
4068    for (i = 0;i < num;i++)
4069    {
4070        bool exists = false;
4071        wchar_t *s = LvGetStr(hWnd, id, i, 0);
4072        if (Search(new_list, s) != NULL)
4073        {
4074            exists = true;
4075        }
4076        if (exists == false)
4077        {
4078            // 追加予定バッチリスト内に存在しない項目はリストビューから削除する
4079            LvDeleteItem(hWnd, id, i);
4080            num = LvNum(hWnd, id);
4081            i--;
4082            Free(s);
4083        }
4084        else
4085        {
4086            Add(exist_list, s);
4087        }
4088    }
4089
4090    Sort(exist_list);
4091
4092    // バッチ内の項目を 1 つずつ追加していく
4093    for (i = 0;i < LIST_NUM(b->ItemList);i++)
4094    {
4095        LVB_ITEM *t = LIST_DATA(b->ItemList, i);
4096        UINT index;
4097        UINT j;
4098        bool exists = false;
4099
4100        if (Search(exist_list, t->Strings[0]) != NULL)
4101        {
4102            index = LvSearchStr(hWnd, id, 0, t->Strings[0]);
4103        }
4104        else
4105        {
4106            index = INFINITE;
4107        }
4108
4109        if (index != INFINITE)
4110        {
4111            UINT j;
4112            // 追加しようとする項目と同じ文字列の項目がすでに存在する場合は
4113            // 追加ではなく更新を行う
4114            for (j = 0;j < t->NumStrings;j++)
4115            {
4116                LvSetItem(hWnd, id, index, j, t->Strings[j]);
4117            }
4118            LvSetItemImageByImageListId(hWnd, id, index, t->Image);
4119            LvSetItemParam(hWnd, id, index, t->Param);
4120        }
4121        else
4122        {
4123            // 新しく追加を行う
4124            UINT index = INFINITE;
4125            UINT j;
4126            for (j = 0;j < t->NumStrings;j++)
4127            {
4128                if (j == 0)
4129                {
4130                    index = LvInsertItemByImageListId(hWnd, id, t->Image, t->Param, t->Strings[j]);
4131                }
4132                else
4133                {
4134                    LvSetItem(hWnd, id, index, j, t->Strings[j]);
4135                }
4136            }
4137        }
4138
4139        // メモリを解放する
4140        for (j = 0;j < t->NumStrings;j++)
4141        {
4142            Free(t->Strings[j]);
4143        }
4144        Free(t->Strings);
4145        Free(t);
4146    }
4147
4148    // リストを解放する
4149    ReleaseList(b->ItemList);
4150
4151    // メモリを解放する
4152    Free(b);
4153
4154    ReleaseList(new_list);
4155
4156    for (i = 0;i < LIST_NUM(exist_list);i++)
4157    {
4158        Free(LIST_DATA(exist_list, i));
4159    }
4160    ReleaseList(exist_list);
4161
4162    if (last_selected != NULL)
4163    {
4164        UINT pos = LvSearchStr(hWnd, id, 0, last_selected);
4165
4166        if (pos != INFINITE)
4167        {
4168            LvSelect(hWnd, id, pos);
4169        }
4170
4171        Free(last_selected);
4172    }
4173}
4174
4175// カラム数の取得
4176UINT LvGetColumnNum(HWND hWnd, UINT id)
4177{
4178    UINT i;
4179    LVCOLUMN c;
4180    if (hWnd == NULL)
4181    {
4182        return 0;
4183    }
4184
4185    for (i = 0;;i++)
4186    {
4187        Zero(&c, sizeof(c));
4188        c.mask = LVCF_SUBITEM;
4189        if (ListView_GetColumn(DlgItem(hWnd, id), i, &c) == false)
4190        {
4191            break;
4192        }
4193    }
4194
4195    return i;
4196}
4197
4198// ソート関数
4199int CALLBACK LvSortProc(LPARAM param1, LPARAM param2, LPARAM sort_param)
4200{
4201    WINUI_LV_SORT *sort = (WINUI_LV_SORT *)sort_param;
4202    HWND hWnd;
4203    UINT id;
4204    UINT i1, i2;
4205    int ret = 0;
4206    wchar_t *s1, *s2;
4207    if (sort == NULL)
4208    {
4209        return 0;
4210    }
4211
4212    hWnd = sort->hWnd;
4213    id = sort->id;
4214
4215    if (hWnd == NULL)
4216    {
4217        return 0;
4218    }
4219
4220    i1 = (UINT)param1;
4221    i2 = (UINT)param2;
4222
4223    s1 = LvGetStr(hWnd, id, i1, sort->subitem);
4224    if (s1 == NULL)
4225    {
4226        return 0;
4227    }
4228
4229    s2 = LvGetStr(hWnd, id, i2, sort->subitem);
4230    if (s2 == NULL)
4231    {
4232        Free(s1);
4233        return 0;
4234    }
4235
4236    if (sort->numeric == false)
4237    {
4238        if (UniStrCmpi(s1, _UU("CM_NEW_ICON")) == 0)
4239        {
4240            ret = -1;
4241        }
4242        else if (UniStrCmpi(s1, _UU("CM_ASP")) == 0)
4243        {
4244            ret = -1;
4245        }
4246        else if (UniStrCmpi(s2, _UU("CM_NEW_ICON")) == 0)
4247        {
4248            ret = 1;
4249        }
4250        else if (UniStrCmpi(s2, _UU("CM_ASP")) == 0)
4251        {
4252            return 1;
4253        }
4254        else
4255        {
4256            ret = UniStrCmpi(s1, s2);
4257        }
4258    }
4259    else
4260    {
4261        UINT64 v1, v2;
4262        v1 = UniToInt64(s1);
4263        v2 = UniToInt64(s2);
4264        if (v1 > v2)
4265        {
4266            ret = 1;
4267        }
4268        else if (v1 < v2)
4269        {
4270            ret = -1;
4271        }
4272        else
4273        {
4274            ret = 0;
4275        }
4276    }
4277
4278    Free(s1);
4279    Free(s2);
4280
4281    if (sort->desc)
4282    {
4283        ret = -ret;
4284    }
4285
4286    return ret;
4287}
4288
4289// 標準的なハンドラ
4290void LvStandardHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id)
4291{
4292    NMHDR *n;
4293    NMLVKEYDOWN *key;
4294    // 引数チェック
4295    if (hWnd == NULL)
4296    {
4297        return;
4298    }
4299
4300    LvSortHander(hWnd, msg, wParam, lParam, id);
4301
4302    switch (msg)
4303    {
4304    case WM_NOTIFY:
4305        n = (NMHDR *)lParam;
4306        if (n->idFrom == id)
4307        {
4308            switch (n->code)
4309            {
4310            case NM_DBLCLK:
4311                Command(hWnd, IDOK);
4312                break;
4313            case LVN_KEYDOWN:
4314                key = (NMLVKEYDOWN *)n;
4315                if (key != NULL)
4316                {
4317                    UINT code = key->wVKey;
4318                    switch (code)
4319                    {
4320                    case VK_DELETE:
4321                        Command(hWnd, B_DELETE);
4322                        break;
4323
4324                    case VK_RETURN:
4325                        Command(hWnd, IDOK);
4326                        break;
4327
4328                    case VK_F5:
4329                        Command(hWnd, B_REFRESH);
4330                        break;
4331                    }
4332                }
4333                break;
4334            }
4335        }
4336        break;
4337    }
4338}
4339
4340// ソートヘッダハンドラ
4341void LvSortHander(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id)
4342{
4343    NMHDR *nmhdr;
4344    UINT subitem;
4345    bool desc;
4346    // 引数チェック
4347    if (hWnd == NULL)
4348    {
4349        return;
4350    }
4351
4352    switch (msg)
4353    {
4354    case WM_NOTIFY:
4355        nmhdr = (NMHDR *)lParam;
4356
4357        if (nmhdr != NULL)
4358        {
4359            if (nmhdr->idFrom == id)
4360            {
4361                NMLISTVIEW *v;
4362                switch (nmhdr->code)
4363                {
4364                case LVN_COLUMNCLICK:
4365                    desc = false;
4366                    v = (NMLISTVIEW *)lParam;
4367                    subitem = v->iSubItem;
4368
4369                    if ((GetStyle(hWnd, id) & LVS_SORTDESCENDING) == 0)
4370                    {
4371                        desc = true;
4372                        SetStyle(hWnd, id, LVS_SORTDESCENDING);
4373                        RemoveStyle(hWnd, id, LVS_SORTASCENDING);
4374                    }
4375                    else
4376                    {
4377                        SetStyle(hWnd, id, LVS_SORTASCENDING);
4378                        RemoveStyle(hWnd, id, LVS_SORTDESCENDING);
4379                    }
4380
4381                    LvSort(hWnd, id, subitem, desc);
4382                    break;
4383                }
4384            }
4385        }
4386        break;
4387    }
4388}
4389
4390// ソートを行う
4391void LvSort(HWND hWnd, UINT id, UINT subitem, bool desc)
4392{
4393    UINT i, num;
4394    bool numeric = true;
4395    // 引数チェック
4396    if (hWnd == NULL)
4397    {
4398        return;
4399    }
4400
4401    num = LvNum(hWnd, id);
4402    for (i = 0;i < num;i++)
4403    {
4404        wchar_t *s = LvGetStr(hWnd, id, i, subitem);
4405        if (s != NULL)
4406        {
4407            if (UniIsNum(s) == false)
4408            {
4409                numeric = false;
4410                Free(s);
4411                break;
4412            }
4413            Free(s);
4414        }
4415        else
4416        {
4417            numeric = false;
4418            break;
4419        }
4420    }
4421
4422    LvSortEx(hWnd, id, subitem, desc, numeric);
4423}
4424
4425void LvSortEx(HWND hWnd, UINT id, UINT subitem, bool desc, bool numeric)
4426{
4427    WINUI_LV_SORT s;
4428    // 引数チェック
4429    if (hWnd == NULL)
4430    {
4431        return;
4432    }
4433    if (subitem >= LvGetColumnNum(hWnd, id))
4434    {
4435        return;
4436    }
4437
4438    Zero(&s, sizeof(s));
4439    s.desc = desc;
4440    s.numeric = numeric;
4441    s.id = id;
4442    s.hWnd = hWnd;
4443    s.subitem = subitem;
4444
4445    ListView_SortItemsEx(DlgItem(hWnd, id), LvSortProc, (LPARAM)&s);
4446}
4447
4448// 項目追加バッチへの追加
4449void LvInsertAdd(LVB *b, UINT icon, void *param, UINT num_str, ...)
4450{
4451    UINT i;
4452    va_list va;
4453    UINT index = 0;
4454    LVB_ITEM *t;
4455    // 引数チェック
4456    if (b == NULL || num_str == 0)
4457    {
4458        return;
4459    }
4460
4461    t = ZeroMalloc(sizeof(LVB_ITEM));
4462
4463    va_start(va, num_str);
4464
4465    t->Strings = (wchar_t **)ZeroMalloc(sizeof(wchar_t *) * num_str);
4466    t->NumStrings = num_str;
4467
4468    for (i = 0;i < num_str;i++)
4469    {
4470        wchar_t *s = va_arg(va, wchar_t *);
4471
4472        t->Strings[i] = UniCopyStr(s);
4473    }
4474
4475    t->Param = param;
4476    t->Image = GetIcon(icon);
4477
4478    Add(b->ItemList, t);
4479
4480    va_end(va);
4481}
4482
4483// 項目追加バッチの開始
4484LVB *LvInsertStart()
4485{
4486    LVB *b = ZeroMalloc(sizeof(LVB));
4487    b->ItemList = NewListFast(NULL);
4488
4489    return b;
4490}
4491
4492// リストビューに項目を追加する
4493void LvInsert(HWND hWnd, UINT id, UINT icon, void *param, UINT num_str, ...)
4494{
4495    UINT i;
4496    va_list va;
4497    UINT index = 0;
4498    // 引数チェック
4499    if (hWnd == NULL)
4500    {
4501        return;
4502    }
4503
4504    va_start(va, num_str);
4505
4506    for (i = 0;i < num_str;i++)
4507    {
4508        wchar_t *s = va_arg(va, wchar_t *);
4509        if (i == 0)
4510        {
4511            index = LvInsertItem(hWnd, id, icon, param, s);
4512        }
4513        else
4514        {
4515            LvSetItem(hWnd, id, index, i, s);
4516        }
4517    }
4518
4519    va_end(va);
4520}
4521
4522// アイテムのサイズを自動調整する
4523void LvAutoSize(HWND hWnd, UINT id)
4524{
4525    UINT i;
4526    // 引数チェック
4527    if (hWnd == NULL)
4528    {
4529        return;
4530    }
4531
4532    i = 0;
4533    while (true)
4534    {
4535        if (ListView_SetColumnWidth(DlgItem(hWnd, id), i, LVSCW_AUTOSIZE) == false)
4536        {
4537            break;
4538        }
4539        i++;
4540    }
4541}
4542
4543// アイテムを追加する
4544UINT LvInsertItem(HWND hWnd, UINT id, UINT icon, void *param, wchar_t *str)
4545{
4546    return LvInsertItemByImageListId(hWnd, id, GetIcon(icon), param, str);
4547}
4548UINT LvInsertItemByImageListId(HWND hWnd, UINT id, UINT image, void *param, wchar_t *str)
4549{
4550    LVITEMW t;
4551    // 引数チェック
4552    if (hWnd == NULL || str == NULL)
4553    {
4554        return INFINITE;
4555    }
4556    if (MsIsNt() == false)
4557    {
4558        char *s = CopyUniToStr(str);
4559        UINT ret;
4560        ret = LvInsertItemByImageListIdA(hWnd, id, image, param, s);
4561        Free(s);
4562        return ret;
4563    }
4564
4565    Zero(&t, sizeof(t));
4566    t.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
4567    t.pszText = str;
4568    t.iImage = image;
4569    t.lParam = (LPARAM)param;
4570    t.iItem = LvNum(hWnd, id);
4571
4572    return SendMsg(hWnd, id, LVM_INSERTITEMW, 0, (LPARAM)&t);
4573}
4574UINT LvInsertItemByImageListIdA(HWND hWnd, UINT id, UINT image, void *param, char *str)
4575{
4576    LVITEM t;
4577    // 引数チェック
4578    if (hWnd == NULL || str == NULL)
4579    {
4580        return INFINITE;
4581    }
4582
4583    Zero(&t, sizeof(t));
4584    t.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
4585    t.pszText = str;
4586    t.iImage = image;
4587    t.lParam = (LPARAM)param;
4588    t.iItem = LvNum(hWnd, id);
4589
4590    return SendMsg(hWnd, id, LVM_INSERTITEM, 0, (LPARAM)&t);
4591}
4592
4593// イメージを変更する
4594void LvSetItemImage(HWND hWnd, UINT id, UINT index, UINT icon)
4595{
4596    LvSetItemImageByImageListId(hWnd, id, index, GetIcon(icon));
4597}
4598void LvSetItemImageByImageListId(HWND hWnd, UINT id, UINT index, UINT image)
4599{
4600    LVITEM t;
4601    // 引数チェック
4602    if (hWnd == NULL)
4603    {
4604        return;
4605    }
4606
4607    Zero(&t, sizeof(t));
4608    t.mask = LVIF_IMAGE;
4609    t.iImage = image;
4610    t.iItem = index;
4611
4612    SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
4613}
4614
4615// アイテムのパラメータを設定する
4616void LvSetItemParam(HWND hWnd, UINT id, UINT index, void *param)
4617{
4618    LvSetItemParamEx(hWnd, id, index, 0, param);
4619}
4620void LvSetItemParamEx(HWND hWnd, UINT id, UINT index, UINT subitem, void *param)
4621{
4622    LVITEM t;
4623    // 引数チェック
4624    if (hWnd == NULL)
4625    {
4626        return;
4627    }
4628
4629    Zero(&t, sizeof(t));
4630    t.mask = LVIF_PARAM;
4631    t.iItem = index;
4632    t.iSubItem = subitem;
4633    t.lParam = (LPARAM)param;
4634
4635    SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
4636}
4637
4638// アイテムを設定する
4639void LvSetItem(HWND hWnd, UINT id, UINT index, UINT pos, wchar_t *str)
4640{
4641    LVITEMW t;
4642    wchar_t *old_str;
4643    // 引数チェック
4644    if (hWnd == NULL || str == NULL)
4645    {
4646        return;
4647    }
4648    if (MsIsNt() == false)
4649    {
4650        char *s = CopyUniToStr(str);
4651        LvSetItemA(hWnd, id, index, pos, s);
4652        Free(s);
4653        return;
4654    }
4655
4656    Zero(&t, sizeof(t));
4657    t.mask = LVIF_TEXT;
4658    t.pszText = str;
4659    t.iItem = index;
4660    t.iSubItem = pos;
4661
4662    old_str = LvGetStr(hWnd, id, index, pos);
4663
4664    if (UniStrCmp(old_str, str) != 0)
4665    {
4666        SendMsg(hWnd, id, LVM_SETITEMW, 0, (LPARAM)&t);
4667    }
4668
4669    Free(old_str);
4670}
4671void LvSetItemA(HWND hWnd, UINT id, UINT index, UINT pos, char *str)
4672{
4673    LVITEM t;
4674    wchar_t *old_str;
4675    char *old_str_2;
4676    // 引数チェック
4677    if (hWnd == NULL || str == NULL)
4678    {
4679        return;
4680    }
4681
4682    Zero(&t, sizeof(t));
4683    t.mask = LVIF_TEXT;
4684    t.pszText = str;
4685    t.iItem = index;
4686    t.iSubItem = pos;
4687
4688    old_str = LvGetStr(hWnd, id, index, pos);
4689    old_str_2 = CopyUniToStr(old_str);
4690
4691    if (StrCmp(old_str_2, str) != 0)
4692    {
4693        SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
4694    }
4695
4696    Free(old_str_2);
4697    Free(old_str);
4698}
4699
4700// リストボックスのビューを設定
4701void LvSetView(HWND hWnd, UINT id, bool details)
4702{
4703    // 引数チェック
4704    if (hWnd == NULL)
4705    {
4706        return;
4707    }
4708
4709    if (details)
4710    {
4711        RemoveStyle(hWnd, id, LVS_ICON);
4712        SetStyle(hWnd, id, LVS_REPORT);
4713    }
4714    else
4715    {
4716        RemoveStyle(hWnd, id, LVS_REPORT);
4717        SetStyle(hWnd, id, LVS_ICON);
4718    }
4719}
4720
4721// 指定したアイテムが必ず表示されるようにする
4722void LvShow(HWND hWnd, UINT id, UINT index)
4723{
4724    // 引数チェック
4725    if (hWnd == NULL)
4726    {
4727        return;
4728    }
4729
4730    ListView_EnsureVisible(DlgItem(hWnd, id), index, false);
4731}
4732
4733// 現在選択されている項目が存在するかどうかを取得する
4734bool LvIsSelected(HWND hWnd, UINT id)
4735{
4736    // 引数チェック
4737    if (hWnd == NULL)
4738    {
4739        return false;
4740    }
4741
4742    if (LvGetSelected(hWnd, id) == INFINITE)
4743    {
4744        return false;
4745    }
4746
4747    return true;
4748}
4749
4750// 現在選択されている項目を取得する
4751UINT LvGetFocused(HWND hWnd, UINT id)
4752{
4753    // 引数チェック
4754    if (hWnd == NULL)
4755    {
4756        return INFINITE;
4757    }
4758
4759    return ListView_GetNextItem(DlgItem(hWnd, id), -1, LVNI_FOCUSED);
4760}
4761
4762// 現在選択されている文字列を取得する
4763wchar_t *LvGetFocusedStr(HWND hWnd, UINT id, UINT pos)
4764{
4765    UINT i;
4766    // 引数チェック
4767    if (hWnd == NULL)
4768    {
4769        return NULL;
4770    }
4771
4772    i = LvGetFocused(hWnd, id);
4773    if (i == INFINITE)
4774    {
4775        return NULL;
4776    }
4777
4778    return LvGetStr(hWnd, id, i, pos);
4779}
4780
4781// 現在選択されている項目を取得する
4782UINT LvGetSelected(HWND hWnd, UINT id)
4783{
4784    // 引数チェック
4785    if (hWnd == NULL)
4786    {
4787        return INFINITE;
4788    }
4789
4790    return ListView_GetNextItem(DlgItem(hWnd, id), -1, LVNI_FOCUSED | LVNI_SELECTED);
4791}
4792
4793// 現在選択されている文字列を取得する
4794wchar_t *LvGetSelectedStr(HWND hWnd, UINT id, UINT pos)
4795{
4796    UINT i;
4797    // 引数チェック
4798    if (hWnd == NULL)
4799    {
4800        return NULL;
4801    }
4802
4803    i = LvGetSelected(hWnd, id);
4804    if (i == INFINITE)
4805    {
4806        return NULL;
4807    }
4808
4809    return LvGetStr(hWnd, id, i, pos);
4810}
4811char *LvGetSelectedStrA(HWND hWnd, UINT id, UINT pos)
4812{
4813    char *ret;
4814    wchar_t *tmp = LvGetSelectedStr(hWnd, id, pos);
4815    if (tmp == NULL)
4816    {
4817        return NULL;
4818    }
4819    ret = CopyUniToStr(tmp);
4820    Free(tmp);
4821    return ret;
4822}
4823
4824// 2 つ以上の項目がマスクされているかどうかを取得する
4825bool LvIsMultiMasked(HWND hWnd, UINT id)
4826{
4827    UINT i;
4828    // 引数チェック
4829    if (hWnd == NULL)
4830    {
4831        return false;
4832    }
4833
4834    i = INFINITE;
4835    i = LvGetNextMasked(hWnd, id, i);
4836    if (i != INFINITE)
4837    {
4838        if (LvGetNextMasked(hWnd, id, i) != INFINITE)
4839        {
4840            return true;
4841        }
4842    }
4843
4844    return false;
4845}
4846
4847// ただ 1 つの項目だけが選択されているかどうか調べる
4848bool LvIsSingleSelected(HWND hWnd, UINT id)
4849{
4850    return LvIsSelected(hWnd, id) && (LvIsMultiMasked(hWnd, id) == false);
4851}
4852
4853// 現在マスクされている項目が存在するかどうかを取得する
4854bool LvIsMasked(HWND hWnd, UINT id)
4855{
4856    // 引数チェック
4857    if (hWnd == NULL)
4858    {
4859        return false;
4860    }
4861
4862    if (LvGetNextMasked(hWnd, id, INFINITE) == INFINITE)
4863    {
4864        return false;
4865    }
4866
4867    return true;
4868}
4869
4870// 現在マスクされている項目数を取得する
4871UINT LvGetMaskedNum(HWND hWnd, UINT id)
4872{
4873    UINT i = INFINITE;
4874    UINT num = 0;
4875    // 引数チェック
4876    if (hWnd == NULL)
4877    {
4878        return 0;
4879    }
4880
4881    while (true)
4882    {
4883        i = LvGetNextMasked(hWnd, id, i);
4884        if (i == INFINITE)
4885        {
4886            break;
4887        }
4888
4889        num++;
4890    }
4891
4892    return num;
4893}
4894
4895// 現在マスクされている項目を取得する
4896UINT LvGetNextMasked(HWND hWnd, UINT id, UINT start)
4897{
4898    // 引数チェック
4899    if (hWnd == NULL)
4900    {
4901        return INFINITE;
4902    }
4903
4904    return ListView_GetNextItem(DlgItem(hWnd, id), start, LVNI_SELECTED);
4905}
4906
4907// 指定した文字列を持つ項目を検索する
4908UINT LvSearchStr_(HWND hWnd, UINT id, UINT pos, wchar_t *str)
4909{
4910    UINT ret;
4911    LVFINDINFOW t;
4912    // 引数チェック
4913    if (hWnd == NULL || str == NULL)
4914    {
4915        return INFINITE;
4916    }
4917
4918    Zero(&t, sizeof(t));
4919    t.flags = LVFI_STRING;
4920    t.psz = str;
4921    t.vkDirection = VK_DOWN;
4922
4923    ret = SendMsg(hWnd, id, LVM_FINDITEMW, -1, (LPARAM)&t);
4924
4925    return ret;
4926}
4927
4928// 指定した文字列を持つ項目を検索する
4929UINT LvSearchStr(HWND hWnd, UINT id, UINT pos, wchar_t *str)
4930{
4931    UINT i, num;
4932    // 引数チェック
4933    if (hWnd == NULL || str == NULL)
4934    {
4935        return INFINITE;
4936    }
4937
4938    num = LvNum(hWnd, id);
4939
4940    for (i = 0;i < num;i++)
4941    {
4942        wchar_t *s = LvGetStr(hWnd, id, i, pos);
4943        if (s != NULL)
4944        {
4945            if (UniStrCmpi(s, str) == 0)
4946            {
4947                Free(s);
4948                return i;
4949            }
4950            else
4951            {
4952                Free(s);
4953            }
4954        }
4955    }
4956
4957    return INFINITE;
4958}
4959UINT LvSearchStrA(HWND hWnd, UINT id, UINT pos, char *str)
4960{
4961    wchar_t *tmp = CopyStrToUni(str);
4962    UINT ret = LvSearchStr(hWnd, id, pos, tmp);
4963    Free(tmp);
4964    return ret;
4965}
4966
4967// 指定した param を持つ項目を検索する
4968UINT LvSearchParam(HWND hWnd, UINT id, void *param)
4969{
4970    UINT i, num;
4971    // 引数チェック
4972    if (hWnd == NULL)
4973    {
4974        return INFINITE;
4975    }
4976
4977    num = LvNum(hWnd, id);
4978
4979    for (i = 0;i < num;i++)
4980    {
4981        if (LvGetParam(hWnd, id, i) == param)
4982        {
4983            return i;
4984        }
4985    }
4986
4987    return INFINITE;
4988}
4989
4990// 項目数を取得する
4991UINT LvNum(HWND hWnd, UINT id)
4992{
4993    // 引数チェック
4994    if (hWnd == NULL)
4995    {
4996        return 0;
4997    }
4998
4999    return ListView_GetItemCount(DlgItem(hWnd, id));
5000}
5001
5002// 項目を削除する
5003void LvDeleteItem(HWND hWnd, UINT id, UINT index)
5004{
5005    UINT i;
5006    // 引数チェック
5007    if (hWnd == NULL)
5008    {
5009        return;
5010    }
5011
5012    ListView_DeleteItem(DlgItem(hWnd, id), index);
5013
5014    i = LvGetSelected(hWnd, id);
5015    if (i != INFINITE)
5016    {
5017        LvSelect(hWnd, id, i);
5018    }
5019}
5020
5021// 項目からデータを取得する
5022void *LvGetParam(HWND hWnd, UINT id, UINT index)
5023{
5024    return LvGetParamEx(hWnd, id, index, 0);
5025}
5026void *LvGetParamEx(HWND hWnd, UINT id, UINT index, UINT subitem)
5027{
5028    LVITEM t;
5029    // 引数チェック
5030    if (hWnd == NULL)
5031    {
5032        return NULL;
5033    }
5034    if (index == INFINITE)
5035    {
5036        return NULL;
5037    }
5038
5039    Zero(&t, sizeof(t));
5040    t.mask = LVIF_PARAM;
5041    t.iItem = index;
5042    t.iSubItem = subitem;
5043
5044    if (ListView_GetItem(DlgItem(hWnd, id), &t) == false)
5045    {
5046        return NULL;
5047    }
5048
5049    return (void *)t.lParam;
5050}
5051
5052// 項目の文字列を取得する
5053wchar_t *LvGetStr(HWND hWnd, UINT id, UINT index, UINT pos)
5054{
5055    wchar_t *tmp;
5056    UINT size;
5057    LVITEMW t;
5058    // 引数チェック
5059    if (hWnd == NULL)
5060    {
5061        return NULL;
5062    }
5063    if (MsIsNt() == false)
5064    {
5065        char *s = LvGetStrA(hWnd, id, index, pos);
5066        if (s == NULL)
5067        {
5068            return NULL;
5069        }
5070        else
5071        {
5072            wchar_t *ret = CopyStrToUni(s);
5073            Free(s);
5074
5075            return ret;
5076        }
5077    }
5078
5079    size = 65536;
5080    tmp = Malloc(size);
5081
5082    Zero(&t, sizeof(t));
5083    t.mask = LVIF_TEXT;
5084    t.iItem = index;
5085    t.iSubItem = pos;
5086    t.pszText = tmp;
5087    t.cchTextMax = size;
5088
5089    if (SendMsg(hWnd, id, LVM_GETITEMTEXTW, index, (LPARAM)&t) <= 0)
5090    {
5091        Free(tmp);
5092        return UniCopyStr(L"");
5093    }
5094    else
5095    {
5096        wchar_t *ret = UniCopyStr(tmp);
5097        Free(tmp);
5098        return ret;
5099    }
5100}
5101char *LvGetStrA(HWND hWnd, UINT id, UINT index, UINT pos)
5102{
5103    char *tmp;
5104    UINT size;
5105    LVITEM t;
5106    // 引数チェック
5107    if (hWnd == NULL)
5108    {
5109        return NULL;
5110    }
5111
5112    size = 65536;
5113    tmp = Malloc(size);
5114
5115    Zero(&t, sizeof(t));
5116    t.mask = LVIF_TEXT;
5117    t.iItem = index;
5118    t.iSubItem = pos;
5119    t.pszText = tmp;
5120    t.cchTextMax = size;
5121
5122    if (SendMsg(hWnd, id, LVM_GETITEMTEXT, index, (LPARAM)&t) <= 0)
5123    {
5124        Free(tmp);
5125        return CopyStr("");
5126    }
5127    else
5128    {
5129        char *ret = CopyStr(tmp);
5130        Free(tmp);
5131        return ret;
5132    }
5133}
5134
5135// スタイルを設定する
5136void LvSetStyle(HWND hWnd, UINT id, UINT style)
5137{
5138    // 引数チェック
5139    if (hWnd == NULL)
5140    {
5141        return;
5142    }
5143
5144    if ((ListView_GetExtendedListViewStyle(DlgItem(hWnd, id)) & style) == 0)
5145    {
5146        ListView_SetExtendedListViewStyleEx(DlgItem(hWnd, id), style, style);
5147    }
5148}
5149
5150// スタイルを削除する
5151void LvRemoveStyle(HWND hWnd, UINT id, UINT style)
5152{
5153    // 引数チェック
5154    if (hWnd == NULL)
5155    {
5156        return;
5157    }
5158
5159    if ((ListView_GetExtendedListViewStyle(DlgItem(hWnd, id)) & style) != 0)
5160    {
5161        ListView_SetExtendedListViewStyleEx(DlgItem(hWnd, id), style, 0);
5162    }
5163}
5164
5165// 項目の選択を反転する
5166void LvSwitchSelect(HWND hWnd, UINT id)
5167{
5168    UINT i, num;
5169    bool *states;
5170    // 引数チェック
5171    if (hWnd == NULL)
5172    {
5173        return;
5174    }
5175
5176    num = LvNum(hWnd, id);
5177    states = ZeroMalloc(sizeof(bool) * num);
5178
5179    i = INFINITE;
5180    while (true)
5181    {
5182        i = LvGetNextMasked(hWnd, id, i);
5183        if (i == INFINITE)
5184        {
5185            break;
5186        }
5187
5188        states[i] = true;
5189    }
5190
5191    for (i = 0;i < num;i++)
5192    {
5193        if (states[i] == false)
5194        {
5195            ListView_SetItemState(DlgItem(hWnd, id), i, LVIS_SELECTED, LVIS_SELECTED);
5196        }
5197        else
5198        {
5199            ListView_SetItemState(DlgItem(hWnd, id), i, 0, LVIS_SELECTED);
5200        }
5201    }
5202
5203    Free(states);
5204}
5205
5206// すべての項目を選択する
5207void LvSelectAll(HWND hWnd, UINT id)
5208{
5209    UINT i, num;
5210    // 引数チェック
5211    if (hWnd == NULL)
5212    {
5213        return;
5214    }
5215
5216    num = LvNum(hWnd, id);
5217    for (i = 0;i < num;i++)
5218    {
5219        ListView_SetItemState(DlgItem(hWnd, id), i, LVIS_SELECTED, LVIS_SELECTED);
5220    }
5221}
5222
5223// 項目を選択する
5224void LvSelect(HWND hWnd, UINT id, UINT index)
5225{
5226    // 引数チェック
5227    if (hWnd == NULL)
5228    {
5229        return;
5230    }
5231
5232    if (index == INFINITE)
5233    {
5234        UINT i, num;
5235        // すべて選択解除する
5236        num = LvNum(hWnd, id);
5237        for (i = 0;i < num;i++)
5238        {
5239            ListView_SetItemState(DlgItem(hWnd, id), i, 0, LVIS_SELECTED);
5240        }
5241    }
5242    else
5243    {
5244        // 選択する
5245        ListView_SetItemState(DlgItem(hWnd, id), index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
5246        ListView_EnsureVisible(DlgItem(hWnd, id), index, true);
5247    }
5248}
5249
5250// 証明書情報を表示する
5251void PrintCertInfo(HWND hWnd, CERT_DLG *p)
5252{
5253    X *x;
5254    char *serial_tmp;
5255    UINT serial_size;
5256    wchar_t *wchar_tmp;
5257    wchar_t tmp[1024 * 5];
5258    UCHAR md5[MD5_SIZE];
5259    UCHAR sha1[SHA1_SIZE];
5260    char *s_tmp;
5261    K *k;
5262    // 引数チェック
5263    if (p == NULL || hWnd == NULL)
5264    {
5265        return;
5266    }
5267
5268    x = p->x;
5269
5270    // シリアル番号
5271    if (x->serial != NULL)
5272    {
5273        serial_size = x->serial->size * 3 + 1;
5274        serial_tmp = ZeroMalloc(serial_size);
5275        BinToStrEx(serial_tmp, serial_size, x->serial->data, x->serial->size);
5276        wchar_tmp = CopyStrToUni(serial_tmp);
5277        Free(serial_tmp);
5278    }
5279    else
5280    {
5281        wchar_tmp = CopyUniStr(_UU("CERT_NO_SERIAL"));
5282    }
5283    LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_SERIAL"), wchar_tmp);
5284
5285    // 発行者
5286    GetAllNameFromName(tmp, sizeof(tmp), x->issuer_name);
5287    LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_ISSUER"), tmp);
5288
5289    // サブジェクト
5290    GetAllNameFromName(tmp, sizeof(tmp), x->subject_name);
5291    LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_SUBJECT"), tmp);
5292
5293    // 有効期限の開始
5294    GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notBefore), NULL);
5295    LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_NOT_BEFORE"), tmp);
5296
5297    // 有効期限の終了
5298    GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
5299    LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_NOT_AFTER"), tmp);
5300
5301    // ビット数
5302    if (x->is_compatible_bit)
5303    {
5304        UniFormat(tmp, sizeof(tmp), _UU("CERT_BITS_FORMAT"), x->bits);
5305        LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_BITS"), tmp);
5306    }
5307
5308    // 公開鍵
5309    k = GetKFromX(x);
5310    if (k != NULL)
5311    {
5312        BUF *b = KToBuf(k, false, NULL);
5313        s_tmp = CopyBinToStrEx(b->Buf, b->Size);
5314        StrToUni(tmp, sizeof(tmp), s_tmp);
5315        Free(s_tmp);
5316        LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_PUBLIC_KEY"), tmp);
5317        FreeBuf(b);
5318    }
5319    FreeK(k);
5320
5321    GetXDigest(x, md5, false);
5322    GetXDigest(x, sha1, true);
5323
5324    // ダイジェスト (MD5)
5325    s_tmp = CopyBinToStrEx(md5, sizeof(md5));
5326    StrToUni(tmp, sizeof(tmp), s_tmp);
5327    Free(s_tmp);
5328    LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_DIGEST_MD5"), tmp);
5329
5330    // ダイジェスト (SHA-1)
5331    s_tmp = CopyBinToStrEx(sha1, sizeof(sha1));
5332    StrToUni(tmp, sizeof(tmp), s_tmp);
5333    Free(s_tmp);
5334    LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_DIGEST_SHA1"), tmp);
5335
5336    Free(wchar_tmp);
5337
5338    LvSelect(hWnd, L_CERTINFO, 0);
5339}
5340
5341// 表示の更新
5342void CertDlgUpdate(HWND hWnd, CERT_DLG *p)
5343{
5344    // 引数チェック
5345    if (hWnd == NULL || p == NULL)
5346    {
5347        return;
5348    }
5349
5350    if (LvIsSelected(hWnd, L_CERTINFO) == false)
5351    {
5352        SetText(hWnd, E_DETAIL, L"");
5353    }
5354    else
5355    {
5356        UINT i = LvGetSelected(hWnd, L_CERTINFO);
5357        wchar_t *tmp = LvGetStr(hWnd, L_CERTINFO, i, 1);
5358        SetText(hWnd, E_DETAIL, tmp);
5359        Free(tmp);
5360    }
5361}
5362
5363// 証明書の保存
5364void CertDlgSave(HWND hWnd, CERT_DLG *p)
5365{
5366    wchar_t *name;
5367    X *x;
5368    // 引数チェック
5369    if (hWnd == NULL || p == NULL)
5370    {
5371        return;
5372    }
5373
5374    // 保存
5375    name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
5376    x = p->x;
5377    if (name != NULL)
5378    {
5379        char str[MAX_SIZE];
5380        UniToStr(str, sizeof(str), name);
5381        if (XToFile(x, str, true))
5382        {
5383            MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_CERT_SAVE_OK"));
5384        }
5385        else
5386        {
5387            MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
5388        }
5389        Free(name);
5390    }
5391}
5392
5393// 証明書表示ダイアログプロシージャ
5394UINT CertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
5395{
5396    CERT_DLG *p = (CERT_DLG *)param;
5397    X *x;
5398    wchar_t tmp[MAX_SIZE];
5399    NMHDR *n;
5400    // 引数チェック
5401    if (hWnd == NULL)
5402    {
5403        return 0;
5404    }
5405
5406    switch (msg)
5407    {
5408    case WM_INITDIALOG:
5409        SetIcon(hWnd, 0, ICO_CERT);
5410        x = p->x;
5411        GetAllNameFromNameEx(tmp, sizeof(tmp), x->subject_name);
5412        SetText(hWnd, E_SUBJECT, tmp);
5413        GetAllNameFromNameEx(tmp, sizeof(tmp), x->issuer_name);
5414        SetText(hWnd, E_ISSUER, tmp);
5415        GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
5416        SetText(hWnd, E_EXPIRES, tmp);
5417        SetFont(hWnd, E_SUBJECT, Font(0, 1));
5418        SetFont(hWnd, E_ISSUER, Font(0, 1));
5419        SetFont(hWnd, E_EXPIRES, Font(0, 1));
5420        SetIcon(hWnd, B_PARENT, ICO_CERT);
5421        if (x->root_cert)
5422        {
5423            // ルート証明書
5424            Hide(hWnd, S_WARNING_ICON);
5425            SetText(hWnd, S_PARENT, _UU("CERT_ROOT"));
5426            Hide(hWnd, B_PARENT);
5427            Hide(hWnd, S_PARENT_BUTTON_STR);
5428        }
5429        else if (p->issuer_x != NULL)
5430        {
5431            // 親証明書がある
5432            Hide(hWnd, S_WARNING_ICON);
5433        }
5434        else
5435        {
5436            // 親証明書が無い
5437            Hide(hWnd, S_CERT_ICON);
5438            Hide(hWnd, B_PARENT);
5439            Hide(hWnd, S_PARENT_BUTTON_STR);
5440            SetText(hWnd, S_PARENT, _UU("CERT_NOT_FOUND"));
5441            if (p->ManagerMode)
5442            {
5443                Hide(hWnd, IDC_STATIC1);
5444                Hide(hWnd, S_PARENT);
5445                Hide(hWnd, S_WARNING_ICON);
5446                Hide(hWnd, S_CERT_ICON);
5447                Hide(hWnd, B_PARENT);
5448                Hide(hWnd, S_PARENT_BUTTON_STR);
5449            }
5450        }
5451
5452
5453        LvInit(hWnd, L_CERTINFO);
5454        LvInsertColumn(hWnd, L_CERTINFO, 0, _UU("CERT_LV_C1"), 130);
5455        LvInsertColumn(hWnd, L_CERTINFO, 1, _UU("CERT_LV_C2"), 250);
5456
5457        PrintCertInfo(hWnd, p);
5458        Focus(hWnd, L_CERTINFO);
5459
5460        CertDlgUpdate(hWnd, p);
5461
5462        if (p->ManagerMode)
5463        {
5464            Show(hWnd, B_SAVE);
5465        }
5466        else
5467        {
5468            // セキュリティのため非表示にする
5469            Hide(hWnd, B_SAVE);
5470        }
5471
5472        break;
5473    case WM_COMMAND:
5474        switch (wParam)
5475        {
5476        case IDOK:
5477        case IDCANCEL:
5478            Close(hWnd);
5479            break;
5480        case B_PARENT:
5481            CertDlg(hWnd, p->issuer_x, NULL, p->ManagerMode);
5482            break;
5483        case B_SAVE:
5484            // ファイルに保存
5485            CertDlgSave(hWnd, p);
5486            break;
5487        }
5488        break;
5489    case WM_CLOSE:
5490        EndDialog(hWnd, false);
5491        break;
5492    case WM_NOTIFY:
5493        n = (NMHDR *)lParam;
5494        switch (n->idFrom)
5495        {
5496        case L_CERTINFO:
5497            switch (n->code)
5498            {
5499            case LVN_ITEMCHANGED:
5500                CertDlgUpdate(hWnd, p);
5501                break;
5502            }
5503            break;
5504        }
5505        break;
5506    }
5507
5508    LvSortHander(hWnd, msg, wParam, lParam, L_CERTINFO);
5509
5510    return 0;
5511}
5512
5513// 証明書表示ダイアログ
5514void CertDlg(HWND hWnd, X *x, X *issuer_x, bool manager)
5515{
5516    CERT_DLG p;
5517    // 引数チェック
5518    if (x == NULL)
5519    {
5520        return;
5521    }
5522
5523    Zero(&p, sizeof(p));
5524    p.x = x;
5525    if (CompareX(x, issuer_x) == false)
5526    {
5527        p.issuer_x = issuer_x;
5528    }
5529    p.ManagerMode = manager;
5530    Dialog(hWnd, D_CERT, CertDlgProc, &p);
5531}
5532
5533// ステータスウインドウダイアログ
5534UINT StatusPrinterWindowDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
5535{
5536    STATUS_WINDOW_PARAM *p = (STATUS_WINDOW_PARAM *)param;
5537    PACK *pack;
5538    // 引数チェック
5539    if (hWnd == NULL)
5540    {
5541        return 0;
5542    }
5543
5544    switch (msg)
5545    {
5546    case WM_INITDIALOG:
5547        // 初期化
5548        SetIcon(hWnd, 0, ICO_SERVER_ONLINE);
5549        RemoveExStyle(hWnd, 0, WS_EX_APPWINDOW);
5550        p->hWnd = hWnd;
5551        NoticeThreadInit(p->Thread);
5552        FormatText(hWnd, 0, p->AccountName);
5553        break;
5554
5555    case WM_COMMAND:
5556        switch (wParam)
5557        {
5558        case IDOK:
5559        case IDCANCEL:
5560            // キャンセルボタン
5561            Close(hWnd);
5562            break;
5563        }
5564
5565        break;
5566
5567    case WM_APP + 1:
5568        // 文字列を設定
5569        SetText(hWnd, S_STATUS, (wchar_t *)lParam);
5570        break;
5571
5572    case WM_APP + 2:
5573        // このウインドウを閉じる
5574        EndDialog(hWnd, false);
5575        break;
5576
5577    case WM_CLOSE:
5578        // セッションを終了する
5579        pack = NewPack();
5580        SendPack(p->Sock, pack);
5581        EndDialog(hWnd, false);
5582        break;
5583    }
5584
5585    return 0;
5586}
5587
5588// ステータスウインドウ制御用スレッド
5589void StatusPrinterWindowThread(THREAD *thread, void *param)
5590{
5591    STATUS_WINDOW_PARAM *p = (STATUS_WINDOW_PARAM *)param;
5592    // 引数チェック
5593    if (thread == NULL || param == NULL)
5594    {
5595        return;
5596    }
5597
5598    p->Thread = thread;
5599    DialogEx2(NULL, D_STATUS, StatusPrinterWindowDlg, p, true, true);
5600
5601    Free(p);
5602}
5603
5604// ステータスウインドウにメッセージを表示する
5605void StatusPrinterWindowPrint(STATUS_WINDOW *sw, wchar_t *str)
5606{
5607    // 引数チェック
5608    if (sw == NULL)
5609    {
5610        return;
5611    }
5612
5613    SendMessage(sw->hWnd, WM_APP + 1, 0, (LPARAM)str);
5614}
5615
5616// ステータスウインドウの終了と解放
5617void StatusPrinterWindowStop(STATUS_WINDOW *sw)
5618{
5619    // 引数チェック
5620    if (sw == NULL)
5621    {
5622        return;
5623    }
5624
5625    // 停止メッセージを送信
5626    SendMessage(sw->hWnd, WM_APP + 2, 0, 0);
5627
5628    // スレッド停止まで待機
5629    WaitThread(sw->Thread, INFINITE);
5630
5631    // メモリ解放
5632    ReleaseThread(sw->Thread);
5633    Free(sw);
5634}
5635
5636// ステータスウインドウの初期化
5637STATUS_WINDOW *StatusPrinterWindowStart(SOCK *s, wchar_t *account_name)
5638{
5639    STATUS_WINDOW_PARAM *p;
5640    STATUS_WINDOW *sw;
5641    THREAD *t;
5642    // 引数チェック
5643    if (s == NULL || account_name == NULL)
5644    {
5645        return NULL;
5646    }
5647
5648    p = ZeroMalloc(sizeof(STATUS_WINDOW_PARAM));
5649    p->Sock = s;
5650    UniStrCpy(p->AccountName, sizeof(p->AccountName), account_name);
5651
5652    // スレッド作成
5653    t = NewThread(StatusPrinterWindowThread, p);
5654    WaitThreadInit(t);
5655
5656    sw = ZeroMalloc(sizeof(STATUS_WINDOW));
5657    sw->hWnd = p->hWnd;
5658    sw->Thread = t;
5659
5660    return sw;
5661}
5662
5663// 文字列を取得
5664wchar_t *LbGetStr(HWND hWnd, UINT id)
5665{
5666    // 引数チェック
5667    if (hWnd == NULL)
5668    {
5669        return NULL;
5670    }
5671
5672    return GetText(hWnd, id);
5673}
5674
5675// 文字列検索
5676UINT LbFindStr(HWND hWnd, UINT id, wchar_t *str)
5677{
5678    UINT ret;
5679    // 引数チェック
5680    if (hWnd == NULL || str == NULL)
5681    {
5682        return INFINITE;
5683    }
5684
5685    ret = SendMsg(hWnd, id, LB_FINDSTRING, -1, (LPARAM)str);
5686
5687    return ret;
5688}
5689
5690// 項目数を取得
5691UINT LbNum(HWND hWnd, UINT id)
5692{
5693    // 引数チェック
5694    if (hWnd == NULL)
5695    {
5696        return INFINITE;
5697    }
5698
5699    return SendMsg(hWnd, id, LB_GETCOUNT, 0, 0);
5700}
5701
5702// 文字列追加
5703UINT LbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data)
5704{
5705    UINT ret;
5706
5707    if (MsIsNt() == false)
5708    {
5709        char *s = CopyUniToStr(str);
5710        ret = LbAddStrA(hWnd, id, s, data);
5711        Free(s);
5712        return ret;
5713    }
5714
5715    // 引数チェック
5716    if (hWnd == NULL || str == NULL)
5717    {
5718        return INFINITE;
5719    }
5720
5721    ret = SendMsg(hWnd, id, LB_ADDSTRING, 0, (LPARAM)str);
5722    SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
5723
5724    if (LbNum(hWnd, id) == 1)
5725    {
5726        LbSelectIndex(hWnd, id, 0);
5727    }
5728
5729    return ret;
5730}
5731UINT LbAddStrA(HWND hWnd, UINT id, char *str, UINT data)
5732{
5733    UINT ret;
5734    // 引数チェック
5735    if (hWnd == NULL || str == NULL)
5736    {
5737        return INFINITE;
5738    }
5739
5740    ret = SendMsg(hWnd, id, LB_ADDSTRING, 0, (LPARAM)str);
5741    SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
5742
5743    if (LbNum(hWnd, id) == 1)
5744    {
5745        LbSelectIndex(hWnd, id, 0);
5746    }
5747
5748    return ret;
5749}
5750
5751// 文字列挿入
5752UINT LbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data)
5753{
5754    UINT ret;
5755
5756    if (MsIsNt() == false)
5757    {
5758        char *s = CopyUniToStr(str);
5759        ret = LbInsertStrA(hWnd, id, index, s, data);
5760        Free(s);
5761        return ret;
5762    }
5763
5764    // 引数チェック
5765    if (hWnd == NULL || str == NULL)
5766    {
5767        return INFINITE;
5768    }
5769
5770    ret = SendMsg(hWnd, id, LB_INSERTSTRING, index, (LPARAM)str);
5771    SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
5772
5773    if (LbNum(hWnd, id) == 1)
5774    {
5775        LbSelect(hWnd, id, 0);
5776    }
5777
5778    return ret;
5779}
5780UINT LbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
5781{
5782    UINT ret;
5783    // 引数チェック
5784    if (hWnd == NULL || str == NULL)
5785    {
5786        return INFINITE;
5787    }
5788
5789    ret = SendMsg(hWnd, id, LB_INSERTSTRING, index, (LPARAM)str);
5790    SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
5791
5792    if (LbNum(hWnd, id) == 1)
5793    {
5794        LbSelect(hWnd, id, 0);
5795    }
5796
5797    return ret;
5798}
5799
5800// すべて削除
5801void LbReset(HWND hWnd, UINT id)
5802{
5803    // 引数チェック
5804    if (hWnd == NULL)
5805    {
5806        return;
5807    }
5808
5809    SendMsg(hWnd, id, LB_RESETCONTENT, 0, 0);
5810}
5811
5812// インデックスを指定して選択
5813void LbSelectIndex(HWND hWnd, UINT id, UINT index)
5814{
5815    // 引数チェック
5816    if (hWnd == NULL)
5817    {
5818        return;
5819    }
5820
5821    SendMsg(hWnd, id, LB_SETCURSEL, index, 0);
5822}
5823
5824// データを取得
5825UINT LbGetData(HWND hWnd, UINT id, UINT index)
5826{
5827    // 引数チェック
5828    if (hWnd == NULL || index == INFINITE)
5829    {
5830        return INFINITE;
5831    }
5832
5833    return SendMsg(hWnd, id, LB_GETITEMDATA, index, 0);
5834}
5835
5836// データを検索
5837UINT LbFindData(HWND hWnd, UINT id, UINT data)
5838{
5839    UINT i, num;
5840    // 引数チェック
5841    if (hWnd == NULL)
5842    {
5843        return INFINITE;
5844    }
5845
5846    num = LbNum(hWnd, id);
5847    if (num == INFINITE)
5848    {
5849        return INFINITE;
5850    }
5851
5852    for (i = 0;i < num;i++)
5853    {
5854        if (LbGetData(hWnd, id, i) == data)
5855        {
5856            return i;
5857        }
5858    }
5859
5860    return INFINITE;
5861}
5862
5863// アイテムの高さを設定
5864void LbSetHeight(HWND hWnd, UINT id, UINT value)
5865{
5866    // 引数チェック
5867    if (hWnd == NULL)
5868    {
5869        return;
5870    }
5871
5872    SendMsg(hWnd, id, LB_SETITEMHEIGHT, 0, value);
5873}
5874
5875// データを指定して検索
5876void LbSelect(HWND hWnd, UINT id, int data)
5877{
5878    UINT index;
5879    // 引数チェック
5880    if (hWnd == NULL)
5881    {
5882        return;
5883    }
5884
5885    if (data == INFINITE)
5886    {
5887        // 最初の項目を取得
5888        LbSelectIndex(hWnd, id, 0);
5889        return;
5890    }
5891
5892    index = LbFindData(hWnd, id, data);
5893    if (index == INFINITE)
5894    {
5895        // 発見できなかった
5896        return;
5897    }
5898
5899    // 選択する
5900    LbSelectIndex(hWnd, id, index);
5901}
5902
5903// 現在選択されている項目を取得
5904UINT LbGetSelectIndex(HWND hWnd, UINT id)
5905{
5906    // 引数チェック
5907    if (hWnd == NULL)
5908    {
5909        return INFINITE;
5910    }
5911
5912    return SendMsg(hWnd, id, LB_GETCURSEL, 0, 0);
5913}
5914
5915// 現在選択されている値を取得
5916UINT LbGetSelect(HWND hWnd, UINT id)
5917{
5918    UINT index;
5919    // 引数チェック
5920    if (hWnd == NULL)
5921    {
5922        return INFINITE;
5923    }
5924
5925    index = LbGetSelectIndex(hWnd, id);
5926    if (index == INFINITE)
5927    {
5928        return INFINITE;
5929    }
5930
5931    return LbGetData(hWnd, id, index);
5932}
5933
5934// パスワード入力ダイアログ状態変化
5935void PasswordDlgProcChange(HWND hWnd, UI_PASSWORD_DLG *p)
5936{
5937    bool b;
5938    // 引数チェック
5939    if (hWnd == NULL || p == NULL)
5940    {
5941        return;
5942    }
5943
5944    b = true;
5945    if (IsEmpty(hWnd, E_USERNAME))
5946    {
5947        b = false;
5948    }
5949
5950    SetEnable(hWnd, IDOK, b);
5951
5952    p->StartTick = Tick64();
5953    if (p->RetryIntervalSec)
5954    {
5955        KillTimer(hWnd, 1);
5956        Hide(hWnd, P_PROGRESS);
5957        Hide(hWnd, S_COUNTDOWN);
5958    }
5959}
5960
5961// 文字列を取得
5962wchar_t *CbGetStr(HWND hWnd, UINT id)
5963{
5964    // 引数チェック
5965    if (hWnd == NULL)
5966    {
5967        return NULL;
5968    }
5969
5970    return GetText(hWnd, id);
5971}
5972
5973// 文字列検索
5974UINT CbFindStr(HWND hWnd, UINT id, wchar_t *str)
5975{
5976    UINT ret;
5977    if (MsIsNt() == false)
5978    {
5979        char *tmp = CopyUniToStr(str);
5980        ret = CbFindStr9xA(hWnd, id, tmp);
5981        Free(tmp);
5982        return ret;
5983    }
5984    // 引数チェック
5985    if (hWnd == NULL || str == NULL)
5986    {
5987        return INFINITE;
5988    }
5989
5990    ret = SendMsg(hWnd, id, CB_FINDSTRINGEXACT, -1, (LPARAM)str);
5991
5992    return ret;
5993}
5994UINT CbFindStr9xA(HWND hWnd, UINT id, char *str)
5995{
5996    UINT ret;
5997    // 引数チェック
5998    if (hWnd == NULL || str == NULL)
5999    {
6000        return INFINITE;
6001    }
6002
6003    ret = SendMsg(hWnd, id, CB_FINDSTRINGEXACT, -1, (LPARAM)str);
6004
6005    return ret;
6006}
6007
6008// 項目数を取得
6009UINT CbNum(HWND hWnd, UINT id)
6010{
6011    // 引数チェック
6012    if (hWnd == NULL)
6013    {
6014        return INFINITE;
6015    }
6016
6017    return SendMsg(hWnd, id, CB_GETCOUNT, 0, 0);
6018}
6019
6020// 文字列追加
6021UINT CbAddStrA(HWND hWnd, UINT id, char *str, UINT data)
6022{
6023    wchar_t *tmp;
6024    UINT ret;
6025    // 引く数チェック
6026    if (hWnd == NULL || str == NULL)
6027    {
6028        return INFINITE;
6029    }
6030    tmp = CopyStrToUni(str);
6031    ret = CbAddStr(hWnd, id, tmp, data);
6032    Free(tmp);
6033    return ret;
6034}
6035UINT CbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data)
6036{
6037    UINT ret;
6038    if (MsIsNt() == false)
6039    {
6040        char *s = CopyUniToStr(str);
6041        ret = CbAddStr9xA(hWnd, id, s, data);
6042        Free(s);
6043        return ret;
6044    }
6045    // 引数チェック
6046    if (hWnd == NULL || str == NULL)
6047    {
6048        return INFINITE;
6049    }
6050
6051    ret = SendMsg(hWnd, id, CB_ADDSTRING, 0, (LPARAM)str);
6052    SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
6053
6054    if (CbNum(hWnd, id) == 1)
6055    {
6056        wchar_t tmp[MAX_SIZE];
6057        GetTxt(hWnd, id, tmp, sizeof(tmp));
6058        if (UniStrLen(tmp) == 0)
6059        {
6060            CbSelectIndex(hWnd, id, 0);
6061        }
6062    }
6063
6064    return ret;
6065}
6066UINT CbAddStr9xA(HWND hWnd, UINT id, char *str, UINT data)
6067{
6068    UINT ret;
6069    // 引数チェック
6070    if (hWnd == NULL || str == NULL)
6071    {
6072        return INFINITE;
6073    }
6074
6075    ret = SendMsg(hWnd, id, CB_ADDSTRING, 0, (LPARAM)str);
6076    SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
6077
6078    if (CbNum(hWnd, id) == 1)
6079    {
6080        wchar_t tmp[MAX_SIZE];
6081        GetTxt(hWnd, id, tmp, sizeof(tmp));
6082        if (UniStrLen(tmp) == 0)
6083        {
6084            CbSelectIndex(hWnd, id, 0);
6085        }
6086    }
6087
6088    return ret;
6089}
6090
6091// 文字列挿入
6092UINT CbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
6093{
6094    wchar_t *tmp;
6095    UINT ret;
6096    // 引数チェック
6097    if (hWnd == NULL || str == NULL)
6098    {
6099        return INFINITE;
6100    }
6101    tmp = CopyStrToUni(str);
6102    ret = CbInsertStr(hWnd, id, index, tmp, data);
6103    Free(tmp);
6104    return ret;
6105}
6106UINT CbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data)
6107{
6108    UINT ret;
6109    // 引数チェック
6110    if (hWnd == NULL || str == NULL)
6111    {
6112        return INFINITE;
6113    }
6114
6115    if (MsIsNt() == false)
6116    {
6117        char *s = CopyUniToStr(str);
6118        ret = CbInsertStr9xA(hWnd, id, index, s, data);
6119        Free(s);
6120        return ret;
6121    }
6122
6123    ret = SendMsg(hWnd, id, CB_INSERTSTRING, index, (LPARAM)str);
6124    SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
6125
6126    if (CbNum(hWnd, id) == 1)
6127    {
6128        CbSelect(hWnd, id, 0);
6129    }
6130
6131    return ret;
6132}
6133UINT CbInsertStr9xA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
6134{
6135    UINT ret;
6136    // 引数チェック
6137    if (hWnd == NULL || str == NULL)
6138    {
6139        return INFINITE;
6140    }
6141
6142    ret = SendMsg(hWnd, id, CB_INSERTSTRING, index, (LPARAM)str);
6143    SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
6144
6145    if (CbNum(hWnd, id) == 1)
6146    {
6147        CbSelect(hWnd, id, 0);
6148    }
6149
6150    return ret;
6151}
6152
6153// すべて削除
6154void CbReset(HWND hWnd, UINT id)
6155{
6156    wchar_t *s;
6157    // 引数チェック
6158    if (hWnd == NULL)
6159    {
6160        return;
6161    }
6162
6163    s = GetText(hWnd, id);
6164
6165    SendMsg(hWnd, id, CB_RESETCONTENT, 0, 0);
6166
6167    if (s != NULL)
6168    {
6169        SetText(hWnd, id, s);
6170        Free(s);
6171    }
6172}
6173
6174// インデックスを指定して選択
6175void CbSelectIndex(HWND hWnd, UINT id, UINT index)
6176{
6177    // 引数チェック
6178    if (hWnd == NULL)
6179    {
6180        return;
6181    }
6182
6183    SendMsg(hWnd, id, CB_SETCURSEL, index, 0);
6184}
6185
6186// データを取得
6187UINT CbGetData(HWND hWnd, UINT id, UINT index)
6188{
6189    // 引数チェック
6190    if (hWnd == NULL || index == INFINITE)
6191    {
6192        return INFINITE;
6193    }
6194
6195    return SendMsg(hWnd, id, CB_GETITEMDATA, index, 0);
6196}
6197
6198// データを検索
6199UINT CbFindData(HWND hWnd, UINT id, UINT data)
6200{
6201    UINT i, num;
6202    // 引数チェック
6203    if (hWnd == NULL)
6204    {
6205        return INFINITE;
6206    }
6207
6208    num = CbNum(hWnd, id);
6209    if (num == INFINITE)
6210    {
6211        return INFINITE;
6212    }
6213
6214    for (i = 0;i < num;i++)
6215    {
6216        if (CbGetData(hWnd, id, i) == data)
6217        {
6218            return i;
6219        }
6220    }
6221
6222    return INFINITE;
6223}
6224
6225// アイテムの高さを設定
6226void CbSetHeight(HWND hWnd, UINT id, UINT value)
6227{
6228    // 引数チェック
6229    if (hWnd == NULL)
6230    {
6231        return;
6232    }
6233
6234    SendMsg(hWnd, id, CB_SETITEMHEIGHT, 0, value);
6235}
6236
6237// データを指定して検索
6238void CbSelect(HWND hWnd, UINT id, int data)
6239{
6240    UINT index;
6241    // 引数チェック
6242    if (hWnd == NULL)
6243    {
6244        return;
6245    }
6246
6247    if (data == INFINITE)
6248    {
6249        // 最初の項目を取得
6250        CbSelectIndex(hWnd, id, 0);
6251        return;
6252    }
6253
6254    index = CbFindData(hWnd, id, data);
6255    if (index == INFINITE)
6256    {
6257        // 発見できなかった
6258        return;
6259    }
6260
6261    // 選択する
6262    CbSelectIndex(hWnd, id, index);
6263}
6264
6265// 現在選択されている項目を取得
6266UINT CbGetSelectIndex(HWND hWnd, UINT id)
6267{
6268    // 引数チェック
6269    if (hWnd == NULL)
6270    {
6271        return INFINITE;
6272    }
6273
6274    return SendMsg(hWnd, id, CB_GETCURSEL, 0, 0);
6275}
6276
6277// 現在選択されている値を取得
6278UINT CbGetSelect(HWND hWnd, UINT id)
6279{
6280    UINT index;
6281    // 引数チェック
6282    if (hWnd == NULL)
6283    {
6284        return INFINITE;
6285    }
6286
6287    index = CbGetSelectIndex(hWnd, id);
6288    if (index == INFINITE)
6289    {
6290        return INFINITE;
6291    }
6292
6293    return CbGetData(hWnd, id, index);
6294}
6295
6296// OK ボタンが押された
6297void PasswordDlgOnOk(HWND hWnd, UI_PASSWORD_DLG *p)
6298{
6299    // 引数チェック
6300    if (hWnd == NULL || p == NULL)
6301    {
6302        return;
6303    }
6304
6305    GetTxtA(hWnd, E_USERNAME, p->Username, sizeof(p->Username));
6306    GetTxtA(hWnd, E_PASSWORD, p->Password, sizeof(p->Password));
6307    p->Type = CbGetSelect(hWnd, C_TYPE);
6308
6309    if (p->ShowNoSavePassword)
6310    {
6311        p->NoSavePassword = IsChecked(hWnd, R_NO_SAVE_PASSWORD);
6312    }
6313
6314    EndDialog(hWnd, true);
6315}
6316
6317// パスワード入力ダイアログプロシージャ
6318UINT PasswordDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
6319{
6320    UI_PASSWORD_DLG *p = (UI_PASSWORD_DLG *)param;
6321    // 引数チェック
6322    if (hWnd == NULL)
6323    {
6324        return 0;
6325    }
6326
6327    switch (msg)
6328    {
6329    case WM_INITDIALOG:
6330        SetIcon(hWnd, 0, ICO_KEY);
6331        CbSetHeight(hWnd, C_TYPE, 18);
6332        if (p->ServerName != NULL)
6333        {
6334            FormatText(hWnd, 0, p->ServerName);
6335        }
6336        else
6337        {
6338            SetText(hWnd, 0, _UU("PW_LOGIN_DLG_TITLE"));
6339        }
6340
6341        if (p->ProxyServer == false)
6342        {
6343            FormatText(hWnd, S_TITLE, p->ServerName == NULL ? "" : p->ServerName);
6344        }
6345        else
6346        {
6347            wchar_t tmp[MAX_SIZE];
6348            UniFormat(tmp, sizeof(tmp), _UU("PW_MSG_PROXY"), p->ServerName == NULL ? "" : p->ServerName);
6349            SetText(hWnd, S_TITLE, tmp);
6350        }
6351
6352        // 接続方法の列挙
6353        SendMsg(hWnd, C_TYPE, CBEM_SETUNICODEFORMAT, true, 0);
6354
6355        if (StrCmpi(p->Username, WINUI_PASSWORD_NULL_USERNAME) != 0)
6356        {
6357            SetTextA(hWnd, E_USERNAME, p->Username);
6358            SetTextA(hWnd, E_PASSWORD, p->Password);
6359        }
6360        else
6361        {
6362            p->RetryIntervalSec = 0;
6363            SetTextA(hWnd, E_USERNAME, "");
6364            SetTextA(hWnd, E_PASSWORD, "");
6365        }
6366
6367        if (p->AdminMode == false)
6368        {
6369            if (p->ProxyServer == false)
6370            {
6371                CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_1"), CLIENT_AUTHTYPE_PASSWORD);
6372                CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_2"), CLIENT_AUTHTYPE_PLAIN_PASSWORD);
6373            }
6374            else
6375            {
6376                CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_PROXY"), 0);
6377                Disable(hWnd, C_TYPE);
6378            }
6379
6380            CbSelect(hWnd, C_TYPE, p->Type);
6381        }
6382        else
6383        {
6384            CbAddStr(hWnd, C_TYPE, _UU("SM_PASSWORD_TYPE_STR"), 0);
6385            Disable(hWnd, C_TYPE);
6386            SetTextA(hWnd, E_USERNAME, "Administrator");
6387            Disable(hWnd, E_USERNAME);
6388        }
6389
6390        if (IsEmpty(hWnd, E_USERNAME))
6391        {
6392            FocusEx(hWnd, E_USERNAME);
6393        }
6394        else
6395        {
6396            FocusEx(hWnd, E_PASSWORD);
6397        }
6398        LimitText(hWnd, E_USERNAME, MAX_USERNAME_LEN);
6399        LimitText(hWnd, E_PASSWORD, MAX_PASSWORD_LEN);
6400
6401        PasswordDlgProcChange(hWnd, p);
6402
6403        if (p->RetryIntervalSec != 0)
6404        {
6405            SetTimer(hWnd, 1, 50, NULL);
6406            FormatText(hWnd, S_COUNTDOWN, p->RetryIntervalSec);
6407            Show(hWnd, S_COUNTDOWN);
6408            Show(hWnd, P_PROGRESS);
6409            SetRange(hWnd, P_PROGRESS, 0, p->RetryIntervalSec * 1000);
6410        }
6411        else
6412        {
6413            Hide(hWnd, S_COUNTDOWN);
6414            Hide(hWnd, P_PROGRESS);
6415        }
6416
6417        if (p->ShowNoSavePassword)
6418        {
6419            Show(hWnd, R_NO_SAVE_PASSWORD);
6420            Check(hWnd, R_NO_SAVE_PASSWORD, p->NoSavePassword);
6421        }
6422        else
6423        {
6424            Hide(hWnd, R_NO_SAVE_PASSWORD);
6425        }
6426
6427        p->StartTick = Tick64();
6428
6429        if (p->CancelEvent != NULL)
6430        {
6431            SetTimer(hWnd, 2, 50, NULL);
6432        }
6433
6434        break;
6435
6436    case WM_CLOSE:
6437        EndDialog(hWnd, false);
6438        break;
6439
6440    case WM_TIMER:
6441        switch (wParam)
6442        {
6443        case 1:
6444            if (p->RetryIntervalSec != 0)
6445            {
6446                wchar_t tmp[MAX_SIZE];
6447                UINT64 end, now, start;
6448                start = p->StartTick;
6449                end = p->StartTick + (UINT64)(p->RetryIntervalSec * 1000);
6450                now = Tick64();
6451
6452                if (now <= end)
6453                {
6454                    UniFormat(tmp, sizeof(tmp), _UU("PW_RETRYCOUNT"), (UINT)((end - now) / 1000));
6455                    SetText(hWnd, S_COUNTDOWN, tmp);
6456                    SetPos(hWnd, P_PROGRESS, (UINT)(now - start));
6457                }
6458                else
6459                {
6460                    EndDialog(hWnd, true);
6461                }
6462            }
6463            break;
6464
6465        case 2:
6466            if (p->CancelEvent != NULL)
6467            {
6468                // 終了イベントを待機する
6469                HANDLE hEvent = (HANDLE)p->CancelEvent->pData;
6470                UINT ret = WaitForSingleObject(hEvent, 0);
6471                if (ret != WAIT_TIMEOUT)
6472                {
6473                    // 強制終了イベントがセットされた
6474                    Close(hWnd);
6475                }
6476            }
6477            break;
6478        }
6479        break;
6480
6481    case WM_COMMAND:
6482        switch (wParam)
6483        {
6484        case IDOK:
6485            PasswordDlgOnOk(hWnd, p);
6486            break;
6487        case IDCANCEL:
6488            Close(hWnd);
6489            break;
6490        }
6491        switch (HIWORD(wParam))
6492        {
6493        case EN_CHANGE:
6494            switch (LOWORD(wParam))
6495            {
6496            case E_USERNAME:
6497            case E_PASSWORD:
6498                PasswordDlgProcChange(hWnd, p);
6499                break;
6500            }
6501            break;
6502        case CBN_SELCHANGE:
6503            switch (LOWORD(wParam))
6504            {
6505            case C_TYPE:
6506                PasswordDlgProcChange(hWnd, p);
6507                if (IsEmpty(hWnd, E_USERNAME))
6508                {
6509                    FocusEx(hWnd, E_USERNAME);
6510                }
6511                else
6512                {
6513                    FocusEx(hWnd, E_PASSWORD);
6514                }
6515                break;
6516            }
6517            break;
6518        }
6519        break;
6520    }
6521
6522    return 0;
6523}
6524
6525// プログレスバーの位置を設定
6526void SetPos(HWND hWnd, UINT id, UINT pos)
6527{
6528    // 引数チェック
6529    if (hWnd == NULL)
6530    {
6531        return;
6532    }
6533
6534    SendMsg(hWnd, id, PBM_SETPOS, pos, 0);
6535}
6536
6537// プログレスバーの範囲を設定
6538void SetRange(HWND hWnd, UINT id, UINT start, UINT end)
6539{
6540    // 引数チェック
6541    if (hWnd == NULL)
6542    {
6543        return;
6544    }
6545
6546    SendMsg(hWnd, id, PBM_SETRANGE32, start, end);
6547}
6548
6549// パスワード入力ダイアログ
6550bool PasswordDlg(HWND hWnd, UI_PASSWORD_DLG *p)
6551{
6552    // 引数チェック
6553    if (p == NULL)
6554    {
6555        return false;
6556    }
6557
6558    p->StartTick = Tick64();
6559
6560    return Dialog(hWnd, D_PASSWORD, PasswordDlgProc, p);
6561}
6562
6563// パスフレーズ入力ダイアログ
6564bool PassphraseDlg(HWND hWnd, char *pass, UINT pass_size, BUF *buf, bool p12)
6565{
6566    PASSPHRASE_DLG p;
6567    // 引数チェック
6568    if (pass == NULL || buf == NULL)
6569    {
6570        return false;
6571    }
6572
6573    Zero(&p, sizeof(PASSPHRASE_DLG));
6574
6575    p.buf = buf;
6576    p.p12 = p12;
6577
6578    // まず暗号化されているかどうかを調べる
6579    if (p12 == false)
6580    {
6581        // 秘密鍵
6582        if (IsEncryptedK(buf, true) == false)
6583        {
6584            // 暗号化されていない
6585            StrCpy(pass, pass_size, "");
6586            return true;
6587        }
6588    }
6589    else
6590    {
6591        // PKCS#12
6592        P12 *p12 = BufToP12(buf);
6593        if (p12 == NULL)
6594        {
6595            // 不明な形式だが暗号化されていない
6596            StrCpy(pass, pass_size, "");
6597            return true;
6598        }
6599
6600        if (IsEncryptedP12(p12) == false)
6601        {
6602            // 暗号化されていない
6603            StrCpy(pass, pass_size, "");
6604            FreeP12(p12);
6605            return true;
6606        }
6607        FreeP12(p12);
6608    }
6609
6610    // ダイアログ表示
6611    if (Dialog(hWnd, D_PASSPHRASE, PassphraseDlgProc, &p) == false)
6612    {
6613        // キャンセル
6614        return false;
6615    }
6616
6617    StrCpy(pass, pass_size, p.pass);
6618
6619    return true;
6620}
6621
6622// WM_COMMAND ハンドラ
6623void PassphraseDlgProcCommand(HWND hWnd, PASSPHRASE_DLG *p)
6624{
6625    char *pass;
6626    bool ok;
6627    // 引数チェック
6628    if (hWnd == NULL || p == NULL)
6629    {
6630        return;
6631    }
6632
6633    pass = GetTextA(hWnd, E_PASSPHRASE);
6634    if (pass == NULL)
6635    {
6636        return;
6637    }
6638
6639    ok = false;
6640
6641    if (p->p12 == false)
6642    {
6643        K *k;
6644        k = BufToK(p->buf, true, true, pass);
6645        if (k != NULL)
6646        {
6647            ok = true;
6648            FreeK(k);
6649        }
6650    }
6651    else
6652    {
6653        X *x;
6654        K *k;
6655        P12 *p12;
6656        p12 = BufToP12(p->buf);
6657        if (p12 != NULL)
6658        {
6659            if (ParseP12(p12, &x, &k, pass))
6660            {
6661                FreeX(x);
6662                FreeK(k);
6663                ok = true;
6664            }
6665            FreeP12(p12);
6666        }
6667    }
6668
6669    Free(pass);
6670
6671    SetEnable(hWnd, IDOK, ok);
6672}
6673
6674// パスフレーズ入力ダイアログプロシージャ
6675UINT PassphraseDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
6676{
6677    PASSPHRASE_DLG *p = (PASSPHRASE_DLG *)param;
6678    // 引数チェック
6679    if (hWnd == NULL)
6680    {
6681        return 0;
6682    }
6683
6684    switch (msg)
6685    {
6686    case WM_INITDIALOG:
6687        PassphraseDlgProcCommand(hWnd, p);
6688        break;
6689
6690    case WM_COMMAND:
6691        switch (wParam)
6692        {
6693        case IDOK:
6694            GetTxtA(hWnd, E_PASSPHRASE, p->pass, sizeof(p->pass));
6695            EndDialog(hWnd, true);
6696            break;
6697
6698        case IDCANCEL:
6699            Close(hWnd);
6700            break;
6701        }
6702
6703        switch (LOWORD(wParam))
6704        {
6705        case E_PASSPHRASE:
6706            PassphraseDlgProcCommand(hWnd, p);
6707            break;
6708        }
6709        break;
6710
6711    case WM_CLOSE:
6712        EndDialog(hWnd, false);
6713        break;
6714    }
6715
6716    return 0;
6717}
6718
6719// PKCS ユーティリティ
6720void PkcsUtil()
6721{
6722    InitWinUi(_UU("PKCS_UTIL_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
6723    Dialog(NULL, D_PKCSUTIL, PkcsUtilProc, NULL);
6724    FreeWinUi();
6725}
6726
6727// PKCS 書き込み
6728void PkcsUtilWrite(HWND hWnd)
6729{
6730    wchar_t *filename;
6731    BUF *in_buf;
6732    char filename_ansi[MAX_SIZE];
6733    char pass[MAX_SIZE];
6734    // 引数チェック
6735    if (hWnd == NULL)
6736    {
6737        return;
6738    }
6739
6740    filename = OpenDlg(hWnd, _UU("DLG_PKCS12_FILTER"), _UU("PKCS_UTIL_SAVEDLG_TITLE"));
6741    if (filename == NULL)
6742    {
6743        return;
6744    }
6745
6746    UniToStr(filename_ansi, sizeof(filename_ansi), filename);
6747
6748    in_buf = ReadDump(filename_ansi);
6749
6750    if (in_buf == NULL)
6751    {
6752        MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("PKCS_UTIL_READ_ERROR"), filename);
6753    }
6754    else
6755    {
6756        if (PassphraseDlg(hWnd, pass, sizeof(pass), in_buf, true))
6757        {
6758            P12 *p12 = BufToP12(in_buf);
6759            if (p12 == NULL)
6760            {
6761                MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("PKCS_UTIL_BAD_FILE"));
6762            }
6763            else
6764            {
6765                X *x = NULL;
6766                K *k = NULL;
6767                BUF *b;
6768                ParseP12(p12, &x, &k, pass);
6769                FreeP12(p12);
6770                p12 = NewP12(x, k, NULL);
6771                FreeX(x);
6772                FreeK(k);
6773                b = P12ToBuf(p12);
6774                FreeP12(p12);
6775                if (b != NULL)
6776                {
6777                    // バッチ処理
6778                    WINUI_SECURE_BATCH batch[] =
6779                    {
6780                        {WINUI_SECURE_WRITE_DATA, _SS("PKCS_UTIL_SECA_FILENAME"), false,
6781                            b, NULL, NULL, NULL, NULL, NULL},
6782                    };
6783
6784                    if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), 2, 0))
6785                    {
6786                        MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("PKCS_UTIL_WRITE_OK_MSG"), filename);
6787                    }
6788                }
6789                FreeBuf(b);
6790            }
6791        }
6792
6793        FreeBuf(in_buf);
6794    }
6795
6796    Free(filename);
6797}
6798
6799// PKCS 消去
6800void PkcsUtilErase(HWND hWnd)
6801{
6802    // 引数チェック
6803    if (hWnd == NULL)
6804    {
6805        return;
6806    }
6807
6808    if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
6809        _UU("PKCS_MAKE_SURE")) == IDYES)
6810    {
6811        // バッチ処理
6812        WINUI_SECURE_BATCH batch[] =
6813        {
6814            {WINUI_SECURE_DELETE_OBJECT, _SS("PKCS_UTIL_SECA_FILENAME"), false,
6815                NULL, NULL, NULL, NULL, NULL, NULL},
6816        };
6817
6818        if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), 2, 0))
6819        {
6820            MsgBox(hWnd, MB_ICONINFORMATION, _UU("PKCS_UTIL_DELETE_OK_MSG"));
6821        }
6822    }
6823}
6824
6825// PKCS ユーティリティ ダイアログ
6826UINT PkcsUtilProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
6827{
6828    // 引数チェック
6829    if (hWnd == NULL)
6830    {
6831        return 0;
6832    }
6833
6834    switch (msg)
6835    {
6836    case WM_INITDIALOG:
6837        DlgFont(hWnd, S_TITLE, 12, true);
6838        SetIcon(hWnd, 0, ICO_CERT);
6839        SetFont(hWnd, S_COPYRIGHT, GetFont("Arial", 8, false, false, false, false));
6840        break;
6841
6842    case WM_COMMAND:
6843        switch (wParam)
6844        {
6845        case B_WRITE:
6846            PkcsUtilWrite(hWnd);
6847            break;
6848
6849        case B_ERASE:
6850            PkcsUtilErase(hWnd);
6851            break;
6852
6853        case IDCANCEL:
6854            Close(hWnd);
6855            break;
6856        }
6857
6858        break;
6859
6860    case WM_CLOSE:
6861        EndDialog(hWnd, 0);
6862        break;
6863    }
6864
6865    return 0;
6866}
6867
6868// [ファイルを保存する] ダイアログ
6869wchar_t *SaveDlg(HWND hWnd, wchar_t *filter, wchar_t *title, wchar_t *default_name, wchar_t *default_ext)
6870{
6871    wchar_t *filter_str;
6872    wchar_t tmp[MAX_SIZE];
6873    OPENFILENAMEW o;
6874
6875    if (MsIsNt() == false)
6876    {
6877        char *ret, *s1, *s2, *s3, *s4;
6878        wchar_t *wr;
6879        s1 = CopyUniToStr(filter);
6880        s2 = CopyUniToStr(title);
6881        s3 = CopyUniToStr(default_name);
6882        s4 = CopyUniToStr(default_ext);
6883        ret = SaveDlgA(hWnd, s1, s2, s3, s4);
6884        Free(s1);
6885        Free(s2);
6886        Free(s3);
6887        Free(s4);
6888        wr = CopyStrToUni(ret);
6889        Free(ret);
6890        return wr;
6891    }
6892
6893    // 引数チェック
6894    if (filter == NULL)
6895    {
6896        filter = _UU("DLG_ALL_FILES");
6897    }
6898
6899    filter_str = MakeFilter(filter);
6900
6901    Zero(&o, sizeof(o));
6902    Zero(tmp, sizeof(tmp));
6903
6904    if (default_name != NULL)
6905    {
6906        UniStrCpy(tmp, sizeof(tmp), default_name);
6907    }
6908
6909    o.lStructSize = sizeof(o);
6910   
6911    if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
6912    {
6913        o.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
6914    }
6915
6916    o.hwndOwner = hWnd;
6917    o.hInstance = GetModuleHandleA(NULL);
6918    o.lpstrFile = tmp;
6919    o.lpstrTitle = title;
6920    o.lpstrFilter = filter_str;
6921    o.nMaxFile = sizeof(tmp);
6922    o.Flags = OFN_OVERWRITEPROMPT;
6923    o.lpstrDefExt = default_ext;
6924
6925    if (GetSaveFileNameW(&o) == false)
6926    {
6927        Free(filter_str);
6928        return NULL;
6929    }
6930
6931    Free(filter_str);
6932
6933    return UniCopyStr(tmp);
6934}
6935char *SaveDlgA(HWND hWnd, char *filter, char *title, char *default_name, char *default_ext)
6936{
6937    char *filter_str;
6938    char tmp[MAX_SIZE];
6939    OPENFILENAME o;
6940    // 引数チェック
6941    if (filter == NULL)
6942    {
6943        filter = _SS("DLG_ALL_FILES");
6944    }
6945
6946    filter_str = MakeFilterA(filter);
6947
6948    Zero(&o, sizeof(o));
6949    Zero(tmp, sizeof(tmp));
6950
6951    if (default_name != NULL)
6952    {
6953        StrCpy(tmp, sizeof(tmp), default_name);
6954    }
6955
6956    o.lStructSize = sizeof(o);
6957   
6958    if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
6959    {
6960        o.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
6961    }
6962
6963    o.hwndOwner = hWnd;
6964    o.hInstance = GetModuleHandleA(NULL);
6965    o.lpstrFile = tmp;
6966    o.lpstrTitle = title;
6967    o.lpstrFilter = filter_str;
6968    o.nMaxFile = sizeof(tmp);
6969    o.Flags = OFN_OVERWRITEPROMPT;
6970    o.lpstrDefExt = default_ext;
6971
6972    if (GetSaveFileName(&o) == false)
6973    {
6974        Free(filter_str);
6975        return NULL;
6976    }
6977
6978    Free(filter_str);
6979
6980    return CopyStr(tmp);
6981}
6982
6983// [ファイルを開く] ダイアログ
6984wchar_t *OpenDlg(HWND hWnd, wchar_t *filter, wchar_t *title)
6985{
6986    wchar_t *filter_str;
6987    wchar_t tmp[MAX_SIZE];
6988    OPENFILENAMEW o;
6989
6990    if (MsIsNt() == false)
6991    {
6992        char *ret;
6993        char *filter_a;
6994        char *title_a;
6995        wchar_t *w;
6996        filter_a = CopyUniToStr(filter);
6997        title_a = CopyUniToStr(title);
6998        ret = OpenDlgA(hWnd, filter_a, title_a);
6999        Free(filter_a);
7000        Free(title_a);
7001        w = CopyStrToUni(ret);
7002        Free(ret);
7003        return w;
7004    }
7005
7006    // 引数チェック
7007    if (filter == NULL)
7008    {
7009        filter = _UU("DLG_ALL_FILES");
7010    }
7011
7012    filter_str = MakeFilter(filter);
7013
7014    Zero(&o, sizeof(OPENFILENAMEW));
7015    Zero(tmp, sizeof(tmp));
7016
7017    o.lStructSize = sizeof(o);
7018
7019
7020    if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
7021    {
7022        o.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
7023    }
7024
7025
7026    o.hwndOwner = hWnd;
7027    o.hInstance = GetModuleHandleA(NULL);
7028    o.lpstrFilter = filter_str;
7029    o.lpstrFile = tmp;
7030    o.nMaxFile = sizeof(tmp);
7031    o.lpstrTitle = title;
7032    o.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
7033
7034    if (GetOpenFileNameW(&o) == false)
7035    {
7036        Free(filter_str);
7037        return NULL;
7038    }
7039
7040    Free(filter_str);
7041
7042    return UniCopyStr(tmp);
7043}
7044char *OpenDlgA(HWND hWnd, char *filter, char *title)
7045{
7046    char *filter_str;
7047    char tmp[MAX_SIZE];
7048    OPENFILENAME o;
7049    // 引数チェック
7050    if (filter == NULL)
7051    {
7052        filter = _SS("DLG_ALL_FILES");
7053    }
7054
7055    filter_str = MakeFilterA(filter);
7056
7057    Zero(&o, sizeof(OPENFILENAME));
7058    Zero(tmp, sizeof(tmp));
7059
7060    o.lStructSize = sizeof(o);
7061
7062    if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
7063    {
7064        o.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
7065    }
7066
7067    o.hwndOwner = hWnd;
7068    o.hInstance = GetModuleHandleA(NULL);
7069    o.lpstrFilter = filter_str;
7070    o.lpstrFile = tmp;
7071    o.nMaxFile = sizeof(tmp);
7072    o.lpstrTitle = title;
7073    o.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
7074
7075    if (GetOpenFileName(&o) == false)
7076    {
7077        Free(filter_str);
7078        return NULL;
7079    }
7080
7081    Free(filter_str);
7082
7083    return CopyStr(tmp);
7084}
7085
7086// フィルタ文字列の生成
7087wchar_t *MakeFilter(wchar_t *str)
7088{
7089    UINT i;
7090    wchar_t *ret;
7091    // 引数チェック
7092    if (str == NULL)
7093    {
7094        return NULL;
7095    }
7096
7097    ret = ZeroMalloc(UniStrSize(str) + 32);
7098
7099    for (i = 0;i < UniStrLen(str);i++)
7100    {
7101        if (str[i] == L'|')
7102        {
7103            ret[i] = L'\0';
7104        }
7105        else
7106        {
7107            ret[i] = str[i];
7108        }
7109    }
7110
7111    return ret;
7112}
7113char *MakeFilterA(char *str)
7114{
7115    UINT i;
7116    char *ret;
7117    // 引数チェック
7118    if (str == NULL)
7119    {
7120        return NULL;
7121    }
7122
7123    ret = ZeroMalloc(StrSize(str) + 32);
7124
7125    for (i = 0;i < StrLen(str);i++)
7126    {
7127        if (str[i] == '|')
7128        {
7129            ret[i] = '\0';
7130        }
7131        else
7132        {
7133            ret[i] = str[i];
7134        }
7135    }
7136
7137    return ret;
7138}
7139
7140// バッチの実行
7141bool ExecuteSecureDeviceBatch(HWND hWnd, SECURE *sec, SECURE_DEVICE_THREAD *p, SECURE_DEVICE *dev, WINUI_SECURE_BATCH *batch)
7142{
7143    LIST *o;
7144    void *buf;
7145    UINT size = 10 * 1024;      // データの最大サイズ
7146    UINT type = INFINITE;
7147    // 引数チェック
7148    if (hWnd == NULL || p == NULL || dev == NULL || batch == NULL || sec == NULL)
7149    {
7150        return false;
7151    }
7152
7153    switch (batch->Type)
7154    {
7155    case WINUI_SECURE_DELETE_CERT:
7156        type = SEC_X;
7157        goto DELETE_OBJECT;
7158
7159    case WINUI_SECURE_DELETE_KEY:
7160        type = SEC_K;
7161        goto DELETE_OBJECT;
7162
7163    case WINUI_SECURE_DELETE_DATA:
7164        type = SEC_DATA;
7165        goto DELETE_OBJECT;
7166
7167    case WINUI_SECURE_DELETE_OBJECT:
7168        // オブジェクトの削除
7169DELETE_OBJECT:
7170        SetText(hWnd, S_STATUS, _UU("SEC_DELETE"));
7171        if (DeleteSecObjectByName(sec, batch->Name, type) == false)
7172        {
7173            p->ErrorMessage = UniCopyStr(_UU("SEC_ERROR_DELETE"));
7174            return false;
7175        }
7176        break;
7177
7178    case WINUI_SECURE_ENUM_OBJECTS:
7179        // オブジェクトの列挙
7180        SetText(hWnd, S_STATUS, _UU("SEC_ENUM"));
7181        o = EnumSecObject(sec);
7182        if (o == NULL)
7183        {
7184            p->ErrorMessage = UniCopyStr(_UU("SEC_ERROR_ENUM"));
7185            return false;
7186        }
7187
7188        batch->EnumList = o;
7189        break;
7190
7191    case WINUI_SECURE_WRITE_DATA:
7192        // データの書き込み
7193        SetText(hWnd, S_STATUS, _UU("SEC_WRITE_DATA"));
7194        if (WriteSecData(sec, batch->Private, batch->Name, batch->InputData->Buf, batch->InputData->Size) == false)
7195        {
7196            p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
7197                _UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
7198            return false;
7199        }
7200        break;
7201
7202    case WINUI_SECURE_READ_DATA:
7203        // データの読み込み
7204        SetText(hWnd, S_STATUS, _UU("SEC_READ_DATA"));
7205        buf = MallocEx(size, true);
7206        size = ReadSecData(sec, batch->Name, buf, size);
7207        if (size == 0)
7208        {
7209            Free(buf);
7210            p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
7211                _UU("SEC_ERROR_NOT_FOUND_1") : _UU("SEC_ERROR_NOT_FOUND_2"));
7212            return false;
7213        }
7214        batch->OutputData = NewBuf();
7215        WriteBuf(batch->OutputData, buf, size);
7216        SeekBuf(batch->OutputData, 0, 0);
7217        Free(buf);
7218        break;
7219
7220    case WINUI_SECURE_WRITE_CERT:
7221        // 証明書の書き込み
7222        SetText(hWnd, S_STATUS, _UU("SEC_WRITE_CERT"));
7223        if (WriteSecCert(sec, batch->Private, batch->Name, batch->InputX) == false)
7224        {
7225            p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
7226                _UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
7227            return false;
7228        }
7229        break;
7230
7231    case WINUI_SECURE_READ_CERT:
7232        // 証明書の読み込み
7233        SetText(hWnd, S_STATUS, _UU("SEC_READ_CERT"));
7234        batch->OutputX = ReadSecCert(sec, batch->Name);
7235        if (batch->OutputX == NULL)
7236        {
7237            p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
7238                _UU("SEC_ERROR_NOT_FOUND_1") : _UU("SEC_ERROR_NOT_FOUND_2"));
7239            return false;
7240        }
7241        break;
7242
7243    case WINUI_SECURE_WRITE_KEY:
7244        // 秘密鍵の書き込み
7245        SetText(hWnd, S_STATUS, _UU("SEC_WRITE_KEY"));
7246        if (WriteSecKey(sec, batch->Private, batch->Name, batch->InputK) == false)
7247        {
7248            p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
7249                _UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
7250            return false;
7251        }
7252        break;
7253
7254    case WINUI_SECURE_SIGN_WITH_KEY:
7255        // 署名
7256        SetText(hWnd, S_STATUS, _UU("SEC_SIGN"));
7257        if (SignSec(sec, batch->Name, batch->OutputSign, batch->InputData->Buf, batch->InputData->Size) == false)
7258        {
7259            p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
7260                _UU("SEC_ERROR_SIGN_1") : _UU("SEC_ERROR_SIGN_2"));
7261            return false;
7262        }
7263        break;
7264    }
7265
7266    return true;
7267}
7268
7269// セキュアデバイス操作をバッチ処理で実行する
7270void SecureDeviceBatch(HWND hWnd, SECURE *sec, SECURE_DEVICE_THREAD *p, SECURE_DEVICE *dev)
7271{
7272    UINT i;
7273    // 引数チェック
7274    if (hWnd == NULL || p == NULL || dev == NULL || sec == NULL)
7275    {
7276        return;
7277    }
7278
7279    // 逐次処理を行う
7280    for (i = 0;i < p->w->num_batch;i++)
7281    {
7282        WINUI_SECURE_BATCH *batch = &p->w->batch[i];
7283
7284        if (ExecuteSecureDeviceBatch(hWnd, sec, p, dev, batch) == false)
7285        {
7286            // 1 つでも失敗したら直ちに中断する
7287            return;
7288        }
7289    }
7290
7291    // すべてのバッチ処理が成功した
7292    p->Succeed = true;
7293}
7294
7295// セキュアデバイス操作を行うスレッド
7296void SecureDeviceThread(THREAD *t, void *param)
7297{
7298    SECURE *sec;
7299    SECURE_DEVICE_THREAD *p = (SECURE_DEVICE_THREAD *)param;
7300    SECURE_DEVICE *dev;
7301    HWND hWnd;
7302    // 引数チェック
7303    if (t == NULL || param == NULL)
7304    {
7305        return;
7306    }
7307
7308    p->Succeed = false;
7309    p->ErrorMessage = NULL;
7310
7311    hWnd = p->hWnd;
7312
7313    // デバイスを開く
7314    dev = GetSecureDevice(p->w->device_id);
7315    SetText(hWnd, S_STATUS, _UU("SEC_OPENING"));
7316    sec = OpenSec(p->w->device_id);
7317    if (sec == NULL)
7318    {
7319        // デバイスオープン失敗
7320        if (p->w->device_id != 9)
7321        {
7322            p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_DEVICE"), dev->DeviceName);
7323        }
7324        else
7325        {
7326            p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_DEVICEEX"), dev->DeviceName);
7327        }
7328    }
7329    else
7330    {
7331        // セッションを開く
7332        SetText(hWnd, S_STATUS, _UU("SEC_OPEN_SESSION"));
7333        if (OpenSecSession(sec, 0) == false)
7334        {
7335            // セッション初期化失敗
7336            p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_SESSION"), dev->DeviceName);
7337        }
7338        else
7339        {
7340            // ログイン
7341            SetText(hWnd, S_STATUS, _UU("SEC_LOGIN"));
7342            if (LoginSec(sec, p->pin) == false)
7343            {
7344                // ログイン失敗
7345                p->ErrorMessage =UniCopyStr(_UU("SEC_ERROR_LOGIN"));
7346            }
7347            else
7348            {
7349                // バッチ処理メイン
7350                SetText(hWnd, S_STATUS, _UU("SEC_INIT_BATCH"));
7351                SecureDeviceBatch(hWnd, sec, p, dev);
7352
7353                // ログアウト
7354                SetText(hWnd, S_STATUS, _UU("SEC_LOGOUT"));
7355                LogoutSec(sec);
7356            }
7357
7358            // セッションを閉じる
7359            SetText(hWnd, S_STATUS, _UU("SEC_CLOSE_SESSION"));
7360            CloseSecSession(sec);
7361        }
7362
7363        // デバイスを閉じる
7364        SetText(hWnd, S_STATUS, _UU("SEC_CLOSING"));
7365        CloseSec(sec);
7366    }
7367
7368    if (p->Succeed)
7369    {
7370        // 成功した場合は 150ms メッセージを表示する (サービス)
7371        SetText(hWnd, S_STATUS, _UU("SEC_FINISHED"));
7372        SleepThread(150);
7373    }
7374
7375    SendMessage(p->hWnd, WM_APP + 1, 0, 0);
7376}
7377
7378// セキュアデバイス操作を開始する
7379void StartSecureDevice(HWND hWnd, SECURE_DEVICE_WINDOW *w)
7380{
7381    SECURE_DEVICE_THREAD *p;
7382    // 引数チェック
7383    if (hWnd == NULL || w == NULL)
7384    {
7385        return;
7386    }
7387
7388    // コントロールを無効にする
7389    EnableSecureDeviceWindowControls(hWnd, false);
7390
7391    // スレッドを開始する
7392    p = ZeroMalloc(sizeof(SECURE_DEVICE_THREAD));
7393    p->w = w;
7394    p->hWnd = hWnd;
7395    w->p = p;
7396    p->pin = GetTextA(hWnd, E_PIN);
7397    ReleaseThread(NewThread(SecureDeviceThread, p));
7398}
7399
7400// セキュアデバイス操作用ウインドウのコントロールを有効・無効化する
7401void EnableSecureDeviceWindowControls(HWND hWnd, bool enable)
7402{
7403    // 引数チェック
7404    if (hWnd == NULL)
7405    {
7406        return;
7407    }
7408
7409    if (enable)
7410    {
7411        Show(hWnd, S_PIN_CODE);
7412        Show(hWnd, E_PIN);
7413        Show(hWnd, S_WARNING);
7414    }
7415    else
7416    {
7417        Hide(hWnd, S_PIN_CODE);
7418        Hide(hWnd, E_PIN);
7419        Hide(hWnd, S_WARNING);
7420    }
7421
7422    SetEnable(hWnd, IDOK, enable);
7423    SetEnable(hWnd, IDCANCEL, enable);
7424    SetEnable(hWnd, S_TITLE, enable);
7425    SetEnable(hWnd, S_DEVICE_INFO, enable);
7426    SetEnable(hWnd, S_INSERT_SECURE, enable);
7427
7428    if (enable == false)
7429    {
7430        DisableClose(hWnd);
7431        SetText(hWnd, S_STATUS, L"");
7432        Show(hWnd, S_STATUS);
7433        PlayAvi(hWnd, A_PROGRESS, true);
7434    }
7435    else
7436    {
7437        EnableClose(hWnd);
7438        SetText(hWnd, S_STATUS, L"");
7439        Hide(hWnd, S_STATUS);
7440        StopAvi(hWnd, A_PROGRESS);
7441    }
7442}
7443
7444// セキュアデバイス操作用ウインドウプロシージャ
7445UINT SecureDeviceWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
7446{
7447    SECURE_DEVICE_WINDOW *w = (SECURE_DEVICE_WINDOW *)param;
7448    SECURE_DEVICE *dev = GetSecureDevice(w->device_id);
7449
7450    switch (msg)
7451    {
7452    case WM_INITDIALOG:
7453        if (dev == NULL)
7454        {
7455            MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_ERROR_INVALID_ID"), w->device_id);
7456            EndDialog(hWnd, 0);
7457            break;
7458        }
7459
7460        if (IsJPKI(dev->Id))
7461        {
7462            // 住基カード
7463            Hide(hWnd, S_IMAGE);
7464            Show(hWnd, S_IMAGE2);
7465            Hide(hWnd, S_IMAGE_TSUKUBA);
7466        }
7467        else
7468        {
7469            // 普通のカード
7470            Hide(hWnd, S_IMAGE2);
7471
7472            if (w->BitmapId != 0)
7473            {
7474                // 筑波大学用
7475                Hide(hWnd, S_IMAGE);
7476                Show(hWnd, S_IMAGE_TSUKUBA);
7477            }
7478            else
7479            {
7480                // 一般用
7481                Show(hWnd, S_IMAGE);
7482                Hide(hWnd, S_IMAGE_TSUKUBA);
7483            }
7484        }
7485
7486        FormatText(hWnd, 0, dev->Type != SECURE_USB_TOKEN ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN"),
7487            dev->DeviceName);
7488        FormatText(hWnd, S_TITLE, dev->DeviceName);
7489        FormatText(hWnd, S_INSERT_SECURE,
7490            dev->Type != SECURE_USB_TOKEN ? _UU("SEC_INIT_MSG_1") : _UU("SEC_INIT_MSG_2"));
7491        FormatText(hWnd, S_DEVICE_INFO,
7492            dev->DeviceName, dev->Manufacturer, dev->ModuleName);
7493
7494        DlgFont(hWnd, S_SOFTWARE_TITLE, 11, 0);
7495        SetText(hWnd, S_SOFTWARE_TITLE, title_bar);
7496
7497        DlgFont(hWnd, S_TITLE, 14, true);
7498        DlgFont(hWnd, S_DEVICE_INFO, 11, false);
7499        DlgFont(hWnd, S_STATUS, 13, true);
7500        EnableSecureDeviceWindowControls(hWnd, true);
7501        OpenAvi(hWnd, A_PROGRESS, AVI_PROGRESS);
7502
7503        SetIcon(hWnd, 0, ICO_KEY);
7504
7505        // 初期 PIN
7506        if ((w->default_pin != NULL && StrLen(w->default_pin) != 0) || (cached_pin_code_expires >= Tick64()))
7507        {
7508            if (w->default_pin != NULL && StrLen(w->default_pin) != 0)
7509            {
7510                SetTextA(hWnd, E_PIN, w->default_pin);
7511            }
7512            else
7513            {
7514                SetTextA(hWnd, E_PIN, cached_pin_code);
7515            }
7516            SetTimer(hWnd, 1, 1, NULL);
7517        }
7518
7519        break;
7520
7521    case WM_TIMER:
7522        switch (wParam)
7523        {
7524        case 1:
7525            KillTimer(hWnd, 1);
7526            Command(hWnd, IDOK);
7527            break;
7528        }
7529        break;
7530
7531    case WM_COMMAND:
7532        switch (wParam)
7533        {
7534        case IDOK:
7535            StartSecureDevice(hWnd, w);
7536            break;
7537
7538        case IDCANCEL:
7539            Close(hWnd);
7540            break;
7541        }
7542        break;
7543
7544    case WM_CLOSE:
7545        if (IsEnable(hWnd, IDCANCEL))
7546        {
7547            CloseAvi(hWnd, A_PROGRESS);
7548            EndDialog(hWnd, false);
7549        }
7550        break;
7551
7552    case WM_APP + 1:
7553        // スレッドから応答があった
7554        if (w->p != NULL)
7555        {
7556            if (w->p->Succeed)
7557            {
7558                // 成功
7559                if (w->default_pin != NULL)
7560                {
7561                    StrCpy(w->default_pin, 128, w->p->pin);
7562                }
7563                StrCpy(cached_pin_code, sizeof(cached_pin_code), w->p->pin);
7564                cached_pin_code_expires = Tick64() + (UINT64)WINUI_SECUREDEVICE_PIN_CACHE_TIME;
7565                Free(w->p->pin);
7566                Free(w->p);
7567                EndDialog(hWnd, true);
7568            }
7569            else
7570            {
7571                // 失敗
7572                cached_pin_code_expires = 0;
7573                EnableSecureDeviceWindowControls(hWnd, true);
7574                FocusEx(hWnd, E_PIN);
7575                MsgBox(hWnd, MB_ICONEXCLAMATION, w->p->ErrorMessage);
7576                Free(w->p->pin);
7577                Free(w->p->ErrorMessage);
7578                Free(w->p);
7579            }
7580        }
7581        break;
7582    }
7583
7584    return 0;
7585}
7586
7587// WM_COMMAND を送信する
7588void Command(HWND hWnd, UINT id)
7589{
7590    SendMessage(hWnd, WM_COMMAND, id, 0);
7591}
7592
7593// セキュアデバイスウインドウを表示する
7594bool SecureDeviceWindow(HWND hWnd, WINUI_SECURE_BATCH *batch, UINT num_batch, UINT device_id, UINT bitmap_id)
7595{
7596    SECURE_DEVICE_WINDOW w;
7597    UINT i;
7598    // 引数チェック
7599    if (batch == NULL || num_batch == 0 || device_id == 0)
7600    {
7601        return false;
7602    }
7603
7604    // 成功フラグを初期化
7605    for (i = 0;i < num_batch;i++)
7606    {
7607        batch[i].Succeed = false;
7608    }
7609
7610    Zero(&w, sizeof(w));
7611    w.batch = batch;
7612    w.device_id = device_id;
7613    w.num_batch = num_batch;
7614    w.BitmapId = bitmap_id;
7615
7616    // ダイアログを開く
7617    return (bool)Dialog(hWnd, D_SECURE, SecureDeviceWindowProc, &w);
7618}
7619
7620// AVI を停止する
7621void StopAvi(HWND hWnd, UINT id)
7622{
7623    // 引数チェック
7624    if (hWnd == NULL)
7625    {
7626        return;
7627    }
7628
7629    Animate_Stop(DlgItem(hWnd, id));
7630    Hide(hWnd, id);
7631}
7632
7633// AVI を再生する
7634void PlayAvi(HWND hWnd, UINT id, bool repeat)
7635{
7636    // 引数チェック
7637    if (hWnd == NULL)
7638    {
7639        return;
7640    }
7641
7642    Show(hWnd, id);
7643    Animate_Play(DlgItem(hWnd, id), 0, -1, (repeat ? -1 : 0));
7644}
7645
7646// AVI ファイルを閉じる
7647void CloseAvi(HWND hWnd, UINT id)
7648{
7649    // 引数チェック
7650    if (hWnd == NULL)
7651    {
7652        return;
7653    }
7654
7655    StopAvi(hWnd, id);
7656    Animate_Close(DlgItem(hWnd, id));
7657}
7658
7659// AVI ファイルを開く
7660void OpenAvi(HWND hWnd, UINT id, UINT avi_id)
7661{
7662    // 引数チェック
7663    if (hWnd == NULL || avi_id == 0)
7664    {
7665        return;
7666    }
7667
7668    Hide(hWnd, id);
7669    Animate_OpenEx(DlgItem(hWnd, id), hDll, MAKEINTRESOURCE(avi_id));
7670}
7671
7672// フォントをコントロールに設定する
7673void DlgFont(HWND hWnd, UINT id, UINT size, UINT bold)
7674{
7675    DIALOG_PARAM *param = (DIALOG_PARAM *)GetParam(hWnd);
7676
7677    if (param == NULL || param->meiryo == false)
7678    {
7679        SetFont(hWnd, id, Font(size, bold));
7680    }
7681    else
7682    {
7683        SetFont(hWnd, id, GetFont((_GETLANG() == 2 ? "Microsoft YaHei" : "Meiryo"), size, bold, false, false, false));
7684    }
7685}
7686
7687// 標準的なフォントを生成する
7688HFONT Font(UINT size, UINT bold)
7689{
7690    return GetFont(NULL, size, bold, false, false, false);
7691}
7692
7693// 内部管理用ダイアログプロシージャ
7694UINT CALLBACK InternalDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
7695{
7696    DIALOG_PARAM *param = (DIALOG_PARAM *)GetParam(hWnd);
7697    void *app_param = NULL;
7698    bool white_flag = false;
7699    UINT ret;
7700    // 引数チェック
7701    if (hWnd == NULL)
7702    {
7703        return 0;
7704    }
7705
7706    if (msg == WM_INITDIALOG)
7707    {
7708        DoEvents(hWnd);
7709    }
7710
7711    if (param == NULL)
7712    {
7713        if (msg == WM_INITDIALOG)
7714        {
7715            param = (void *)lParam;
7716            InitDialogInternational(hWnd, param);
7717        }
7718    }
7719    if (param != NULL)
7720    {
7721        app_param = param->param;
7722        white_flag = param->white;
7723    }
7724
7725    ret = DlgProc(hWnd, msg, wParam, lParam, white_flag);
7726    if (ret != 0)
7727    {
7728        return ret;
7729    }
7730
7731    ret = 0;
7732
7733    if (param != NULL)
7734    {
7735        if (param->proc != NULL)
7736        {
7737            ret = param->proc(hWnd, msg, wParam, lParam, app_param);
7738        }
7739        else
7740        {
7741            if (msg == WM_CLOSE)
7742            {
7743                EndDialog(hWnd, 0);
7744            }
7745            else if (msg == WM_COMMAND && (wParam == IDOK || wParam == IDCANCEL))
7746            {
7747                Close(hWnd);
7748            }
7749        }
7750    }
7751
7752    if (msg == WM_INITDIALOG)
7753    {
7754        SetForegroundWindow(hWnd);
7755        SetActiveWindow(hWnd);
7756    }
7757
7758    return ret;
7759}
7760
7761// ダイアログ ボックスを表示する
7762UINT Dialog(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param)
7763{
7764    bool white = true;
7765
7766    return DialogEx(hWnd, id, proc, param, white);
7767}
7768UINT DialogEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white)
7769{
7770    return DialogEx2(hWnd, id, proc, param, white, false);
7771}
7772UINT DialogEx2(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white, bool meiryo)
7773{
7774    UINT ret;
7775    DIALOG_PARAM p;
7776    // 引数チェック
7777    if (id == 0)
7778    {
7779        return 0;
7780    }
7781
7782    Zero(&p, sizeof(p));
7783    p.param = param;
7784    p.white = white;
7785    p.proc = proc;
7786
7787    if (MsIsVista())
7788    {
7789        p.meiryo = meiryo;
7790    }
7791
7792    ret = DialogInternal(hWnd, id, InternalDialogProc, &p);
7793
7794    return ret;
7795}
7796
7797// モードレスダイアログを作成する
7798HWND DialogCreateEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white)
7799{
7800    HWND ret = NULL;
7801    DIALOG_PARAM p;
7802    // 引数チェック
7803    if (id == 0)
7804    {
7805        return 0;
7806    }
7807
7808    Zero(&p, sizeof(p));
7809    p.param = param;
7810    p.white = white;
7811    p.proc = proc;
7812
7813    if (MsIsNt() == false)
7814    {
7815        // Win9x
7816        ret = CreateDialogParamA(hDll, MAKEINTRESOURCEA(id), hWnd,
7817            (DLGPROC)proc, (LPARAM)param);
7818    }
7819    else
7820    {
7821        // WinNT
7822        ret = CreateDialogParamW(hDll, MAKEINTRESOURCEW(id), hWnd,
7823            (DLGPROC)proc, (LPARAM)param);
7824    }
7825
7826    return ret;
7827}
7828
7829// ビットマップをボタンに設定する
7830void SetBitmap(HWND hWnd, UINT id, UINT bmp_id)
7831{
7832    HBITMAP bmp;
7833    char *class_name;
7834    // 引数チェック
7835    if (hWnd == NULL)
7836    {
7837        return;
7838    }
7839
7840    bmp = LoadImage(hDll, MAKEINTRESOURCE(bmp_id), IMAGE_BITMAP, 0, 0, (MsIsNt() ? LR_SHARED : 0) | LR_VGACOLOR);
7841    if (bmp == NULL)
7842    {
7843        return;
7844    }
7845
7846    class_name = GetClassA(hWnd, id);
7847
7848    if (StrCmpi(class_name, "Static") != 0)
7849    {
7850        SendMsg(hWnd, id, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp);
7851    }
7852    else
7853    {
7854        SendMsg(hWnd, id, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp);
7855    }
7856
7857    Free(class_name);
7858}
7859
7860// アイコンキャッシュの初期化
7861void InitIconCache()
7862{
7863    if (icon_cache_list != NULL)
7864    {
7865        return;
7866    }
7867
7868    icon_cache_list = NewList(NULL);
7869}
7870
7871// アイコンキャッシュの解放
7872void FreeIconCache()
7873{
7874    UINT i;
7875    if (icon_cache_list == NULL)
7876    {
7877        return;
7878    }
7879
7880    for (i = 0;i < LIST_NUM(icon_cache_list);i++)
7881    {
7882        ICON_CACHE *c = LIST_DATA(icon_cache_list, i);
7883        DestroyIcon(c->hIcon);
7884        Free(c);
7885    }
7886
7887    ReleaseList(icon_cache_list);
7888    icon_cache_list = NULL;
7889}
7890
7891// アイコン取得
7892HICON LoadIconEx(UINT id, bool small_icon)
7893{
7894    HICON h = NULL;
7895    UINT i;
7896    if (icon_cache_list == NULL)
7897    {
7898        return small_icon == false ? LoadLargeIconInner(id) : LoadSmallIconInner(id);
7899    }
7900
7901    LockList(icon_cache_list);
7902    {
7903        for (i = 0;i < LIST_NUM(icon_cache_list);i++)
7904        {
7905            ICON_CACHE *c = LIST_DATA(icon_cache_list, i);
7906            if (c->id == id && c->small_icon == small_icon)
7907            {
7908                h = c->hIcon;
7909                break;
7910            }
7911        }
7912
7913        if (h == NULL)
7914        {
7915            h = small_icon == false ? LoadLargeIconInner(id) : LoadSmallIconInner(id);
7916            if (h != NULL)
7917            {
7918                ICON_CACHE *c = ZeroMalloc(sizeof(ICON_CACHE));
7919                c->hIcon = h;
7920                c->id = id;
7921                c->small_icon = small_icon;
7922                Add(icon_cache_list, c);
7923            }
7924        }
7925    }
7926    UnlockList(icon_cache_list);
7927
7928    return h;
7929}
7930
7931// 大きいアイコン取得
7932HICON LoadLargeIcon(UINT id)
7933{
7934    return LoadIconEx(id, false);
7935}
7936
7937// 小さいアイコン取得
7938HICON LoadSmallIcon(UINT id)
7939{
7940    return LoadIconEx(id, true);
7941}
7942
7943// 大きいアイコンを取得する
7944HICON LoadLargeIconInner(UINT id)
7945{
7946    HICON ret;
7947    ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 32, 32, 0);
7948    if (ret == NULL)
7949    {
7950        ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 32, 32, LR_VGACOLOR);
7951        if (ret == NULL)
7952        {
7953            ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, 0);
7954            if (ret == NULL)
7955            {
7956                ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_VGACOLOR);
7957                if (ret == NULL)
7958                {
7959                    ret = LoadIcon(hDll, MAKEINTRESOURCE(id));
7960                }
7961            }
7962        }
7963    }
7964    return ret;
7965}
7966
7967// 小さいアイコンを取得する
7968HICON LoadSmallIconInner(UINT id)
7969{
7970    HICON ret;
7971    ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 16, 16, 0);
7972    if (ret == NULL)
7973    {
7974        ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 16, 16, LR_VGACOLOR);
7975        if (ret == NULL)
7976        {
7977            ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, 0);
7978            if (ret == NULL)
7979            {
7980                ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_VGACOLOR);
7981                if (ret == NULL)
7982                {
7983                    ret = LoadLargeIconInner(id);
7984                }
7985            }
7986        }
7987    }
7988    return ret;
7989}
7990
7991// アイコンをウインドウまたはボタンに設定する
7992void SetIcon(HWND hWnd, UINT id, UINT icon_id)
7993{
7994    HICON icon1, icon2;
7995    // 引数チェック
7996    if (hWnd == NULL)
7997    {
7998        return;
7999    }
8000
8001    icon1 = LoadLargeIcon(icon_id);
8002    if (icon1 == NULL)
8003    {
8004        return;
8005    }
8006
8007    if (id == 0)
8008    {
8009        SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon1);
8010        icon2 = LoadSmallIcon(icon_id);
8011        if (icon2 == NULL)
8012        {
8013            icon2 = icon1;
8014        }
8015        SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon2);
8016    }
8017    else
8018    {
8019        bool is_btn = true;
8020        wchar_t *s = GetClass(hWnd, id);
8021        if (s != NULL)
8022        {
8023            if (UniStrCmpi(s, L"Static") == 0)
8024            {
8025                is_btn = false;
8026            }
8027            Free(s);
8028        }
8029
8030        if (is_btn)
8031        {
8032            SendMsg(hWnd, id, BM_SETIMAGE, IMAGE_ICON, (LPARAM)icon1);
8033        }
8034        else
8035        {
8036            SendMsg(hWnd, id, STM_SETICON, (WPARAM)icon1, 0);
8037        }
8038    }
8039}
8040
8041// ラジオボタンがチェックされているか確認する
8042bool IsChecked(HWND hWnd, UINT id)
8043{
8044    // 引数チェック
8045    if (hWnd == NULL)
8046    {
8047        return false;
8048    }
8049
8050    return IsDlgButtonChecked(hWnd, id) == BST_CHECKED ? true : false;
8051}
8052
8053// ラジオボタンをチェック
8054void Check(HWND hWnd, UINT id, bool b)
8055{
8056    // 引数チェック
8057    if (hWnd == NULL)
8058    {
8059        return;
8060    }
8061
8062    if ((!(!IsChecked(hWnd, id))) != (!(!b)))
8063    {
8064        CheckDlgButton(hWnd, id, b ? BST_CHECKED : BST_UNCHECKED);
8065    }
8066}
8067
8068// テキストボックスの文字サイズが指定されたサイズ以下であることを確認する
8069bool CheckTextSize(HWND hWnd, UINT id, UINT size, bool unicode)
8070{
8071    // 引数チェック
8072    if (hWnd == NULL)
8073    {
8074        return false;
8075    }
8076
8077    if (GetTextSize(hWnd, id, unicode) <= size)
8078    {
8079        return true;
8080    }
8081    else
8082    {
8083        return false;
8084    }
8085}
8086
8087// テキストボックスに入っている文字列数が指定された文字列数以下であることを確認する
8088bool CheckTextLen(HWND hWnd, UINT id, UINT len, bool unicode)
8089{
8090    // 引数チェック
8091    if (hWnd == NULL)
8092    {
8093        return false;
8094    }
8095
8096    if (GetTextLen(hWnd, id, unicode) <= len)
8097    {
8098        return true;
8099    }
8100    else
8101    {
8102        return false;
8103    }
8104}
8105
8106// テキストボックスに入力できる文字数を制限する
8107void LimitText(HWND hWnd, UINT id, UINT count)
8108{
8109    // 引数チェック
8110    if (hWnd == NULL)
8111    {
8112        return;
8113    }
8114
8115    SendMsg(hWnd, id, EM_LIMITTEXT, count, 0);
8116}
8117
8118// フォントの設定
8119void SetFont(HWND hWnd, UINT id, HFONT hFont)
8120{
8121    // 引数チェック
8122    if (hWnd == NULL || hFont == NULL)
8123    {
8124        return;
8125    }
8126
8127    SendMessage(DlgItem(hWnd, id), WM_SETFONT, (WPARAM)hFont, true);
8128}
8129
8130// フォントサイズの取得
8131bool GetFontSize(HFONT hFont, UINT *x, UINT *y)
8132{
8133    bool ret = false;
8134    UINT xx = 0;
8135    UINT yy = 0;
8136
8137    // フォントハンドルを検索
8138    LockList(font_list);
8139    {
8140        UINT i;
8141
8142        for (i = 0;i < LIST_NUM(font_list);i++)
8143        {
8144            FONT *f = LIST_DATA(font_list, i);
8145
8146            if (f->hFont == hFont)
8147            {
8148                xx = f->x;
8149                yy = f->y;
8150
8151                ret = true;
8152                break;
8153            }
8154        }
8155    }
8156    UnlockList(font_list);
8157
8158    if (ret == false)
8159    {
8160        ret = CalcFontSize(hFont, &xx, &yy);
8161    }
8162
8163    if (xx == 0 || yy == 0)
8164    {
8165        xx = 8;
8166        yy = 16;
8167    }
8168
8169    if (x != NULL)
8170    {
8171        *x = xx;
8172    }
8173
8174    if (y != NULL)
8175    {
8176        *y = yy;
8177    }
8178
8179    return ret;
8180}
8181
8182// フォントサイズの計算
8183bool CalcFontSize(HFONT hFont, UINT *x, UINT *y)
8184{
8185    UINT xx = 0, yy = 0;
8186    TEXTMETRIC tm;
8187    SIZE sz;
8188    bool ret = false;
8189    HDC hDC;
8190
8191    hDC = CreateCompatibleDC(NULL);
8192
8193    SelectObject(hDC, hFont);
8194
8195    Zero(&tm, sizeof(tm));
8196    Zero(&sz, sizeof(sz));
8197
8198    if (GetTextMetrics(hDC, &tm))
8199    {
8200        xx = tm.tmAveCharWidth;
8201        yy = tm.tmHeight;
8202
8203        ret = true;
8204
8205        if (GetTextExtentPoint32(hDC,
8206            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
8207            52, &sz))
8208        {
8209            xx = (sz.cx / 26 + 1) / 2;
8210        }
8211    }
8212
8213    if (x != NULL)
8214    {
8215        *x = xx;
8216    }
8217
8218    if (y != NULL)
8219    {
8220        *y = yy;
8221    }
8222
8223    DeleteDC(hDC);
8224
8225    return ret;
8226}
8227
8228// フォントの取得
8229HFONT GetFont(char *name, UINT size, bool bold, bool italic, bool underline, bool strikeout)
8230{
8231    HFONT hFont;
8232    HDC hDC;
8233    // 引数チェック
8234    if (name == NULL)
8235    {
8236        name = font_name;
8237    }
8238    if (size == 0)
8239    {
8240        size = font_size;
8241        if (size == 0)
8242        {
8243            size = 9;
8244        }
8245    }
8246
8247    // 既存のフォントを探す
8248    LockList(font_list);
8249    {
8250        FONT *f, t;
8251        DWORD font_quality = ANTIALIASED_QUALITY;
8252        OS_INFO *os = GetOsInfo();
8253        UINT x = 0;
8254        UINT y = 0;
8255        int rotate = 0;
8256
8257        Zero(&t, sizeof(t));
8258        t.Bold = bold;
8259        t.Italic = italic;
8260        t.Size = size;
8261        t.StrikeOut = strikeout;
8262        t.UnderLine = underline;
8263        t.Name = CopyStr(name);
8264        f = Search(font_list, &t);
8265        Free(t.Name);
8266
8267        if (f != NULL)
8268        {
8269            // フォントを発見した
8270            UnlockList(font_list);
8271            return f->hFont;
8272        }
8273
8274        // 新しいフォントを作成する
8275        hDC = CreateCompatibleDC(NULL);
8276
8277        // Windows XP 以降では ClearType を指定する
8278        if (OS_IS_WINDOWS_NT(os->OsType) && GET_KETA(os->OsType, 100) >= 3)
8279        {
8280            font_quality = CLEARTYPE_NATURAL_QUALITY;
8281            rotate = 3600;
8282        }
8283
8284        // フォント作成
8285        hFont = CreateFontA(-MulDiv(size, GetDeviceCaps(hDC, LOGPIXELSY), 72),
8286            0, rotate, rotate, (bold == false ? 500 : FW_BOLD),
8287            italic, underline, strikeout, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
8288            CLIP_DEFAULT_PRECIS, font_quality, DEFAULT_PITCH, name);
8289
8290        if (hFont == NULL)
8291        {
8292            // 失敗
8293            DeleteDC(hDC);
8294            UnlockList(font_list);
8295
8296            return NULL;
8297        }
8298
8299        CalcFontSize(hFont, &x, &y);
8300
8301        // テーブルに追加
8302        f = ZeroMalloc(sizeof(FONT));
8303        f->Bold = bold;
8304        f->hFont = hFont;
8305        f->Italic = italic;
8306        f->Name = CopyStr(name);
8307        f->Size = size;
8308        f->StrikeOut = strikeout;
8309        f->UnderLine = underline;
8310        f->x = x;
8311        f->y = y;
8312
8313        Insert(font_list, f);
8314
8315        DeleteDC(hDC);
8316    }
8317    UnlockList(font_list);
8318
8319    return hFont;
8320}
8321
8322// フォントの比較
8323int CompareFont(void *p1, void *p2)
8324{
8325    FONT *f1, *f2;
8326    UINT r;
8327    if (p1 == NULL || p2 == NULL)
8328    {
8329        return 0;
8330    }
8331    f1 = *(FONT **)p1;
8332    f2 = *(FONT **)p2;
8333    if (f1 == NULL || f2 == NULL)
8334    {
8335        return 0;
8336    }
8337    r = StrCmpi(f1->Name, f2->Name);
8338    if (r != 0)
8339    {
8340        return r;
8341    }
8342    else
8343    {
8344        if (f1->Bold > f2->Bold)
8345        {
8346            return 1;
8347        }
8348        else if (f1->Bold < f2->Bold)
8349        {
8350            return -1;
8351        }
8352        else if (f1->Italic > f2->Italic)
8353        {
8354            return 1;
8355        }
8356        else if (f1->Italic < f2->Italic)
8357        {
8358            return -1;
8359        }
8360        else if (f1->Size > f2->Size)
8361        {
8362            return 1;
8363        }
8364        else if (f1->Size < f2->Size)
8365        {
8366            return -1;
8367        }
8368        else if (f1->StrikeOut > f2->StrikeOut)
8369        {
8370            return 1;
8371        }
8372        else if (f1->StrikeOut < f2->StrikeOut)
8373        {
8374            return -1;
8375        }
8376        else if (f1->UnderLine > f2->UnderLine)
8377        {
8378            return 1;
8379        }
8380        else if (f1->UnderLine < f2->UnderLine)
8381        {
8382            return -1;
8383        }
8384        else
8385        {
8386            return 0;
8387        }
8388    }
8389}
8390
8391// フォントの初期化
8392void InitFont()
8393{
8394    if (font_list != NULL)
8395    {
8396        return;
8397    }
8398    font_list = NewList(CompareFont);
8399}
8400
8401// フォントの解放
8402void FreeFont()
8403{
8404    UINT i;
8405    if (font_list == NULL)
8406    {
8407        return;
8408    }
8409    for (i = 0;i < LIST_NUM(font_list);i++)
8410    {
8411        FONT *f = LIST_DATA(font_list, i);
8412        Free(f->Name);
8413        DeleteObject((HGDIOBJ)f->hFont);
8414        Free(f);
8415    }
8416    ReleaseList(font_list);
8417    font_list = NULL;
8418}
8419
8420// ウインドウを閉じるボタンを出す
8421void EnableClose(HWND hWnd)
8422{
8423    HMENU h;
8424    // 引数チェック
8425    if (hWnd == NULL)
8426    {
8427        return;
8428    }
8429
8430    h = GetSystemMenu(hWnd, false);
8431    EnableMenuItem(h, SC_CLOSE, MF_ENABLED);
8432    DrawMenuBar(hWnd);
8433}
8434
8435// ウインドウを閉じるボタンを消す
8436void DisableClose(HWND hWnd)
8437{
8438    HMENU h;
8439    // 引数チェック
8440    if (hWnd == NULL)
8441    {
8442        return;
8443    }
8444
8445    h = GetSystemMenu(hWnd, false);
8446    EnableMenuItem(h, SC_CLOSE, MF_GRAYED);
8447    DrawMenuBar(hWnd);
8448}
8449
8450// 親ウインドウの中央に移動する
8451void CenterParent(HWND hWnd)
8452{
8453    RECT rp;
8454    RECT r;
8455    HWND hWndParent = GetParent(hWnd);
8456    int win_x, win_y;
8457    int x, y;
8458
8459    if (hWndParent == NULL || IsHide(hWndParent, 0) || IsIconic(hWndParent))
8460    {
8461        Center(hWnd);
8462        return;
8463    }
8464
8465    if (GetWindowRect(hWndParent, &rp) == false)
8466    {
8467        Center(hWnd);
8468        return;
8469    }
8470
8471    GetWindowRect(hWnd, &r);
8472
8473    win_x = r.right - r.left;
8474    win_y = r.bottom - r.top;
8475
8476    x = (rp.right - rp.left - win_x) / 2 + rp.left;
8477    y = (rp.bottom - rp.top - win_y) / 2 + rp.top;
8478
8479    x = MAX(x, 0);
8480    y = MAX(y, 0);
8481
8482    SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
8483}
8484
8485// ウインドウを中央に移動する
8486void Center(HWND hWnd)
8487{
8488    RECT screen;
8489    RECT win;
8490    UINT x, y;
8491    UINT win_x, win_y;
8492    // 引数チェック
8493    if (hWnd == NULL)
8494    {
8495        return;
8496    }
8497
8498    if (SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0) == false)
8499    {
8500        return;
8501    }
8502
8503    GetWindowRect(hWnd, &win);
8504    win_x = win.right - win.left;
8505    win_y = win.bottom - win.top;
8506
8507    if (win_x < (UINT)(screen.right - screen.left))
8508    {
8509        x = (screen.right - screen.left - win_x) / 2;
8510    }
8511    else
8512    {
8513        x = 0;
8514    }
8515
8516    if (win_y < (UINT)(screen.bottom - screen.top))
8517    {
8518        y = (screen.bottom - screen.top - win_y) / 2;
8519    }
8520    else
8521    {
8522        y = 0;
8523    }
8524
8525    SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
8526}
8527
8528// ウインドウを中央に移動する 2
8529void Center2(HWND hWnd)
8530{
8531    RECT screen;
8532    RECT win;
8533    UINT x, y;
8534    UINT win_x, win_y;
8535    // 引数チェック
8536    if (hWnd == NULL)
8537    {
8538        return;
8539    }
8540
8541    if (SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0) == false)
8542    {
8543        return;
8544    }
8545
8546    GetWindowRect(hWnd, &win);
8547    win_x = win.right - win.left;
8548    win_y = win.bottom - win.top;
8549
8550    if (win_x < (UINT)(screen.right - screen.left))
8551    {
8552        x = (screen.right - screen.left - win_x) / 2;
8553    }
8554    else
8555    {
8556        x = 0;
8557    }
8558
8559    if (win_y < (UINT)(screen.bottom - screen.top))
8560    {
8561        y = (screen.bottom - screen.top - win_y) / 4;
8562    }
8563    else
8564    {
8565        y = 0;
8566    }
8567
8568    SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
8569}
8570
8571// モニタのサイズを取得する
8572void GetMonitorSize(UINT *width, UINT *height)
8573{
8574    // 引数チェック
8575    if (width == NULL || height == NULL)
8576    {
8577        return;
8578    }
8579
8580    *width = GetSystemMetrics(SM_CXSCREEN);
8581    *height = GetSystemMetrics(SM_CYSCREEN);
8582}
8583
8584// ウインドウ内の文字列をフォーマットする
8585void FormatText(HWND hWnd, UINT id, ...)
8586{
8587    va_list args;
8588    wchar_t *buf;
8589    UINT size;
8590    wchar_t *str;
8591    // 引数チェック
8592    if (hWnd == NULL)
8593    {
8594        return;
8595    }
8596
8597    str = GetText(hWnd, id);
8598    if (str == NULL)
8599    {
8600        return;
8601    }
8602
8603    size = MAX(UniStrSize(str) * 10, MAX_SIZE * 10);
8604    buf = MallocEx(size, true);
8605
8606    va_start(args, id);
8607    UniFormatArgs(buf, size, str, args);
8608
8609    SetText(hWnd, id, buf);
8610
8611    Free(buf);
8612
8613    Free(str);
8614    va_end(args);
8615}
8616void FormatTextA(HWND hWnd, UINT id, ...)
8617{
8618    va_list args;
8619    char *buf;
8620    UINT size;
8621    char *str;
8622    // 引数チェック
8623    if (hWnd == NULL)
8624    {
8625        return;
8626    }
8627
8628    str = GetTextA(hWnd, id);
8629    if (str == NULL)
8630    {
8631        return;
8632    }
8633
8634    size = MAX(StrSize(str) * 10, MAX_SIZE * 10);
8635    buf = MallocEx(size, true);
8636
8637    va_start(args, id);
8638    FormatArgs(buf, size, str, args);
8639
8640    SetTextA(hWnd, id, buf);
8641
8642    Free(buf);
8643
8644    Free(str);
8645    va_end(args);
8646}
8647
8648// 可変長引数の文字列をウインドウに設定
8649void SetTextEx(HWND hWnd, UINT id, wchar_t *str, ...)
8650{
8651    va_list args;
8652    wchar_t *buf;
8653    UINT size;
8654    // 引数チェック
8655    if (str == NULL || hWnd == NULL)
8656    {
8657        return;
8658    }
8659
8660    size = MAX(UniStrSize(str) * 10, MAX_SIZE * 10);
8661    buf = MallocEx(size, true);
8662
8663    va_start(args, str);
8664    UniFormatArgs(buf, size, str, args);
8665
8666    SetText(hWnd, id, buf);
8667
8668    Free(buf);
8669    va_end(args);
8670}
8671void SetTextExA(HWND hWnd, UINT id, char *str, ...)
8672{
8673    va_list args;
8674    char *buf;
8675    UINT size;
8676    // 引数チェック
8677    if (str == NULL || hWnd == NULL)
8678    {
8679        return;
8680    }
8681
8682    size = MAX(StrSize(str) * 10, MAX_SIZE * 10);
8683    buf = MallocEx(size, true);
8684
8685    va_start(args, str);
8686    FormatArgs(buf, size, str, args);
8687
8688    SetTextA(hWnd, id, buf);
8689
8690    Free(buf);
8691    va_end(args);
8692}
8693
8694// 可変長メッセージボックスの表示
8695UINT MsgBoxEx(HWND hWnd, UINT flag, wchar_t *msg, ...)
8696{
8697    va_list args;
8698    wchar_t *buf;
8699    UINT size;
8700    UINT ret;
8701    // 引数チェック
8702    if (msg == NULL)
8703    {
8704        msg = L"MessageBox";
8705    }
8706
8707    size = MAX(UniStrSize(msg) * 10, MAX_SIZE * 10);
8708    buf = MallocEx(size, true);
8709
8710    va_start(args, msg);
8711    UniFormatArgs(buf, size, msg, args);
8712
8713    ret = MsgBox(hWnd, flag, buf);
8714    Free(buf);
8715    va_end(args);
8716
8717    return ret;
8718}
8719
8720// メッセージボックスの表示
8721UINT MsgBox(HWND hWnd, UINT flag, wchar_t *msg)
8722{
8723    UINT ret;
8724    wchar_t *title;
8725    // 引数チェック
8726    if (msg == NULL)
8727    {
8728        msg = L"MessageBox";
8729    }
8730
8731    if (title_bar != NULL)
8732    {
8733        title = CopyUniStr(title_bar);
8734    }
8735    else
8736    {
8737        title = CopyStrToUni(CEDAR_PRODUCT_STR);
8738    }
8739
8740    if (hWnd)
8741    {
8742        // 親ウインドウが最上位ウインドウの場合はメッセージボックスも最上位にする
8743        if (GetExStyle(hWnd, 0) & WS_EX_TOPMOST)
8744        {
8745            flag |= MB_SYSTEMMODAL;
8746        }
8747    }
8748
8749    ret = MessageBoxW(hWnd, msg, title, flag);
8750
8751    Free(title);
8752
8753    return ret;
8754}
8755
8756// ダイアログの作成 (内部)
8757UINT DialogInternal(HWND hWnd, UINT id, DIALOG_PROC *proc, void *param)
8758{
8759    // 引数チェック
8760    if (proc == NULL)
8761    {
8762        return 0;
8763    }
8764
8765    if (MsIsNt() == false)
8766    {
8767        // Win9x
8768        return (UINT)DialogBoxParam(hDll, MAKEINTRESOURCE(id), hWnd, (DLGPROC)proc, (LPARAM)param);
8769    }
8770    else
8771    {
8772        // WinNT
8773        return (UINT)DialogBoxParamW(hDll, MAKEINTRESOURCEW(id), hWnd, (DLGPROC)proc, (LPARAM)param);
8774    }
8775}
8776
8777// システム設定が更新されたことを通知する
8778void NoticeSettingChange()
8779{
8780    PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
8781    DoEvents(NULL);
8782}
8783
8784// ウインドウを半透明にする
8785void SetAplha(HWND hWnd, UINT value0_255)
8786{
8787    // 引数チェック
8788    if (hWnd == NULL)
8789    {
8790        return;
8791    }
8792
8793    value0_255 = MAKESURE(value0_255, 0, 255);
8794
8795    if (true)
8796    {
8797        UINT os_type = GetOsInfo()->OsType;
8798        if (OS_IS_WINDOWS_NT(os_type) && GET_KETA(os_type, 100) >= 2)
8799        {
8800            bool (WINAPI *_SetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD);
8801            HINSTANCE hInst;
8802
8803            hInst = LoadLibrary("user32.dll");
8804
8805            _SetLayeredWindowAttributes =
8806                (bool (__stdcall *)(HWND,COLORREF,BYTE,DWORD))
8807                GetProcAddress(hInst, "SetLayeredWindowAttributes");
8808
8809            if (_SetLayeredWindowAttributes != NULL)
8810            {
8811                // Windows 2000 以降でのみ対応
8812                SetExStyle(hWnd, 0, WS_EX_LAYERED);
8813                _SetLayeredWindowAttributes(hWnd, 0, value0_255, LWA_ALPHA);
8814            }
8815
8816            FreeLibrary(hInst);
8817        }
8818    }
8819}
8820
8821// WinUi が管理するダイアログボックスプロシージャ
8822UINT DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, bool white_color)
8823{
8824    void *param;
8825    HWND hWndParent;
8826    // 引数チェック
8827    if (hWnd == NULL)
8828    {
8829        return 0;
8830    }
8831
8832    switch (msg)
8833    {
8834    case WM_INITDIALOG:
8835        param = (void *)lParam;
8836        SetParam(hWnd, param);
8837
8838        // 親ウインドウが存在するかどうか調べる
8839        hWndParent = GetParent(hWnd);
8840        if (hWndParent == NULL || IsShow(hWndParent, 0) == false)
8841        {
8842            // 存在しない場合は中央に配置する
8843            Center(hWnd);
8844        }
8845
8846        if (UseAlpha)
8847        {
8848            SetAplha(hWnd, AlphaValue * 255 / 100);
8849        }
8850
8851        break;
8852    }
8853
8854    if (white_color)
8855    {
8856        if (IsNewStyleModeEnabled() == false)
8857        {
8858            switch (msg)
8859            {
8860            case WM_CTLCOLORBTN:
8861            case WM_CTLCOLORDLG:
8862            case WM_CTLCOLOREDIT:
8863            case WM_CTLCOLORLISTBOX:
8864            case WM_CTLCOLORMSGBOX:
8865            case WM_CTLCOLORSCROLLBAR:
8866            case WM_CTLCOLORSTATIC:
8867                return (UINT)GetStockObject(WHITE_BRUSH);
8868            }
8869        }
8870        else
8871        {
8872            switch (msg)
8873            {
8874            case WM_CTLCOLORDLG:
8875                // ダイアログの背景色
8876                return (UINT)gdi_cache.BackgroundColorBrush;
8877
8878            case WM_CTLCOLORBTN:
8879                // ボタンの背景色
8880                SetTextColor((HDC)wParam, gdi_cache.ForegroundColor);
8881                SetBkColor((HDC)wParam, gdi_cache.BackgroundColor);
8882                return (UINT)gdi_cache.BackgroundColorBrush;
8883
8884            case WM_CTLCOLORSTATIC:
8885                // ラベルの色
8886                SetTextColor((HDC)wParam, gdi_cache.ForegroundColor);
8887                SetBkColor((HDC)wParam, gdi_cache.BackgroundColor);
8888                return (UINT)gdi_cache.BackgroundColorBrush;
8889
8890            case WM_CTLCOLOREDIT:
8891                // エディットコントロールの色
8892                return (UINT)gdi_cache.TextBoxBackgroundColorBrush;
8893            }
8894        }
8895    }
8896
8897    return 0;
8898}
8899
8900// ダイアログボックスのパラメータの設定
8901void SetParam(HWND hWnd, void *param)
8902{
8903    // 引数チェック
8904    if (hWnd == NULL)
8905    {
8906        return;
8907    }
8908
8909    SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)param);
8910}
8911
8912// ダイアログボックスのパラメータの取得
8913void *GetParam(HWND hWnd)
8914{
8915    void *ret;
8916    // 引数チェック
8917    if (hWnd == NULL)
8918    {
8919        return NULL;
8920    }
8921
8922    ret = (void *)GetWindowLongPtr(hWnd, DWLP_USER);
8923    return ret;
8924}
8925
8926// ウインドウを最前面でなくする
8927void NoTop(HWND hWnd)
8928{
8929    // 引数チェック
8930    if (hWnd == NULL)
8931    {
8932        return;
8933    }
8934
8935    SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
8936}
8937
8938// ウインドウを最前面に表示する
8939void Top(HWND hWnd)
8940{
8941    // 引数チェック
8942    if (hWnd == NULL)
8943    {
8944        return;
8945    }
8946
8947    SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
8948}
8949
8950// ウインドウを隠す
8951void Hide(HWND hWnd, UINT id)
8952{
8953    // 引数チェック
8954    if (hWnd == NULL)
8955    {
8956        return;
8957    }
8958
8959    if (IsShow(hWnd, id))
8960    {
8961        ShowWindow(DlgItem(hWnd, id), SW_HIDE);
8962    }
8963}
8964
8965// ウインドウを表示する
8966void Show(HWND hWnd, UINT id)
8967{
8968    // 引数チェック
8969    if (hWnd == NULL)
8970    {
8971        return;
8972    }
8973
8974    if (IsHide(hWnd, id))
8975    {
8976        ShowWindow(DlgItem(hWnd, id), SW_SHOW);
8977    }
8978}
8979
8980// 表示設定の変更
8981void SetShow(HWND hWnd, UINT id, bool b)
8982{
8983    // 引数チェック
8984    if (hWnd == NULL)
8985    {
8986        return;
8987    }
8988
8989    if (b)
8990    {
8991        Show(hWnd, id);
8992    }
8993    else
8994    {
8995        Hide(hWnd, id);
8996    }
8997}
8998
8999// ウインドウが表示されているかどうか取得する
9000bool IsShow(HWND hWnd, UINT id)
9001{
9002    return IsHide(hWnd, id) ? false : true;
9003}
9004
9005// ウインドウが隠れているかどうか取得する
9006bool IsHide(HWND hWnd, UINT id)
9007{
9008    // 引数チェック
9009    if (hWnd == NULL)
9010    {
9011        return true;
9012    }
9013
9014    if (GetStyle(hWnd, id) & WS_VISIBLE)
9015    {
9016        return false;
9017    }
9018    else
9019    {
9020        return true;
9021    }
9022}
9023
9024// ウインドウスタイルを削除する
9025void RemoveExStyle(HWND hWnd, UINT id, UINT style)
9026{
9027    UINT old;
9028    // 引数チェック
9029    if (hWnd == NULL)
9030    {
9031        return;
9032    }
9033
9034    old = GetExStyle(hWnd, id);
9035    if ((old & style) == 0)
9036    {
9037        return;
9038    }
9039
9040    SetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE, old & ~style);
9041    Refresh(DlgItem(hWnd, id));
9042}
9043
9044// ウインドウスタイルを設定する
9045void SetExStyle(HWND hWnd, UINT id, UINT style)
9046{
9047    UINT old;
9048    // 引数チェック
9049    if (hWnd == NULL)
9050    {
9051        return;
9052    }
9053
9054    old = GetExStyle(hWnd, id);
9055    if (old & style)
9056    {
9057        return;
9058    }
9059
9060    SetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE, old | style);
9061    Refresh(DlgItem(hWnd, id));
9062}
9063
9064// ウインドウスタイルを取得する
9065UINT GetExStyle(HWND hWnd, UINT id)
9066{
9067    // 引数チェック
9068    if (hWnd == NULL)
9069    {
9070        return 0;
9071    }
9072
9073    return GetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE);
9074}
9075
9076// ウインドウスタイルを削除する
9077void RemoveStyle(HWND hWnd, UINT id, UINT style)
9078{
9079    UINT old;
9080    // 引数チェック
9081    if (hWnd == NULL)
9082    {
9083        return;
9084    }
9085
9086    old = GetStyle(hWnd, id);
9087    if ((old & style) == 0)
9088    {
9089        return;
9090    }
9091
9092    SetWindowLong(DlgItem(hWnd, id), GWL_STYLE, old & ~style);
9093    Refresh(DlgItem(hWnd, id));
9094}
9095
9096// ウインドウスタイルを設定する
9097void SetStyle(HWND hWnd, UINT id, UINT style)
9098{
9099    UINT old;
9100    // 引数チェック
9101    if (hWnd == NULL)
9102    {
9103        return;
9104    }
9105
9106    old = GetStyle(hWnd, id);
9107    if (old & style)
9108    {
9109        return;
9110    }
9111
9112    SetWindowLong(DlgItem(hWnd, id), GWL_STYLE, old | style);
9113    Refresh(DlgItem(hWnd, id));
9114}
9115
9116// ウインドウスタイルを取得する
9117UINT GetStyle(HWND hWnd, UINT id)
9118{
9119    // 引数チェック
9120    if (hWnd == NULL)
9121    {
9122        return 0;
9123    }
9124
9125    return GetWindowLong(DlgItem(hWnd, id), GWL_STYLE);
9126}
9127
9128// テキストのバイト数を取得する
9129UINT GetTextSize(HWND hWnd, UINT id, bool unicode)
9130{
9131    UINT len;
9132    // 引数チェック
9133    if (hWnd == NULL)
9134    {
9135        return 0;
9136    }
9137
9138    len = GetTextLen(hWnd, id, unicode);
9139
9140    return len + (unicode ? 2 : 1);
9141}
9142
9143// テキストの文字数を取得する
9144UINT GetTextLen(HWND hWnd, UINT id, bool unicode)
9145{
9146    wchar_t *s;
9147    UINT ret;
9148    // 引数チェック
9149    if (hWnd == NULL)
9150    {
9151        return 0;
9152    }
9153
9154    s = GetText(hWnd, id);
9155    if (s == NULL)
9156    {
9157        return 0;
9158    }
9159
9160    if (unicode)
9161    {
9162        ret = UniStrLen(s);
9163    }
9164    else
9165    {
9166        char *tmp = CopyUniToStr(s);
9167        ret = StrLen(tmp);
9168        Free(tmp);
9169    }
9170
9171    Free(s);
9172
9173    return ret;
9174}
9175
9176// テキストが空白かどうかチェックする
9177bool IsEmpty(HWND hWnd, UINT id)
9178{
9179    bool ret;
9180    wchar_t *s;
9181    // 引数チェック
9182    if (hWnd == NULL)
9183    {
9184        return true;
9185    }
9186
9187    s = GetText(hWnd, id);
9188
9189    UniTrim(s);
9190    if (UniStrLen(s) == 0)
9191    {
9192        ret = true;
9193    }
9194    else
9195    {
9196        ret = false;
9197    }
9198
9199    Free(s);
9200
9201    return ret;
9202}
9203
9204// ウインドウクラスを取得する
9205wchar_t *GetClass(HWND hWnd, UINT id)
9206{
9207    wchar_t tmp[MAX_SIZE];
9208
9209    if (MsIsNt() == false)
9210    {
9211        wchar_t *ret;
9212        char *s;
9213        s = GetClassA(hWnd, id);
9214        ret = CopyStrToUni(s);
9215        Free(s);
9216        return ret;
9217    }
9218
9219    // 引数チェック
9220    if (hWnd == NULL)
9221    {
9222        return CopyUniStr(L"");
9223    }
9224
9225    GetClassNameW(DlgItem(hWnd, id), tmp, sizeof(tmp));
9226
9227    return UniCopyStr(tmp);
9228}
9229char *GetClassA(HWND hWnd, UINT id)
9230{
9231    char tmp[MAX_SIZE];
9232    // 引数チェック
9233    if (hWnd == NULL)
9234    {
9235        return CopyStr("");
9236    }
9237
9238    GetClassName(DlgItem(hWnd, id), tmp, sizeof(tmp));
9239
9240    return CopyStr(tmp);
9241}
9242
9243// コントロールにメッセージを送信する
9244UINT SendMsg(HWND hWnd, UINT id, UINT msg, WPARAM wParam, LPARAM lParam)
9245{
9246    // 引数チェック
9247    if (hWnd == NULL)
9248    {
9249        return 0;
9250    }
9251
9252    if (MsIsNt())
9253    {
9254        return (UINT)SendMessageW(DlgItem(hWnd, id), msg, wParam, lParam);
9255    }
9256    else
9257    {
9258        return (UINT)SendMessageA(DlgItem(hWnd, id), msg, wParam, lParam);
9259    }
9260}
9261
9262// EDIT のテキストをすべて選択する
9263void SelectEdit(HWND hWnd, UINT id)
9264{
9265    wchar_t *class_name;
9266
9267    // 引数チェック
9268    if (hWnd == NULL)
9269    {
9270        return;
9271    }
9272
9273    class_name = GetClass(hWnd, id);
9274
9275    if (class_name != NULL)
9276    {
9277        if (UniStrCmpi(class_name, L"edit") == 0)
9278        {
9279            SendMsg(hWnd, id, EM_SETSEL, 0, -1);
9280        }
9281        Free(class_name);
9282    }
9283}
9284
9285// EDIT のテキストの選択を解除する
9286void UnselectEdit(HWND hWnd, UINT id)
9287{
9288    wchar_t *class_name;
9289
9290    // 引数チェック
9291    if (hWnd == NULL)
9292    {
9293        return;
9294    }
9295
9296    class_name = GetClass(hWnd, id);
9297
9298    if (class_name != NULL)
9299    {
9300        if (UniStrCmpi(class_name, L"edit") == 0)
9301        {
9302            SendMsg(hWnd, id, EM_SETSEL, -1, 0);
9303        }
9304        Free(class_name);
9305    }
9306}
9307
9308// EDIT にフォーカスを設定してすべて選択する
9309void FocusEx(HWND hWnd, UINT id)
9310{
9311    // 引数チェック
9312    if (hWnd == NULL)
9313    {
9314        return;
9315    }
9316
9317    if (IsEnable(hWnd, id) == false || IsShow(hWnd, id) == false)
9318    {
9319        return;
9320    }
9321
9322    SelectEdit(hWnd, id);
9323
9324    Focus(hWnd, id);
9325}
9326
9327// 指定したウインドウがフォーカスを持っているかどうか取得する
9328bool IsFocus(HWND hWnd, UINT id)
9329{
9330    // 引数チェック
9331    if (hWnd == NULL)
9332    {
9333        return false;
9334    }
9335
9336    if (GetFocus() == DlgItem(hWnd, id))
9337    {
9338        return true;
9339    }
9340
9341    return false;
9342}
9343
9344// フォーカスを設定する
9345void Focus(HWND hWnd, UINT id)
9346{
9347    // 引数チェック
9348    if (hWnd == NULL)
9349    {
9350        return;
9351    }
9352
9353    if (IsEnable(hWnd, id) == false || IsShow(hWnd, id) == false)
9354    {
9355        return;
9356    }
9357
9358    SetFocus(DlgItem(hWnd, id));
9359}
9360
9361// int 型の値を設定する
9362void SetInt(HWND hWnd, UINT id, UINT value)
9363{
9364    wchar_t tmp[MAX_SIZE];
9365    // 引数チェック
9366    if (hWnd == NULL)
9367    {
9368        return;
9369    }
9370
9371    UniToStru(tmp, value);
9372    SetText(hWnd, id, tmp);
9373}
9374void SetIntEx(HWND hWnd, UINT id, UINT value)
9375{
9376    // 引数チェック
9377    if (hWnd == NULL)
9378    {
9379        return;
9380    }
9381
9382    if (value == 0)
9383    {
9384        // 0 の場合は空欄にする
9385        SetText(hWnd, id, L"");
9386    }
9387    else
9388    {
9389        SetInt(hWnd, id, value);
9390    }
9391}
9392
9393// int 型の値を取得する
9394UINT GetInt(HWND hWnd, UINT id)
9395{
9396    wchar_t *s;
9397    UINT ret;
9398    // 引数チェック
9399    if (hWnd == NULL)
9400    {
9401        return 0;
9402    }
9403
9404    s = GetText(hWnd, id);
9405    if (s == NULL)
9406    {
9407        return 0;
9408    }
9409
9410    ret = UniToInt(s);
9411    Free(s);
9412
9413    return ret;
9414}
9415
9416// ウインドウ表示を更新する
9417void Refresh(HWND hWnd)
9418{
9419    HWND parent;
9420    // 引数チェック
9421    if (hWnd == NULL)
9422    {
9423        return;
9424    }
9425
9426    DoEvents(hWnd);
9427    UpdateWindow(hWnd);
9428    DoEvents(hWnd);
9429
9430    parent = GetParent(hWnd);
9431    if (parent != NULL)
9432    {
9433        Refresh(parent);
9434    }
9435}
9436
9437// イベントを処理する
9438void DoEvents(HWND hWnd)
9439{
9440    MSG msg;
9441
9442    if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
9443    {
9444        TranslateMessage(&msg);
9445        DispatchMessage(&msg);
9446    }
9447    UpdateWindow(hWnd);
9448
9449    if (hWnd)
9450    {
9451        DoEvents(NULL);
9452    }
9453}
9454
9455// ウインドウを閉じる
9456void Close(HWND hWnd)
9457{
9458    // 引数チェック
9459    if (hWnd == NULL)
9460    {
9461        return;
9462    }
9463
9464    SendMessage(hWnd, WM_CLOSE, 0, 0);
9465}
9466
9467// ウインドウを無効にする
9468void Disable(HWND hWnd, UINT id)
9469{
9470    SetEnable(hWnd, id, false);
9471}
9472
9473// ウインドウを有効にする
9474void Enable(HWND hWnd, UINT id)
9475{
9476    SetEnable(hWnd, id, true);
9477}
9478
9479// ウインドウの有効状態を設定する
9480void SetEnable(HWND hWnd, UINT id, bool b)
9481{
9482    // 引数チェック
9483    if (hWnd == NULL)
9484    {
9485        return;
9486    }
9487
9488    if (b == false)
9489    {
9490        if (IsEnable(hWnd, id))
9491        {
9492            if (id != 0 && IsFocus(hWnd, id))
9493            {
9494                Focus(hWnd, IDCANCEL);
9495                Focus(hWnd, IDOK);
9496            }
9497            EnableWindow(DlgItem(hWnd, id), false);
9498            Refresh(DlgItem(hWnd, id));
9499        }
9500    }
9501    else
9502    {
9503        if (IsDisable(hWnd, id))
9504        {
9505            EnableWindow(DlgItem(hWnd, id), true);
9506            Refresh(DlgItem(hWnd, id));
9507        }
9508    }
9509}
9510
9511// ウインドウが無効かどうか調べる
9512bool IsDisable(HWND hWnd, UINT id)
9513{
9514    return IsEnable(hWnd, id) ? false : true;
9515}
9516
9517// ウインドウが有効かどうか調べる
9518bool IsEnable(HWND hWnd, UINT id)
9519{
9520    // 引数チェック
9521    if (hWnd == NULL)
9522    {
9523        return false;
9524    }
9525
9526    return IsWindowEnabled(DlgItem(hWnd, id));
9527}
9528
9529static LOCK *winui_debug_lock = NULL;
9530
9531// デバッグの初期化
9532void WinUiDebugInit()
9533{
9534    winui_debug_lock = NewLock();
9535}
9536
9537// デバッグの解放
9538void WinUiDebugFree()
9539{
9540    DeleteLock(winui_debug_lock);
9541}
9542
9543// デバッグファイルに文字列を書き込む
9544void WinUiDebug(wchar_t *str)
9545{
9546    wchar_t tmp[1024];
9547    char dtstr[256];
9548    char *buf;
9549    wchar_t exename[MAX_PATH];
9550    UINT tid;
9551    // 引数チェック
9552    if (str == NULL)
9553    {
9554        return;
9555    }
9556
9557    tid = GetCurrentThreadId();
9558
9559    GetExeNameW(exename, sizeof(exename));
9560    GetFileNameFromFilePathW(exename, sizeof(exename), exename);
9561
9562    GetDateTimeStrMilli64(dtstr, sizeof(dtstr), LocalTime64());
9563
9564    UniFormat(tmp, sizeof(tmp), L"[%S] (%s:%u) %s\r\n", dtstr, exename, tid, str);
9565
9566    buf = CopyUniToUtf(tmp);
9567
9568    Lock(winui_debug_lock);
9569    {
9570        IO *o = FileOpenEx(WINUI_DEBUG_TEXT, true, true);
9571        if (o == NULL)
9572        {
9573            o = FileCreate(WINUI_DEBUG_TEXT);
9574        }
9575
9576        if (o != NULL)
9577        {
9578            UINT size = FileSize(o);
9579
9580            FileSeek(o, FILE_BEGIN, size);
9581
9582            FileWrite(o, buf, StrLen(buf));
9583            FileFlush(o);
9584
9585            FileClose(o);
9586        }
9587    }
9588    Unlock(winui_debug_lock);
9589
9590    Free(buf);
9591}
9592
9593
9594// テキスト文字列の設定
9595void SetText(HWND hWnd, UINT id, wchar_t *str)
9596{
9597    // 引数チェック
9598    if (hWnd == NULL || str == NULL)
9599    {
9600        return;
9601    }
9602
9603    SetTextInner(hWnd, id, str);
9604}
9605void SetTextInner(HWND hWnd, UINT id, wchar_t *str)
9606{
9607    wchar_t *old;
9608    // 引数チェック
9609    if (hWnd == NULL || str == NULL)
9610    {
9611        return;
9612    }
9613
9614    // 古い文字列を取得
9615    old = GetText(hWnd, id);
9616    if (UniStrCmp(str, old) == 0)
9617    {
9618        // 同一
9619        Free(old);
9620        return;
9621    }
9622
9623    Free(old);
9624
9625    if (MsIsNt())
9626    {
9627        SetWindowTextW(DlgItem(hWnd, id), str);
9628    }
9629    else
9630    {
9631        char *tmp = CopyUniToStr(str);
9632
9633        if (MsIsNt() == false && StrLen(tmp) >= 32000)
9634        {
9635            // 32k 以下にきりつめる
9636            tmp[32000] = 0;
9637        }
9638
9639        SetWindowTextA(DlgItem(hWnd, id), tmp);
9640        Free(tmp);
9641    }
9642
9643    if (id != 0)
9644    {
9645        Refresh(DlgItem(hWnd, id));
9646    }
9647}
9648void SetTextA(HWND hWnd, UINT id, char *str)
9649{
9650    wchar_t *s;
9651    // 引数チェック
9652    if (hWnd == NULL || str == NULL)
9653    {
9654        return;
9655    }
9656
9657    s = CopyStrToUni(str);
9658    if (s == NULL)
9659    {
9660        return;
9661    }
9662
9663    SetText(hWnd, id, s);
9664
9665    Free(s);
9666}
9667
9668// テキスト文字列をバッファへ取得
9669bool GetTxt(HWND hWnd, UINT id, wchar_t *str, UINT size)
9670{
9671    wchar_t *s;
9672    // 引数チェック
9673    if (hWnd == NULL || str == NULL)
9674    {
9675        return false;
9676    }
9677
9678    s = GetText(hWnd, id);
9679    if (s == NULL)
9680    {
9681        UniStrCpy(str, size, L"");
9682        return false;
9683    }
9684
9685    UniStrCpy(str, size, s);
9686    Free(s);
9687
9688    return true;
9689}
9690bool GetTxtA(HWND hWnd, UINT id, char *str, UINT size)
9691{
9692    char *s;
9693    // 引数チェック
9694    if (hWnd == NULL || str == NULL)
9695    {
9696        return false;
9697    }
9698
9699    s = GetTextA(hWnd, id);
9700    if (s == NULL)
9701    {
9702        StrCpy(str, size, "");
9703        return false;
9704    }
9705
9706    StrCpy(str, size, s);
9707    Free(s);
9708
9709    return true;
9710}
9711
9712// テキスト文字列の取得
9713wchar_t *GetText(HWND hWnd, UINT id)
9714{
9715    wchar_t *ret;
9716    UINT size, len;
9717    // 引数チェック
9718    if (hWnd == NULL)
9719    {
9720        return NULL;
9721    }
9722
9723    if (MsIsNt() == false)
9724    {
9725        char *s = GetTextA(hWnd, id);
9726        ret = CopyStrToUni(s);
9727        Free(s);
9728
9729        return ret;
9730    }
9731
9732    len = GetWindowTextLengthW(DlgItem(hWnd, id));
9733    if (len == 0)
9734    {
9735        return CopyUniStr(L"");
9736    }
9737
9738    size = (len + 1) * 2;
9739    ret = ZeroMallocEx(size, true);
9740
9741    GetWindowTextW(DlgItem(hWnd, id), ret, size);
9742
9743    return ret;
9744}
9745char *GetTextA(HWND hWnd, UINT id)
9746{
9747    char *ret;
9748    UINT size, len;
9749    // 引数チェック
9750    if (hWnd == NULL)
9751    {
9752        return NULL;
9753    }
9754
9755    len = GetWindowTextLengthA(DlgItem(hWnd, id));
9756    if (len == 0)
9757    {
9758        return CopyStr("");
9759    }
9760
9761    size = len + 1;
9762    ret = ZeroMallocEx(size, true);
9763
9764    GetWindowTextA(DlgItem(hWnd, id), ret, size);
9765
9766    return ret;
9767}
9768
9769// ダイアログ内のアイテムの取得
9770HWND DlgItem(HWND hWnd, UINT id)
9771{
9772    // 引数チェック
9773    if (hWnd == NULL)
9774    {
9775        return NULL;
9776    }
9777
9778    if (id == 0)
9779    {
9780        return hWnd;
9781    }
9782    else
9783    {
9784        return GetDlgItem(hWnd, id);
9785    }
9786}
9787
9788// タイトルの設定
9789void SetWinUiTitle(wchar_t *title)
9790{
9791    // 引数チェック
9792    if (title == NULL)
9793    {
9794        return;
9795    }
9796
9797    Free(title_bar);
9798    title_bar = CopyUniStr(title);
9799}
9800
9801// WinUi の初期化
9802void InitWinUi(wchar_t *software_name, char *font, UINT fontsize)
9803{
9804    if ((init_winui_counter++) != 0)
9805    {
9806        return;
9807    }
9808
9809    if (hDll != NULL)
9810    {
9811        return;
9812    }
9813
9814    WinUiDebugInit();
9815
9816    if (MayaquaIsMinimalMode() == false)
9817    {
9818        if (Is64())
9819        {
9820            hDll = MsLoadLibraryAsDataFile(MsGetPenCoreDllFileName());
9821        }
9822        else
9823        {
9824            hDll = MsLoadLibrary(MsGetPenCoreDllFileName());
9825        }
9826
9827        if (hDll == NULL)
9828        {
9829            Alert(PENCORE_DLL_NAME " not found. SoftEther UT-VPN couldn't start.\r\n\r\n"
9830                "Please reinstall all files with SoftEther UT-VPN Installer.",
9831                NULL);
9832            exit(0);
9833        }
9834    }
9835    else
9836    {
9837        hDll = LoadLibrary(MsGetExeFileName());
9838
9839        if (hDll == NULL)
9840        {
9841            Alert("MsLoadLibrary() Error.",
9842                NULL);
9843            exit(0);
9844        }
9845    }
9846
9847    if (software_name != NULL)
9848    {
9849        title_bar = CopyUniStr(software_name);
9850    }
9851    else
9852    {
9853        title_bar = CopyUniStr(L"SoftEther UT-VPN");
9854    }
9855
9856    if (font != NULL)
9857    {
9858        font_name = CopyStr(font);
9859    }
9860    else
9861    {
9862        font_name = CopyStr(_SS("DEFAULT_FONT"));
9863    }
9864
9865    if (fontsize != 0)
9866    {
9867        font_size = fontsize;
9868    }
9869    else
9870    {
9871        font_size = _II("DEFAULT_FONT_SIZE");
9872        if (font_size == 0)
9873        {
9874            font_size = 9;
9875        }
9876    }
9877
9878    InitIconCache();
9879
9880    InitFont();
9881
9882    InitImageList();
9883
9884    InitGdiCache();
9885
9886    EnableNewStyleMode();
9887}
9888
9889// WinUi の解放
9890void FreeWinUi()
9891{
9892    if ((--init_winui_counter) != 0)
9893    {
9894        return;
9895    }
9896
9897    if (hDll == NULL)
9898    {
9899        return;
9900    }
9901
9902    FreeImageList();
9903
9904    FreeFont();
9905
9906    FreeIconCache();
9907
9908    FreeLibrary(hDll);
9909    hDll = NULL;
9910
9911    Free(title_bar);
9912    title_bar = NULL;
9913
9914    Free(font_name);
9915    font_name = NULL;
9916
9917    WinUiDebugFree();
9918}
9919
9920#endif  // WIN32
Note: See TracBrowser for help on using the repository browser.