سجل التعديلات (النسخة الأولى، نُشرت في 21 Aug، 2026)
- النشر الأول
الاستشهاد بهذا المقال(DOI (الأرشيف المسجّل): 10.5281/zenodo.22176587)
تشير معرّفات DOI أدناه إلى إصدارات مؤرشفة سابقًا، وقد تختلف عن النص الحالي. للإشارة إلى النص الحالي، استخدم رابط هذه الصفحة.
غو كومورا (2026). كيف تعمل الحافظة والسحب والإفلات ── معالجة نقل بيانات OLE بشكل صحيح في تطبيقات الأعمال. شركة كومورا سوفت ذ.م.م.. https://comcomponent.com/ar/blog/windows-clipboard-drag-drop-ole-data-transfer/
- DOI (الأرشيف المسجّل)
- 10.5281/zenodo.22176587
- DOI (آخر إصدار مسجّل)
- 10.5281/zenodo.22241132
«ينهار التنسيق عندما نلصق جدولاً من Excel.» «المحتوى المنسوخ من تطبيقنا لا يخرج بالشكل الذي قصدناه عندما يُلصَق في Word.» «نريد استقبال ملفّات بالسحب والإفلات.» — طلبات كهذه تظهر كثيراً عند مراجعة تطبيقات الأعمال.
هذه كلّها عمليّات يوميّة، لكن إن فكّرت في الحافظة كـ «صندوق يحمل قطعة بيانات واحدة»، فستقرأ كيف تعمل خطأً. في الواقع، إنّها آليّة تضع المحتوى نفسه بعدّة تنسيقات دفعة واحدة وتدع جانب اللصق يختار التنسيق الذي يفهمه. لذلك تنتج النسخة نفسها نتائج مختلفة بحسب مكان اللصق.
مشكلة فشل اللصق بعد إغلاق المصدر تتضمّن «العرض المؤجَّل»، الذي ينتج البيانات فقط عندما تُحتاج. وسحب وإفلات OLE (D&D) يسلّم IDataObject، تمثيل البيانات نفسه الذي تستخدمه حافظة OLE، عبر واجهات COM. النسخ واللصق وD&D ميزتان مرتبطتان: تشتركان في تنسيق البيانات وتختلفان في كيفيّة حمله.
هذا المقال مكتوب لـ موظّفي تقنيّة المعلومات في المنشآت الصغيرة والمتوسّطة ومطوّري تطبيقات Windows. يغطّي أوّلاً كيف تعمل التنسيقات، ثمّ ينظر إلى تنفيذات جانب اللصق وجانب النسخ والمراقبة، ثمّ ينتقل إلى إدارة السجلّ والمزامنة وRDP وإلى محاذير D&D في OLE.
1. الخلاصة أوّلاً
ثمّة ثلاثة محاور تُحفَظ في الحسبان.
- جانب النسخ يعرض عدّة تنسيقات، وجانب اللصق يختار من بينها. الأساسيّات
CF_UNICODETEXTللنصّ، وCF_HDROPلقائمة مسارات ملفّات، والتنسيق المسجَّل «HTML Format» للنصّ المنسَّق.1234 - صمِّم لا تنسيق البيانات فحسب بل أيضاً التحقّق منها وعمرها. تحقّق من بيانات اللصق كدخل خارجيّ غير موثوق. جانب نسخ يستخدم العرض المؤجَّل ينفِّذ أيضاً خطوة التجسيد عند الخروج. راقب بـ
AddClipboardFormatListenerوWM_CLIPBOARDUPDATE، واستعد لتنازع القراءة بإعادة المحاولة.5678 - وضِّح إلى أيّ مدى تسافر البيانات وما يحدث متى سُلِّمت. السجلّ ومزامنة السحابة وإعادة توجيه RDP أمور تُدار. يتطلّب D&D في OLE تهيئة STA عبر
OleInitialize، والإفلات من صلاحيّة عاديّة على تطبيق مرتفع يحجبه UIPI. كذلك،Moveعقد تختفي بموجبه البيانات الأصليّة.910111213
إن أردت القراءة حسب الهدف، ابدأ من الفصل أدناه.
| المشكلة أو الهدف | ما تفحصه أوّلاً | الفصل |
|---|---|---|
| جدول Excel ملصوق ينهار | التنسيقات التي يعرضها جانب النسخ والتنسيق الذي يختاره جانب اللصق | الفصول 2–4 |
| جعل نسخة من تطبيقنا قابلة للاستخدام في تطبيقات أخرى | عرض عدّة تنسيقات، وإبقاء البيانات بعد الخروج | الفصل 5 |
| اكتشاف نسخة واستيرادها تلقائيّاً | تسجيل المستمع وإعادة محاولات القراءة | الفصل 6 |
| إبقاء الأسرار خارج السجلّ والمزامنة وRDP | تنسيقات الاستبعاد في جانب التطبيق وسياسة المنظّمة | القسم 6.3، الفصل 7 |
| تنفيذ D&D؛ يفشل فقط عند الارتفاع | تهيئة OLE، وحدّ الصلاحيّة، والتأثيرات والتحقّق من المسار | الفصلان 8–9 |
في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 20، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle
2. ما الحافظة حقّاً ── ليست «قطعة بيانات واحدة» بل «المحتوى نفسه بعدّة تنسيقات»
الحافظة آليّة لمشاركة البيانات بين التطبيقات. تطبيقات سطح المكتب نفسه تستطيع استخدامها، لكنّ وحدة المشاركة الدقيقة هي محطّة النافذة. جلسة مستخدم أخرى أو جلسة RDP لها حافظة منفصلة خاصّة بها. النسخ واللصق يعمل عبر RDP لأنّ ميزة إعادة التوجيه تجسر الاثنتين (الفصل 7).
المبدأ الحاكم أنّ الاستخدام يقوده المستخدم. الموقف التصميميّ الرسميّ أنّ تطبيقاً لا يضع بيانات أو يخرجها دون علم المستخدم.1
بعد إفراغ الحافظة، يضع جانب النسخ المحتوى نفسه بعدّة تنسيقات، من الأكثر تعبيراً نزولاً.6 مفهوميّاً، نسخ جدول في تطبيق جداول يمتدّ هكذا.
| الأولويّة | التنسيق | المحتويات |
|---|---|---|
| 1 | تنسيق خاصّ بالتطبيق | تمثيل داخليّ كامل يشمل الصيغ والتنسيق (للصق مرّة أخرى في التطبيق نفسه) |
| 2 | HTML Format | شظيّة HTML تحفظ بنية الجدول والتنسيق |
| 3 | CSV | نصّ مفصول بالخلايا |
| 4 | CF_UNICODETEXT | نصّ بسيط مفصول بعلامات جدولة |
| 5 | تنسيق صورة | صورة نقطيّة لشكل الجدول |
ما يستخرجه جانب اللصق هو التنسيق الذي يفهمه من هذه القائمة. Word يحصل على جدول منسَّق والمفكّرة على نصّ مفصول بعلامات جدولة لأنّ الاثنين اختارا تنسيقين مختلفين.
بعبارة أخرى، «النتيجة تعتمد على وجهة اللصق» ليست بذاتها خطأ. تحتاج إلى النظر إلى عرض جانب النسخ واختيار جانب اللصق معاً.
flowchart TB
accTitle: كيف تنتج النسخة نفسها نتائج مختلفة بحسب مكان اللصق
accDescr: يضع جانب النسخ المحتوى نفسه على الحافظة بعدّة تنسيقات ويختار جانب اللصق التنسيق الذي يفهمه، لذا يحصل Word على جدول منسَّق والمفكّرة على نصّ مفصول بعلامات جدولة
copy["جانب النسخ: تطبيق جداول"] --> cb["الحافظة (المحتوى نفسه بعدّة تنسيقات)"]
cb --> f1["تنسيق خاصّ بالتطبيق"]
cb --> f2["HTML Format"]
cb --> f3["CSV"]
cb --> f4["CF_UNICODETEXT"]
f2 -->|"Word يختار هذا"| word["جدول منسَّق"]
f4 -->|"المفكّرة تختار هذا"| notepad["نصّ مفصول بعلامات جدولة"]
بعبارة معكوسة، الشكاوى الافتتاحيّة — «ينهار التنسيق»، «يُلصَق شيء غريب» — يمكن اختزالها شبه كلّها إلى كيف يختار أحد الجانبين التنسيقات أو يعرضها. يغطّي الفصل 4 جانب اللصق والفصل 5 جانب النسخ.
3. التنسيقات القياسيّة والمسجَّلة ── CF_UNICODETEXT وCF_HDROP وHTML Format
3.1. التنسيقات القياسيّة ── استخدم جانب يونيكود للنصّ
التنسيقات التي يعرّفها نظام التشغيل مسبقاً تُدعى تنسيقات قياسيّة. هذه التي تظهر أكثر في تطبيقات الأعمال.2
| التنسيق | القيمة | المحتويات |
|---|---|---|
| CF_TEXT | 1 | نصّ ANSI (معتمد على صفحة الرموز) |
| CF_UNICODETEXT | 13 | نصّ يونيكود. هذا التنسيق القانونيّ للنصّ |
| CF_HDROP | 15 | قائمة مسارات ملفّات (مقبض HDROP) |
| CF_DIB | 8 | صورة نقطيّة مستقلّة عن الجهاز |
| CF_LOCALE | 16 | معرّف المحليّة المرتبط بالنصّ |
CF_TEXT وCF_UNICODETEXT «تنسيقات مركَّبة» يحوّل النظام بينهما ضمنيّاً. التحويل يستخدم صفحة الرموز المرتبطة بـ CF_LOCALE.2
غير أنّ الأحرف التي لا يستطيع ANSI تمثيلها تُفقَد في التحويل. إن تعاملت مع رموز يونيكود فقط وأحرف تركيب وما شابه، ترك الأمر للتحويل يؤدّي إلى تشويه. القاعدة توحيد قراءات التطبيق وكتاباته على CF_UNICODETEXT، أو DataFormats.UnicodeText في .NET.
flowchart LR
accTitle: التحويل الضمنيّ بين CF_UNICODETEXT وCF_TEXT
accDescr: يقرأ التطبيق ويكتب CF_UNICODETEXT فقط؛ يركِّب النظام CF_TEXT بتحويل ضمنيّ باستخدام صفحة رموز CF_LOCALE. الأحرف التي لا يستطيع ANSI تمثيلها تُسقَط في هذا التحويل
apprw["قراءات التطبيق وكتاباته"] --> uni["CF_UNICODETEXT (قانونيّ)"]
uni <-->|"يحوّل النظام ضمنيّاً (صفحة رموز CF_LOCALE)"| ansi["CF_TEXT (ANSI، معتمد على صفحة الرموز)"]
ansi -.-> loss["الأحرف غير القابلة للتمثيل تُسقَط في التحويل (مرتع للتشويه)"]
3.2. CF_HDROP ── الملفّات تسافر كـ «قائمة مسارات»
CF_HDROP ما يستخدمه مستكشف الملفّات لنسخ الملفّات وD&D. أوّل ما يُحفَظ أنّ ما يسافر قائمة مسارات كاملة، لا الملفّات نفسها.
بنية DROPFILES تجلس في بداية كتلة الذاكرة، تليها سلاسل مسارات مفصولة بأحرف NUL. تُوضَع سلسلة فارغة أخيراً، لذا تنتهي الكتلة بـ «NUL مزدوج». في الترويسة، pFiles إزاحة بداية قائمة المسارات وfWide يشير إلى ما إذا كانت السلاسل يونيكود.3
[ترويسة DROPFILES: pFiles=إزاحة بداية قائمة المسارات، fWide=1 (يونيكود)]
C:\data\a.txt(NUL)C:\data\b.txt(NUL)(NUL)
في الشيفرة الأصليّة تسترجعها واحداً واحداً بـ DragQueryFile؛ في .NET تستقبلها كـ string[] عبر DataFormats.FileDrop. نقطة أنّ «المسارات فقط تسافر، لا الملفّات نفسها» تهمّ مرّة أخرى لـ D&D في الفصلين 8 و9.
flowchart TB
accTitle: بنية كتلة ذاكرة CF_HDROP
accDescr: تجلس بنية DROPFILES في بداية الذاكرة العامّة؛ pFiles يعطي إزاحة بداية قائمة المسارات وfWide يشير إلى ما إذا كانت يونيكود. تتبع مسارات كاملة مفصولة بـ NUL، وتنتهي بسلسلة فارغة كخاتمة NUL مزدوج. المسارات فقط تسافر، لا الملفّات نفسها
hdr["بنية DROPFILES (pFiles = إزاحة بداية القائمة / fWide = 1)"] --> p1["C:\\data\\a.txt + NUL"]
p1 --> p2["C:\\data\\b.txt + NUL"]
p2 --> tail["سلسلة إنهاء فارغة (NUL مزدوج)"]
hdr -.-> note["المسارات فقط تسافر، لا الملفّات نفسها"]
3.3. التنسيقات المسجَّلة ── RegisterClipboardFormat و«HTML Format»
البيانات التي لا تستطيع التنسيقات القياسيّة التعبير عنها يمكن مشاركتها كتنسيق مسجَّل باسم تختاره. مرِّر اسماً إلى RegisterClipboardFormat فتحصل على معرّف تنسيق. تسجيل الاسم نفسه من تطبيق آخر يعطي المعرّف نفسه، لذا الاتّفاق على اسم بين التطبيقات هو نقطة الاتّصال.1
عند تمرير بيانات منظَّمة بين مجموعة تطبيقاتك، استخدم اسماً لن يتصادم، مثل KomuraSoft.Report.RowData.
HTML Format هو «UTF-8 بترويسة»
التنسيق المسجَّل التمثيليّ هو «HTML Format»، تنسيق نصّ منسَّق يقف إلى جانب RTF. الجسم نصّ UTF-8، لكنّ ترويسة تسرد إزاحات بايت تُرفَق في المقدّمة.4
Version:0.9
StartHTML:<موضع البايت حيث يبدأ HTML بالكامل>
EndHTML:<موضع البايت حيث ينتهي HTML بالكامل>
StartFragment:<موضع البايت حيث يبدأ المقطع>
EndFragment:<موضع البايت حيث ينتهي المقطع>
<html><body>
<!--StartFragment--><b>عريض</b> نصّ المقطع<!--EndFragment-->
</body></html>
كلّ إزاحة تُقاس من بداية البيانات، بما في ذلك الترويسة نفسها. StartHTML / EndHTML يشيران إلى HTML كلّه، وStartFragment / EndFragment إلى بداية الشظيّة التي اختارها المستخدم ونهايتها. الوحدة بايتات، لا أحرف.
عند توليده، جمِّعه بهذا الترتيب.
- احجز حقول الإزاحة بعرض ثابت (مثلاً 10 أرقام).
- ابنِ جسم HTML ورمِّزه كـ UTF-8.
- قِس مواضع البايت بعد الترميز واكتبها راجعاً في الترويسة.
في UTF-8 يحتوي عربيّة أو يابانيّة، عدد الأحرف وعدد البايتات لا يتطابقان. أخطأ هنا فيُقطَع البداية أو النهاية عند اللصق في تطبيق آخر.4
flowchart TB
accTitle: كيف ترتبط ترويسة HTML Format بالإزاحات
accDescr: في الترويسة، StartHTML وEndHTML يشيران إلى HTML كلّه وStartFragment وEndFragment إلى الشظيّة التي اختارها المستخدم، كلّها كمواضع بايت من بداية البيانات. لأنّ عدد الأحرف وعدد البايتات يتباعدان في UTF-8، املأها بمواضع بايت مقيسة بعد الترميز
header["الترويسة (Version / StartHTML / EndHTML / StartFragment / EndFragment)"] --> html["HTML كلّه (StartHTML إلى EndHTML)"]
html --> frag["الشظيّة المختارة (StartFragment إلى EndFragment)"]
header -.-> byte["كلّ إزاحة = موضع بايت من بداية البيانات (يُقاس بعد ترميز UTF-8 ويُكتَب راجعاً)"]
إلى جانب هذه، يُستخدَم CSV (DataFormats.CommaSeparatedValue في .NET) أيضاً كثيراً للبيانات الجدوليّة. للتوافق مع Excel، عرض HTML Format (منسَّق) وCSV (قيم فقط) وCF_UNICODETEXT (مفصول بعلامات جدولة) معاً يعمل أيّاً كانت وجهة اللصق.
4. ممارسات جانب اللصق ── أولويّة التنسيق والتحقّق
4.1. ابحث من التنسيقات الغنيّة نزولاً
جانب اللصق يبحث في التنسيقات التي يستطيع معالجتها، بادئاً من الأكثر معلومات. يمكنك إمّا استخدام الترتيب الذي وضع به جانب النسخ التنسيقات، من الأكثر تعبيراً نزولاً، أو تحديد ترتيب أولويّتك.6
| واجهة Win32 | كيف تختار |
|---|---|
EnumClipboardFormats |
تعدِّد بالترتيب الذي وضعها به جانب النسخ؛ استخدم أوّل تنسيق تتعرّف عليه |
GetPriorityClipboardFormat |
يختار تنسيقاً متاحاً من قائمة الأولويّة التي يمرّرها جانب اللصق |
في .NET يبدو التفريع هكذا.
// لصق جدول: ابحث من الغنيّ إلى البسيط
var data = Clipboard.GetDataObject();
if (data is null) return;
// الإعلان عن تنسيق لا يضمن أنّ الحمولة سلسلة. ادخل هذا
// الفرع فقط عندما يطابق النوع أيضاً؛ وإلا فاسقط إلى المرشّح التالي
if (data.GetDataPresent(DataFormats.Html)
&& data.GetData(DataFormats.Html) is string html)
{
// تحقّق من ترويسة HTML Format ثمّ استورد كجدول
}
else if (data.GetDataPresent(DataFormats.CommaSeparatedValue))
{
// استورد كـ CSV
}
else if (data.GetDataPresent(DataFormats.UnicodeText))
{
// استورد كنصّ مفصول بعلامات جدولة
}
هذا جواب الشكوى الافتتاحيّة أنّ «جدول Excel ملصوق ينهار». بنية الجدول لا تصل أبداً إلى تطبيق يقرأ النصّ البسيط فقط. إلى أيّ حدّ تقبل من قائمة التنسيقات قرار تصميم لجانب اللصق.
flowchart TB
accTitle: تفريع اللصق الذي يبحث من التنسيقات الغنيّة نزولاً
accDescr: إن وُجد HTML Format وكانت الحمولة سلسلة، استورد كجدول؛ وإلا CSV؛ فإن فشل ذلك، نصّ مفصول بعلامات جدولة، ساقطاً من التنسيق الأكثر تعبيراً نزولاً. إن لم يوجد مرشّح، ارفض
startsel["بدء اللصق"] --> h{"HTML Format موجود والحمولة سلسلة؟"}
h -->|"نعم"| useh["تحقّق من الترويسة واستورد كجدول"]
h -->|"لا"| c{"CSV موجود؟"}
c -->|"نعم"| usec["استورد كـ CSV"]
c -->|"لا"| t{"UnicodeText موجود؟"}
t -->|"نعم"| uset["استورد كنصّ مفصول بعلامات جدولة"]
t -->|"لا"| giveup["ارفض"]
4.2. بيانات اللصق دخل خارجيّ
يسهل إغفال ذلك، لكنّ محتويات الحافظة بيانات من أصل خارجيّ، ولا تعرف أيّ تطبيق وضعها. تحذّر مايكروسوفت نفسها في وثائق حافظة OLE أنّ «بيانات الحافظة غير موثوقة؛ حلِّلها بعناية قبل استخدامها في التطبيق».5
وجود تنسيق وحده لا يخبرك أنّ البيانات يمكن استيرادها. افحص نوع الحمولة الفعليّة أيضاً، وأجرِ الفحوص التالية.
| ما يُتحقَّق منه | ما تفحصه |
|---|---|
| ترويسة HTML Format | ما إذا كانت الإزاحات تشير خارج النطاق. بعض التطبيقات تُصدر ترويسات مكسورة |
| قيم كالأرقام والتواريخ والرموز | ما إذا مرّت بالتحقّق نفسه الذي لإدخال الشاشة |
| حجم البيانات | ما إذا تجاوز حدّ القبول، كصور بمئات الميغابايتات أو نصّ بملايين الأسطر |
لاحظ أنّ التجسيد يبدأ قبل أن تستطيع فحص الحجم
لدفاعات ضدّ بيانات ضخمة، ميّز حمل أيّ مرحلة تستطيع منعه. GetData في .NET أيضاً يطلق العرض المؤجَّل عندما يُستدعى، وللنصّ يجسِّد حتّى سلسلة مُدارة. فحص الحجم فقط بعد الاسترجاع لا يمنع حمل ذلك التجسيد.
إن فحصت HGLOBAL الذي يعيده GetClipboardData في Win32 بـ GlobalSize، تستطيع الدفاع ضدّ دفع بيانات ضخمة قدماً إلى التحويل إلى سلسلة مُدارة والتحليل. غير أنّه للتنسيقات ذات العرض المؤجَّل، GetClipboardData نفسه يطلق العرض. لا تستطيع منع مصدر النسخ من تجسيد البيانات نفسها.
لكي لا تتجمّد الواجهة، انقل الاسترجاع خارج مؤشّر ترابط الواجهة وارفض بيانات تتجاوز الحدّ. حتّى حينها، Clipboard في .NET يتطلّب STA. استخدم مؤشّراً مخصَّصاً مضبوطاً على STA، لا تجمّع مؤشّرات (MTA) لـ Task.Run (القسم 5.1).
فكرة أنّ «قيمة تأتي من الخارج تُتحقَّق قبل الاستخدام، أيّاً كان مسارها» هي الفكرة نفسها المعروضة في «لا تستخدم قيمة QR مفكوكة كما هي». افتراض أنّ اللصق آمن لأنّه فعل مستخدم هو كيف تسوء الأمور.
flowchart LR
accTitle: التحقّق من بيانات اللصق قبل استخدامها
accDescr: البيانات المأخوذة من الحافظة تمرّ بفحوص وجود التنسيق ونوع الحمولة وحدّ الحجم والمحتوى بهذا الترتيب؛ إن فشل أيّ فحص، ارفض أو اسقط إلى التنسيق المرشّح التالي
present["افحص أنّ التنسيق موجود (GetDataPresent)"] --> type["افحص نوع الحمولة (is string / string[])"]
type --> size["افحص حدّ الحجم"]
size --> content["تحقّق من المحتوى (ترويسة، مسارات، قيم)"]
content --> ok["استورد"]
type -.->|"نوع خاطئ"| rej["ارفض / التنسيق المرشّح التالي"]
size -.->|"كبير جدّاً"| rej
content -.->|"غير صالح"| rej
5. ممارسات جانب النسخ ── عرض عدّة تنسيقات دفعة، والعرض المؤجَّل
5.1. ضع عدّة تنسيقات دفعة واحدة
ممارسة جانب النسخ صورة مرآة لـ 4.1: اعرض تنسيقاً غنيّاً وتنسيقاً بسيطاً في الوقت نفسه. مع DataObject في WinForms/WPF يستغرق أسطر قليلة.14
// WinForms (System.Windows.Forms). لـ WPF الشكل نفسه بـ DataObject/Clipboard في System.Windows
var data = new DataObject();
data.SetData(DataFormats.Html, htmlFormatText); // سلسلة HTML Format مع الترويسة
data.SetData(DataFormats.CommaSeparatedValue, csv); // CSV
data.SetData(DataFormats.UnicodeText, plainText); // نصّ بسيط
Clipboard.SetDataObject(data, copy: true); // copy:true = أبقِ بعد خروج التطبيق
هنا ننظر منفصلين إلى متطلّب المؤشّر والعمر بعد الخروج.
متطلّب المؤشّر: صنف Clipboard في .NET يمكن استخدامه فقط من مؤشّر STA.14 مؤشّر واجهة WinForms/WPF هو STA بسبب [STAThread]، لذا هذه عادة ليست مشكلة، لكن لا يمكن استخدامه من مؤشّر خلفيّ ليس STA. الخلفيّة مشروحة في «أساسيات COM STA/MTA».
العمر بعد الخروج: copy: true يعني «أبقه بعد خروج التطبيق». فهمه مع العرض المؤجَّل، التالي، يوضّح لماذا هذه المواصفة لازمة.
5.2. العرض المؤجَّل ── لماذا «أغلقه فلا تستطيع اللصق»
توليد كلّ تنسيق من تنسيقات كثيرة عند كلّ نسخ يعني عملاً حتّى للتنسيقات التي لا تُستخدم أبداً. الآليّة التي تتجنّب هذا هي العرض المؤجَّل.6
عند النسخ، مرِّر NULL كمقبض بيانات إلى SetClipboardData، مسجِّلاً لا البيانات نفسها بل وعداً بـ «إنتاجها عند الطلب». عندما يُطلَب ذلك التنسيق، تصل WM_RENDERFORMAT إلى مصدر النسخ، وعندها فقط تُولَّد البيانات.
عند الخروج، حوِّل «الوعد» إلى بيانات
إن خرج مصدر النسخ تاركاً تنسيقات غير معروضة، لم يعد جانب اللصق يستطيع تلقّي تلك البيانات. هذه مشكلة «أغلق المصدر فلا تستطيع اللصق».
قبل الخروج، مصدر النسخ مسؤول عن الاستجابة لـ WM_RENDERALLFORMATS وتجسيد كلّ تنسيق غير معروض. التنسيقات التي لم تُجسَّد تُفقَد عندما يخرج مصدر النسخ.6
flowchart TB
accTitle: تدفّق العرض المؤجَّل و«أغلقه فلا تستطيع اللصق»
accDescr: يسجّل مصدر النسخ وعداً فقط بمقبض NULL ويجسِّد البيانات بـ WM_RENDERFORMAT عندما يصل طلب. عند الخروج هو مسؤول عن تجسيد كلّ تنسيق بـ WM_RENDERALLFORMATS؛ أهمل ذلك فيُفقَد التنسيق
promise["مصدر النسخ: سجّل وعداً فقط بـ SetClipboardData(format, NULL)"] --> req["جانب اللصق يطلب ذلك التنسيق"]
req --> render["WM_RENDERFORMAT ← ولِّد البيانات في المكان"]
promise --> quit["مصدر النسخ على وشك الخروج"]
quit -->|"جسِّد بـ WM_RENDERALLFORMATS"| ok["اللصق ما زال يعمل بعد الخروج"]
quit -->|"أهمل التجسيد"| lost["ذلك التنسيق يُفقَد (أغلقه فلا تستطيع اللصق)"]
على حافظة OLE، تضع IDataObject بـ OleSetClipboard. عند تلك النقطة، ما تحمله الحافظة مؤشّر إلى كائن البيانات.
استدعاء OleFlushClipboard عند الخروج يجسِّد البيانات على الحافظة، لذا اللصق ما زال يعمل بعد الخروج.7 Clipboard.SetDataObject(data, copy: true) في .NET يحدِّد سلوك «أبق بعد الخروج» هذا.
عندما تنسخ نطاقاً كبيراً في Excel ثمّ تخرج، المحثّ الذي يسأل ما إذا كنت تريد إبقاء كمّ المعلومات الكبير على الحافظة هو تأكيد ما إذا يؤدَّى هذا التجسيد (الـ flush). في تطبيقك أيضاً، صمِّم العرض المؤجَّل والتجسيد عند الخروج مجموعة واحدة.
التأجيل لا يضمن بقاء الواجهة مستجيبة
العرض المؤجَّل تحسين أداء، لكنّ توليد البيانات المطلوبة يعمل بشكل متزامن داخل معالجة الرسائل. المقايضة أنّ الواجهة تتجمّد إن استغرق التوليد وقتاً طويلاً.6
6. ممارسات مراقبة الحافظة ── المستمع، وإعادة المحاولة، واستبعاد السجلّ
6.1. استخدم AddClipboardFormatListener
متطلّبات مثل «اكتشف قيمة قارئ باركود أو نسخة من نظام الأعمال الأساسيّ واستوردها تلقائيّاً» تستدعي مراقبة تغييرات الحافظة. تاريخيّاً ثمّة ثلاث طرق، لكنّ اليوم جواباً صحيحاً واحداً.8
| الطريقة | التقييم |
|---|---|
| القراءة دوريّاً على مؤقّت (استطلاع) | مهدرة، ويمكن أن تفوّت تغييرات. لا تستخدم |
| SetClipboardViewer (سلسلة العارض) | عيب في تطبيق واحد في السلسلة يكسر الكلّ. تُحفَظ فقط للتوافق الخلفيّ |
| AddClipboardFormatListener | موصى به. تُسلَّم WM_CLIPBOARDUPDATE إلى النافذة المسجَّلة |
flowchart LR
accTitle: تدفّق مراقبة الحافظة
accDescr: سجّل بـ AddClipboardFormatListener عندما يُنشأ المقبض، وتصل WM_CLIPBOARDUPDATE أيّاً كان التطبيق الذي ينسخ. اقرأ بإعادة محاولات، وألغِ التسجيل بشكل متناظر بـ RemoveClipboardFormatListener عندما يُدمَّر المقبض
created["OnHandleCreated: AddClipboardFormatListener"] --> wait["انتظر"]
anyapp["تطبيق ما ينسخ"] --> notify["تصل WM_CLIPBOARDUPDATE"]
wait --> notify
notify --> readtry["اقرأ بإعادة محاولات (القسم 6.2)"]
readtry --> wait
destroyed["OnHandleDestroyed: RemoveClipboardFormatListener"] -.->|"ألغِ التسجيل بشكل متناظر"| created
// تنفيذ WinForms بالحدّ الأدنى
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)
{
// ألغِ التسجيل تناظريّاً، بموازاة تدمير المقبض وإعادة إنشائه
RemoveClipboardFormatListener(Handle);
base.OnHandleDestroyed(e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE)
{
// اقرأ Clipboard.GetDataObject() هنا واستورد إن كان التنسيق ممّا تحتاجه
}
base.WndProc(ref m);
}
}
6.2. أعد المحاولة عندما لا يمكن الفتح
نافذة واحدة في الوقت تستطيع فتح الحافظة. بينما عمليّة أخرى تفتحها، يفشل OpenClipboard.6
مباشرة بعد WM_CLIPBOARDUPDATE أيضاً، قد يكون مصدر النسخ أو تطبيق مراقبة آخر ما زال يعمل عليها. عامل فشل قراءة مؤقّتاً حدثاً عاديّاً، وأضف منطقاً ينتظر عشرات مليّ ثوانٍ ويعيد المحاولة بضع مرّات.
نقطة تُلاحظ في .NET أنّ زيادات التحميل التي تتيح تحديد عدد إعادة المحاولة والفاصل موجودة فقط في جانب الكتابة، SetDataObject. جانب القراءة، GetDataObject وما شابه، ليس له شيء.
| جانب القراءة | معالجة التنازع |
|---|---|
| WinForms | التقط ExternalException، انتظر، وأعد المحاولة |
| WPF | التقط COMException، انتظر، وأعد المحاولة |
انتظار القراءة وإعادة المحاولة يُنفَّذان في جانب التطبيق.
flowchart LR
accTitle: تدفّق إعادة محاولة قراءة الحافظة
accDescr: نافذة واحدة في الوقت تستطيع فتح الحافظة، لذا قراءة مباشرة بعد إشعار التغيير يمكن أن تفشل بسبب التنازع مع عمليّة أخرى. عند استثناء، انتظر عشرات مليّ ثوانٍ وأعد المحاولة؛ متى بُلغ الحدّ، تخلَّ هذه المرّة والتقطه في التحديث التالي
upd["WM_CLIPBOARDUPDATE"] --> tryread["حاول القراءة"]
tryread -->|"نجاح"| useok["استورد (تحقّق الفصل 4)"]
tryread -->|"فشل (نافذة أخرى تستخدمها)"| waitretry["انتظر عشرات مليّ ثوانٍ"]
waitretry -->|"أعد المحاولة حتّى بضع مرّات"| tryread
waitretry -->|"بُلغ الحدّ"| giveup2["تخلَّ هذه المرّة (التقطه في التحديث التالي)"]
6.3. أبقه خارج السجلّ والمزامنة ── اعتبارات لميزات نسخ تعامل أسراراً
لدى Windows سجلّ حافظة (Win+V) ومزامنة عبر الأجهزة (حافظة السحابة)، والبيانات التي يضعها تطبيق خاضعة لكليهما افتراضيّاً. تطبيق تحمل ميزة نسخه أسراراً ككلمات مرور أو أرقام حسابات يضع أيضاً تنسيقاً مسجَّلاً يستبعد البيانات من السجلّ والمزامنة.1
| التنسيق المسجَّل | ما يكبحه |
|---|---|
ExcludeClipboardContentFromMonitorProcessing |
يستبعد المحتوى المنسوخ كلّه من السجلّ والمزامنة عبر الأجهزة |
CanIncludeInClipboardHistory (DWORD 0) |
السجلّ فقط |
CanUploadToCloudClipboard (DWORD 0) |
المزامنة عبر الأجهزة فقط |
مدراء كلمات المرور يبقون كلمات المرور المنسوخة خارج Win+V عبر هذه الآليّة. كلّ ما يتطلّبه تمرير الاسم إلى RegisterClipboardFormat للحصول على معرّف تنسيق وضبطه إلى جانب البيانات العاديّة، لذا يستحقّ التنفيذ في تطبيقات أعمال تعامل أسراراً.
7. الحافظة من منظور تقنيّة المعلومات ── التحكّم في السجلّ ومزامنة السحابة وRDP
التحكّم في المحتوى المنسوخ في جانب التطبيق وقرار ما تسمح به المنظّمة كلّها سؤالان منفصلان. ما ينظر إليه المسؤول ثلاثة أشياء: السجلّ، ومزامنة السحابة، وإعادة توجيه RDP.
يسجّل سجلّ الحافظة المحتوى المنسوخ حديثاً. حافظة السحابة تزامنه بين أجهزة مسجَّل دخولها بالحساب نفسه من Microsoft أو Microsoft Entra.10
مريح كما هو، يؤدّي إلى بقايا وتسرّب: معلومات شخصيّة منسوخة من نظام الأعمال الأساسيّ تبقى في السجلّ، أو محتوى منسوخ على حاسوب عمل يُزامَن إلى حاسوب شخصيّ.
7.1. التحكّم في السجلّ والمزامنة عبر الأجهزة
السياستان للتحكّم المنظَّميّ هما هاتان.
| ما يُتحكَّم فيه | GPO (Computer Configuration > Administrative Templates > System > OS Policies) | Policy CSP (Intune) | الافتراضيّ |
|---|---|---|---|
| سجلّ الحافظة | Allow Clipboard History | Experience/AllowClipboardHistory | مسموح |
| المزامنة عبر الأجهزة | Allow Clipboard synchronization across devices | Privacy/AllowCrossDeviceClipboard | مسموح |
كلاهما متاح من Windows 10 الإصدار 1809 فصاعداً؛ عند التعطيل، العناصر المقابلة في تطبيق الإعدادات تُرمَّد، وتسري السياسة فوراً.910
7.2. التحكّم في النقل بين جلسات RDP
إعادة توجيه حافظة RDP (Remote Desktop) تجسر الحاسوب المحلّيّ والجلسة البعيدة. لأنّ النسخ واللصق يعمل افتراضيّاً، يمكن أن يصير أيضاً مساراً لإخراج أسرار من خادم.
الإعداد الذي يحجب الاتجاهين هو سياسة «Do not allow Clipboard redirection» (قيمة السجلّ fDisableClip).11
إصدارات Windows Server وWindows 11 الحديثة أضافت أيضاً سياسات لتحكّم أدقّ، كقصر اتجاه الخادم إلى العميل فقط على النصّ. ما إذا تُحظَر صراحة أو تُقيَّد الاتجاهات والتنسيقات على مراحل توازن بين التشغيل والأمان.
flowchart LR
accTitle: المسارات التي ينتشر عبرها محتوى الحافظة، ونقاط التحكّم
accDescr: المحتوى المنسوخ خاضع للسجلّ ومزامنة السحابة افتراضيّاً، وعبر RDP يمرّ إلى جلسة أخرى عبر إعادة التوجيه. كلّ يمكن التحكّم فيه بسياسة، وجانب التطبيق يستطيع استبعاد محتوى من السجلّ والمزامنة بتنسيقات الاستبعاد
cb["الحافظة"] --> hist["السجلّ (Win+V)"]
cb --> cloud["مزامنة السحابة ← جهاز آخر"]
cb --> rdp["إعادة توجيه RDP ← جلسة أخرى"]
hist -.-> p1["التحكّم: AllowClipboardHistory"]
cloud -.-> p2["التحكّم: AllowCrossDeviceClipboard"]
rdp -.-> p3["التحكّم: fDisableClip"]
cb -.-> p4["جانب التطبيق: استبعد بـ ExcludeClipboardContentFromMonitorProcessing وما شابه (القسم 6.3)"]
8. السحب والإفلات COM ── IDataObject + IDropSource + IDropTarget
8.1. البيانات نفسها التي للحافظة، محمولة بشكل مختلف
يعمل سحب وإفلات OLE على الأطراف الثلاثة التالية.15
| الدور | ينفِّذه | العمل |
|---|---|---|
| IDataObject | مصدر السحب | البيانات المحمولة. كائن البيانات متعدّد التنسيقات نفسه الذي للحافظة |
| IDropSource | مصدر السحب | تقرير ما إذا يستمرّ السحب أو يُلغى، وتغذية راجعة للمؤشّر |
| IDropTarget | هدف الإفلات | إعلان القبول وتلقّي البيانات في DragEnter/DragOver/DragLeave/Drop |
تسير العمليّة كما يلي.
- يستدعي مصدر السحب
DoDragDrop، بادئاً حلقة السحب. - عندما تدخل الفأرة نافذة هدف إفلات، يُشعَر
IDropTarget. - يعلن هدف الإفلات ما إذا يقبل، وعند الإفلات يستخرج التنسيق الذي يحتاجه من
IDataObject.
تشرح الوثائق الرسميّة أيضاً أنّ D&D يوفّر الوظيفة نفسها التي لنسخ الحافظة ولصقها، وأنّ تطبيقاً ينفِّذ أصلاً النسخ واللصق يحتاج إضافة صغيرة فقط.15 بعبارة أخرى، كائن DataObject متعدّد التنسيقات المعدّ في الفصول 2 إلى 5 هو أيضاً البيانات التي يحملها D&D.
flowchart LR
accTitle: تدفّق سحب وإفلات OLE
accDescr: يستدعي مصدر السحب DoDragDrop بـ IDataObject كحمولة وتبدأ حلقة السحب؛ يعلن IDropTarget لهدف الإفلات القبول في DragEnter وDragOver، وعند Drop يختار ويستخرج تنسيقاً من IDataObject
src["مصدر السحب: IDataObject + IDropSource"] -->|"DoDragDrop"| loop["حلقة السحب"]
loop -->|"الفأرة تدخل النافذة"| enter["IDropTarget.DragEnter/DragOver (أعلن الـ Effect كلّ مرّة)"]
enter -->|"أُفلِت الزرّ"| drop["IDropTarget.Drop"]
drop --> data["اختر واستخرج تنسيقاً من IDataObject"]
8.2. OleInitialize (STA) مطلوب
نافذة هدف إفلات تُسجَّل بـ RegisterDragDrop. كمتطلّبات مسبقة، افحص شيئين: تهيئة OLE ومعالجة الرسائل.
استخدم OleInitialize للتهيئة. إن استخدمت CoInitialize / CoInitializeEx بدلاً منه، يفشل RegisterDragDrop بـ E_OUTOFMEMORY. OleInitialize يهيّئ COM كـ STA.12
مؤشّر التسجيل يجب أن يشغِّل مضخّة رسائل. D&D في OLE ميزة متجذّرة في النوافذ ومعالجة الرسائل؛ أهمل هذا فتعلَّق تطبيقات أخرى أثناء سحب.12 الخلفيّة نموذج الترابط نفسه كما في «أساسيات COM STA/MTA».
في WinForms/WPF، استقبل عبر الأحداث
في WinForms/WPF، يتولّى الإطار تهيئة OLE وتنفيذات الواجهات. يكتب المطوِّر إعلان القبول والاستيراد الفعليّ في الأحداث.
// WinForms: اقبل الملفّات المُسقَطة
listView1.AllowDrop = true;
listView1.DragEnter += (s, e) =>
{
// افحص أيضاً أنّ المصدر يسمح بـ Copy (بعض المصادر تسمح بـ Move/Link فقط)
e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop)
&& (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy
? DragDropEffects.Copy // قبول: استقبل كنسخة
: DragDropEffects.None; // لا تقبل
};
listView1.DragDrop += (s, e) =>
{
// بيانات السحب إدخال خارجيّ أيضاً. حتّى إن أعلنت FileDrop، قد تكون الحمولة
// فارغة أو من نوع مختلف، وقد يفشل الاسترجاع نفسه
object data;
try { data = e.Data.GetData(DataFormats.FileDrop); }
catch (COMException) { return; }
if (data is not string[] paths) return;
foreach (var path in paths)
{
// تحقّق من المسار قبل الاستيراد (القسم 9.3)
}
};
الصورة نفسها في WPF. استقبل بـ AllowDrop="True" على العنصر وأحداث DragOver / Drop، واستخرج مصفوفة المسارات بـ e.Data.GetData(DataFormats.FileDrop).
إعلان القبول (الـ Effect) كلّ مرّة في DragEnter / DragOver اصطلاح IDropTarget. أحذفه فيبقى المؤشّر عند «غير مسموح». افحص لا وجود التنسيق فحسب بل أيضاً، كما في عيّنة الشيفرة، ما إذا كان مصدر السحب يسمح بـ Copy.
9. مطبّات D&D ── الارتفاع، وMove، والتحقّق من المسار
9.1. لا تستطيع الإفلات على تطبيق مرتفع إلى مسؤول
أسقط ملفّاً من مستكشف الملفّات على تطبيق أُطلق بـ «تشغيل كمسؤول» فلا يحدث شيء — هذا ليس خطأ تنفيذ بل تصميم نظام التشغيل. UIPI (User Interface Privilege Isolation) يحجب افتراضيّاً الرسائل من عمليّة سلامة أدنى إلى نافذة سلامة أعلى، لذا إشعارات الإفلات من مستكشف الملفّات العامل بصلاحيّة عاديّة (سلامة متوسّطة) لا تصل أبداً إلى تطبيق مرتفع.13
flowchart LR
accTitle: كيف يحجب UIPI إفلاتاً على تطبيق مرتفع
accDescr: يحجب UIPI افتراضيّاً إشعار الإفلات من مستكشف ملفّات سلامة متوسّطة إلى تطبيق مرتفع سلامة عالية، لذا لا يصل أبداً. أبقِ الواجهة بصلاحيّة عاديّة واعزل العمل المميَّز، فيصل الإفلات
explorer["مستكشف الملفّات (سلامة متوسّطة)"] -->|"إشعار إفلات"| uipi{"UIPI"}
uipi -->|"محجوب (افتراضيّ)"| elevated["تطبيق مرتفع (سلامة عالية): لا استجابة"]
uipi -->|"يمرّ"| normal["واجهة بصلاحيّة عاديّة: يصل الإفلات"]
normal -.->|"فوِّض العمل المميَّز فقط"| broker["عمليّة منفصلة تعزل العمل الذي يحتاج الارتفاع"]
ثمّة أيضاً حلّ التفافيّ يسمح بـ WM_DROPFILES ورسائل مشابهة فرديّاً بـ ChangeWindowMessageFilterEx.13 غير أنّ هذا إجراء مضادّ لإشعار الإفلات الأقدم عبر WM_DROPFILES، ولا يحلّ D&D في OLE كلّه.
الإرشاد الجذريّ ألّا تشغِّل التطبيق مرتفعاً طوال الوقت. إن عزلت العمل الذي يحتاج الارتفاع فقط إلى عمليّة منفصلة، تستطيع الواجهة نفسها البقاء بصلاحيّة عاديّة وقبول D&D. تصميم العزل مشروح بالتفصيل في «صلاحيّات المسؤول وعمليّات الوسيط في تطبيقات Windows».
9.2. ماذا يعني DragDropEffects ── Move عقد أنّ «الأصل يختفي»
Copy / Move / Link في DragDropEffects ليست زخرفة مؤشّر؛ إنّها عقد بين مصدر السحب وهدف الإفلات.
يعلن مصدر السحب مجموعة التأثيرات التي يسمح بها في DoDragDrop، ويختار هدف الإفلات التأثير الفعليّ. بالاصطلاح، عندما يُتَّفَق على Move، يحذف مصدر السحب البيانات (الملفّ).
إن أعاد جانب الاستقبال Move دون تفكير، ينتهي بك الأمر بـ «أسقطته واختفى الملفّ الأصليّ». لاستيرادات تطبيقات الأعمال، اجعل جانب الاستقبال يصرِّح بـ Copy صراحة الافتراضيّ الآمن.
flowchart LR
accTitle: عقد DragDropEffects ── مع Move، الأصل يختفي
accDescr: يعلن مصدر السحب مجموعة التأثيرات التي يسمح بها في DoDragDrop، ويختار هدف الإفلات التأثير الفعليّ. لأنّ الاصطلاح أنّ مصدر السحب يحذف الملفّ عندما يُتَّفَق على Move، جانب استقبال يستورد ينبغي أن يصرِّح Copy صراحة
srcdecl["مصدر السحب: أعلن التأثيرات المسموحة (Copy | Move | Link)"] --> tgtsel["هدف الإفلات: اختر التأثير الفعليّ"]
tgtsel -->|"Copy"| copyok["الملفّ الأصليّ يبقى (الجانب الآمن للاستيرادات)"]
tgtsel -->|"Move"| moveact["مصدر السحب يحذف الملفّ — من أين يأتي «اختفى الأصل»"]
9.3. التحقّق من المسارات المُسقَطة
ما يسافر في CF_HDROP/FileDrop مسارات فقط (القسم 3.2). قبل الاستيراد، مرِّرها بالتحقّق نفسه الذي للدخل الخارجيّ، تماماً كما مع اللصق.
- ملفّ أو مجلّد: قرِّر كمواصفة ماذا يحدث عندما يُسقَط مجلّد كامل (استورد تكراريّاً، أو ارفض).
- عناصر OneDrive النائبة: إن وُجد المسار لكنّ جسم الملفّ ليس محلّيّاً — ملفّ عند الطلب — يبدأ تنزيل في اللحظة التي تفتحه، ويفشل عند عدم الاتّصال. للسلوك والإجراءات المضادّة، انظر ملفات OneDrive عند الطلب وتطبيقات الأعمال.
- مسارات طويلة وخاصّة: اقبل مسارات تتجاوز MAX_PATH، ومسارات شبكة (UNC)، ومسارات على وسائط قابلة للإزالة فقط بعد تأكيد أنّ المعالجة اللاحقة تستطيع التعامل معها.
- العدد والحجم الإجماليّ: كي لا يجمِّد إسقاط آلاف الملفّات الواجهة، اجعل الاستيراد غير متزامن وأضف حدّاً وعرض تقدّم.
10. الخلاصة
- الحافظة آليّة تضع المحتوى نفسه بعدّة تنسيقات دفعة واحدة في منطقة واحدة مشتركة داخل سطح المكتب نفسه (محطّة النافذة). لأنّ وجهة اللصق تختار التنسيق، تنتج النسخة نفسها نتائج مختلفة.
- النصّ CF_UNICODETEXT، والملفّات CF_HDROP، والنصّ المنسَّق التنسيق المسجَّل HTML Format (ترويسة إزاحات بايت + UTF-8).
- جانب اللصق يبحث في التنسيقات من الغنيّ إلى البسيط ويتحقّق من المحتوى كدخل خارجيّ. جانب النسخ يعرض عدّة تنسيقات دفعة، وإن استخدم العرض المؤجَّل، ينفِّذ التجسيد عند الخروج (WM_RENDERALLFORMATS / OleFlushClipboard) أيضاً.
- المراقبة AddClipboardFormatListener + WM_CLIPBOARDUPDATE. استعد لتنازع OpenClipboard بإعادة المحاولة، واستبعد الأسرار من السجلّ والمزامنة بـ ExcludeClipboardContentFromMonitorProcessing وما شابه.
- يستطيع موظّفو تقنيّة المعلومات التحكّم في سجلّ الحافظة ومزامنة السحابة وإعادة توجيه RDP عبر GPO/Intune. كلّها مسموحة افتراضيّاً، لذا قرِّر بوعي في بيئات تعامل أسراراً.
- D&D هو COM: يمرّر IDropSource/IDropTarget كائن IDataObject نفسه الذي للحافظة. يتطلّب RegisterDragDrop OleInitialize (STA).
- الإفلاتات على تطبيق مرتفع يحجبها UIPI. Move في DragDropEffects عقد أنّ «الأصل يختفي»، ومسارات الإفلات تُتحقَّق قبل الاستيراد.
للمستخدمين، النسخ واللصق وD&D ميزات عاديّة كالهواء. لذلك بالضبط تتضرّر التجربة كثيراً عندما يحدث «لا أستطيع اللصق» أو «ينهار» أو «اختفى» — وبالعكس، تطبيق يعرض عدّة تنسيقات ويعالج الإفلاتات بدقّة يجعل التشغيل اليوميّ أكثر سلاسة بذلك وحده. آمل أن يصلح هذا مدخلاً عندما تزن أولويّة المراجعات.
مقالات ذات صلة
- ما هي COM / ActiveX / OCX: الفروق والعلاقات
- أساسيات COM STA/MTA - نموذج الخيوط وتجنّب التعليق
- تكامل صدفة ويندوز اليوم ── قوائم السياق وارتباطات الملف وما تغيّر في ويندوز 11
- مشكلة بقاء EXCEL.EXE عند التعامل مع Excel من C# ── أنماط تحرير مراجع COM وقرار الاستبدال
- تصميم UX لتطبيقات Windows - أولويات حسب بيئة الاستخدام
- ملفات OneDrive عند الطلب وتطبيقات الأعمال — الافتراضات التي يكسرها العنصر النائب وكيف تتعامل معها
مجالات الاستشارة ذات الصلة
تتعامل شركة كومورا سوفت ذ.م.م. مع تصميم وتنفيذ دعم النسخ واللصق والسحب والإفلات في تطبيقات الأعمال (عرض عدّة تنسيقات، تكامل Excel، استيراد ملفّات مُسقَطة)، وتحقيق السبب الجذريّ لعيوب مثل «ينهار عند اللصق» أو «تختفي النسخة»، وأتمتة الإدخال باستخدام مراقبة الحافظة، وتنفيذ حمايات السجلّ والمزامنة للمعلومات السرّيّة. الحالات التي تتضمّن الطبقات الأدنى من COM وOLE مرحَّب بها حتّى إن بدأت من عزل العَرَض.
روابط مرجعيّة
-
Microsoft Learn, Clipboard Formats. حول قدرة نافذة على وضع المعلومات نفسها بعدّة تنسيقات حافظة؛ والتنسيقات المسجَّلة عبر RegisterClipboardFormat (تسجيل الاسم نفسه يعيد القيمة نفسها، لذا تستطيع التطبيقات مشاركته)؛ والتنسيقات المركَّبة؛ واستبعاد المحتوى من سجلّ الحافظة ومزامنة السحابة بـ ExcludeClipboardContentFromMonitorProcessing وCanIncludeInClipboardHistory وCanUploadToCloudClipboard. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Standard Clipboard Formats. حول تعريفات التنسيقات القياسيّة مثل CF_TEXT (ANSI) وCF_UNICODETEXT وCF_HDROP وCF_DIB وCF_LOCALE، وحول تحويل النظام ضمنيّاً بين CF_TEXT وCF_UNICODETEXT باستخدام صفحة الرموز المرتبطة بـ CF_LOCALE. ↩ ↩2 ↩3
-
Microsoft Learn, Shell Clipboard Formats. حول تكوّن CF_HDROP من بنية DROPFILES زائد مصفوفة سلاسل مسار كامل منتهية بـ NUL مزدوج؛ واسترجاع المسارات فرديّاً بـ DragQueryFile؛ وتنسيقات الصدفة CFSTR_ التي تتطلّب تسجيلاً عبر RegisterClipboardFormat. ↩ ↩2
-
Microsoft Learn, HTML Clipboard Format. حول كون الاسم المسجَّل «HTML Format»؛ وبنية الترويسة بإزاحات (بالبايت) مثل Version وStartHTML وEndHTML وStartFragment وEndFragment؛ وكون الترميز دائماً UTF-8؛ واصطلاح تعليقات StartFragment/EndFragment. ↩ ↩2 ↩3
-
Microsoft Learn, OleGetClipboard function (ole2.h). حول كيفيّة الحصول على IDataObject من الحافظة، وحول التحذير أنّ بيانات الحافظة غير موثوقة وينبغي تحليلها بعناية قبل أن يستخدمها التطبيق. ↩ ↩2
-
Microsoft Learn, Clipboard Operations. حول قدرة نافذة واحدة في الوقت على فتح الحافظة؛ ووضع التنسيقات من الأكثر تعبيراً نزولاً عند النسخ؛ واختيار التنسيق عند اللصق بـ EnumClipboardFormats / GetPriorityClipboardFormat؛ والعرض المؤجَّل بتمرير NULL إلى SetClipboardData ومسؤوليّات WM_RENDERFORMAT / WM_RENDERALLFORMATS؛ ومقايضات العرض المؤجَّل. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn, OleFlushClipboard function (ole2.h). حول حمل الحافظة مؤشّراً فقط إلى كائن البيانات بعد OleSetClipboard؛ وتجسيد OleFlushClipboard البيانات على الحافظة كي يبقى اللصق ممكناً بعد خروج التطبيق؛ وإفراغ الحافظة بـ OleSetClipboard(NULL) عندما لا حاجة لإبقاء البيانات عند الخروج. ↩ ↩2
-
Microsoft Learn, Using the clipboard. حول مقارنة الطرق الثلاث لمراقبة الحافظة (نوافذ العارض، وأرقام التسلسل، ومستمعو التنسيق)؛ وتوقّع أن تستخدم البرامج الجديدة مستمعاً عبر AddClipboardFormatListener؛ وكون سلسلة العارض عرضة لثغرات في صيانة السلسلة؛ وأنّ أرقام التسلسل ليست شيئاً يُستطلَع. ↩ ↩2
-
Microsoft Learn, Policy CSP - Experience. حول السماح بسجلّ الحافظة أو حجبه بسياسة Experience/AllowClipboardHistory؛ والإتاحة من Windows 10 الإصدار 1809 فصاعداً؛ وكون الافتراضيّ السماح؛ وتعيين GPO تحت «System > OS Policies» مع سريان التغييرات فوراً. ↩ ↩2
-
Microsoft Learn, Policy CSP - Privacy. حول السماح بمزامنة الحافظة عبر الأجهزة أو حجبها بسياسة Privacy/AllowCrossDeviceClipboard؛ وحدوث المزامنة بين أجهزة مسجَّل دخولها بالحساب نفسه من Microsoft أو Microsoft Entra؛ وكون الافتراضيّ السماح. ↩ ↩2 ↩3
-
Microsoft Learn, Policy CSP - ADMX_TerminalServer. حول قدرة TS_CLIENT_CLIPBOARD («Do not allow Clipboard redirection»، قيمة السجلّ fDisableClip) على حظر مشاركة الحافظة بين المحلّيّ والبعيد في جلسة Remote Desktop، وحول السماح بإعادة التوجيه افتراضيّاً. ↩ ↩2
-
Microsoft Learn, RegisterDragDrop function (ole2.h). حول كيفيّة تسجيل نافذة هدف إفلات وIDropTarget الخاصّ بها؛ وفشل الاستدعاء دائماً بـ E_OUTOFMEMORY عندما هُيِّئ COM بـ CoInitialize/CoInitializeEx، لذا يلزم OleInitialize؛ وتعليق تطبيق مصدر السحب عندما لا يشغِّل مؤشّر الاستدعاء مضخّة رسائل. ↩ ↩2 ↩3
-
Microsoft Learn, ChangeWindowMessageFilterEx function (winuser.h). حول كون UIPI آليّة أمان تحجب افتراضيّاً تلقّي رسائل من مرسِل سلامة أدنى، وحول السماح برسائل محدَّدة (MSGFLT_ALLOW) بمرشّح رسائل لكلّ نافذة. ↩ ↩2 ↩3
-
Microsoft Learn, How to add data to the Clipboard (Windows Forms). حول وضع بيانات بعدّة تنسيقات دفعة بـ DataObject وClipboard.SetDataObject؛ وإضافة بيانات بعدّة تنسيقات كي تتمكّن تطبيقات أخرى من التعرّف عليها؛ وكون صنف Clipboard قابلاً للاستخدام فقط من مؤشّر STA، لذا يلزم [STAThread]. ↩ ↩2
-
Microsoft Learn, Drag and Drop (COM). حول عمل سحب وإفلات OLE على الأطراف الثلاثة IDropSource (مصدر السحب) وIDropTarget (هدف الإفلات) وDoDragDrop (الحلقة التي يوفّرها OLE)؛ وتوفير الوظيفة نفسها التي لنسخ الحافظة ولصقها، لذا يحتاج تطبيق ينفِّذ أصلاً النسخ واللصق إضافة صغيرة فقط؛ وأنواع التغذية الراجعة. ↩ ↩2
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
ما ينبغي تنظيمه قبل طلب التعهيد أو التطوير التعاقديّ لتطبيق Windows
قبل تكليف جهة خارجية بتطوير تطبيق Windows تعاقديّاً، إليك النقاط التي ينبغي تنظيمها: تعديل البرمجيّات القائمة، وتكامل الأجهزة، وCOM/Activ...
انتهاء خدمة برامج تشغيل الطابعات في Windows ── كيف تستعد تطبيقات الأعمال لطباعة التقارير والملصقات
تُنهى Microsoft تدريجيّاً خدمة برامج تشغيل الطابعات v3/v4، ومن تمّوز/يوليو 2026 يُفضَّل برنامج تشغيل فئة IPP. نرتّب في جداول قرار ما يختف...
ما كائن OLE؟ ── آلية التضمين والربط ومطبّات مستندات الأعمال
حقيقة ميزة تضمين جدول Excel في Word هي كائن OLE. نشرح الفرق بين التضمين والربط، والملفّ المركَّب والتخزين المنظَّم، وآلية In-Place Activa...
ما الذي يعنيه «لا يستجيب» حقّاً ── كيف يقرِّر Windows أنّ تطبيقاً تجمّد، وكيف تصمِّم تطبيقات لا تتجمّد
يحكم Windows أنّ نافذة «لا تستجيب» بعد 5 ثوانٍ بلا استخراج رسالة ويعرض نافذة شبح: الحكم، وأسباب التعليق، وتصميم مؤشّر ترابط الواجهة، وإجر...
الوضع الداكن وسمة التباين في تطبيقات Windows ── شريط العنوان الداكن عبر DWM، وتتبع سمة النظام في WinForms/WPF، والرسم عند التباين العالي
شرح جعل تطبيقات WinForms/WPF تتبع الوضع الداكن وسمة التباين في Windows 11. نرتّب شريط العنوان الداكن عبر DWM، وSetColorMode وThemeMode في...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
دعم إعادة استخدام الأصول القديمة وترحيلها
ندعم إعادة استخدام وترحيل الأصول التي تحمل قيود COM / ActiveX / OCX أو 32bit / 64bit.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- لماذا ينهار التنسيق عندما ألصق جدولاً منسوخاً من Excel في تطبيقي؟
- لأنّ الحافظة لا تحمل «قطعة بيانات واحدة»: يُوضَع المحتوى نفسه بعدّة تنسيقات دفعة واحدة (التنسيق الخاصّ للتطبيق، وHTML Format، وCSV، ونصّ يونيكود، وما شابه)، ويختار تطبيق الوجهة التنسيق الذي يفهمه ويستخرجه. عندما ينهار التنسيق، السبب النموذجيّ أنّ الوجهة تقرأ النصّ البسيط فقط (CF_UNICODETEXT). إن أردت بنية الجدول أيضاً، نفِّذ جانب اللصق بحيث يفضّل HTML Format أو CSV. وبالعكس، إن أردت أن تلصق تطبيقات أخرى بشكل صحيح من نسخة صُنعت في تطبيقك، فاعرض عند النسخ تنسيقاً غنيّاً وتنسيقاً بسيطاً معاً.
- لماذا لا أستطيع اللصق بعد أن أغلقت التطبيق الذي نسخت منه؟
- لأنّ المصدر يستخدم العرض المؤجَّل. التطبيقات التي تعالج بيانات كبيرة لا تضع البيانات نفسها عند النسخ؛ تسجّل على الحافظة وعداً فقط بأنّها «ستنتجها عند الطلب». إن خرج المصدر بعد ذلك دون تجسيد البيانات استجابةً لـ WM_RENDERALLFORMATS عند الإغلاق، تُفقَد التنسيقات غير المعروضة. تطبيق يستخدم حافظة OLE (IDataObject) يمكنه إبقاء اللصق ممكناً بعد الخروج باستدعاء OleFlushClipboard عند الإغلاق لتجسيد البيانات.
- كيف يراقب تطبيقي الحافظة بحثاً عن تغييرات؟
- الطريقة الموصى بها حالياً تسجيل نافذتك مستمعاً بـ AddClipboardFormatListener ومعالجة رسالة WM_CLIPBOARDUPDATE التي تصل في كلّ مرّة يتغيّر المحتوى. استطلاع المحتوى على مؤقّت يهدر عملاً، وسلسلة العارض القديمة القائمة على SetClipboardViewer تُحفَظ فقط للتوافق الخلفيّ، لأنّ عيباً في تطبيق واحد في السلسلة يكسر السلسلة كلّها. لاحظ أيضاً أنّ OpenClipboard عند القراءة قد يفشل بسبب التنازع مع عمليّة أخرى، لذا تنفيذ إعادة محاولة بانتظار قصير يجعله مستقرّاً.
- هل ثمّة طريقة لإبقاء أسرار مثل كلمات المرور خارج سجلّ الحافظة (Win+V)؟
- ثمّة وسيلتان، واحدة في جانب التطبيق وواحدة في جانب السياسة. في جانب التطبيق، إن وضعت أيضاً تنسيقاً مسجَّلاً باسم ExcludeClipboardContentFromMonitorProcessing عند النسخ، فإنّ ذلك المحتوى لا يُدرَج لا في السجلّ ولا في المزامنة عبر الأجهزة. يمكنك أيضاً التحكّم في كلّ منهما مستقلّاً بـ CanIncludeInClipboardHistory (السجلّ فقط) وCanUploadToCloudClipboard (المزامنة فقط). هذه الآليّة التي تستخدمها مدراء كلمات المرور. لإيقافه للمنظّمة كلّها، يمكنك تعطيل السجلّ ومزامنة السحابة نفسيهما بـ AllowClipboardHistory وAllowCrossDeviceClipboard عبر نهج المجموعة أو Intune (Policy CSP).
- لماذا لا أستطيع سحب ملفّ وإفلاته على تطبيق يعمل كمسؤول؟
- لأنّ آليّة أمان تُدعى UIPI (User Interface Privilege Isolation) تحجب الرسائل المُرسَلة من عمليّة سلامة أدنى إلى نافذة سلامة أعلى. مستكشف الملفّات يعمل بصلاحيّة عاديّة (سلامة متوسّطة)، لذا إشعارات السحب والإفلات لا تصل أبداً إلى نافذة تطبيق مرتفع. حلّ التفافيّ يسمح برسائل مثل WM_DROPFILES فرديّاً بـ ChangeWindowMessageFilterEx معروف، لكنّه مقصور على إشعار الإفلات الأقدم. الإصلاح الحقيقيّ التوقّف عن تصميم التطبيق ليعمل مرتفعاً طوال الوقت وعزل العمل الذي يحتاج الارتفاع فقط إلى عمليّة منفصلة.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.