Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

(시리즈 글이 21개 있습니다.)
Windows: 226. Win32 C/C++ - Dialog에서 값을 반환하는 방법
; https://www.sysnet.pe.kr/2/0/13284

Windows: 227. Win32 C/C++ - Dialog Procedure를 재정의하는 방법
; https://www.sysnet.pe.kr/2/0/13285

Windows: 228. Win32 - 리소스에 포함된 대화창 Template의 2진 코드 해석 방법
; https://www.sysnet.pe.kr/2/0/13286

Windows: 229. Win32 - 대화창 템플릿의 2진 리소스를 읽어들여 윈도우를 직접 띄우는 방법
; https://www.sysnet.pe.kr/2/0/13287

Windows: 230. Win32 - 대화창의 DLU 단위를 pixel로 변경하는 방법
; https://www.sysnet.pe.kr/2/0/13288

Windows: 231. Win32 - 대화창 템플릿의 2진 리소스를 읽어들여 자식 윈도우를 생성하는 방법
; https://www.sysnet.pe.kr/2/0/13289

Windows: 232. C/C++ - 일반 창에도 사용 가능한 IsDialogMessage
; https://www.sysnet.pe.kr/2/0/13292

Windows: 233.  Win32 - modeless 대화창을 modal처럼 동작하게 만드는 방법
; https://www.sysnet.pe.kr/2/0/13295

Windows: 234. IsDialogMessage와 협업하는 WM_GETDLGCODE Win32 메시지
; https://www.sysnet.pe.kr/2/0/13296

Windows: 235. Win32 - Code Modal과 UI Modal
; https://www.sysnet.pe.kr/2/0/13297

Windows: 237. Win32 - 모든 메시지 루프를 탈출하는 WM_QUIT 메시지
; https://www.sysnet.pe.kr/2/0/13299

Windows: 238. Win32 - Modal UI 창에 올바른 Owner(HWND)를 설정해야 하는 이유
; https://www.sysnet.pe.kr/2/0/13300

Windows: 242. Win32 - 시간 만료를 갖는 MessageBox 대화창 구현 (쉬운 버전)
; https://www.sysnet.pe.kr/2/0/13305

Windows: 243. Win32 - 윈도우(cbWndExtra) 및 윈도우 클래스(cbClsExtra) 저장소 사용 방법
; https://www.sysnet.pe.kr/2/0/13306

Windows: 244. Win32 - 시간 만료를 갖는 MessageBox 대화창 구현 (개선된 버전)
; https://www.sysnet.pe.kr/2/0/13312

Windows: 245. Win32 - 시간 만료를 갖는 컨텍스트 메뉴와 윈도우 메시지의 영역별 정의
; https://www.sysnet.pe.kr/2/0/13315

Windows: 246. Win32 C/C++ - 직접 띄운 대화창 템플릿을 위한 Modal 메시지 루프 생성
; https://www.sysnet.pe.kr/2/0/13329

Windows: 247. Win32 C/C++ - CS_GLOBALCLASS 설명
; https://www.sysnet.pe.kr/2/0/13330

Windows: 248. Win32 C/C++ - 대화창을 위한 메시지 루프 사용자 정의
; https://www.sysnet.pe.kr/2/0/13332

Windows: 249. Win32 C/C++ - 대화창 템플릿을 런타임에 코딩해서 사용
; https://www.sysnet.pe.kr/2/0/13333

Windows: 250. Win32 C/C++ - Modal 메시지 루프 내에서 SetWindowsHookEx를 이용한 Thread 메시지 처리 방법
; https://www.sysnet.pe.kr/2/0/13334




Win32 - 리소스에 포함된 대화창 Template의 2진 코드 해석 방법

이번에는 다음의 글로 시작하는 시리즈 6개를 제 맘대로 정리해 봤습니다. ^^

The evolution of dialog templates – Introduction
; https://devblogs.microsoft.com/oldnewthing/20040617-00/?p=38833




비주얼 스튜디오로 기본 생성한 C/C++ 윈도우 프로젝트를 보면 텍스트 형식의 RC 파일이 하나 들어 있고, 그 안에 IDD_ABOUTBOX 대화창으로 식별되는 텍스트가 추가돼 있습니다.

IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About Project1"
FONT 8, "MS Shell Dlg"
BEGIN
    ICON            IDR_MAINFRAME,IDC_STATIC,14,14,21,20
    LTEXT           "Project1, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX
    LTEXT           "Copyright (c) 2023",IDC_STATIC,42,26,114,8
    DEFPUSHBUTTON   "OK",IDOK,113,41,50,14,WS_GROUP
END

C# 세대에게 설명하자면, "폼 디자이너"의 초기 모델이라고 보면 될 듯합니다. ^^ 실제로 Visual studio는 위의 대화창 템플릿을 읽어들여 다음과 같이 디자인 창을 띄워 사용자가 컨트롤을 쉽게 추가/삭제/배치할 수 있도록 돕습니다.

dialog_template_part1_1.png

단지 C# Windows Forms 프로젝트의 경우에는 디자인 창의 내용을 C# 코드로 직렬화하는 반면, 위의 dialog template 파일은 Win32 리소스 문법에 따라 직렬화한다는 차이가 있는 정도입니다.

실제로 여러분은 Resource Compiler(rc.exe)를 이용해 위의 dialog template만을 담은 파일을 컴파일할 수 있습니다. 이를 위해 필요한 include와 상수를 정의하고,

#include "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\Windows.h"

#define IDD_ABOUTBOX              103
#define IDR_MAINFRAME			128
#ifndef IDC_STATIC
#define IDC_STATIC				-1
#endif

IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About Project1"
FONT 8, "MS Shell Dlg"
BEGIN
    ICON            IDR_MAINFRAME,IDC_STATIC,14,14,21,20
    LTEXT           "Project1, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX
    LTEXT           "Copyright (c) 2023",IDC_STATIC,42,26,114,8
    DEFPUSHBUTTON   "OK",IDOK,113,41,50,14,WS_GROUP
END

Visual Studio 명령행 창에서 다음과 같이 명령을 내리면 됩니다.

c:\temp> rc test.rc
Microsoft (R) Windows (R) Resource Compiler Version 10.0.10011.16384
Copyright (C) Microsoft Corporation.  All rights reserved.

그럼, 결과 파일로 res 확장자를 가진 이진 파일이 생성됩니다.

00 00 00 00 20 00 00 00 FF FF 00 00 FF FF 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
34 01 00 00 20 00 00 00 FF FF 05 00 FF FF 67 00 
00 00 00 00 30 10 09 04 00 00 00 00 00 00 00 00 
01 00 FF FF 00 00 00 00 00 00 00 00 C8 00 C8 80 
04 00 00 00 00 00 AA 00 3E 00 00 00 00 00 41 00 
62 00 6F 00 75 00 74 00 20 00 50 00 72 00 6F 00 
6A 00 65 00 63 00 74 00 31 00 00 00 08 00 00 00 
...[생략]...
29 00 20 00 32 00 30 00 32 00 33 00 00 00 00 00 
00 00 00 00 00 00 00 00 01 00 03 50 71 00 29 00 
32 00 0E 00 01 00 00 00 FF FF 80 00 4F 00 4B 00 
00 00 00 00

비주얼 스튜디오로 C/C++ Windows 응용 프로그램을 빌드하면 저 res 2진 파일을 EXE/DLL 바이너리에 추가합니다. 그리고 다시 코드에서는 저 내용 중 원하는 대화상자, 이번 글에서는 IDD_ABOUTBOX 식별자로 구분되는 리소스의 내용을 이렇게 추출할 수 있습니다.

HRSRC hrsrc = ::FindResource(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), RT_DIALOG);
HGLOBAL hglobal = ::LoadResource(hInst, hrsrc);
LPVOID lpv = ::LockResource(hglobal);
DWORD resSize = SizeofResource(hInst, hrsrc);

BYTE* pBuffer = (BYTE*)lpv;
wchar_t buffer[1024] = { 0 };

for (int i = 1; i <= resSize; i++)
{
    wsprintf(buffer, L"%02X ", pBuffer[i - 1]);
    OutputDebugString(buffer);
                        
    if (i % 16 == 0)
    {
        OutputDebugString(L"\n");
    }
}
                    
::FreeResource(hglobal);

출력 내용은 우리가 컴파일했던 test.res의 5번째 줄부터 해당하는 바이트가 동일하게 나옵니다.

01 00 FF FF 00 00 00 00 00 00 00 00 C8 00 C8 80 
04 00 00 00 00 00 AA 00 3E 00 00 00 00 00 41 00 
62 00 6F 00 75 00 74 00 20 00 50 00 72 00 6F 00 
6A 00 65 00 63 00 74 00 31 00 00 00 08 00 00 00 
00 01 4D 00 53 00 20 00 53 00 68 00 65 00 6C 00 
6C 00 20 00 44 00 6C 00 67 00 00 00 00 00 00 00 
00 00 00 00 03 00 00 50 0E 00 0E 00 15 00 14 00 
FF FF FF FF FF FF 82 00 FF FF 80 00 00 00 00 00 
00 00 00 00 00 00 00 00 80 00 02 50 2A 00 0E 00 
72 00 08 00 FF FF FF FF FF FF 82 00 50 00 72 00 
6F 00 6A 00 65 00 63 00 74 00 31 00 2C 00 20 00 
56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 20 00 
31 00 2E 00 30 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 02 50 2A 00 1A 00 72 00 08 00 
FF FF FF FF FF FF 82 00 43 00 6F 00 70 00 79 00 
72 00 69 00 67 00 68 00 74 00 20 00 28 00 63 00 
29 00 20 00 32 00 30 00 32 00 33 00 00 00 00 00 
00 00 00 00 00 00 00 00 01 00 03 50 71 00 29 00 
32 00 0E 00 01 00 00 00 FF FF 80 00 4F 00 4B 00 
00 00 00 00 

그리고 위의 2진 파일의 내용을 해석하는 방법을 시리즈의 2~5번째 글에서 소개합니다.

The evolution of dialog templates – 16-bit Classic Templates
; https://devblogs.microsoft.com/oldnewthing/20040618-00/?p=38803

The evolution of dialog templates – 16-bit Extended Templates
; https://devblogs.microsoft.com/oldnewthing/20040622-00/?p=38773

The evolution of dialog templates – 32-bit Classic Templates
; https://devblogs.microsoft.com/oldnewthing/20040621-00/?p=38793

The evolution of dialog templates – 32-bit Extended Templates
; https://devblogs.microsoft.com/oldnewthing/20040623-00/?p=38753

버전별로 4개의 dialog template이 제공되는데 이 관계를 아래의 그림에서 잘 나타내고 있습니다.

dialog_template_part1_2.png

16비트 포맷에 해당하는 DIALOG는 Windows 1.0 시절에, 16비트 DIALOGEX는 Windows 95와 후속 버전만 지원합니다. 그리고 각각의 버전이 다시 32비트 포맷으로 포팅됐습니다. 아주 오래된 프로그램이 아니라면 현재 32-bit DIALOGEX 이외의 형식은 구경조차 힘들 것입니다.

따라서, 예전 버전의 해석 방식은 각각 "The evolution of dialog templates – 16-bit Classic Templates", "The evolution of dialog templates – 16-bit Extended Templates", "The evolution of dialog templates – 32-bit Classic Templates" 글에서 설명하고 있으니 참고하시고, 이번 글에서는 위의 예제로 나온 바이너리를 해석해야 하므로 "32-bit Extended Templates"을 기준으로 설명합니다.




대화창의 헤더(32-bit extended header)는 다음과 같은 구조체로 시작한다고 합니다.

WORD  wDlgVer;      // version number - always 1
WORD  wSignature;   // always 0xFFFF
DWORD dwHelpID;     // help ID
DWORD dwExStyle;    // window extended style

DWORD dwStyle;      // dialog style
WORD  cItems;       // number of controls in this dialog, 즉 대화창 1개에 65,535개까지의 컨트롤을 담을 수 있음
WORD  x;            // x-coordinate
WORD  y;            // y-coordinate
WORD  cx;           // width
WORD  cy;           // height

이 글의 예제에서 사용한 리소스의 경우에는 각각 다음과 같은 정보로 연결될 수 있고,

wDlgVer == 1
wSignature == 0xffff
dwHelpID == 0
dwExStyle == 0

dwStyle == DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
        == 2160591048 == 80 C8 00 C8
cItems == BEGIN/END 사이의 컨트롤 수 == ICON/LTEXT/LTEXT/DEFPUSHBUTTON 총 4개
x == 0 
y == 0
cx == 170 (0xaa)
cy == 62 (0x3e)

실제로 위의 바이트를 LockResource로 구한 바이트 배열에서 찾을 수 있습니다.

01 00 FF FF 00 00 00 00 00 00 00 00 C8 00 C8 80
04 00 : 컨트롤 수
00 00 : x
00 00 : y
AA 00 : cx
3E 00 : cy

그다음은 3개의 문자열 정보가 나오는데,

00 00: menu name 문자열 또는 ordinal
00 00: class name 문자열
41 00 62 00 6F 00 75 00 74 00 20 00 50 00 72 00 6F 00 6A 00 65 00 63 00 74 00 31 00 00 00: CAPTION 문자열 "About Project1"

해당 값이 문자열(위의 경우 "About Project1")인 경우라면 UNICODE 값과 함께 끝을 알리는 null 문자(\0\0)가 나옵니다. 반면 ordinal로 표현된다면 0xff, 0x00이 먼저 나오고 이어서 ordinal 2바이트가 나온다고 합니다. 예를 들어 위에서 menu name의 ordinal 값이 "2A 00"이라면 다음의 4바이트가 기록되는 것입니다.

FF 00 2A 00 

어쨌든 위의 예제에서는 menu와 class name에 할당된 문자열이 없기 때문에 널 종료 문자(\0\0)만이 있습니다. (참고로 대화창의 class name 지정은 지난 예제에서 설명한 적이 있습니다.)




그다음은 가변 항목이 나오는데요, 대화창의 STYLE에,

STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About Project1"
FONT 8, "MS Shell Dlg"

위와 같이 DS_SETFONT가 설정돼 있다면 함께 명시한 FONT 정보가 나온다고 합니다.

WORD wPoint;        // point size
WORD wWeight;       // font weight
BYTE bItalic;       // 1 if italic, 0 if not
BYTE bCharSet;      // character set
WCHAR szFontName[]; // variable-length

08 00: point size
00 00: font weight (0x0000 == FW_DONTCARE)
00: 1 if italic, 0 if not
01: character set, 0x01 = DEFAULT_CHARSET
4D 00 53 00 20 00 53 00 68 00 65 00 6C 00 6C 00 20 00 44 00 6C 00 67 00 00 00: "MS Shell Dlg" (널 종료 문자 포함)

자, 그다음부터는 이제 cItems에 지정한 컨트롤의 수만큼 다음의 정보들이 DWORD(4바이트) 정렬로 나열됩니다.

DWORD dwHelpID;     // help identifier
DWORD dwExStyle;    // window extended style
DWORD dwStyle;      // window style
WORD  x;            // x-coordinate (DLUs)
WORD  y;            // y-coordinate (DLUs)
WORD  cx;           // width (DLUs)
WORD  cy;           // height (DLUs)
DWORD dwID;         // control ID, 32비트 값이긴 하지만 WM_COMMAND 등의 메시지에서는 여전히 16비트 값으로 다루기 때문에 사실상 16비트만 사용 가능

WCHAR szClassName[];// variable-length (possibly ordinal)
WCHAR szText[];     // variable-length (possibly ordinal)
WORD  cbExtra;      // amount of extra data
BYTE  rgbExtra[cbExtra]; // extra data follows (usually none)

szClassName, szText, rgbExtra 때문에 크기가 가변적이므로 고정 레코드로 읽어들일 수 없다는 점이 귀찮군요. 그래도 4개밖에 없으니 ^^ 아래와 같이 정리해 봤습니다.

00 00 00 00: dwHelpID
00 00 00 00: dwExStyle
03 00 00 50: window style, 0x50000003, 아마도 WS_CHILD(0x40000000) | WS_VISIBLE(0x10000000) | SS_ICON (0x03)
0E 00: x (14)
0E 00: y (14)
15 00: cx (21)
14 00: cy (20)
FF FF FF FF: control ID (-1)
FF FF 82 00: szClass == ordinal 0x0082 == static
FF FF 80 00: szText == ordinal 0x0080
00 00: cbExtra
00 00: 위의 cbExtra가 0이므로 이후 rgbExtra 바이트 배열이 아님. 4바이트 정렬이므로 padding 바이트 

00 00 00 00: dwHelpID
00 00 00 00: dwExStyle
80 00 02 50: window style, 0x50020080, 아마도 WS_GROUP(0x020000) | WS_CHILD(0x40000000) | WS_VISIBLE(0x10000000) | SS_NOPREFIX(0x80)
2A 00: x (42)
0E 00: y (14)
72 00: cx (114)
08 00: cy (8)
FF FF FF FF: control ID (-1)
FF FF 82 00: szClass == ordinal 0x0082 == static
50 00 72 00 6F 00 6A 00 65 00 63 00 74 00 31 00 2C 00 20 00 56 00 65 00 72 00 73 00 69 00 6F 00 6E 00 20 00 31 00 2E 00 30 00 00 00: "Project1, Version 1.0" 문자열
00 00: cbExtra
00 00: 위의 cbExtra가 0이므로 이후 rgbExtra 바이트 배열이 아님. 4바이트 정렬이므로 padding 바이트 

00 00 00 00: dwHelpID 
00 00 00 00: dwExStyle
00 00 02 50: window style, 0x50020000, 아마도 WS_GROUP(0x020000) | WS_CHILD(0x40000000) | WS_VISIBLE(0x10000000)
2A 00: x (42)
1A 00: y (26)
72 00: cx (114)
08 00: cy (8)
FF FF FF FF: control ID (-1)
FF FF 82 00: szClass == ordinal 0x0082 == static
43 00 6F 00 70 00 79 00 72 00 69 00 67 00 68 00 74 00 20 00 28 00 63 00 29 00 20 00 32 00 30 00 32 00 33 00 00 00: "Copyright (c) 2023"
00 00: cbExtra

00 00 00 00: dwHelpID 
00 00 00 00: dwExStyle
01 00 03 50: window style, 0x50030001, 아마도 WS_GROUP(0x020000) | WS_TABSTOP(0x010000) | WS_CHILD(0x40000000) | WS_VISIBLE(0x10000000) | BS_DEFPUSHBUTTON(0x01)
71 00: x (113)
29 00: y (41)
32 00: cx (50)
0E 00: cy (14)
01 00 00 00: control ID == IDOK(0x01)
FF FF 80 00: szClass == ordinal 0x0080 == button
4F 00 4B 00: "OK"
00 00: cbExtra
00 00: 위의 cbExtra가 0이므로 이후 rgbExtra 바이트 배열이 아님. 4바이트 정렬이므로 padding 바이트 

그러니까 결국, DialogBox 등의 함수들은 res로 컴파일된 바이너리에서 리소스 ID에 해당하는 대화창 정보를 위와 같은 포맷에 따라 해석해 CreateWindow로 보여주는 것입니다. 좀 ^^ 대단하지 않나요?

게다가... 이런 작업들이 Windows 1.0 시절부터 Win32 API와 그에 따른 Visual C++ 초기 IDE 도구가 협업해 대화창에 대한 Form 디자이너를 제공하고 있었다는 것은 매우 혁신적인 아이디어가 아니었을까 싶습니다. 제가 리눅스는 잘 몰라서 확실히 언급할 수는 없지만 아마 제대로 된 폼 디자이너를 아직도 갖추지 못한 것에 비하면 1985년에 이런 생각을 했다는 것에 놀랍기까지 합니다.




이렇게 해서 olenewthing의 6개 글 중 5개를 정리했습니다. 나머지 하나는,

The evolution of dialog templates – Summary
; https://devblogs.microsoft.com/oldnewthing/20040624-00/?p=38733

총정리를 다음의 표 하나로 제시하고 있습니다.

dialog_template_part1_3.png

즉, 4개의 DIALOG Template 버전이 있지만 16비트/32비트에 대한 차이와 약간의 필드 추가 등을 제외하면 거의 비슷합니다.




약간의 첨언을 하자면.

대화창에 포함할 수 있는 컨트롤의 수가 WORD 2바이트로 제한이 되는데요, 사실 이건 제약이라고 볼 수 없습니다. 왜냐하면,

Why is the limit of window handles per process 10,000?
; https://devblogs.microsoft.com/oldnewthing/20070718-00/?p=25963

프로세스 하나가 생성할 수 있는 User Object가 10,000개로 제한이 되기 때문에 Dialog Template의 제약은 오히려 현재로서는 가능성이 없는 수준입니다.

또한, 위에서 설명한 dialog 포맷에 해당하는 구조체가 winuser.h 헤더 파일에 정의돼 있는데,

DLGTEMPLATE structure (winuser.h)
; https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-dlgtemplate

/*
 * original NT 32 bit dialog template:
 */
typedef struct {
    DWORD style;
    DWORD dwExtendedStyle;
    WORD cdit;
    short x;
    short y;
    short cx;
    short cy;
} DLGTEMPLATE;

DLGITEMTEMPLATE structure (winuser.h)
; https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-dlgitemtemplate

/*
 * 32 bit Dialog item template.
 */
typedef struct {
    DWORD style;
    DWORD dwExtendedStyle;
    short x;
    short y;
    short cx;
    short cy;
    WORD id;
} DLGITEMTEMPLATE;

아쉽게도 이 글에서 설명한 "32-bit Extended Templates" 유형이 아닌 "32-bit Classic Templates"에 해당하니 유의할 필요가 있습니다.

마지막으로, 본문에서 컨트롤들의 클래스에 대한 ordinal id를 설명 없이 언급했지만, 기본적인 컨트롤은 다음의 내용으로 문서에 나와 있습니다.

0x0080  Button
0x0081  Edit
0x0082  Static
0x0083  List box
0x0084  Scroll bar
0x0085  Combo box




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 10/26/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13645정성태6/13/2024447개발 환경 구성: 711. Visual Studio로 개발 시 기본 등록하는 dev tag 이미지로 Docker Desktop k8s에서 실행하는 방법
13644정성태6/12/2024488닷넷: 2265. C# - System.Text.Json의 기본적인 (한글 등에서의) escape 처리
13643정성태6/12/2024459오류 유형: 907. MySqlConnector 사용 시 System.IO.FileLoadException 오류
13642정성태6/11/2024492스크립트: 65. 파이썬 - asgi 버전(2, 3)에 따라 달라지는 uvicorn 호스팅
13641정성태6/11/2024494Linux: 71. Ubuntu 20.04를 22.04로 업데이트
13640정성태6/10/2024678Phone: 21. C# MAUI - Android 환경에서의 파일 다운로드(DownloadManager)
13639정성태6/8/2024719오류 유형: 906. C# MAUI - Android Emulator에서 "Waiting For Debugger"로 무한 대기
13638정성태6/8/2024865오류 유형: 905. C# MAUI - 추가한 layout XML 파일이 Resource.Layout 멤버로 나오지 않는 문제
13637정성태6/6/20241024Phone: 20. C# MAUI - 유튜브 동영상을 MediaElement로 재생하는 방법
13636정성태5/30/20241078닷넷: 2264. C# - 형식 인자로 인터페이스를 갖는 제네릭 타입으로의 형변환파일 다운로드1
13635정성태5/29/2024909Phone: 19. C# MAUI - 안드로이드 "Share" 대상으로 등록하는 방법
13634정성태5/24/20241175Phone: 18. C# MAUI - 안드로이드 플랫폼에서의 Activity 제어
13633정성태5/22/20241115스크립트: 64. 파이썬 - ASGI를 만족하는 최소한의 구현 코드
13632정성태5/20/20241229Phone: 17. C# MAUI - Android 내에 Web 서비스 호스팅
13631정성태5/19/20241215Phone: 16. C# MAUI - /Download 등의 공용 디렉터리에 접근하는 방법
13630정성태5/19/20241565닷넷: 2263. C# - Thread가 Task보다 더 빠르다는 어떤 예제(?)
13629정성태5/18/20241393개발 환경 구성: 710. Android - adb.exe를 이용한 파일 전송
13628정성태5/17/20241383개발 환경 구성: 709. Windows - WHPX(Windows Hypervisor Platform)를 이용한 Android Emulator 가속
13627정성태5/17/20241364오류 유형: 904. 파이썬 - UnicodeEncodeError: 'ascii' codec can't encode character '...' in position ...: ordinal not in range(128)
13626정성태5/15/20241488Phone: 15. C# MAUI - MediaElement Source 경로 지정 방법파일 다운로드1
13625정성태5/14/20241762닷넷: 2262. C# - Exception Filter 조건(when)을 갖는 catch 절의 IL 구조
13624정성태5/12/20241951Phone: 14. C# - MAUI에서 MediaElement 사용파일 다운로드1
13623정성태5/11/20242135닷넷: 2261. C# - 구글 OAuth의 JWT (JSON Web Tokens) 해석파일 다운로드1
13622정성태5/10/20242055닷넷: 2260. C# - Google 로그인 연동 (ASP.NET 예제)파일 다운로드1
13621정성태5/10/20242098오류 유형: 903. IISExpress - Failed to register URL "..." for site "..." application "/". Error description: Cannot create a file when that file already exists. (0x800700b7)
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...