클립보드와 드래그 앤 드롭의 구조 ── 업무 앱에서 OLE 데이터 전송을 올바르게 다루기

· · Windows, 클립보드, 드래그 앤 드롭, OLE, COM, Windows 개발, WinForms, WPF

「Excel에서 복사한 표를 붙여 넣으면 서식이 무너진다. 표로 붙여 넣고 싶다」. 「우리 앱에서 복사한 내용이 Word에 붙여 넣으면 이상한 것이 된다」. 「파일을 드래그 앤 드롭으로 받고 싶다」── 업무 앱 변경 상담에서 복사·붙여 넣기와 드래그 앤 드롭(D&D) 주변의 요청은 단골입니다.

바로 「누구나 당연하게 여기는 기능」이기 때문에, 실제 동작은 의외로 잘 알려지지 않습니다. 클립보드를 「데이터 한 덩어리를 넣는 상자」로 생각하면, 같은 복사가 붙여 넣는 곳에 따라 다른 결과가 나는 이유나, 원본 앱을 닫은 뒤에 붙여 넣기가 멈추는 이유를 설명할 수 없습니다. 진짜 클립보드는 같은 내용을 여러 형식으로 한꺼번에 두고, 붙여 넣는 쪽이 이해하는 형식을 고르게 하는 메커니즘입니다.

그리고 드래그 앤 드롭은, 밑바닥에서 보면, 클립보드와 정확히 같은 데이터 표현(IDataObject)을 COM 인터페이스로 넘기는 OLE 데이터 전송입니다. 즉 복사·붙여 넣기와 D&D는 형제입니다. 한쪽을 올바르게 이해하면 다른 쪽은 바로 옆에 있습니다.

이 글은 중소기업의 IT 담당자와 Windows 앱 개발자를 대상으로 합니다. 클립보드 형식의 동작, 붙여 넣기 측과 복사 측의 실무, 클립보드를 올바르게 감시하는 방법, 클립보드 기록·클라우드 동기·RDP의 관리 정책, OLE 드래그 앤 드롭의 구조와 함정을 한 장의 그림으로 묶습니다.

1. 먼저 결론

  • 클립보드는 같은 데스크톱(윈도우 스테이션)의 앱이 공유하는 단일 영역이며, 거기에 있는 것은 「데이터 한 덩어리」가 아니라 같은 내용을 여러 형식으로 한꺼번에 둔 것입니다. RDP 같은 다른 세션은 원래 다른 클립보드를 갖고, 두 쪽을 잇는 것은 리다이렉션 기능입니다. 붙여 넣는 쪽이 이해하는 형식을 고르므로, 같은 복사가 붙여 넣는 곳에 따라 다른 결과가 납니다.12
  • 텍스트는 CF_UNICODETEXT를 씁니다. CF_TEXT는 ANSI이며 코드 페이지에 의존하고, 일본어 시스템에서는 문자 깨짐의 온상입니다. 시스템은 둘을 암묵으로 변환하지만, 정본 측은 유니코드입니다.3
  • 파일은 CF_HDROP(이중 NUL 종료 경로 배열)로 다니고, 서식 있는 텍스트는 등록 형식 「HTML Format」을 씁니다. HTML Format은 특이한 구조입니다. 바이트 오프셋 헤더가 붙은 UTF-8 텍스트입니다.45
  • 「원본 앱을 닫으니 붙여 넣을 수 없다」의 진짜 원인은 지연 렌더링입니다. 페이로드가 아니라 「요청되면 만들겠다」는 약속만 두는 메커니즘이며, 종료 때 실체화(WM_RENDERALLFORMATS에 응답, 또는 OLE에서는 OleFlushClipboard)를 건너뛰면 붙여 넣기가 멈춥니다.26
  • 붙여 넣은 데이터는 밖의 신뢰할 수 없는 입력으로 다룹니다. Microsoft 자신도 「클립보드 데이터는 신뢰되지 않는다. 신중히 파싱하라」고 분명히 말합니다.7
  • 클립보드 감시에는 AddClipboardFormatListener + WM_CLIPBOARDUPDATE가 유일한 선택입니다. 폴링을 쓰지 말고, 옛 SetClipboardViewer(뷰어 체인)도 쓰지 마십시오. 비밀을 기록과 동기에서 빼는 등록 형식(ExcludeClipboardContentFromMonitorProcessing과 동료들)도 제공됩니다.81
  • 클립보드 기록(Win+V)과 클라우드 동기는 IT 관리의 관심사입니다. GPO / Intune(Policy CSP)의 AllowClipboardHistory와 AllowCrossDeviceClipboard로 제어할 수 있고, RDP 클립보드 리다이렉션에는 전용 정책이 있습니다.91011
  • 드래그 앤 드롭은 COM입니다. 클립보드와 같은 IDataObject가 IDropSource(드래그 원본)와 IDropTarget(드롭 대상) 사이에서 DoDragDrop 루프를 통해 넘겨집니다. RegisterDragDrop에는 OleInitialize(STA)로 초기화가 필요합니다.1213
  • 보통 권한의 파일 탐색기에서 승격된 앱으로는 드롭할 수 없습니다. 원인은 UIPI(무결성 수준에 의한 메시지 차단)이며, 설계 때 알아야 할 제약입니다.14

이하는 클립보드의 기초부터 따라갑니다.

2. 클립보드의 정체 ── 「데이터 한 덩어리」가 아니라 「같은 내용의 여러 형식」

클립보드는 같은 데스크톱을 공유하는 모든 앱이 닿을 수 있는 공통 데이터 공유 메커니즘입니다(더 정확히는 윈도우 스테이션마다입니다. 다른 사용자 세션이나 RDP 세션은 각각 자체 클립보드를 갖습니다. RDP에서 복사·붙여 넣기가 되는 것은 리다이렉션 기능이 둘을 잇기 때문입니다── 7장). 첫 원칙은 사용자 구동입니다. 공식 설계 자세는 사용자 등 뒤에서 데이터를 넣거나 꺼내지 않는다는 것입니다.1

중요한 점은 복사가 「데이터 한 덩어리」를 두지 않는다는 것입니다. 복사하는 창은 클립보드를 비운 뒤 같은 내용을 더 풍부한 형식에서 덜 풍부한 형식으로 여러 형식을 연달아 둡니다.2 예를 들어 스프레드시트에서 표를 복사하면, 개념적으로 다음과 같은 것이 동시에 클립보드에 있습니다.

우선순위 형식 내용
1 앱 사설 형식 수식과 서식을 포함한 완전한 내부 표현(같은 앱으로 다시 붙여 넣기용)
2 HTML Format 표 구조와 서식을 유지하는 HTML 조각
3 CSV 셀 구분 텍스트
4 CF_UNICODETEXT 탭 구분 일반 텍스트
5 이미지 형식 표가 보이는 모습의 비트맵

붙여 넣는 쪽은 이 목록에서 이해하는 형식을 골라 꺼냅니다. Word에 붙여 넣으면 서식 있는 표가 되고, 메모장에 붙여 넣으면 탭 구분 텍스트가 되는 것은── 둘이 다른 형식을 골랐기 때문입니다. 「붙여 넣는 곳에 따라 결과가 다르다」는 버그가 아니라, 이 설계의 정상적인 귀결입니다.

같은 복사가 붙여 넣는 곳에 따라 다른 결과가 나는 이유복사 측이 같은 내용을 여러 형식으로 클립보드에 두고, 붙여 넣는 쪽이 이해하는 형식을 고르므로, Word는 서식 있는 표를, 메모장은 탭 구분 텍스트를 얻는다Word메모장복사: 스프레드시트클립보드(여러 형식)더 풍부한 형식더 단순한 형식앱 사설HTML FormatCSVCF_UNICODETEXT서식 있는 표탭 구분 텍스트

반대로 말하면, 글머리의 불만── 「서식이 무너진다」, 「이상한 것이 붙여 넣어진다」── 는 거의 모두 한쪽이 형식을 고르는 방법, 또는 다른 쪽이 형식을 제공하는 방법의 문제로 줄어듭니다. 4장은 붙여 넣기 측을, 5장은 복사 측을 다룹니다.

3. 표준 형식과 등록 형식 ── CF_UNICODETEXT, CF_HDROP, HTML Format

3.1. 표준 형식 ── 텍스트는 유니코드 측을 쓴다

OS가 처음부터 정의하는 형식을 표준 형식이라고 합니다. 업무 앱에서 끊임없이 나오는 것은 다음입니다.3

형식 내용
CF_TEXT 1 ANSI 텍스트(코드 페이지 의존)
CF_UNICODETEXT 13 유니코드 텍스트. 이것이 텍스트의 정본 형식이다
CF_HDROP 15 파일 경로 목록(HDROP 핸들)
CF_DIB 8 장치 독립 비트맵
CF_LOCALE 16 텍스트에 연관된 로케일 식별자

CF_TEXT와 CF_UNICODETEXT는 시스템이 암묵으로 서로 변환합니다(합성 형식). 문자 코드 변환은 CF_LOCALE에 연관된 코드 페이지를 씁니다.3 그 변환에 의존하면 ANSI가 표현하지 못하는 문자(예를 들어 유니코드 전용 기호와 결합 문자)가 떨어지므로, 규칙은 앱이 읽고 쓰는 것을 CF_UNICODETEXT(.NET에서는 DataFormats.UnicodeText)로 통일하는 것입니다.

CF_UNICODETEXT와 CF_TEXT 사이의 암묵 변환앱은 CF_UNICODETEXT만 읽고 쓰고, 시스템은 CF_LOCALE 코드 페이지로 암묵 변환해 CF_TEXT를 합성한다. ANSI가 표현하지 못하는 문자는 그 변환에서 떨어진다CF_LOCALE 변환앱이 읽고 쓴다CF_UNICODETEXTCF_TEXT(ANSI)표현 불가 문자는 떨어진다

3.2. CF_HDROP ── 파일은 「경로 목록」으로 다닌다

CF_HDROP은 파일 탐색기에서 파일을 복사하거나, 파일을 드래그 앤 드롭할 때 쓰입니다. 페이로드는 파일 자체가 아니라, DROPFILES 구조 헤더 뒤에 NUL 문자로 구분된 전체 경로 문자열, 끝에 빈 문자열이 놓인 「이중 NUL 종료」 배열을 펼친 메모리 블록입니다. 헤더의 pFiles는 경로 목록의 시작 오프셋이고, fWide는 문자열이 유니코드인지를 말합니다.4

[DROPFILES header: pFiles=start offset of the path list, fWide=1(Unicode)]
C:\data\a.txt(NUL)C:\data\b.txt(NUL)(NUL)

네이티브 코드에서는 DragQueryFile로 하나씩 꺼내고, .NET에서는 DataFormats.FileDrop을 통해 string[]로 받습니다. 「다니는 것은 파일 자체가 아니라 경로뿐」이라는 사실은 8장과 9장의 D&D에서 다시 중요합니다.

CF_HDROP의 메모리 블록 배치전역 메모리의 앞에 DROPFILES 구조가 있고, pFiles는 경로 목록의 시작 오프셋, fWide는 유니코드 여부를 말한다. 이어서 전체 경로가 NUL로 구분되어 이어지고, 블록은 빈 문자열(이중 NUL)로 끝난다. 다니는 것은 파일이 아니라 경로뿐이다DROPFILES(pFiles / fWide)C:\\data\\a.txt + NULC:\\data\\b.txt + NUL빈 문자열(이중 NUL)파일이 아니라 경로만 다닌다

3.3. 등록 형식 ── RegisterClipboardFormat과 「HTML Format」

표준 형식이 표현하지 못하는 데이터에는, 앱이 이름을 골라 자체 형식을 등록할 수 있습니다. 이름을 RegisterClipboardFormat에 넘기면 형식 ID가 돌아오고, 다른 앱에서 같은 이름으로 등록하면 같은 ID가 돌아오므로, 이름만 합의하면 앱 간에 데이터를 공유할 수 있습니다.1 자체 앱 스위트 간에 구조화 데이터를 넘길 때는 KomuraSoft.Report.RowData처럼 충돌하지 않을 이름을 씁니다.

대표적인 등록 형식은 서식 있는 텍스트용 「HTML Format」입니다(RTF와 함께 두 주요 리치 텍스트 형식). 페이로드는 UTF-8 텍스트이지만, 특이한 구조가 있습니다. 바이트 오프셋을 나열하는 헤더가 앞에 붙습니다.5

Version:0.9
StartHTML:<byte offset of the start of the whole HTML>
EndHTML:<byte offset of the end of the whole HTML>
StartFragment:<byte offset of the start of the fragment>
EndFragment:<byte offset of the end of the fragment>
<html><body>
<!--StartFragment--><b>bold</b> fragment text<!--EndFragment-->
</body></html>

각 오프셋은 헤더 자신을 포함한, 데이터 시작부터의 바이트 위치이며, 보통의 실무는 고정 폭(예를 들어 10자리)을 예약하고 본문을 만든 뒤에 측정값을 다시 씁니다. StartFragment/EndFragment는 「사용자가 실제로 선택한 조각」의 시작과 끝을 바이트로 표시합니다(문자가 아닙니다). 한국어가 들어가는 UTF-8에서는 문자 수와 바이트 수가 어긋나므로, 이 오프셋 계산을 틀리면 다른 앱에 붙여 넣을 때 앞이나 뒤가 잘립니다. HTML Format을 스스로 만들면, UTF-8로 인코딩한 뒤에 측정한 바이트 위치로 헤더를 채워야 합니다.5

HTML Format 헤더와 오프셋의 관계헤더의 StartHTML과 EndHTML은 전체 HTML을, StartFragment와 EndFragment는 사용자가 선택한 조각을, 둘 다 데이터 시작부터의 바이트 위치로 가리킨다. UTF-8에서는 문자 수와 바이트 수가 어긋나므로, 인코딩 뒤에 측정한 바이트 위치로 헤더를 채운다헤더(바이트 오프셋)전체 HTML선택한 조각오프셋은 UTF-8 뒤의 바이트

CSV(.NET에서는 DataFormats.CommaSeparatedValue)도 표 데이터에 흔히 쓰입니다. Excel과의 상호 운용에는 HTML Format(서식 포함), CSV(값만), CF_UNICODETEXT(탭 구분)를 함께 제공하면, 붙여 넣는 곳을 하나로 고를 필요가 없습니다.

4. 붙여 넣기 측의 실무 ── 형식 우선순위와 검증

4.1. 풍부한 형식부터 내려다본다

클립보드의 형식은 복사 측이 둔 순서(즉 더 표현력 있는 것에서 덜한 것으로)로 늘어서 있습니다. 붙여 넣기 측의 기본선은 다룰 수 있는 형식 중에서 정보가 가장 많은 것부터 보는 것입니다. Win32에서는 EnumClipboardFormats로 열거해 처음 알아보는 형식을 쓰거나, 자체 우선순위 목록을 GetPriorityClipboardFormat에 넘겨 고르게 합니다.2

.NET에서의 분기는 대략 다음과 같습니다.

// Pasting a table: look from rich to plain
var data = Clipboard.GetDataObject();
if (data is null) return;

// Advertising a format does not guarantee the payload is a string. Use this
// branch only when the type also checks out; otherwise fall through to the next candidate
if (data.GetDataPresent(DataFormats.Html)
    && data.GetData(DataFormats.Html) is string html)
{
    // Validate the HTML Format header, then import as a table
}
else if (data.GetDataPresent(DataFormats.CommaSeparatedValue))
{
    // Import as CSV
}
else if (data.GetDataPresent(DataFormats.UnicodeText))
{
    // Import as tab-separated text
}

그것이 글머리의 불만, 「Excel 표를 붙여 넣으면 무너진다」에 대한 답입니다. 일반 텍스트만 읽는 앱은 표 구조를 받지 못합니다. 형식 목록을 어디까지 받아들일지는 붙여 넣기 측의 설계 결정입니다.

풍부한 형식부터 내려다보는 붙여 넣기 분기HTML Format이 있고 페이로드도 문자열이면 표로 가져오고, 아니면 CSV를 시도하며, 그것도 없으면 탭 구분 텍스트로 떨어진다. 후보가 하나도 없으면 거절한다아니오아니오아니오붙여 넣기 시작HTML Format + 문자열?헤더를 검증 → 표CSV가 있는가?CSV로 가져온다UnicodeText?탭 구분 텍스트거절

4.2. 붙여 넣은 데이터는 외부 입력이다

놓치기 쉽지만, 클립보드 내용은 밖의 데이터이며, 어느 앱이 두었는지 모릅니다. Microsoft도 OLE 클립보드 문서에서 「클립보드 데이터는 신뢰되지 않는다. 앱에서 쓰기 전에 신중히 파싱하라」고 경고합니다.7

  • HTML Format 헤더 오프셋이 버퍼 밖을 가리키지 않는지 검증합니다(깨진 헤더를 내는 앱이 있습니다).
  • 숫자, 날짜, 코드로 가져오는 값은 화면 입력과 같은 검증을 거칩니다.
  • 거대한 데이터에 대한 방어를 넣습니다. 수백 메가바이트 이미지나 수백만 줄 텍스트를 붙여 넣어도 UI를 막지 말고, 한도를 넘으면 거절합니다. 주의: .NET의 GetData는 호출하는 순간에 페이로드 전체를 매니지드 문자열로 실체화하고(지연 렌더링도 그 일부로 돕니다), GetData 뒤에 크기 검사를 두는 것은 방어가 아닙니다. Win32에서는 GetClipboardData가 반환하는 HGLOBAL의 GlobalSize를 확인하면 「매니지드 문자열로 변환·파싱에 들어가지 않는다」는 단계의 방어는 되지만, 지연 렌더링 형식에서는 GetClipboardData 자체가 렌더링을 시작하므로, 복사 원본 측의 실체화는 여전히 막지 못합니다. UI가 멈추지 않게 하려면 가져오기를 UI 스레드에서 떼어 냅니다(그때도 .NET의 Clipboard는 STA를 요구하므로, Task.Run 스레드 풀 스레드(MTA)가 아니라 STA로 설정한 전용 스레드에서 합니다── 5.1절).

「밖의 경로로 도착한 값은, 쓰기 전에 검증한다」는 생각은 「QR코드 판독값을 그대로 사용해서는 안 된다」에서 펼친 것과 같습니다. 붙여 넣기가 사용자 동작이니 안전하다는 가정이 사고의 시작입니다.

붙여 넣은 데이터를 쓰기 전에 검증한다클립보드에서 꺼낸 데이터는 형식 존재, 페이로드 타입, 크기 한도, 내용 검증을 그 순서로 거치고, 하나라도 실패하면 거절하거나 다음 후보 형식으로 떨어진다타입 불일치너무 큼무효형식이 있는가?페이로드 타입이 맞는가?크기가 한도 안인가?내용을 검증한다가져온다거절 / 다음 형식

5. 복사 측의 실무 ── 여러 형식을 한꺼번에 제공하기, 그리고 지연 렌더링

5.1. 여러 형식을 한꺼번에 둔다

복사 측의 실무는 4.1의 반대입니다. 풍부한 형식과 일반 형식을 동시에 제공합니다. WinForms/WPF DataObject로는 몇 줄로 쓸 수 있습니다.15

// WinForms (System.Windows.Forms). WPF is the same shape with System.Windows DataObject/Clipboard
var data = new DataObject();
data.SetData(DataFormats.Html, htmlFormatText);       // HTML Format string including the header
data.SetData(DataFormats.CommaSeparatedValue, csv);   // CSV
data.SetData(DataFormats.UnicodeText, plainText);     // Plain text
Clipboard.SetDataObject(data, copy: true);            // copy:true = keep after the app exits

주의가 둘입니다. 첫째, .NET의 Clipboard 클래스는 STA 스레드에서만 쓸 수 있습니다.15 WinForms/WPF UI 스레드는 [STAThread] 때문에 STA이므로 보통은 문제가 아니지만, 백그라운드 스레드에서 건드리면 실패합니다(STA/MTA 기초는 「COM STA/MTA 기초」에 있습니다). 둘째, copy: true의 의미는 다음 절의 지연 렌더링과 묶여 있습니다.

5.2. 지연 렌더링 ── 「원본을 닫으면 붙여 넣을 수 없다」의 이유

큰 페이로드를 여러 형식으로 매번 만드는 것은 낭비이므로, 클립보드에는 지연 렌더링이라는 메커니즘이 있습니다. SetClipboardData에 데이터 핸들로 NULL을 넘기면, 페이로드 대신 「요청되면 만들겠다」는 약속만 등록되고, 누군가 그 형식을 요청하면 복사 원본에 WM_RENDERFORMAT이 도착한 뒤에야 데이터가 생성됩니다.2

이 설계의 귀결이 글머리의 「원본 앱을 닫으니 붙여 넣을 수 없다」입니다. 나가기 전에 복사 원본은 WM_RENDERALLFORMATS를 받고, 아직 렌더링되지 않은 모든 형식을 실체화할 책임이 있으며, 그것을 하지 않고 나가면 형식이 사라집니다.2

지연 렌더링과 닫은 뒤 붙여 넣기가 실패하는 이유복사 원본은 NULL 핸들로 약속만 등록하고, WM_RENDERFORMAT으로 요청 때 실체화한다. 종료 때는 WM_RENDERALLFORMATS로 모든 형식을 실체화할 책임이 있으며, 건너뛰면 형식이 사라진다RENDERALLFORMATS실체화를 건너뜀SetClipboardData NULL = 약속붙여 넣는 쪽이 요청한다WM_RENDERFORMAT → 지금 만든다복사 원본이 나가려 한다종료 뒤에도 붙여 넣기가 된다닫은 뒤 형식이 사라진다

OLE 클립보드(IDataObject를 OleSetClipboard로 두는 스타일)에서는 이 관계가 더 분명합니다. 클립보드가 쥐는 것은 데이터 객체에 대한 포인터뿐이며, 앱 종료 때 OleFlushClipboard를 호출하면 데이터가 클립보드에 실체화되어, 종료 뒤에도 붙여 넣기가 됩니다.6 .NET의 Clipboard.SetDataObject(data, copy: true)가 이 「종료 뒤에 남긴다」는 동작을 지정하는 것입니다.

Excel에서 큰 범위를 복사하고 종료하려 하면 「클립보드에 많은 양의 정보가 있습니다. 나중에 다른 프로그램에 이 정보를 붙여 넣을 수 있게 하시겠습니까?」라는 프롬프트가 나오는데, 바로 이 실체화(flush)를 할지에 대한 확인입니다. 자체 앱에서 지연 렌더링을 쓰면, 종료 때 실체화가 같은 세트의 일부임을 기억하십시오. 지연 렌더링은 성능 최적화이며, 렌더 요청이 메시지 처리 안에서 동기로 돌므로, 만드는 데 오래 걸리는 데이터는 UI를 멈추는 트레이드오프가 있습니다.2

6. 클립보드 감시의 실무 ── 리스너, 재시도, 기록 제외

6.1. AddClipboardFormatListener를 쓴다

「바코드 리더 값이나 기간 시스템의 복사를 감지해 자동으로 가져오고 싶다」는 요구에는 클립보드 변경을 감시해야 합니다. 역사적으로 방법이 셋 있고, 지금은 정답이 하나입니다.8

방법 평가
타이머로 읽기(폴링) 낭비이고, 갱신을 놓칠 수 있다. 쓰지 말 것
SetClipboardViewer(뷰어 체인) 체인의 앱 하나 버그가 체인 전체를 깨뜨린다. 하위 호환만 위해 남음
AddClipboardFormatListener 권장. 등록한 창에 WM_CLIPBOARDUPDATE가 도착한다
클립보드 감시의 흐름핸들이 만들어질 때 AddClipboardFormatListener로 등록하면, 어느 앱이 복사하든 WM_CLIPBOARDUPDATE가 도착한다. 재시도로 읽고, 핸들이 파괴될 때 RemoveClipboardFormatListener로 대칭 해제한다해제AddClipboardFormatListener대기어떤 앱이 복사한다WM_CLIPBOARDUPDATE재시도로 읽기(6.2)RemoveClipboardFormatListener
// Minimal WinForms implementation
public partial class MainForm : Form
{
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool AddClipboardFormatListener(IntPtr hwnd);
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
    const int WM_CLIPBOARDUPDATE = 0x031D;

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        AddClipboardFormatListener(Handle);
    }

    protected override void OnHandleDestroyed(EventArgs e)
    {
        // Unregister symmetrically to match handle destruction / recreation
        RemoveClipboardFormatListener(Handle);
        base.OnHandleDestroyed(e);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_CLIPBOARDUPDATE)
        {
            // Read Clipboard.GetDataObject() here and import if the format is one you need
        }
        base.WndProc(ref m);
    }
}

6.2. 열 수 없을 때의 재시도

클립보드를 열 수 있는 창은 한 번에 하나뿐이며, 다른 프로세스가 열어 둔 동안 OpenClipboard는 실패합니다.2 WM_CLIPBOARDUPDATE 직후에는 복사 원본이나 다른 감시자가 아직 조작 중인 경우가 많아, 일시적 읽기 실패는 일상 이벤트입니다. 짧은 대기(수십 밀리초)를 사이에 둔 몇 번의 재시도를 항상 넣으십시오. 참고로 재시도 횟수와 간격을 지정할 수 있는 .NET Clipboard 오버로드는 쓰기 측, SetDataObject에만 있습니다. 읽기 측(GetDataObject 등)에는 동등한 것이 없으므로, 잡고-기다리고-재시도를 직접 씁니다── WinForms에서는 ExternalException, WPF에서는 COMException입니다.

클립보드 읽기 재시도의 흐름클립보드를 열 수 있는 창은 한 번에 하나뿐이므로, 변경 알림 직후의 읽기는 다른 프로세스와 경합해 실패할 수 있다. 예외가 나면 수십 밀리초 기다리고 재시도하고, 한도에 닿으면 이번은 포기하고 다음 갱신에서 줍는다성공사용 중재시도한도WM_CLIPBOARDUPDATE읽기를 시도한다가져온다(4장 검사)수십 ms 대기이번은 포기

6.3. 기록과 동기에서 빼기 ── 비밀을 다루는 복사 기능의 배려

Windows에는 클립보드 기록(Win+V)과 기기 간 동기(클라우드 클립보드)가 있고, 앱이 두는 데이터는 기본으로 둘 다의 범위에 들어갑니다. 암호나 계좌 번호 같은 비밀을 복사 기능에 두는 앱은 내용을 기록과 동기에서 빼는 등록 형식도 함께 둡니다.1

  • ExcludeClipboardContentFromMonitorProcessing: 이것을 두면 그 복사의 내용은 기록에도 동기에도 들어가지 않습니다.
  • CanIncludeInClipboardHistory(DWORD 0): 기록만 억제합니다.
  • CanUploadToCloudClipboard(DWORD 0): 기기 간 동기만 억제합니다.

암호 관리자가 복사한 암호가 Win+V에 남지 않는 이유는 이 메커니즘입니다. 이름을 RegisterClipboardFormat에 넘겨 형식 ID를 얻고 보통 데이터와 나란히 설정하면 되므로, 비밀을 다루는 업무 앱이라면 구현할 가치가 있습니다.

7. IT 관점의 클립보드 ── 기록, 클라우드 동기, RDP 제어

개발에서 조금 떨어져, 관리자에게 중요한 점을 둡니다. 클립보드 기록은 최근 복사를 쌓고, 클라우드 클립보드는 같은 Microsoft 계정 / Microsoft Entra 계정으로 로그인한 기기 간에 복사를 동기합니다.10 편리한 만큼, 기간 시스템에서 복사한 개인정보가 기록에 쌓이고, 업무 PC에서 복사한 내용이 개인 PC로 동기되는 잔여와 유출도 만듭니다.

조직에서 이것을 제어하는 정책은 다음 둘입니다.

제어하는 것 GPO(컴퓨터 구성 > 관리 템플릿 > 시스템 > OS 정책) Policy CSP(Intune) 기본값
클립보드 기록 Allow Clipboard History Experience/AllowClipboardHistory 허용
기기 간 동기 Allow Clipboard synchronization across devices Privacy/AllowCrossDeviceClipboard 허용

둘 다 Windows 10 버전 1809부터 쓸 수 있고, 비활성화하면 설정 앱의 해당 항목이 회색이 되며, 정책은 즉시 효력을 냅니다.910

다른 단골은 RDP(원격 데스크톱) 클립보드 리다이렉션입니다. 기본값으로는 로컬 PC와 원격 세션 사이에 복사·붙여 넣기가 되므로, 서버에서 비밀을 빼내는 경로가 될 수 있습니다. 「클립보드 리다이렉션 허용 안 함」 정책(레지스트리 값 fDisableClip)은 양방향을 막을 수 있습니다.11 최근 Windows Server / Windows 11 릴리스에는 서버→클라이언트 방향을 텍스트만으로 제한하는 같은 더 세밀한 정책도 더해졌습니다. 전면 금지인지 단계적 제한인지는 운용과 보안의 균형입니다.

클립보드 내용이 퍼질 수 있는 경로와 제어점복사한 내용은 기본으로 기록과 클라우드 동기의 범위에 들어가고, RDP에서는 리다이렉션으로 다른 세션에 간다. 각 경로는 정책으로 제어할 수 있고, 앱 측은 제외 형식으로 기록과 동기에서 자신을 뺄 수 있다클립보드기록(Win+V)클라우드 동기RDP 리다이렉션AllowClipboardHistoryAllowCrossDeviceClipboardfDisableClip앱 제외 형식(6.3)

8. 드래그 앤 드롭은 COM이다 ── IDataObject + IDropSource + IDropTarget

8.1. 클립보드와 같은 데이터, 나르는 방법만 다르다

OLE 드래그 앤 드롭은 다음 세 역할로 돕니다.12

역할 구현하는 쪽
IDataObject 드래그 원본 나르는 페이로드. 클립보드와 같은 다중 형식 데이터 객체
IDropSource 드래그 원본 드래그가 계속되는지 취소되는지의 결정, 커서 피드백
IDropTarget 드롭 대상 DragEnter/DragOver/DragLeave/Drop에서 수락/거절을 선언하고, 드롭을 받는다

드래그 원본이 DoDragDrop을 호출하면 드래그 루프가 시작되고, 마우스가 드롭 대상 창에 들어가면 그 IDropTarget에 알림이 가며, 드롭 때 IDataObject가 넘겨집니다. 공식 문서도 「D&D는 클립보드 복사·붙여 넣기와 정확히 같은 기능을 제공한다. 앱이 이미 복사·붙여 넣기를 구현했다면 추가는 작다」고 말합니다.122장부터 5장에서 만든 다중 형식 DataObject가 그대로 D&D 페이로드가 됩니다.

OLE 드래그 앤 드롭의 흐름드래그 원본이 IDataObject를 페이로드에 넣고 DoDragDrop을 호출해 드래그 루프를 시작하고, 드롭 대상의 IDropTarget이 DragEnter와 DragOver에서 수락/거절을 선언하며, Drop에서 IDataObject의 형식을 골라 꺼낸다DoDragDrop마우스가 들어옴버튼 업IDataObject + IDropSource드래그 루프DragEnter/Over: EffectIDropTarget.Drop형식을 골라 꺼낸다

8.2. OleInitialize(STA)가 필요하다

드롭 대상이 될 창은 RegisterDragDrop로 등록하고, 여기에 고전적 함정이 있습니다. COM을 CoInitialize/CoInitializeEx로 초기화하면 RegisterDragDrop는 항상 E_OUTOFMEMORY로 실패하고, OleInitialize로 초기화해야 합니다.13 OleInitialize는 COM을 STA로 초기화하는데, D&D가 창과 메시지 펌프의 STA 세계에 뿌리내린 기능이기 때문입니다. 호출 스레드도 메시지 펌프를 돌리고 있어야 하며, 건너뛰면 드래그 중에 다른 앱이 멈춥니다.13 여기의 배경은 바로 「COM STA/MTA 기초」의 스레드 모델 논의입니다.

WinForms/WPF 앱에서는 프레임워크가 OLE 초기화와 인터페이스 구현을 맡으므로, 개발자는 이벤트만 쓰면 됩니다.

// WinForms: accept dropped files
listView1.AllowDrop = true;
listView1.DragEnter += (s, e) =>
{
    // Also check that the source allows Copy (some sources only allow Move/Link)
    e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop)
            && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy
        ? DragDropEffects.Copy      // Accept: receive as a copy
        : DragDropEffects.None;     // Do not accept
};
listView1.DragDrop += (s, e) =>
{
    // Drag data is also untrusted input. Even if it advertises FileDrop, the payload
    // can be null or a different type, and GetData itself can fail
    object data;
    try { data = e.Data.GetData(DataFormats.FileDrop); }
    catch (COMException) { return; }
    if (data is not string[] paths) return;
    foreach (var path in paths)
    {
        // Validate the path before importing (Section 9.3)
    }
};

WPF에서도 형태는 같습니다. 요소의 AllowDrop="True"DragOver/Drop 이벤트로 받고, e.Data.GetData(DataFormats.FileDrop)로 경로 배열을 꺼냅니다. 모든 DragEnter/DragOver에서 수락/거절(Effect)을 선언하는 것이 IDropTarget의 관례이며, 건너뛰면 커서가 「허용 안 함」에 머물러 바뀌지 않는 버그가 납니다.

9. D&D의 함정 ── 승격, 이동, 경로 검증

9.1. 관리자로 승격된 앱에는 드롭할 수 없다

「관리자 권한으로 실행」한 앱에 파일 탐색기에서 파일을 드롭하면 아무 일도 일어나지 않는 것은── 구현 버그가 아니라 OS 동작입니다. UIPI(User Interface Privilege Isolation)는 낮은 무결성 프로세스에서 높은 무결성 창으로의 메시지를 기본으로 막으므로, 보통 권한(중간 무결성) 파일 탐색기의 드롭 알림은 승격된 앱에 닿지 않습니다.14

UIPI가 승격된 앱으로의 드롭을 막는 방식중간 무결성 파일 탐색기에서 높은 무결성 승격 앱으로의 드롭 알림은 기본으로 UIPI에 막혀 도착하지 않는다. UI를 보통 권한에 두고 특권 작업만 격리하면 드롭이 도착한다드롭 알림차단통과특권 작업을 위임탐색기(중간)UIPI승격된 앱: 드롭 없음보통 UI: 드롭이 도착격리된 승격 프로세스

ChangeWindowMessageFilterEx로 WM_DROPFILES 같은 특정 메시지를 개별 허용하는 우회는 잘 알려져 있지만,14 그것이 통과시키는 것은 옛(WM_DROPFILES) 드롭 알림이며, OLE D&D 전체를 해결하지 않습니다. 실무 지침은 분명합니다. 앱을 항상 승격해 돌리도록 설계하지 마십시오. 승격이 필요한 작업만 별도 프로세스로 격리하면, UI 자체는 보통 권한에 머물러 D&D를 받을 수 있습니다(격리 설계는 「Windows 앱에서 「관리자 권한이 필요한 처리만」을 분리하는 구체적인 방법」에서 자세히 다룹니다).

9.2. DragDropEffects의 의미 ── Move는 「원본이 사라진다」는 계약이다

DragDropEffects의 Copy/Move/Link는 장식이 아니라, 드래그 원본과 드롭 대상 사이의 계약입니다. 드래그 원본이 DoDragDrop에서 허용하는 효과 집합을 선언하고, 드롭 대상이 실제 효과를 고르며, Move가 성공하면 드래그 원본이 데이터(파일)를 삭제한다── 그것이 관례입니다. 받는 쪽이 생각 없이 Move를 반환하면 「드롭했더니 원본 파일이 사라졌다」는 사고가 납니다. 업무 앱의 가져오기 용도에서는 받는 쪽이 Copy를 선언하는 것이 안전한 기본값입니다.

DragDropEffects 계약 ── Move는 원본을 삭제한다드래그 원본이 DoDragDrop에서 허용 효과 집합을 선언하고, 드롭 대상이 실제 효과를 고른다. Move가 성공하면 드래그 원본이 파일을 삭제하므로, 가져오기에는 받는 쪽이 Copy를 선언해야 한다CopyMove원본: 허용 효과대상: Effect를 고른다원본이 남는다(가져오기)원본이 파일을 삭제한다

9.3. 드롭된 경로의 검증

CF_HDROP/FileDrop에서 다니는 것은 경로뿐입니다(3.2절). 가져오기 전에 붙여 넣기와 같은 신뢰할 수 없는 입력 검증을 거칩니다.

  • 파일인가 폴더인가: 폴더 전체가 드롭되었을 때 무엇을 할지 사양으로 정합니다(재귀해 가져오기, 또는 거절).
  • OneDrive 플레이스홀더: 경로는 있는데 파일 본체가 로컬에 없는── 온디맨드 파일일 수 있습니다. 여는 순간 다운로드가 시작되고, 오프라인이면 실패합니다. 동작과 대책은 「OneDrive “Files On-Demand” and Business Apps」에 있습니다.
  • 긴 경로와 특이한 경로: MAX_PATH를 넘는 경로, 네트워크(UNC) 경로, 이동식 미디어의 경로는 하류 처리가 다룰 수 있음을 확인한 뒤에만 받습니다.
  • 개수와 총 크기: 수천 개 파일을 드롭해도 UI가 멈추지 않게, 가져오기를 비동기로 하고 한도와 진행 표시를 넣습니다.

10. 정리

  • 클립보드는 같은 데스크톱(윈도우 스테이션) 안에서 공유하는 단일 영역에 같은 내용을 여러 형식으로 한꺼번에 두는 메커니즘입니다. 붙여 넣는 쪽이 형식을 고르므로, 같은 복사가 다른 결과를 냅니다.
  • 텍스트는 CF_UNICODETEXT, 파일은 CF_HDROP, 서식 있는 텍스트는 등록 형식 HTML Format(바이트 오프셋 헤더 + UTF-8)입니다.
  • 붙여 넣기 측은 풍부한 것에서 단순한 것으로 보고 페이로드를 외부 입력으로 다룹니다. 복사 측은 여러 형식을 한꺼번에 제공하고, 지연 렌더링을 쓰면 종료 때 실체화(WM_RENDERALLFORMATS / OleFlushClipboard)도 구현합니다.
  • 감시는 AddClipboardFormatListener + WM_CLIPBOARDUPDATE입니다. OpenClipboard 경합에는 재시도로 대비하고, 비밀은 ExcludeClipboardContentFromMonitorProcessing과 동료들로 기록과 동기에서 뺍니다.
  • IT는 클립보드 기록, 클라우드 동기, RDP 리다이렉션을 GPO / Intune으로 제어할 수 있습니다. 기본값은 모두 허용이므로, 비밀을 다루는 환경에서는 의도적으로 정합니다.
  • D&D는 COM입니다. IDropSource/IDropTarget이 클립보드와 같은 IDataObject를 넘깁니다. RegisterDragDrop에는 OleInitialize(STA)가 필요합니다.
  • 승격된 앱으로의 드롭은 UIPI에 막힙니다. DragDropEffects의 Move는 「원본이 사라진다」는 계약이며, 드롭된 경로는 가져오기 전에 검증합니다.

복사·붙여 넣기와 D&D는 사용자에게 공기처럼 느껴져야 하는 기능입니다. 바로 그래서 「붙여 넣을 수 없다」, 「무너진다」, 「사라졌다」가 경험을 그렇게 해치고── 여러 형식을 제공하고 드롭을 제대로 다루는 앱은 그 자체로 일상의 조작을 매끄럽게 만듭니다. 무엇을 먼저 고칠지 정할 때의 재료가 되기를 바랍니다.

관련 기사

관련 상담 영역

합동회사 코무라소프트에서는 업무 앱의 복사·붙여 넣기와 드래그 앤 드롭 지원 설계·구현(여러 형식 제공, Excel 상호 운용, 드롭된 파일 가져오기), 「붙여 넣으면 무너진다」나 「복사가 사라진다」는 문제의 원인 조사, 클립보드를 감시하는 입력 자동화, 기밀 데이터를 기록과 동기에서 빼는 구현을 다루고 있습니다. COM과 OLE의 아래 계층이 끼는 경우도, 증상을 나누는 단계부터 환영합니다.

참고 링크

  1. Microsoft Learn, Clipboard Formats. 창이 같은 정보를 여러 클립보드 형식으로 둘 수 있다는 점, RegisterClipboardFormat을 통한 등록 형식(같은 이름을 등록하면 같은 값이 돌아와 앱이 공유할 수 있음), 합성 형식, ExcludeClipboardContentFromMonitorProcessing, CanIncludeInClipboardHistory, CanUploadToCloudClipboard로 내용을 클립보드 기록 / 클라우드 동기에서 제외한다는 점에 대해.  2 3 4 5

  2. Microsoft Learn, Clipboard Operations. 한 번에 창 하나만 클립보드를 열 수 있다는 점, 복사 때 더 표현력 있는 형식에서 덜한 형식으로 둔다는 점, 붙여 넣기 때 EnumClipboardFormats / GetPriorityClipboardFormat로 형식을 고른다는 점, SetClipboardData에 NULL을 넘기는 지연 렌더링과 WM_RENDERFORMAT / WM_RENDERALLFORMATS의 책임, 지연 렌더링의 트레이드오프에 대해.  2 3 4 5 6 7 8

  3. Microsoft Learn, Standard Clipboard Formats. 표준 형식 CF_TEXT(ANSI), CF_UNICODETEXT, CF_HDROP, CF_DIB, CF_LOCALE의 정의, 시스템이 CF_LOCALE에 연관된 코드 페이지로 CF_TEXT와 CF_UNICODETEXT를 암묵 변환한다는 점에 대해.  2 3

  4. Microsoft Learn, Shell Clipboard Formats. CF_HDROP이 DROPFILES 구조와 이중 NUL 종료 전체 경로 문자열 배열로 구성된다는 점, DragQueryFile로 개별 경로를 꺼낸다는 점, CFSTR_ 셸 형식은 RegisterClipboardFormat로 등록해야 한다는 점에 대해.  2

  5. Microsoft Learn, HTML Clipboard Format. 등록 이름이 「HTML Format」이라는 점, Version, StartHTML, EndHTML, StartFragment, EndFragment 같은 바이트 오프셋 헤더 구조, 인코딩이 항상 UTF-8이라는 점, StartFragment/EndFragment 주석 관례에 대해.  2 3

  6. Microsoft Learn, OleFlushClipboard function (ole2.h). OleSetClipboard가 클립보드에 데이터 객체에 대한 포인터만 두게 한다는 점, OleFlushClipboard가 데이터를 클립보드에 실체화해 앱 종료 뒤에도 붙여 넣기가 된다는 점, 종료 때 남길 필요가 없으면 OleSetClipboard(NULL)로 클립보드를 비운다는 점에 대해.  2

  7. Microsoft Learn, OleGetClipboard function (ole2.h). 클립보드에서 IDataObject를 얻는 방법, 클립보드 데이터는 신뢰되지 않으므로 앱이 쓰기 전에 신중히 파싱해야 한다는 경고에 대해.  2

  8. Microsoft Learn, Using the clipboard. 클립보드를 감시하는 세 방법(뷰어 창, 시퀀스 번호, 형식 리스너)의 비교, 새 프로그램은 AddClipboardFormatListener를 통한 리스너를 써야 한다는 점, 체인 유지가 불완전하면 뷰어 체인이 취약하다는 점, 시퀀스 번호를 폴링해서는 안 된다는 점에 대해.  2

  9. Microsoft Learn, Policy CSP - Experience. Experience/AllowClipboardHistory 정책으로 클립보드 기록을 허용하거나 거부한다는 점, Windows 10 버전 1809부터 쓸 수 있다는 점, 기본값이 허용이라는 점, 「시스템 > OS 정책」 아래의 GPO 매핑과 변경이 즉시 효력을 낸다는 점에 대해.  2

  10. Microsoft Learn, Policy CSP - Privacy. Privacy/AllowCrossDeviceClipboard 정책으로 기기 간 클립보드 동기를 허용하거나 거부한다는 점, 같은 Microsoft 계정 / Microsoft Entra 계정으로 로그인한 기기 간에 동기가 일어난다는 점, 기본값이 허용이라는 점에 대해.  2 3

  11. Microsoft Learn, Policy CSP - ADMX_TerminalServer. TS_CLIENT_CLIPBOARD(「클립보드 리다이렉션 허용 안 함」, 레지스트리 값 fDisableClip)가 원격 데스크톱 세션에서 로컬과 원격 사이의 클립보드 공유를 금지할 수 있다는 점, 리다이렉션이 기본으로 허용된다는 점에 대해.  2

  12. Microsoft Learn, Drag and Drop (COM). OLE 드래그 앤 드롭이 IDropSource(드래그 원본), IDropTarget(드롭 대상), DoDragDrop(OLE가 제공하는 루프) 셋으로 돈다는 점, 클립보드 복사·붙여 넣기와 같은 기능을 제공하므로 이미 복사·붙여 넣기를 구현한 앱은 작은 추가만 필요하다는 점, 피드백의 종류에 대해.  2 3

  13. Microsoft Learn, RegisterDragDrop function (ole2.h). 드롭 대상 창을 IDropTarget과 함께 등록한다는 점, COM을 CoInitialize/CoInitializeEx로 초기화하면 항상 E_OUTOFMEMORY로 실패하므로 OleInitialize가 필요하다는 점, 호출 스레드가 메시지 펌프를 돌리지 않으면 드래그 원본 앱이 멈춘다는 점에 대해.  2 3

  14. Microsoft Learn, ChangeWindowMessageFilterEx function (winuser.h). UIPI가 낮은 무결성 송신자로부터의 메시지 수신을 기본으로 막는 보안 메커니즘이라는 점, 메시지 필터(MSGFLT_ALLOW)로 창마다 특정 메시지를 허용한다는 점에 대해.  2 3

  15. Microsoft Learn, How to add data to the Clipboard (Windows Forms). DataObject와 Clipboard.SetDataObject로 여러 형식을 한꺼번에 둔다는 점, 다른 앱이 알아볼 수 있게 여러 형식으로 더한다는 점, Clipboard 클래스는 STA 스레드에서만 쓸 수 있어 [STAThread]가 필요하다는 점에 대해.  2

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

ActiveX 이관

COM / ActiveX / OCX 자산을 유지할지, 감쌀지, 교체할지의 단계적 판단을 정리한 토픽 페이지입니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

Excel에서 복사한 표를 앱에 붙여 넣으면 서식이 무너지는 이유는 무엇인가요?
클립보드는 「데이터 한 덩어리」를 두지 않습니다. 같은 내용이 여러 형식(원본 앱의 사설 형식, HTML Format, CSV, 유니코드 텍스트 등)으로 한꺼번에 놓이고, 붙여 넣는 쪽 앱이 이해하는 형식을 골라 꺼냅니다. 서식이 무너질 때의 전형은 붙여 넣는 쪽이 일반 텍스트(CF_UNICODETEXT)만 읽는 것입니다. 표 구조까지 원하면 붙여 넣기 측이 HTML Format이나 CSV를 우선하도록 구현합니다. 반대로 자체 앱에서 복사한 것을 다른 앱이 올바르게 붙여 넣게 하려면, 복사 때 풍부한 형식과 일반 형식을 함께 제공합니다.
복사한 앱을 닫은 뒤에 붙여 넣을 수 없게 되는 이유는 무엇인가요?
원본이 지연 렌더링을 쓰기 때문입니다. 큰 데이터를 다루는 앱은 복사 때 페이로드를 두지 않고, 「요청되면 만들겠다」는 약속만 클립보드에 등록합니다. 그다음 원본이 종료 때의 WM_RENDERALLFORMATS에 응답해 데이터를 실체화하지 않고 나가면, 아직 렌더링되지 않은 형식은 사라집니다. OLE 클립보드(IDataObject)를 쓰는 앱은 종료 때 OleFlushClipboard를 호출해 데이터를 실체화하면, 종료 뒤에도 붙여 넣기가 됩니다.
자체 앱이 클립보드 변경을 어떻게 감시할 수 있나요?
지금 권장되는 방법은 AddClipboardFormatListener로 창을 리스너로 등록하고, 내용이 바뀔 때마다 오는 WM_CLIPBOARDUPDATE 메시지를 처리하는 것입니다. 타이머로 내용을 폴링하는 것은 일을 낭비하고 갱신을 놓칠 수 있으며, SetClipboardViewer에 기반한 옛 뷰어 체인은 체인의 앱 하나 버그가 체인 전체를 깨뜨리므로 하위 호환만 위해 남습니다. 또한 읽기의 OpenClipboard는 다른 프로세스가 클립보드를 쥐고 있으면 실패할 수 있으므로, 읽기를 안정적으로 하려면 짧은 대기를 둔 재시도를 구현합니다.
암호 같은 비밀을 클립보드 기록(Win+V)에 남기지 않는 방법이 있나요?
앱 측과 정책 측, 지렛대가 둘입니다. 앱 측에서는 복사할 때 등록 형식 ExcludeClipboardContentFromMonitorProcessing도 함께 두면, 그 내용은 기록에도 기기 간 동기에도 들어가지 않습니다. CanIncludeInClipboardHistory(기록만)와 CanUploadToCloudClipboard(동기만)로 각각 독립적으로 제어할 수도 있습니다. 암호 관리자가 쓰는 메커니즘입니다. 조직 전체에서 끄고 싶으면 그룹 정책이나 Intune(Policy CSP)의 AllowClipboardHistory와 AllowCrossDeviceClipboard로 기록과 클라우드 동기 자체를 비활성화할 수 있습니다.
관리자로 실행 중인 앱에 파일을 드래그 앤 드롭할 수 없는 이유는 무엇인가요?
UIPI(User Interface Privilege Isolation)라는 보안 메커니즘이 낮은 무결성 프로세스에서 높은 무결성 창으로의 메시지 전달을 막기 때문입니다. 파일 탐색기는 보통 권한(중간 무결성)으로 돌므로, 드래그 앤 드롭 알림이 승격된 앱의 창에 닿지 않습니다. ChangeWindowMessageFilterEx로 WM_DROPFILES 같은 메시지를 개별 허용하는 우회는 잘 알려져 있지만, 그것은 옛 드롭 알림에만 적용됩니다. 진짜 수정은 앱을 항상 승격해 돌리도록 설계하지 않고, 승격이 필요한 작업만 별도 프로세스로 격리하는 것입니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기