Cara kerja clipboard dan seret-dan-lepas — menangani transfer data OLE dengan benar di aplikasi bisnis

· · Windows, Clipboard, Seret dan lepas, OLE, COM, Pengembangan Windows, WinForms, WPF

“Ketika kita menempel tabel yang disalin dari Excel, pemformatan berantakan. Kita ingin ia menempel sebagai tabel.” “Konten yang kita salin di aplikasi kita menjadi sesuatu yang aneh ketika kita menempelnya ke Word.” “Kita ingin dapat menerima berkas lewat seret dan lepas.” — Dalam percakapan konsultasi tentang perubahan aplikasi bisnis, permintaan seputar salin-dan-tempel serta seret dan lepas (D&D) adalah makanan pokok.

Justru karena ini adalah “fitur yang semua orang anggap sudah tentu”, cara kerjanya sebenarnya mengejutkan sedikit diketahui. Jika Anda menganggap clipboard sebagai “kotak tempat Anda menaruh satu potong data”, Anda tidak dapat menjelaskan mengapa salinan yang sama menghasilkan hasil berbeda tergantung ke mana Anda menempel, atau mengapa tempel berhenti bekerja setelah Anda menutup aplikasi sumber. Clipboard yang sungguhan adalah mekanisme yang menaruh konten yang sama dalam beberapa format sekaligus, dan membiarkan sisi tempel memilih format yang dipahaminya.

Dan seret dan lepas, pada dasarnya, adalah transfer data OLE yang menyerahkan persis representasi data yang sama dengan clipboard (IDataObject), lewat antarmuka COM. Dengan kata lain, salin-dan-tempel dan D&D adalah saudara: pahami satu dengan benar dan yang lain ada di situ.

Artikel ini ditujukan kepada staf IT di perusahaan kecil dan menengah serta pengembang aplikasi Windows. Ia mengikat, dalam satu gambaran, cara kerja format clipboard, praktik di sisi tempel dan sisi salin, cara yang benar mengawasi clipboard, kebijakan administratif untuk riwayat clipboard, sinkronisasi awan, dan RDP, serta struktur dan jebakan seret-dan-lepas OLE.

1. Kesimpulan lebih dulu

  • Clipboard adalah satu area yang dibagi oleh aplikasi di desktop yang sama (window station), dan yang duduk di sana bukan “satu potong data” melainkan konten yang sama dalam beberapa format sekaligus. Sesi berbeda, seperti RDP, semula punya clipboard berbeda; fitur pengalihan-lah yang menjembatani keduanya. Karena tujuan memilih format yang dipahaminya, salinan yang sama menghasilkan hasil berbeda tergantung ke mana Anda menempel.12
  • Untuk teks, pakai CF_UNICODETEXT. CF_TEXT adalah ANSI dan bergantung pada code page, dan pada sistem Jepang ia adalah tempat berkembang biaknya mojibake. Sistem mengonversi antara keduanya secara implisit, tetapi sisi kanoniknya adalah Unicode.3
  • Berkas berjalan sebagai CF_HDROP (larik path yang diakhiri double-NUL), dan teks terformat memakai format terdaftar “HTML Format”. HTML Format punya struktur yang tidak biasa: teks UTF-8 dengan header offset byte.45
  • Penyebab sungguhan “saya menutup aplikasi sumber dan tidak dapat menempel lagi” adalah delayed rendering. Itu mekanisme yang menaruh bukan payload melainkan hanya janji untuk “menghasilkannya ketika diminta”; jika Anda melewatkan mewujudkannya saat keluar (merespons WM_RENDERALLFORMATS, atau OleFlushClipboard untuk OLE), tempel berhenti bekerja.26
  • Perlakukan data yang ditempel sebagai input tidak tepercaya dari luar. Microsoft sendiri menyatakan dengan gamblang bahwa “data clipboard tidak tepercaya. Parse dengan hati-hati”.7
  • Untuk mengawasi clipboard, AddClipboardFormatListener + WM_CLIPBOARDUPDATE adalah satu-satunya opsi. Jangan pakai polling, dan jangan pakai SetClipboardViewer lama (rantai viewer). Format terdaftar yang menjaga rahasia keluar dari riwayat dan sinkronisasi (ExcludeClipboardContentFromMonitorProcessing dan kawan-kawannya) juga disediakan.81
  • Riwayat clipboard (Win+V) dan sinkronisasi awan adalah perhatian manajemen IT. Anda dapat mengendalikannya dengan AllowClipboardHistory dan AllowCrossDeviceClipboard lewat GPO / Intune (Policy CSP), dan pengalihan clipboard RDP punya kebijakan khusus sendiri.91011
  • Seret dan lepas adalah COM. IDataObject yang sama dengan clipboard diserahkan antara IDropSource (sumber seret) dan IDropTarget (target lepas) lewat loop DoDragDrop. RegisterDragDrop mensyaratkan inisialisasi dengan OleInitialize (STA).1213
  • Anda tidak dapat melepas dari File Explorer berhak biasa ke aplikasi yang di-elevate. UIPI (pemblokiran pesan menurut tingkat integritas) adalah penyebabnya, dan itu kendala yang harus Anda ketahui pada waktu desain.14

Di bawah kita menelusuri ini dari fondasi clipboard ke atas.

2. Apa sebenarnya clipboard — bukan “satu potong data” melainkan “konten yang sama dalam beberapa format”

Clipboard adalah mekanisme berbagi data bersama yang setiap aplikasi yang berbagi desktop yang sama dapat jangkau (lebih tepatnya, ia per window station: sesi pengguna berbeda atau sesi RDP masing-masing punya clipboard sendiri. Salin-dan-tempel bekerja lewat RDP karena fitur pengalihan menjembatani keduanya — Bab 7). Prinsip pertama adalah ia didorong pengguna: sikap desain resmi adalah bahwa Anda tidak menaruh data masuk atau mengambil data keluar di belakang punggung pengguna.1

Poin pentingnya adalah bahwa salinan tidak menaruh “satu potong data”. Jendela yang menyalin mengosongkan clipboard lalu menaruh beberapa format berurutan, mengekspresikan konten yang sama dari format yang lebih mampu ke yang kurang mampu.2 Misalnya, ketika Anda menyalin tabel di spreadsheet, secara konseptual sesuatu seperti berikut ada di clipboard pada saat yang sama.

Prioritas Format Isi
1 Format privat aplikasi Representasi internal lengkap, termasuk rumus dan pemformatan (untuk tempel kembali ke aplikasi yang sama)
2 HTML Format Fragmen HTML yang menjaga struktur tabel dan pemformatan
3 CSV Teks yang dibatasi sel
4 CF_UNICODETEXT Teks biasa yang dipisah tab
5 Format gambar Bitmap bagaimana tabel terlihat

Sisi tempel memilih format yang dipahaminya dari daftar ini dan mengekstraknya. Tempel ke Word dan Anda mendapat tabel terformat; tempel ke Notepad dan Anda mendapat teks yang dipisah tab — karena keduanya memilih format berbeda. “Hasilnya tergantung ke mana Anda menempel” bukan bug; itu konsekuensi normal desain ini.

Mengapa salinan yang sama menghasilkan hasil berbeda tergantung ke mana Anda menempelSisi salin menaruh konten yang sama di clipboard dalam beberapa format, dan sisi tempel memilih format yang dipahaminya, jadi Word mendapat tabel terformat dan Notepad mendapat teks yang dipisah tabWordNotepadSalin: spreadsheetClipboard (banyak format)Format lebih kayaFormat lebih biasaPrivat aplikasiHTML FormatCSVCF_UNICODETEXTTabel terformatTeks yang dipisah tab

Dibalik, keluhan pembuka — “pemformatan berantakan”, “sesuatu yang aneh tertempel” — hampir semuanya turun ke masalah bagaimana satu sisi memilih format, atau bagaimana sisi lain menawarkannya. Bab 4 membahas sisi tempel; Bab 5 membahas sisi salin.

3. Format standar dan format terdaftar — CF_UNICODETEXT, CF_HDROP, HTML Format

3.1. Format standar — pakai sisi Unicode untuk teks

Format yang OS tetapkan di muka disebut format standar. Yang terus muncul di aplikasi bisnis adalah berikut.3

Format Nilai Isi
CF_TEXT 1 Teks ANSI (bergantung code page)
CF_UNICODETEXT 13 Teks Unicode. Ini format kanonik untuk teks
CF_HDROP 15 Daftar path berkas (handle HDROP)
CF_DIB 8 Bitmap independen perangkat
CF_LOCALE 16 Pengidentifikasi locale yang terkait dengan teks

CF_TEXT dan CF_UNICODETEXT dikonversi satu sama lain secara implisit oleh sistem (format yang disintesis). Konversi kode karakter memakai code page yang terkait dengan CF_LOCALE.3 Mengandalkan konversi itu menjatuhkan karakter yang ANSI tidak dapat wakili (misalnya simbol hanya-Unicode dan karakter penggabung), jadi aturannya adalah satukan apa yang aplikasi baca dan tulis pada CF_UNICODETEXT (DataFormats.UnicodeText di .NET).

Konversi implisit antara CF_UNICODETEXT dan CF_TEXTAplikasi membaca dan menulis hanya CF_UNICODETEXT; sistem mensintesis CF_TEXT lewat konversi implisit dengan code page CF_LOCALE. Karakter yang ANSI tidak dapat wakili dijatuhkan dalam konversi ituKonversi CF_LOCALEAplikasi membaca dan menulisCF_UNICODETEXTCF_TEXT (ANSI)Karakter yang tidak dapat diwakili dijatuhkan

3.2. CF_HDROP — berkas berjalan sebagai “daftar path”

CF_HDROP adalah yang dipakai ketika Anda menyalin berkas di File Explorer, atau ketika Anda menyeret dan melepas berkas. Payload-nya bukan berkas itu sendiri; itu blok memori yang menata larik “diakhiri double-NUL”: setelah header struktur DROPFILES, string path lengkap yang dipisah karakter NUL, dan string kosong di akhir. pFiles header adalah offset awal daftar path, dan fWide mengatakan apakah string-nya Unicode.4

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

Di kode native Anda menariknya satu per satu dengan DragQueryFile; di .NET Anda menerimanya sebagai string[] lewat DataFormats.FileDrop. Fakta bahwa “yang berjalan hanya path, bukan berkas itu sendiri” akan penting lagi di D&D Bab 8 dan 9.

Tata letak blok memori CF_HDROPStruktur DROPFILES duduk di awal memori global; pFiles adalah offset awal daftar path dan fWide mengatakan apakah Unicode. Path lengkap kemudian mengikuti, dipisah NUL, dan blok berakhir dengan string kosong (double NUL). Yang berjalan hanya path, bukan berkas itu sendiriDROPFILES (pFiles / fWide)C:\\data\\a.txt + NULC:\\data\\b.txt + NULString kosong (double NUL)Hanya path yang berjalan, bukan berkas

3.3. Format terdaftar — RegisterClipboardFormat dan “HTML Format”

Untuk data yang format standar tidak dapat ekspresikan, aplikasi dapat memilih nama dan mendaftarkan formatnya sendiri. Lewatkan nama ke RegisterClipboardFormat dan Anda mendapat ID format kembali; mendaftar di bawah nama yang sama dari aplikasi berbeda mengembalikan ID yang sama, jadi begitu Anda sepakat pada nama Anda dapat berbagi data antar aplikasi.1 Ketika Anda melewatkan data terstruktur di antara rangkaian aplikasi Anda sendiri, pakai nama yang tidak akan bertabrakan, seperti KomuraSoft.Report.RowData.

Format terdaftar representatif adalah “HTML Format”, untuk teks terformat (bersama RTF, salah satu dari dua format teks kaya utama). Payload-nya adalah teks UTF-8, tetapi punya struktur yang tidak biasa: header yang mencantumkan offset byte dilekatkan di depan.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>

Setiap offset adalah posisi byte dari awal data, termasuk header itu sendiri; praktik biasa adalah mencadangkan lebar tetap (misalnya 10 digit) dan menulis nilai terukur kembali setelah Anda membangun body. StartFragment/EndFragment menandai awal dan akhir “fragmen yang pengguna sebenarnya pilih” dalam byte (bukan dalam karakter). Di UTF-8 yang mencakup Jepang, jumlah karakter dan jumlah byte menyimpang, jadi jika Anda salah menghitung offset ini, tempel ke aplikasi lain menjatuhkan awal atau akhir. Jika Anda menghasilkan HTML Format sendiri, Anda harus mengisi header dengan posisi byte yang diukur setelah encoding ke UTF-8.5

Bagaimana header HTML Format berhubungan dengan offsetStartHTML dan EndHTML header menunjuk ke seluruh HTML, dan StartFragment serta EndFragment menunjuk ke fragmen yang pengguna pilih, keduanya sebagai posisi byte dari awal data. Karena jumlah karakter dan jumlah byte menyimpang di UTF-8, isi header dengan posisi byte yang diukur setelah encodingHeader (offset byte)Seluruh HTMLFragmen yang dipilihOffset adalah byte setelah UTF-8

CSV (DataFormats.CommaSeparatedValue di .NET) juga umum dipakai untuk data tabular. Untuk interop dengan Excel, menawarkan HTML Format (dengan pemformatan), CSV (hanya nilai), dan CF_UNICODETEXT (dipisah tab) bersama berarti Anda tidak harus memilih satu tujuan tempel.

4. Praktik di sisi tempel — prioritas format dan validasi

4.1. Lihat dari format kaya ke bawah

Format di clipboard berjajar dalam urutan sisi salin menaruhnya (yaitu, dari lebih ekspresif ke kurang). Garis dasar sisi tempel adalah melihat, di antara format yang dapat Anda tangani, mulai dari yang punya informasi paling banyak. Di Win32 Anda mengenumerasi dengan EnumClipboardFormats dan memakai format pertama yang Anda kenali, atau Anda melewatkan daftar prioritas sendiri ke GetPriorityClipboardFormat dan membiarkannya memilih.2

Di .NET cabangnya tampak seperti berikut.

// 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
}

Itulah jawaban untuk keluhan pembuka, “menempel tabel Excel berantakan”. Aplikasi yang hanya membaca teks biasa tidak pernah menerima struktur tabel. Seberapa jauh ke bawah daftar format Anda terima adalah keputusan desain di sisi tempel.

Percabangan tempel yang melihat dari format kaya ke bawahJika HTML Format ada dan payload juga string, impor sebagai tabel; jika tidak coba CSV; jika itu juga hilang, jatuh ke teks yang dipisah tab. Jika tidak ada kandidat yang ada, tolakyatidakyatidakyatidakMulai tempelHTML Format + string?Validasi header → tabelCSV ada?Impor sebagai CSVUnicodeText?Teks yang dipisah tabTolak

4.2. Data yang ditempel adalah input eksternal

Mudah terlewat, tetapi isi clipboard adalah data dari luar, dan Anda tidak tahu aplikasi mana yang menaruhnya. Microsoft juga memperingatkan, di dokumentasi clipboard OLE, bahwa “data clipboard tidak tepercaya. Parse dengan hati-hati sebelum Anda memakainya di aplikasi”.7

  • Validasi bahwa offset header HTML Format tidak menunjuk ke luar buffer (aplikasi yang mengeluarkan header rusak memang ada).
  • Nilai yang Anda impor sebagai angka, tanggal, atau kode harus melalui validasi yang sama seperti input di layar.
  • Pasang pertahanan terhadap data raksasa. Bahkan jika seseorang menempel gambar ratusan megabyte atau jutaan baris teks, jangan blokir UI, dan tolak begitu batas terlampaui. Catatan: GetData .NET, pada saat Anda memanggilnya, mewujudkan seluruh payload menjadi string managed (dan delayed rendering berjalan sebagai bagian dari itu), jadi menaruh pemeriksaan ukuran setelah GetData bukan pertahanan. Di Win32, memeriksa GlobalSize pada HGLOBAL yang GetClipboardData kembalikan memang memberi Anda pertahanan pada tahap “jangan lanjut ke konversi dan parsing sebagai string managed”, tetapi untuk format delayed-rendering GetClipboardData itu sendiri memulai rendering, jadi Anda tetap tidak dapat mencegah perwujudan di sisi sumber salin. Untuk menjaga UI tidak membeku, pindahkan pengambilan dari thread UI (dan bahkan kemudian, karena Clipboard .NET mensyaratkan STA, lakukan di thread khusus yang ditetapkan ke STA, bukan di thread thread-pool Task.Run (MTA) — Bagian 5.1).

Gagasan bahwa “nilai yang datang dari luar, apa pun jalurnya, divalidasi sebelum Anda memakainya” sama dengan yang dijabarkan di “Jangan pernah memakai nilai terdekode kode QR apa adanya”. Asumsi bahwa tempel aman karena itu tindakan pengguna adalah bagaimana kecelakaan dimulai.

Validasi data yang ditempel sebelum Anda memakainyaData yang diambil dari clipboard melalui format-ada, jenis-payload, batas-ukuran, dan validasi isi secara berurutan; gagal salah satunya dan Anda menolak atau jatuh ke format kandidat berikutnyajenis salahterlalu besartidak validFormat ada?Jenis payload OK?Ukuran dalam batas?Validasi isiImporTolak / format berikutnya

5. Praktik di sisi salin — menawarkan beberapa format sekaligus, dan delayed rendering

5.1. Taruh beberapa format sekaligus

Praktik sisi salin adalah kebalikan dari 4.1: tawarkan format kaya dan format biasa pada saat yang sama. Dengan DataObject WinForms/WPF Anda dapat menulisnya dalam beberapa baris.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

Dua catatan. Pertama, kelas Clipboard .NET hanya dapat dipakai dari thread STA.15 Thread UI WinForms/WPF adalah STA karena [STAThread], jadi ini biasanya bukan masalah, tetapi menyentuhnya dari thread latar belakang gagal (dasar STA/MTA ada di “Dasar COM STA/MTA”). Kedua, arti copy: true terikat pada delayed rendering di subbagian berikutnya.

5.2. Delayed rendering — mengapa “tutup sumber dan Anda tidak dapat menempel”

Membangun payload besar dalam banyak format setiap kali adalah pemborosan, jadi clipboard punya mekanisme bernama delayed rendering. Lewatkan NULL sebagai handle data ke SetClipboardData dan, alih-alih payload, hanya janji untuk “menghasilkannya ketika diminta” yang didaftarkan; ketika seseorang meminta format itu, WM_RENDERFORMAT datang ke sumber salin, dan baru kemudian data dihasilkan.2

Konsekuensi desain ini adalah “saya menutup aplikasi sumber dan tidak dapat menempel lagi” di pembuka. Sebelum keluar, sumber salin menerima WM_RENDERALLFORMATS dan bertanggung jawab mewujudkan setiap format yang belum dirender; keluar tanpa melakukan itu dan format hilang.2

Delayed rendering dan mengapa tutup-lalu-tempel gagalSumber salin mendaftarkan hanya janji dengan handle NULL, dan mewujudkan sesuai permintaan lewat WM_RENDERFORMAT. Saat keluar ia bertanggung jawab mewujudkan setiap format dengan WM_RENDERALLFORMATS; lewati itu dan format hilangRENDERALLFORMATSLewati wujudkanSetClipboardData NULL = janjiSisi tempel memintanyaWM_RENDERFORMAT → bangun sekarangSumber salin akan keluarTempel bekerja setelah keluarFormat hilang setelah tutup

Di clipboard OLE (gaya yang menaruh IDataObject dengan OleSetClipboard), hubungan ini bahkan lebih jelas. Semua yang clipboard pegang adalah pointer ke objek data, dan memanggil OleFlushClipboard saat keluar aplikasi mewujudkan data ke clipboard, jadi tempel tetap bekerja setelah keluar.6 Clipboard.SetDataObject(data, copy: true) .NET adalah yang menentukan perilaku “pertahankan setelah keluar” ini.

Ketika Anda menyalin rentang besar di Excel dan mencoba keluar, prompt “There is a large amount of information on the Clipboard. Do you want to be able to paste this information into another program later?” persis adalah konfirmasi apakah menjalankan perwujudan ini (flush). Jika Anda memakai delayed rendering di aplikasi Anda sendiri, ingat bahwa perwujudan saat keluar adalah bagian dari set yang sama. Delayed rendering adalah optimasi performa, dan karena permintaan render berjalan secara sinkron di dalam pemrosesan pesan, data yang memakan waktu lama untuk dihasilkan punya trade-off membekukan UI.2

6. Praktik mengawasi clipboard — listener, coba ulang, dan pengecualian riwayat

6.1. Pakai AddClipboardFormatListener

Persyaratan seperti “kita ingin mendeteksi nilai pembaca barcode atau salinan dari sistem bisnis dan mengimpornya secara otomatis” membutuhkan Anda mengawasi perubahan clipboard. Secara historis ada tiga metode; hari ini jawaban yang benar adalah satu.8

Metode Penilaian
Baca pada timer (polling) Boros, dan Anda dapat melewatkan pembaruan. Jangan pakai
SetClipboardViewer (rantai viewer) Bug di satu aplikasi dalam rantai merusak seluruh rantai. Dipertahankan hanya untuk kompatibilitas mundur
AddClipboardFormatListener Direkomendasikan. WM_CLIPBOARDUPDATE datang ke jendela yang didaftarkan
Alur mengawasi clipboardDaftar dengan AddClipboardFormatListener ketika handle dibuat, dan WM_CLIPBOARDUPDATE datang tidak peduli aplikasi mana yang menyalin. Baca dengan coba ulang, dan batalkan pendaftaran secara simetris dengan RemoveClipboardFormatListener ketika handle dihancurkanbatalkan pendaftaranAddClipboardFormatListenerTungguBeberapa aplikasi menyalinWM_CLIPBOARDUPDATEBaca dengan coba ulang (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. Coba ulang ketika Anda tidak dapat membukanya

Hanya satu jendela pada suatu waktu yang dapat membuka clipboard; sementara proses lain membukanya, OpenClipboard gagal.2 Tepat setelah WM_CLIPBOARDUPDATE, sumber salin atau pengawas lain sering masih beroperasi, jadi kegagalan baca sementara adalah event normal. Selalu pasang beberapa coba ulang dengan tunggu singkat (puluhan milidetik) di antaranya. Perhatikan bahwa overload Clipboard .NET yang membiarkan Anda menentukan jumlah coba ulang dan interval ada hanya di sisi tulis, SetDataObject. Tidak ada yang setara di sisi baca (GetDataObject dan kawan-kawannya), jadi Anda menulis catch-tunggu-coba-ulang sendiri — ExternalException di WinForms, COMException di WPF.

Alur coba ulang baca clipboardHanya satu jendela pada suatu waktu yang dapat membuka clipboard, jadi baca tepat setelah notifikasi perubahan dapat gagal karena balapan dengan proses lain. Pada pengecualian, tunggu puluhan milidetik dan coba ulang; jika Anda menabrak batas, menyerah kali ini dan ambil pada pembaruan berikutnyaberhasilsedang dipakaicoba ulangbatasWM_CLIPBOARDUPDATECoba bacaImpor (pemeriksaan Bab 4)Tunggu puluhan mdMenyerah kali ini

6.3. Jaga keluar dari riwayat dan sinkronisasi — peduli pada fitur salin yang menangani rahasia

Windows punya riwayat clipboard (Win+V) dan sinkronisasi lintas perangkat (clipboard awan), dan data yang aplikasi taruh termasuk dalam cakupan keduanya secara bawaan. Aplikasi yang menaruh rahasia seperti kata sandi atau nomor rekening pada fitur salin juga menaruh format terdaftar yang mengecualikan konten dari riwayat dan sinkronisasi.1

  • ExcludeClipboardContentFromMonitorProcessing: Taruh ini dan isi salinan itu tidak termasuk baik di riwayat maupun sinkronisasi.
  • CanIncludeInClipboardHistory (DWORD 0): Tekan hanya riwayat.
  • CanUploadToCloudClipboard (DWORD 0): Tekan hanya sinkronisasi lintas perangkat.

Alasan kata sandi yang disalin pengelola kata sandi tidak tertinggal di Win+V adalah mekanisme ini. Anda mendapat ID format dengan melewatkan nama ke RegisterClipboardFormat dan menetapkannya di samping data biasa, jadi layak diimplementasikan di setiap aplikasi bisnis yang menangani rahasia.

7. Clipboard dari sudut pandang IT — riwayat, sinkronisasi awan, dan kontrol RDP

Melangkah sedikit menjauh dari pengembangan, berikut poin yang penting bagi administrator. Riwayat clipboard menumpuk salinan terbaru, dan clipboard awan menyinkronkan salinan lintas perangkat yang masuk dengan akun Microsoft / akun Microsoft Entra yang sama.10 Nyaman seperti itu, ia juga menghasilkan residu dan tumpahan: informasi pribadi yang disalin dari sistem bisnis menumpuk di riwayat, dan konten yang disalin di PC kerja tersinkron ke PC pribadi.

Dua kebijakan yang Anda pakai untuk mengendalikan ini di organisasi adalah berikut.

Yang Anda kendalikan GPO (Computer Configuration > Administrative Templates > System > OS Policies) Policy CSP (Intune) Bawaan
Riwayat clipboard Allow Clipboard History Experience/AllowClipboardHistory Diizinkan
Sinkronisasi lintas perangkat Allow Clipboard synchronization across devices Privacy/AllowCrossDeviceClipboard Diizinkan

Keduanya tersedia dari Windows 10 versi 1809 ke atas; nonaktifkan dan item yang sesuai di aplikasi Settings menjadi abu-abu, dan kebijakan berlaku segera.910

Makanan pokok lain adalah pengalihan clipboard RDP (Remote Desktop). Secara bawaan, salin-dan-tempel bekerja antara PC lokal dan sesi jarak jauh, jadi ia dapat menjadi jalur untuk mengambil rahasia dari server. Kebijakan “Do not allow clipboard redirection” (nilai registri fDisableClip) dapat memblokir kedua arah.11 Rilis Windows Server / Windows 11 terbaru juga telah menambahkan kebijakan yang lebih halus, seperti membatasi arah server-ke-klien hanya ke teks. Apakah Anda melarangnya mentah-mentah atau membatasinya secara bertahap adalah keseimbangan operasi dan keamanan.

Jalur isi clipboard dapat menyebar, dan titik kontrolIsi yang disalin termasuk dalam cakupan riwayat dan sinkronisasi awan secara bawaan, dan di RDP mereka berjalan ke sesi lain lewat pengalihan. Setiap jalur dapat dikendalikan oleh kebijakan, dan sisi aplikasi dapat mengecualikan dirinya dari riwayat dan sinkronisasi dengan format pengecualianClipboardRiwayat (Win+V)Sinkronisasi awanPengalihan RDPAllowClipboardHistoryAllowCrossDeviceClipboardfDisableClipFormat pengecualian aplikasi (6.3)

8. Seret dan lepas adalah COM — IDataObject + IDropSource + IDropTarget

8.1. Data yang sama dengan clipboard, cara membawa yang berbeda

Seret-dan-lepas OLE berjalan dengan tiga peran berikut.12

Peran Siapa yang mengimplementasikan Pekerjaan
IDataObject Sumber seret Payload yang dibawa. Objek data multi-format yang sama dengan clipboard
IDropSource Sumber seret Memutuskan apakah seret berlanjut atau dibatalkan, dan umpan balik kursor
IDropTarget Target lepas Menyatakan terima/tolak di DragEnter/DragOver/DragLeave/Drop, dan menerima lepas

Sumber seret memanggil DoDragDrop, loop seret dimulai, dan ketika mouse masuk jendela target-lepas IDropTarget itu diberi tahu; pada lepas, IDataObject diserahkan. Dokumentasi resmi juga mengatakan bahwa “D&D menyediakan persis fungsionalitas yang sama dengan salin-dan-tempel clipboard. Jika aplikasi sudah mengimplementasikan salin-dan-tempel, tambahannya kecil”.12 Dengan kata lain, DataObject multi-format yang Anda bangun di Bab 2 sampai 5 menjadi payload D&D apa adanya.

Alur seret dan lepas OLESumber seret menaruh IDataObject di payload dan memanggil DoDragDrop untuk memulai loop seret; IDropTarget target lepas menyatakan terima/tolak di DragEnter dan DragOver, dan pada Drop memilih format dari IDataObject dan mengekstraknyaDoDragDropmouse masuktombol naikIDataObject + IDropSourceLoop seretDragEnter/Over: EffectIDropTarget.DropPilih format dan ekstrak

8.2. OleInitialize (STA) diperlukan

Jendela yang akan menjadi target lepas mendaftar dengan RegisterDragDrop, dan ada jebakan klasik di sini. Jika Anda menginisialisasi COM dengan CoInitialize/CoInitializeEx, RegisterDragDrop selalu gagal dengan E_OUTOFMEMORY; Anda harus menginisialisasi dengan OleInitialize.13 OleInitialize menginisialisasi COM sebagai STA, karena D&D adalah fitur yang berakar di dunia STA jendela dan message pump. Thread pemanggil juga harus menjalankan message pump; lewati itu dan aplikasi lain hang selama seret.13 Latar belakang di sini persis adalah pembahasan model threading di “Dasar COM STA/MTA”.

Di aplikasi WinForms/WPF kerangka merawat inisialisasi OLE dan implementasi antarmuka, jadi pengembang hanya perlu menulis event.

// 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)
    }
};

Bentuknya sama di WPF: Anda menerima dengan AllowDrop="True" dan event DragOver/Drop pada elemen, dan Anda mengekstrak larik path dengan e.Data.GetData(DataFormats.FileDrop). Menyatakan terima/tolak (Effect) pada setiap DragEnter/DragOver adalah konvensi IDropTarget; lewati itu dan Anda mendapat bug di mana kursor tetap pada “tidak diizinkan” dan tidak pernah berubah.

9. Jebakan D&D — elevasi, Move, dan validasi path

9.1. Anda tidak dapat melepas ke aplikasi yang di-elevate sebagai administrator

Lepas berkas dari File Explorer ke aplikasi yang diluncurkan dengan “Run as administrator” dan tidak terjadi apa-apa — ini bukan bug implementasi, ini perilaku OS. UIPI (User Interface Privilege Isolation) memblokir pesan dari proses integritas lebih rendah ke jendela integritas lebih tinggi secara bawaan, jadi notifikasi lepas dari File Explorer berhak biasa (integritas sedang) tidak pernah sampai ke aplikasi yang di-elevate.14

Bagaimana UIPI memblokir lepas ke aplikasi yang di-elevateNotifikasi lepas dari File Explorer integritas sedang ke aplikasi yang di-elevate integritas tinggi diblokir oleh UIPI secara bawaan dan tidak pernah datang. Pertahankan UI pada hak biasa dan isolasi pekerjaan berhak istimewa, dan lepas datangnotifikasi lepasdiblokirlolosdelegasikan pekerjaan berhak istimewaExplorer (sedang)UIPIAplikasi di-elevate: tidak ada lepasUI biasa: lepas datangProses di-elevate yang terisolasi

Solusi yang secara individual mengizinkan pesan tertentu seperti WM_DROPFILES dengan ChangeWindowMessageFilterEx terkenal,14 tetapi yang diloloskannya adalah notifikasi lepas yang lebih lama (WM_DROPFILES); ia tidak menyelesaikan D&D OLE secara keseluruhan. Panduan praktisnya jelas: berhenti merancang aplikasi agar berjalan elevated sepanjang waktu. Isolasi hanya pekerjaan yang membutuhkan elevasi ke proses terpisah, dan UI itu sendiri dapat tetap pada hak biasa dan menerima D&D (desain isolasi dibahas secara rinci di “Cara mengisolasi secara konkret “hanya operasi yang membutuhkan hak administrator” di aplikasi Windows”).

9.2. Apa arti DragDropEffects — Move adalah kontrak bahwa “aslinya hilang”

Copy/Move/Link pada DragDropEffects bukan dekorasi; mereka adalah kontrak antara sumber seret dan target lepas. Sumber seret menyatakan himpunan efek yang diizinkannya di DoDragDrop, target lepas memilih efek aktual, dan ketika Move berhasil, sumber seret menghapus data (berkas) — itu konvensinya. Jika sisi penerima tanpa pikir mengembalikan Move, Anda mendapat kecelakaan “saya melepasnya dan berkas asli hilang”. Untuk pemakaian impor aplikasi bisnis, sisi penerima menyatakan Copy adalah bawaan yang aman.

Kontrak DragDropEffects — Move menghapus yang asliSumber seret menyatakan himpunan efek yang diizinkan di DoDragDrop, dan target lepas memilih efek aktual. Ketika Move berhasil sumber seret menghapus berkas, jadi untuk impor sisi penerima harus menyatakan CopyCopyMoveSumber: efek yang diizinkanTarget: pilih EffectAsli tetap (impor)Sumber menghapus berkas

9.3. Memvalidasi path yang dilepas

Yang berjalan di CF_HDROP/FileDrop hanya path (Bagian 3.2). Sebelum Anda mengimpor, lewatkan melalui validasi input tidak tepercaya yang sama seperti tempel.

  • Berkas atau folder: Putuskan sebagai spesifikasi apa yang terjadi ketika seluruh folder dilepas (rekursi dan impor, atau tolak).
  • Placeholder OneDrive: Path mungkin ada sementara body berkas tidak lokal — berkas on-demand. Saat Anda membukanya unduhan dimulai, dan offline ia gagal. Perilaku dan penanggulangan ada di “OneDrive “Files On-Demand” dan aplikasi bisnis”.
  • Path panjang dan path tidak biasa: Path di atas MAX_PATH, path jaringan (UNC), dan path di media lepas-pasang sebaiknya diterima hanya setelah Anda mengonfirmasi bahwa pemrosesan hilir dapat menanganinya.
  • Jumlah dan ukuran total: Agar melepas ribuan berkas tidak membekukan UI, buat impor asinkron dan pasang batas serta tampilan kemajuan.

10. Ringkasan

  • Clipboard adalah mekanisme yang menaruh konten yang sama dalam beberapa format sekaligus di satu area yang dibagi dalam desktop yang sama (window station). Sisi tempel memilih format, jadi salinan yang sama menghasilkan hasil berbeda.
  • Teks adalah CF_UNICODETEXT, berkas adalah CF_HDROP, dan teks terformat adalah format terdaftar HTML Format (header offset byte + UTF-8).
  • Sisi tempel melihat dari kaya ke biasa dan memperlakukan payload sebagai input eksternal. Sisi salin menawarkan beberapa format sekaligus, dan jika memakai delayed rendering ia mengimplementasikan perwujudan saat keluar (WM_RENDERALLFORMATS / OleFlushClipboard) juga.
  • Pengawasan adalah AddClipboardFormatListener + WM_CLIPBOARDUPDATE. Bersiaplah untuk balapan OpenClipboard dengan coba ulang, dan jaga rahasia keluar dari riwayat dan sinkronisasi dengan ExcludeClipboardContentFromMonitorProcessing dan kawan-kawannya.
  • IT dapat mengendalikan riwayat clipboard, sinkronisasi awan, dan pengalihan RDP dengan GPO / Intune. Bawaan adalah diizinkan untuk semuanya, jadi putuskan dengan sengaja di lingkungan yang menangani rahasia.
  • D&D adalah COM: IDropSource/IDropTarget menyerahkan IDataObject yang sama dengan clipboard. RegisterDragDrop mensyaratkan OleInitialize (STA).
  • Lepas ke aplikasi yang di-elevate diblokir oleh UIPI. Move pada DragDropEffects adalah kontrak bahwa “aslinya hilang”; validasi path yang dilepas sebelum Anda mengimpornya.

Salin-dan-tempel dan D&D, bagi pengguna, adalah fitur yang harus terasa seperti udara. Justru karena itu “saya tidak dapat menempel”, “berantakan”, dan “hilang” sangat menyakiti pengalaman — dan mengapa aplikasi yang menawarkan beberapa format dan menangani lepas dengan benar membuat operasi sehari-hari lebih lancar dengan sendirinya. Saya harap ini bahan yang berguna ketika Anda memutuskan apa yang diperbaiki lebih dulu.

Artikel terkait

Area konsultasi terkait

KomuraSoft LLC menangani desain dan implementasi dukungan salin-dan-tempel serta seret-dan-lepas di aplikasi bisnis (menawarkan beberapa format, interop Excel, mengimpor berkas yang dilepas), investigasi akar masalah seperti “berantakan ketika saya menempel” atau “salinan hilang”, otomasi input yang mengawasi clipboard, dan implementasi yang menjaga data rahasia keluar dari riwayat dan sinkronisasi. Kasus yang melibatkan lapisan bawah COM dan OLE dipersilakan bahkan jika Anda mulai dari mengisolasi gejala.

Tautan referensi

  1. Microsoft Learn, Clipboard Formats. Tentang jendela yang dapat menaruh informasi yang sama dalam beberapa format clipboard; format terdaftar lewat RegisterClipboardFormat (mendaftar nama yang sama mengembalikan nilai yang sama, jadi aplikasi dapat membaginya); format yang disintesis; dan mengecualikan konten dari riwayat clipboard / sinkronisasi awan dengan ExcludeClipboardContentFromMonitorProcessing, CanIncludeInClipboardHistory, dan CanUploadToCloudClipboard.  2 3 4 5

  2. Microsoft Learn, Clipboard Operations. Tentang hanya satu jendela pada suatu waktu yang dapat membuka clipboard; menaruh format dari lebih ekspresif ke kurang ekspresif pada waktu salin; pemilihan format pada waktu tempel dengan EnumClipboardFormats / GetPriorityClipboardFormat; delayed rendering dengan melewatkan NULL ke SetClipboardData dan tanggung jawab WM_RENDERFORMAT / WM_RENDERALLFORMATS; dan trade-off delayed rendering.  2 3 4 5 6 7 8

  3. Microsoft Learn, Standard Clipboard Formats. Tentang definisi format standar CF_TEXT (ANSI), CF_UNICODETEXT, CF_HDROP, CF_DIB, dan CF_LOCALE, dan tentang sistem yang secara implisit mengonversi CF_TEXT dan CF_UNICODETEXT memakai code page yang terkait dengan CF_LOCALE.  2 3

  4. Microsoft Learn, Shell Clipboard Formats. Tentang CF_HDROP tersusun dari struktur DROPFILES plus larik string path lengkap yang diakhiri double-NUL; mengambil path individual dengan DragQueryFile; dan format shell CFSTR_ mensyaratkan pendaftaran lewat RegisterClipboardFormat.  2

  5. Microsoft Learn, HTML Clipboard Format. Tentang nama terdaftar adalah “HTML Format”; struktur header dengan offset byte seperti Version, StartHTML, EndHTML, StartFragment, dan EndFragment; encoding selalu UTF-8; dan konvensi komentar StartFragment/EndFragment.  2 3

  6. Microsoft Learn, OleFlushClipboard function (ole2.h). Tentang OleSetClipboard membuat clipboard hanya memegang pointer ke objek data; OleFlushClipboard mewujudkan data ke clipboard sehingga tempel tetap bekerja setelah aplikasi keluar; dan mengosongkan clipboard dengan OleSetClipboard(NULL) ketika Anda tidak perlu mempertahankannya saat keluar.  2

  7. Microsoft Learn, OleGetClipboard function (ole2.h). Tentang cara memperoleh IDataObject dari clipboard, dan peringatan bahwa data clipboard tidak tepercaya dan harus di-parse dengan hati-hati sebelum aplikasi memakainya.  2

  8. Microsoft Learn, Using the clipboard. Tentang membandingkan tiga cara mengawasi clipboard (jendela viewer, nomor urut, dan listener format); program baru diharapkan memakai listener lewat AddClipboardFormatListener; rantai viewer rapuh ketika pemeliharaan rantai tidak lengkap; dan nomor urut bukan sesuatu yang harus Anda poll.  2

  9. Microsoft Learn, Policy CSP - Experience. Tentang mengizinkan atau menolak riwayat clipboard dengan kebijakan Experience/AllowClipboardHistory; ketersediaan dari Windows 10 versi 1809 ke atas; bawaan diizinkan; dan pemetaan GPO di bawah “System > OS Policies” dengan perubahan berlaku segera.  2

  10. Microsoft Learn, Policy CSP - Privacy. Tentang mengizinkan atau menolak sinkronisasi clipboard lintas perangkat dengan kebijakan Privacy/AllowCrossDeviceClipboard; sinkronisasi terjadi antara perangkat yang masuk dengan akun Microsoft / akun Microsoft Entra yang sama; dan bawaan diizinkan.  2 3

  11. Microsoft Learn, Policy CSP - ADMX_TerminalServer. Tentang TS_CLIENT_CLIPBOARD (“Do not allow clipboard redirection”, nilai registri fDisableClip) yang dapat melarang berbagi clipboard antara lokal dan jarak jauh dalam sesi Remote Desktop, dan tentang pengalihan diizinkan secara bawaan.  2

  12. Microsoft Learn, Drag and Drop (COM). Tentang seret-dan-lepas OLE berjalan dengan tiga IDropSource (sumber seret), IDropTarget (target lepas), dan DoDragDrop (loop yang OLE sediakan); menyediakan fungsionalitas yang sama dengan salin-dan-tempel clipboard, sehingga aplikasi yang sudah mengimplementasikan salin-dan-tempel hanya membutuhkan tambahan kecil; dan jenis umpan balik.  2 3

  13. Microsoft Learn, RegisterDragDrop function (ole2.h). Tentang mendaftarkan jendela target-lepas dengan IDropTarget; selalu gagal dengan E_OUTOFMEMORY jika COM diinisialisasi dengan CoInitialize/CoInitializeEx, sehingga OleInitialize diperlukan; dan aplikasi sumber-seret hang jika thread pemanggil tidak menjalankan message pump.  2 3

  14. Microsoft Learn, ChangeWindowMessageFilterEx function (winuser.h). Tentang UIPI sebagai mekanisme keamanan yang secara bawaan memblokir menerima pesan dari pengirim integritas lebih rendah, dan tentang mengizinkan pesan tertentu per jendela dengan filter pesan (MSGFLT_ALLOW).  2 3

  15. Microsoft Learn, How to add data to the Clipboard (Windows Forms). Tentang menaruh data dalam beberapa format sekaligus dengan DataObject dan Clipboard.SetDataObject; menambah dalam beberapa format agar aplikasi lain dapat mengenalinya; dan kelas Clipboard hanya dapat dipakai dari thread STA, sehingga [STAThread] diperlukan.  2

Artikel terbaru dengan tag yang sama untuk mendalami topik-topik terdekat.

Halaman-halaman ini menempatkan topik dalam konteks layanan dan keputusan yang lebih luas.

Artikel ini berkaitan langsung dengan layanan berikut.

Pertanyaan yang sering diajukan

Pertanyaan yang sering muncul dalam konsultasi tentang topik artikel ini.

Mengapa pemformatan tabel yang disalin dari Excel berantakan ketika saya menempelnya ke aplikasi saya?
Clipboard tidak menahan "satu potong data". Konten yang sama ditaruh dalam beberapa format sekaligus (format privat aplikasi sumber, HTML Format, CSV, teks Unicode, dan sebagainya), dan aplikasi tujuan memilih format yang dipahaminya dan mengekstraknya. Ketika pemformatan berantakan, penyebab khasnya adalah tujuan hanya membaca teks biasa (CF_UNICODETEXT). Jika Anda ingin struktur tabel juga, implementasikan sisi tempel agar lebih memilih HTML Format atau CSV. Sebaliknya, jika Anda ingin aplikasi lain menempel dengan benar dari salinan yang dibuat di aplikasi Anda sendiri, tawarkan baik format kaya maupun format biasa pada waktu salin.
Mengapa saya tidak dapat menempel lagi setelah menutup aplikasi yang saya salin darinya?
Karena sumber memakai delayed rendering. Aplikasi yang menangani data besar tidak menaruh payload pada waktu salin; mereka mendaftarkan hanya janji di clipboard bahwa mereka akan "menghasilkannya ketika diminta". Jika sumber kemudian keluar tanpa mewujudkan data sebagai respons terhadap WM_RENDERALLFORMATS saat shutdown, setiap format yang belum dirender hilang. Aplikasi yang memakai clipboard OLE (IDataObject) dapat menjaga tempel tetap bekerja setelah keluar dengan memanggil OleFlushClipboard saat shutdown untuk mewujudkan data.
Bagaimana aplikasi saya sendiri dapat mengawasi perubahan clipboard?
Metode yang saat ini direkomendasikan adalah mendaftarkan jendela Anda sebagai listener dengan AddClipboardFormatListener dan menangani pesan WM_CLIPBOARDUPDATE yang datang setiap kali isi berubah. Polling isi pada timer membuang pekerjaan dan dapat melewatkan pembaruan, dan rantai viewer lama berbasis SetClipboardViewer dipertahankan hanya untuk kompatibilitas mundur, karena bug di satu aplikasi dalam rantai merusak seluruh rantai. Perhatikan juga bahwa OpenClipboard pada baca dapat gagal karena proses lain memegang clipboard, jadi implementasikan coba ulang dengan tunggu singkat jika Anda ingin baca tetap stabil.
Apakah ada cara menjaga rahasia seperti kata sandi keluar dari riwayat clipboard (Win+V)?
Ada dua tuas, satu di sisi aplikasi dan satu di sisi kebijakan. Di sisi aplikasi, jika Anda juga menaruh format terdaftar ExcludeClipboardContentFromMonitorProcessing ketika Anda menyalin, konten itu tidak termasuk baik di riwayat maupun sinkronisasi lintas perangkat. Anda juga dapat mengendalikan masing-masing secara independen dengan CanIncludeInClipboardHistory (hanya riwayat) dan CanUploadToCloudClipboard (hanya sinkronisasi). Ini adalah mekanisme yang dipakai pengelola kata sandi. Jika Anda ingin mematikannya untuk seluruh organisasi, Anda dapat menonaktifkan riwayat dan sinkronisasi awan itu sendiri dengan AllowClipboardHistory dan AllowCrossDeviceClipboard lewat Group Policy atau Intune (Policy CSP).
Mengapa saya tidak dapat menyeret dan melepas berkas ke aplikasi yang berjalan sebagai administrator?
Karena mekanisme keamanan bernama UIPI (User Interface Privilege Isolation) memblokir pengiriman pesan dari proses integritas lebih rendah ke jendela integritas lebih tinggi. File Explorer berjalan pada hak biasa (integritas sedang), jadi notifikasi seret-dan-lepas tidak pernah sampai ke jendela aplikasi yang di-elevate. Solusi yang secara individual mengizinkan pesan seperti WM_DROPFILES dengan ChangeWindowMessageFilterEx terkenal, tetapi itu hanya berlaku untuk notifikasi drop yang lebih lama. Perbaikan sungguhan adalah berhenti merancang aplikasi agar berjalan elevated sepanjang waktu, dan mengisolasi hanya pekerjaan yang membutuhkan elevasi ke proses terpisah.

Profil penulis

Halaman perkenalan penulis artikel.

Go Komura

Direktur KomuraSoft LLC

Berspesialisasi dalam pengembangan perangkat lunak Windows, konsultasi teknis, dan investigasi bug, terutama pada proyek dengan sistem yang sudah ada dan bug yang sulit direproduksi.

Kembali ke blog