מה זה Reg-Free COM: COM בלי רישום ב-registry

· עודכן בתאריך: · · COM, Reg-Free COM, Registration-Free COM, פיתוח Windows, legacy

היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 16 Mar 2026)
פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22173587)

מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.

Go Komura (2026). מה זה Reg-Free COM: COM בלי רישום ב-registry. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22173587 https://comcomponent.com/he/blog/what-is-reg-free-com/

DOI (הגרסה האחרונה)
10.5281/zenodo.22173587
DOI (הגרסה הזו)
10.5281/zenodo.22173588

בפרויקטים של COM / ActiveX / OCX, אותן בעיות חוזרות בכל פעם שמפיצים או מעדכנים.

  • צריך regsvr32
  • בדרך כלל צריך הרשאות Administrator
  • מתנגש עם גרסה אחרת שאפליקציה אחרת התקינה
  • uninstall ששובר גם מוצר אחר
  • עובד על מחשב הפיתוח, לא עובד בסביבה נקייה

Reg-Free COM מקטין את זה משמעותית. למרות השם, זה לא קסם שמעלים את כל בעיות COM. מה שנעלם הוא בעיקר הכאבים שמגיעים מרישום גלובלי. bitness, dependent DLL-ים, type library, וקושי ה-threading model לא נעלמים.

מה נעלם ומה נשאר ב-Reg-Free COMתרשים שמראה שב-Reg-Free COM מה שנעלם בעיקר הוא הכאב שנגרם מרישום גלובלי, ואילו bitness, dependent DLL-ים, type library וקושי ה-threading model לא נעלמים.Reg-Free COMפחות כאב של רישום גלובליקשיים שנשאריםbitness / dependent DLL / type library

איור 1: לא קסם. מצפים בנפרד למה שנעלם ולמה שנשאר.

המאמר מתמקד ב-Reg-Free COM בהקשר של שימוש ב-COM DLL / OCX כ-private לאפליקציה אחת, באפליקציית desktop ל-Windows.

למי זה מיועד, ומה מניחים

המאמר מיועד למפתחים שמפיצים אפליקציית desktop ל-Windows שמשתמשת ב-COM DLL / OCX קיימים, ורוצים להיפטר מ-regsvr32 ומהרשאות Administrator. ההנחה היא שכבר נתקלתם ביסודות COM (CLSID, ProgID, CoCreateInstance, in-proc server). אם זה עדיין לא חד, מהיר יותר לקרוא קודם את “מה זה COM / ActiveX / OCX - הסבר על ההבדלים והקשרים”.

חלק ההליכים משתמש ב-mt.exe וב-sxstrace מ-Windows SDK, ולכן ההנחה היא סביבה עם Visual Studio או Windows SDK מותקנים.

1. המסקנה בקצרה

בניסוח גס אבל שימושי:

  • Reg-Free COM היא דרך שבה מידע הרישום של COM יושב ב-manifest במקום ב-registry
  • בזמן ריצה, ב-resolution של CoCreateInstance או CLSIDFromProgID, נבדק קודם activation context
  • לכן אפשר להחזיק COM DLL / OCX כ-private לכל אפליקציה
  • היתרונות העיקריים: קל להפיץ ב-XCOPY, קל יותר להימנע מהתנגשות גרסאות, uninstall שפחות נשבר
  • עם זאת, בעיית 32bit / 64bit לא נעלמת. אי אפשר לעקוף את זה בכתיבת manifest
  • בנוסף צריך לטפל בנפרד ב-dependent DLL-ים, type library, design-time references, ותלות ברישום לא סטנדרטי
  • בפועל זה מתאים מאוד כשרוצים לשים בצד קומפוננטת COM ייעודית לאפליקציה

בקיצור, Reg-Free COM הוא מנגנון שמחזיר את ה-activation של COM לרמת האפליקציה.

מקום מידע הרישום משתנהתרשים שמראה ש-Reg-Free COM מחזיק את מידע הרישום של COM ב-manifest במקום ב-registry, ומכיוון שב-resolution של CoCreateInstance וכדומה נבדק קודם ה-activation context, אפשר להחזיק קומפוננטות COM כ-private לכל אפליקציה.מידע הרישום ב-manifestב-resolution, activation context נבדק קודםאפשר להחזיק COM כ-private לאפליקציהקל יותר XCOPY ופחות התנגשות

איור 2: המהות היא שנקודת הכניסה ל-resolution עוברת מ-registry ל-manifest.

ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 26, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle

2. מה הכוונה ב-Reg-Free COM במאמר הזה

Reg-Free COM הוא קיצור של Registration-Free COM. לפעמים כותבים גם “COM בלי צורך ברישום”.

“בלי רישום” כאן אומר לא להסתמך לגמרי על רישום גלובלי ב-registry דרך HKCR / CLSID / InprocServer32 וכדומה, כדי להשתמש ב-COM. זה לא אומר ש-COM עצמו נעלם, וגם לא שה-GUID כבר לא נחוץ.

המאמר מתמקד בעיקר באלה:

  • native COM DLL
  • COM server מבוסס ATL
  • ActiveX / OCX
  • COM Interop מבוסס .NET Framework
  • חשיפה דרך COM host של .NET 5+ / .NET 8

לעומת זאת, שתי הנקודות שחשוב להדגיש כאן:

  1. Reg-Free COM הוא עניין של activation
  2. הפצה של type information והגדרת design-time references עלולות להישאר כנושא נפרד

אם מערבבים בין השניים, הדיון נהיה מבלבל.

שני נושאים שאסור לערבבתרשים שמראה ש-Reg-Free COM הוא עניין של activation, ושהפצת type information והגדרת design-time references נשארות כנושא נפרד, ולכן ערבוב ביניהם מבלבל את הדיון.Reg-Free COMעניין של activationהפצת types / design-time referenceנשאר כנושא נפרדערבוב מבלבל את הדיון

איור 3: runtime ו-design-time מטופלים בנפרד מלכתחילה.

3. קודם כל, תמונה כללית

לפני שנכנסים לתרשים, נגדיר 4 מונחים שחוזרים לאורך המאמר.

מונח משמעות
activation context מבנה נתונים ב-runtime ששומר “איזו גרסה של איזה assembly ה-thread הזה משתמש בה עכשיו”. CoCreateInstance בודק את זה לפני ה-registry
side-by-side assembly מנגנון ב-Windows שמאפשר לקומפוננטה עם אותו שם, בגרסאות שונות, לחיות יחד על אותה מכונה. מזוהה דרך manifest, ו-assemblyIdentity הוא התג המזהה
application manifest XML שמצמידים לצד ה-EXE, וכותבים בו “באיזה side-by-side assembly זה תלוי”
component manifest (assembly manifest) XML שמצמידים לצד הקומפוננטה, וכותבים בו “אילו קבצים ה-assembly הזה כולל, ואילו COM classes הוא חושף”. מידע שבמקור היה ב-registry עובר לכאן

ה-activation context נשמר לכל thread בנפרד. COM מעביר את ה-activation context של ה-thread היוצר אל ה-thread המארח לפני שהוא קורא ל-LoadLibrary או ל-DllGetClassObject, ולכן מצד הקורא לא צריך הכנה מיוחדת.

עם זאת, מהיר יותר לראות קודם את התמונה הכללית בתרשים אחד.

התמונה הכללית של Reg-Free COMתרשים שמראה שהאפליקציה מפנה דרך application manifest ו-component manifest אל ה-DLL, ובמקביל האפליקציה משתמשת ב-activation context כדי ל-resolve את קריאת ה-COM ולהגיע לאותו DLL בלי registry.MyApp.exeapplication manifestdependentAssemblycomponent manifestfile / comClass / typelibVendorControl.dll / .ocxActivation ContextCLSIDFromProgID / CoCreateInstance

איור 4: עוקבים מ-application manifest ל-component manifest, ומגיעים ל-DLL בלי registry.

ב-COM רגיל, כשקוראים ל-CoCreateInstance, עוברים דרך ה-registry כדי לקבוע איזה DLL לטעון. ב-Reg-Free COM, לפני זה נבדק ה-activation context הפעיל כרגע, ומתוכו נעשה resolve לפי מידע ה-manifest שכתוב שם.

בגלל זה, קל יותר שאפליקציה A ואפליקציה B על אותה מכונה יחזיקו גרסאות שונות של אותה משפחת קומפוננטות COM. זה מחזיר קצת את מודל ה-sharing של COM לכיוון private לאפליקציה.

4. למה הפצה רגילה של COM יוצאת כבדה

הפצה רגילה של COM כבדה לא כי COM עצמו רע, אלא בגלל ההנחה שצריך רישום גלובלי.

כדי להשתמש ב-COM class, בערך צריך את המידע הבא.

מידע תפקיד
CLSID GUID שמזהה את ה-class באופן ייחודי
ProgID שם נוח לבני אדם
InprocServer32 איזה DLL לטעון
ThreadingModel הנחה כמו Apartment / Both
TypeLib type information

כשזה נכנס ל-registry, זה נוח ברמת המכונה: קל לשתף בין כמה אפליקציות.

בפועל, ה-sharing הזה עובד נגדך.

  • ההתקנה של מוצר אחד דורסת את רישום ה-COM של מוצר אחר
  • ה-uninstaller “חושב” שהוא מוחק רק את שלו, ושובר COM משותף
  • registration שקיים במקרה במחשב הפיתוח, לא קיים במכונת הייצור
  • רישום 32bit ו-64bit לא תואמים, ורק הסימפטום נראה מוזר

כלומר, מודל ההפצה, ולא COM עצמו, הוא מה שמטריד אנשים לעיתים קרובות. Reg-Free COM הוא מנגנון שמקטין את הכאב הזה במודל ההפצה.

איך sharing גלובלי עובד נגדךתרשים שמראה שמידע רישום COM שנכנס ל-registry נוח לשיתוף ברמת המכונה, אבל בפועל ה-sharing הזה עובד נגדך דרך overwrite ממוצרים אחרים, uninstall ששובר אחרים, ופער בין סביבות, כך שמודל ההפצה מטריד יותר מ-COM עצמו.מידע רישום ברמת המכונהנוח לכמה אפליקציותבפועל ה-sharing עובד נגדךoverwrite / uninstall / פער סביבותמודל ההפצה מטריד

איור 5: הבעיה האמיתית היא לא COM עצמו, אלא ההנחה של רישום גלובלי.

5. איך המנגנון של Reg-Free COM עובד

5.1 ה-application manifest כותב את התלות

קודם כל, צד האפליקציה כותב ב-application manifest באיזה side-by-side assembly היא תלויה.

את ה-manifest הזה אפשר:

  • לשים ליד ה-EXE כמו MyApp.exe.manifest
  • לעשות embed בתוך ה-EXE כ-resource

בפועל, אם רוצים להקל על הפצה והחלפה: קובץ חיצוני; אם עדיפות לחוסן ולפשטות הפצה: embed.

שימו לב: אם יש גם קובץ חיצוני וגם embed, ה-manifest שב-file system מקבל עדיפות.

5.2 ה-component manifest כותב את מידע ה-COM

בשלב הבא, צד ה-COM מחזיק ב-component manifest מידע שבמקור היה ב-registry.

מה שנכנס לכאן, למשל:

  • comClass
  • clsid
  • progid
  • threadingModel
  • typelib
  • אם צריך, גם proxy / stub או window class

כלומר, במקום registry מתארים את ה-COM ב-XML.

את ה-manifest הזה אפשר להרכיב:

  • כקובץ נפרד מה-DLL
  • כ-embed בתוך ה-DLL כ-resource

בפועל, embed בתוך ה-DLL כ-private assembly נוטה פחות להישבר. תפעול עם קובץ נפרד קל להבנה, אבל קל להיתקע על התאמה בין שם הקובץ ל-assemblyIdentity, על מיקום ההצבה, או על קובץ שנשכח בהעתקה.

איך מחזיקים את ה-component manifestתרשים שמראה שמידע כמו comClass, clsid, typelib שבמקור היה ב-registry, ה-component manifest מחזיק אותו כ-XML, ואפשר לבחור בין קובץ נפרד מה-DLL לבין embed בתוך ה-DLL כ-resource, כאשר בפועל ה-embed נוטה פחות להישבר.מידע מה-registry, ב-XMLמוצב כקובץ נפרדembed בתוך ה-DLLקל לשכוח להעתיקבפועל פחות נשבר

איור 6: תוכן המידע זהה, אבל אופן ההצבה קובע את שיעור הכשלים.

5.3 ב-runtime נבדק קודם ה-activation context

כאן נמצא הלב של Reg-Free COM.

כשהאפליקציה קוראת ל-CLSIDFromProgID או ל-CoCreateInstance, ה-COM runtime בודק את ה-activation context הפעיל. אם יש שם את המידע הנדרש להמרה מ-ProgID ל-CLSID ומ-CLSID ל-DLL, ה-resolution מתבצע בלי registry.

לעומת זאת, אם המידע הנדרש חסר ב-manifest, זה נופל ל-resolution הרגיל לפי registry. בגלל ההתנהגות הזו נוצרת מלכודת: על מחשב הפיתוח זה עובד במקרה. חשבתם שהצלחתם לעבור ל-Reg-Free, אבל בפועל הרישום המקומי עוזר מאחורי הקלעים.

זו המלכודת הכי מעצבנת של Reg-Free COM.

המלכודת שנפלה ל-resolution לפי registryתרשים שמראה שב-resolution של CoCreateInstance נבדק קודם ה-activation context, אבל אם חסר מידע ב-manifest זה נופל ל-resolution הרגיל לפי registry, ולכן נוצרת מלכודת שבה זה עובד במקרה במחשב הפיתוח בזכות registration מקומי.ישאיןה-resolution בודק קודם activation contextיש מספיק מידע ב-manifest?resolve בלי registryנופל ל-resolution לפי registryמלכודת: עובד במקרה אצל המפתח

איור 7: ה-fallback השקט הוא ה-pitfall הכי גדול במנגנון הזה.

6. מה מרוויחים מזה

היתרונות של Reg-Free COM ברורים למדי בפועל.

6.1 קל להפיץ ב-XCOPY

אפשר לשים את כל הקבצים הנדרשים יחד בתיקיית האפליקציה, כך שהתקנה ורישום נעשים קלים יותר. כמובן, כתיבה תחת Program Files היא עדיין עניין של הרשאות, אבל לפחות עבודת Administrator לצורך רישום COM קל יותר לצמצם.

6.2 קל יותר לצמצם התנגשות גרסאות

גם אם יש כמה גרסאות של קומפוננטת COM על אותה מכונה, קל יותר להפריד איזו גרסה כל אפליקציה משתמשת בה. קל יותר להימנע מתקלה של “ההתנהגות השתנתה פתאום בגלל התקנה של מוצר אחר”.

6.3 לרוב אין צורך לשנות משמעותית קוד קיים

Reg-Free COM לא משנה מהיסוד את אופן הקריאה של הקוד הקיים. הוא מנגנון שמשנה את אופן ה-resolution. לכן, אם זה מסתדר, אפשר להטמיע כמעט בלי לגעת בקוד של CoCreateInstance.

6.4 מחיקה ו-rollback נהיים קלים יותר

כי זה סגור לאפליקציה, עדכון ו-rollback נהיים ישירים יותר. בקיצוניות, קל יותר לחשוב במונחי החלפת תיקייה שלמה.

היתרון בסגירה לרמת אפליקציהתרשים שמראה שסגירת קומפוננטות COM לרמת אפליקציה מולידה יתרונות כמו קלות הפצה ב-XCOPY, צמצום התנגשות גרסאות, הטמעה כמעט בלי לגעת בקוד הקיים, ופשטות במחיקה וב-rollback.סוגרים לרמת האפליקציהקל להפיץ ב-XCOPYפחות התנגשות גרסאותאפשר להחליף תיקייה שלמהכמעט בלי לגעת בקוד הקריאה

איור 8: כל היתרונות יוצאים מאותה תכונה: סוגרים את זה לאפליקציה.

7. מתי זה מתאים ומתי לא

7.1 מקרים שמתאימים

במקרים הבאים, Reg-Free COM חזק למדי.

מצב התאמה
רוצים לצרף COM DLL / OCX ייעודי לאפליקציה טוב מאוד
רוצים להחזיק כמה גרסאות באותו PC טוב מאוד
רוצים להימנע מתקלת רישום של קומפוננטת vendor טוב
רוצים להשתמש ב-ActiveX / OCX כ-private באפליקציית desktop קיימת טוב
רוצים להקל על ההפצה בלי לשנות משמעותית את הקריאה הקיימת טוב

בדרך כלל זה מתאים ל-אפליקציות עסקיות ב-desktop, כלי אינטגרציה מול ציוד, ו-assets קיימים של VB6 / MFC / WinForms.

7.2 מקרים שלא מתאימים, או שכדאי לבדוק בזהירות

מצד שני, יש גם מקרים שכדאי לבדוק בזהירות.

מצב הערה
רוצים לשתף COM ברמת המכונה אין כאן הרבה יתרון ל-Reg-Free
ה-bitness לא תואם Reg-Free לא פותר את זה
תלות חזקה במידע רישום לא סטנדרטי או בהתקנה ייחודית קשה לתרגם ל-manifest
הפצת dependent DLL או VC++ runtime לא מסודרת זה יישבר במקום אחר בכל מקרה
כלי design-time או הגדרת references ב-IDE מניחים registry צריך לתכנן תהליך עבודה נפרד

בפרט, הנקודה האחרונה חשובה. Reg-Free COM עוזר ל-activation ב-runtime, אבל לא משנה בבת אחת על מה כלי ההגדרה ב-design-time מניח.

runtime נעזר, design-time נשארתרשים שמראה ש-Reg-Free COM עוזר ל-activation ב-runtime, אבל אם כלי או IDE להגדרת references ב-design-time מניחים registry, זה לא משתנה כך סתם, וצריך לתכנן תהליך עבודה נפרד.activation ב-runtimeReg-Free עוזרUI של design-time referencesלפעמים מניח registryצריך תהליך עבודה נפרד

איור 9: גם כשמנגנון ההפעלה מסודר, מנגנון הפיתוח צריך טיפול נפרד.

8. אי-הבנות נפוצות

8.1 עם Reg-Free COM, בעיית ה-bitness נעלמת

לא נעלמת. process של 32bit יכול לטעון רק in-proc COM DLL של 32bit, ו-process של 64bit רק DLL של 64bit. זה נשאר כמו קודם גם עם Reg-Free.

8.2 עם Reg-Free COM, ה-registry כבר לא נבדק בכלל

גם זה לא נכון. אם חסר מידע נדרש ב-manifest, זה נופל ל-resolution הרגיל לפי registry. בגלל זה, הצלחה במחשב הפיתוח לא אומרת בהכרח שקונפיגורציית ה-Reg-Free נכונה.

8.3 עם Reg-Free COM, גם נושא ה-type library נפתר אוטומטית

זה נכון רק בחצי. אפשר לכתוב גם מידע typelib ב-manifest, אבל הגדרת references ב-VBA, #import ב-C++, יצירת references ב-design-time בצד .NET - הטיפול ב-type information לרוב עדיין דורש תכנון נפרד.

Reg-Free COM הוא בעיקר עניין של לגרום לזה לעלות. איך מפתחים עם types הוא הנושא הבא.

הסדר בין נושא ה-activation לנושא ה-typesתרשים שמראה שגם אם אפשר לכתוב מידע typelib ב-manifest, הטיפול ב-type information, הגדרת references ב-VBA, import ב-C++, יצירת interop ב-.NET, עדיין דורש תכנון נפרד, ו-Reg-Free COM עוסק קודם כל ב-activation, ופיתוח עם types הוא הנושא הבא.מגדירים Reg-Free COMקודם כל, שזה יעלהאחר כך, פיתוח עם typesVBA references / import / interop

איור 10: היכולת לכתוב typelib והשלמת ניהול ה-type information הן שני דברים שונים.

8.4 עם Reg-Free COM, כל ActiveX / OCX עובד ישירות

גם זה מסוכן. אם הקומפוננטה מבוססת על מידע רישום COM סטנדרטי, קל להתקדם, אבל אם יש הגדרת registry ייחודית, התקנה נוספת, עיבוד רישוי, או תלות חזקה בקבוצת מודולים אחרת, המעבר ל-Reg-Free נהיה פתאום קשה.

8.5 Reg-Free COM דומה לחלוטין בין .NET Framework ל-.NET 8

יש דמיון, אבל ה-toolchain שונה למדי. ההקשר של .NET Framework + RegAsm וההקשר של .NET 5+ / .NET 8 + comhost הם אותו COM, אבל ה-tooling שונה.

9. ההבדל בין native / .NET Framework / .NET 5+ / .NET 8

כאן קל להתבלבל, ולכן נפריד את זה פעם אחת.

משפחה בקצרה
native COM DLL / OCX בסיסי לחשוב במונחי application manifest + component manifest
COM Interop מבוסס .NET Framework בנוסף ל-application manifest בסגנון Win32, נדרש גם manifest מצד הקומפוננטה ה-managed
חשיפת COM ב-.NET 5+ / .NET 8 יוצרים COM host עם EnableComHosting, ומייצרים manifest ל-Reg-Free עם EnableRegFreeCom

9.1 COM מבוסס .NET Framework

ב-COM מבוסס .NET Framework יש שתי שכבות: application manifest בסגנון Win32 מצד אפליקציית ה-COM, ו-component manifest מצד הקומפוננטה ה-managed.

כלומר, בהשוואה ל-COM native, נוסף manifest אחד. מגבלת השם ו-resource ID מסעיף 10.4 חלה באותה מידה גם על ה-component manifest כאן.

9.2 חשיפת COM ב-.NET 5+ / .NET 8

ב-.NET 5+ / .NET 8, ה-entry point לחשיפת COM הופך ל-*.comhost.dll. בנוסף, אם מוסיפים EnableRegFreeCom=true, מיוצא side-by-side manifest ל-Reg-Free COM.

הטיפול ב-type information כנושא נפרד כפי שתואר בסעיף 8.3, אבל ב-.NET Core / .NET 5+ זה משתנה עוד יותר. מכיוון שזה לא עולם שבו TLB נוצר באופן טבעי מה-assembly כמו בתקופת .NET Framework, אם נדרש שימוש typed, יש לבנות בנפרד את יצירת ה-TLB, ה-embed וה-registration. השלבים המדויקים מסוכמים ב-“שימוש ב-DLL של .NET 8 מ-VBA עם טיפוסים - חשיפת COM ו-TLB ב-dscom”.

Reg-Free COM ב-.NET 5 ואילךתרשים שמראה שב-.NET 5 ואילך, EnableComHosting יוצר את comhost.dll כ-entry point לחשיפת COM, EnableRegFreeCom מייצא side-by-side manifest ל-Reg-Free COM, אבל יצירה ו-registration של TLB דורשים בנייה נפרדת.build עם EnableComHostingcomhost.dll הופך ל-entry pointמפעילים EnableRegFreeComיוצא manifest ל-Reg-Freeטיפול ב-TLB דורש עבודה נפרדת

איור 11: ב-.NET 8 שני properties מכינים את התשתית, אבל type information דורש עבודה נפרדת.

10. תמונה של קונפיגורציה מינימלית

כאן נציג תמונה מינימלית שבה MyApp.exe משתמש ב-Vendor.CameraControl.dll דרך Reg-Free COM.

10.1 מבנה הקבצים

MyApp.exe
MyApp.exe.manifest
Vendor.CameraControl.Asm.manifest
Vendor.CameraControl.dll
Vendor.Helper.dll

בדוגמה למעלה, ההנחה היא שה-component manifest מוצב כקובץ נפרד. אפשר גם לעשות embed בתוך ה-DLL, אבל אז חלות מגבלות קבועות על שם ה-assembly ועל resource ID. ההליך המלא מובא בסעיף 10.4.

10.2 תמונת ה-application manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="KomuraSoft.MyApp"
    version="1.0.0.0"
    processorArchitecture="amd64" />

  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Vendor.CameraControl.Asm"
        version="1.0.0.0"
        processorArchitecture="amd64" />
    </dependentAssembly>
  </dependency>
</assembly>

10.3 תמונת ה-component manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="Vendor.CameraControl.Asm"
    version="1.0.0.0"
    processorArchitecture="amd64" />

  <file name="Vendor.CameraControl.dll">
    <comClass
      clsid="{01234567-89AB-CDEF-0123-456789ABCDEF}"
      progid="Vendor.CameraControl.1"
      threadingModel="Apartment"
      tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}" />

    <typelib
      tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}"
      version="1.0"
      helpdir="" />
  </file>
</assembly>

מה שבאמת חשוב בדוגמה הזו, יותר מפרטי ה-XML, הוא ש-dependentAssembly בצד האפליקציה ו-assemblyIdentity בצד הקומפוננטה תואמים. אם יש כאן פער, זה הופך לכשל בהפעלה שאי אפשר להבין מהשגיאה עצמה.

שימו לב: ה-GUID והשמות למעלה הם דוגמה להמחשה. בפועל צריך לכתוב אותם נכון לפי ה-CLSID / TLBID / ProgID / threading model שהקומפוננטה חושפת בפועל.

דרישת ההתאמה בין שני ה-manifestsתרשים שמראה שה-dependentAssembly בצד האפליקציה וה-assemblyIdentity בצד הקומפוננטה חייבים להתאים בשם ובגרסה, ואם יש פער זה הופך לכשל בהפעלה שהסיבה לו לא נראית ממראה השגיאה.תואםלא תואםdependentAssembly בצד האפליקציההשם והגרסה תואמים?assemblyIdentity בצד הקומפוננטהה-resolution מצליחכשל בהפעלה בלי סיבה ברורה

איור 12: יותר מפרטי ה-XML, מה שקובע הוא שהשני התגים תואמים.

10.4 איפה מציבים ואיך עושים embed ל-manifest

זו הנקודה שהכי קל להיתקע בה בפועל בהליך. אם מציבים כקובץ נפרד או עושים embed בבינארי, השם המותר משתנה.

side-by-side מחפש private assembly בתיקיית האפליקציה בסדר הזה.

  1. תיקיית WinSxS
  2. <appdir>\<assemblyname>.DLL
  3. <appdir>\<assemblyname>.manifest
  4. <appdir>\<assemblyname>\<assemblyname>.DLL
  5. <appdir>\<assemblyname>\<assemblyname>.manifest

אם נמצא DLL עם שם זהה לשם ה-assembly, החיפוש נעצר שם. מכאן יש רק שתי אפשרויות ישימות.

הצבה שם ה-assembly קובץ resource ID ל-embed
קובץ נפרד שם שונה משם ה-DLL. לדוגמה: Vendor.CameraControl.Asm Vendor.CameraControl.Asm.manifest ליד ה-DLL לא עושים embed
embed ב-DLL יכול להיות זהה לשם ה-DLL. לדוגמה: Vendor.CameraControl רק Vendor.CameraControl.dll 1

כלומר, אם משתמשים בשם Vendor.CameraControl.Asm כמו בדוגמאות 10.2 ו-10.3, זה תפעול לקובץ נפרד. אם עוברים ל-embed, משנים את ה-name של assemblyIdentity ל-Vendor.CameraControl, ומיישרים גם את dependentAssembly לאותו שם.

המנגנון שבו החיפוש נעצרתרשים שמראה ש-side-by-side מחפש private assembly בסדר מ-WinSxS ואילך בתיקיית האפליקציה, ואם נמצא DLL עם שם זהה לשם ה-assembly החיפוש נעצר שם, ולכן בתפעול של קובץ נפרד צריך שהשם יהיה שונה משם ה-DLL.נמצאלא נמצאמתחילים חיפוש private assemblyמחפשים DLL בשם ה-assemblyהחיפוש נעצר שםמחפשים קובץ manifest באותו שםבקובץ נפרד, מבדילים את השם

איור 13: מגבלת השמות מגיעה מזה שהחיפוש נעצר באמצע.

יש עוד מגבלה שקל לטעות בה. אי אפשר לשים component manifest כ-resource ב-EXE. מה שאפשר לשים ב-EXE הוא ה-application manifest.

ל-embed משתמשים ב-mt.exe (Manifest Tool) מ-Windows SDK. הריצו אותו מ-Developer Command Prompt של Visual Studio.

rem 1. לפני ה-embed, קודם עוברים syntax check
mt.exe -manifest MyApp.exe.manifest -validate_manifest
mt.exe -manifest Vendor.CameraControl.manifest -validate_manifest

rem 2. embed של ה-application manifest לתוך ה-EXE
mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;#1

rem 3. embed של ה-component manifest לתוך ה-DLL (resource ID 1)
mt.exe -manifest Vendor.CameraControl.manifest -outputresource:Vendor.CameraControl.dll;#1

rem 4. שולפים ובודקים אם ה-embed הצליח
mt.exe -inputresource:Vendor.CameraControl.dll;#1 -out:extracted.manifest

אם משווים את extracted.manifest שהוצא בפקודה הרביעית ל-XML המקורי, אפשר לתפוס מצב של “חשבתי שעשיתי embed, אבל זה לא נכנס”.

הליך ה-embed עם mt.exeתרשים שמראה שב-mt.exe, קודם עוברים syntax check עם validate_manifest, עושים embed של ה-application manifest ל-EXE, של ה-component manifest ל-DLL עם resource ID 1, ולבסוף שולפים ומשווים ל-XML המקורי.עוברים syntax checkembed של צד האפליקציה ל-EXEembed של הקומפוננטה ל-DLL (ID 1)שולפים ומשווים ל-XML המקורי

איור 14: את ה-embed מריצים כהליך אחד שכולל גם את הבדיקה.

יש שתי הערות ל-mt.exe.

  • הקבצים שה-manifest מפנה אליהם חייבים להיות באותה תיקייה כמו ה-manifest. אם כתוב <file name="Vendor.CameraControl.dll">, יש להציב את ה-DLL הזה ליד ה-manifest לפני ההרצה. אם פלט הבנייה ומיקום ניהול ה-manifest מופרדים, זה ייעצר כאן
  • אם משמיטים את ה-resource ID ב--outputresource, נעשה שימוש ב-CREATEPROCESS_MANIFEST_RESOURCE (= 1). כדי לא להסתמך על 1 בלי כוונה, עדיף לציין ;#1 במפורש. זה גם קריא יותר

אם רוצים רק להחליף embed קיים, אפשר להשתמש ב--updateresource:<file>;#1. זה שקול לזה שמעבירים את אותם arguments ל--inputresource ול--outputresource.

10.5 הליך בדיקה כולל סביבה נקייה

ל-Reg-Free COM כמעט אין משמעות ל”עבד במחשב הפיתוח”. תמיד נשארת האפשרות שזה רק בזכות registration מקומי ב-registry. בודקים בסדר הזה.

  1. בונים, ומרכזים את כל חבילת ההפצה בתיקייה אחת. EXE, manifest, COM DLL, dependent DLL, VC++ runtime, ואפילו DLL של proxy / stub
  2. מכינים סביבת בדיקה. אידיאלי שזו סביבה שה-COM הזה מעולם לא נרשם בה. Windows Sandbox מאפשר לנסות בכל פעם ממצב נקי לגמרי
  3. בסביבה הזו, קודם מוודאים שה-COM הרלוונטי לא רשום. אם הפקודה למטה מחזירה שגיאה שהמפתח לא נמצא, זה סימן שלא נרשם
  4. מעתיקים את התיקייה ומפעילים ישירות. בלי להריץ installer ובלי regsvr32
  5. מוודאים שגם יצירת אובייקט COM עוברת. רק ההפעלה לא בודקת קומפוננטות שנוצרות באיחור. מפעילים בפועל את המסך או הפונקציה שבה CoCreateInstance רץ
  6. אם נכשל, אוספים לוג לפי ההליך בסעיף 11.2

הפקודה בשלב 3 היא כך.

reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:64
reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:32
reg query "HKCR\Vendor.CameraControl.1"

תצוגת ה-registry של 32bit ו-64bit נפרדות, ולכן חובה לבדוק את הצד שתואם ל-bitness של האפליקציה. אם בודקים גם /reg:64 וגם /reg:32, זה בטוח יותר.

כשרוצים לנסות במחשב הפיתוח, מבטלים זמנית את הרישום עם regsvr32 /u Vendor.CameraControl.dll ואז בודקים. עם זאת, בסביבה שבה מוצר אחר משתמש באותו COM, זה משפיע גם עליו, ולכן בטוח יותר להכין סביבה נקייה.

תהליך הבדיקה בסביבה נקייהתרשים שמראה שמרכזים את חבילת ההפצה בתיקייה אחת, מכינים סביבת בדיקה נקייה שה-COM הרלוונטי לא נרשם בה, מוודאים קודם שהוא לא רשום, מעתיקים ומפעילים ישירות, ומריצים עד לפונקציה שבה רץ CoCreateInstance.אם נכשלמרכזים את חבילת ההפצהמכינים סביבת בדיקה נקייהמוודאים קודם שאין registrationמעתיקים ומפעילים ישירותמריצים עד פונקציה שיוצרת COMאוספים לוג וחוקרים

איור 15: שילוב בדיקת אי-הרישום מוציא מהבדיקה את מקרה “עובד במקרה”.

11. מלכודות נפוצות

11.1 עובד במחשב הפיתוח, לא עובד ביעד ההפצה

מה שכדאי לחשוד בו ראשית הוא הדפוס שבו בעצם הרישום ב-registry עזר מאחורי הקלעים. בטוח יותר לבצע את בדיקת Reg-Free COM בסביבה נקייה אם אפשר.

11.2 ההפעלה נכשלת עם “side-by-side configuration is incorrect”

הבעיה הזו קורה בגלל אי-התאמה ב-manifest, dependent DLL חסר, VC++ runtime חסר, או פער בארכיטקטורה. כי הודעת השגיאה עצמה לא ידידותית, מקובל לחקור עם Event Log ו-sxstrace.

את ה-Event Log פותחים דרך Event Viewer > Windows Logs > Application, ומחפשים שגיאה שהמקור שלה SideBySide. שם רואים איזה assembly נכשל ב-resolution.

את sxstrace אוספים תוך שחזור הכשל. עדיף לפתוח Command Prompt כ-Administrator.

rem 1. מתחילים trace. החלון הזה נשאר פתוח
sxstrace trace -logfile:sxstrace.etl

rem 2. בחלון אחר, מפעילים את האפליקציה ומשחזרים את הכשל

rem 3. עוצרים את ה-trace. לוחצים Enter בחלון 1, או מריצים מחלון אחר
sxstrace stoptrace

rem 4. ממירים את ה-.etl הגולמי לפורמט קריא לבני אדם
sxstrace parse -logfile:sxstrace.etl -outfile:sxstrace.txt

אם לא רוצים שתופיע הודעת עצירה, מוסיפים -nostop לשלב 1. אם הפלט ארוך מדי, אפשר להוסיף -filter:MyApp.exe לשלב 4 כדי לצמצם רק לאפליקציה הרלוונטית.

ב-sxstrace.txt שהתקבל אחרי ההמרה, מפורטים לפי הסדר אילו manifest חיפש ואיפה לא היה תואם. גם כשטועים בכללי השם מסעיף 10.4, אפשר לזהות זאת דרך “שם הקובץ שחיפש”.

איך חוקרים שגיאת side-by-sideתרשים שמראה שכשההפעלה נכשלת עם side-by-side configuration is incorrect, בודקים ב-Event Viewer שגיאה עם מקור SideBySide, מתחילים trace עם sxstrace, משחזרים את הכשל, ואחרי העצירה ממירים עם parse וקוראים היכן הייתה אי-התאמה.בודקים SideBySide ב-Event Viewerמתחילים trace עם sxstraceמפעילים את האפליקציה ומשחזרים את הכשלעוצרים וממירים עם parseקוראים איפה היה חיפוש ואי-התאמה

איור 16: לא נתקעים על הודעת השגיאה החיצונית. עוקבים אחרי מסלול ה-resolution בלוג וב-trace.

11.3 ההתאמה בין component manifest ל-application manifest נשברת

  • ה-name שונה
  • ה-version שונה
  • ה-processorArchitecture שונה
  • ה-manifest שחשבו שהעתיקו הוא בעצם ישן

הפערים האלה נראים קטנים לעין, אבל בזמן ההפעלה משפיעים משמעותית.

11.4 שוכחים למקם dependent DLL

אם מסתפקים בבדיקת Vendor.CameraControl.dll בלבד ומרגישים בטוחים, חסרים Vendor.Helper.dll שנקרא מתוכו, VC++ runtime, ו-DLL של proxy / stub. Reg-Free COM מקטין את בעיית רישום ה-COM, אבל לא מוחק את בעיית ה-resolution של תלויות native.

11.5 דוחים את הטיפול ב-type library וב-references

גם אם ה-runtime activation עובר, אם יש דרישות כמו:

  • רוצים early binding מ-VBA
  • רוצים #import ב-C++
  • רוצים יצירת interop ב-design-time בצד .NET

צריך דרך להפיץ type information. Reg-Free COM לא מסדר את זה אוטומטית לגמרי, ולכן חשוב לחשוב בנפרד על runtime ו-design-time.

12. סיכום

אם אומרים את Reg-Free COM במשפט אחד, זה מנגנון שמעביר את מידע רישום ה-COM מרמת המכונה לרמת אפליקציה בודדת.

בזכות זה יש יתרונות כמו:

  • קל לסגור COM DLL / OCX לרמה מקומית לאפליקציה
  • קל יותר לצמצם התנגשות גרסאות
  • קל יותר לפשט הפצה ו-rollback

מצד שני, אלה עדיין חשובים:

  • 32bit / 64bit
  • dependent DLL
  • TLB / הגדרת references
  • תלות ברישום לא סטנדרטי
  • בדיקה בסביבה נקייה

לכן, הגישה הבסיסית להטמעת Reg-Free COM היא כך.

  1. מתייחסים לזה כעניין של activation
  2. מפרידים בין נקודות המבט של runtime ו-design-time
  3. בודקים בסביבה נקייה
  4. מיישרים מראש bitness ו-dependent DLL-ים

אם עוקבים אחר הסדר הזה, קל בהרבה להימנע מתקלות.

הגישה הבסיסית בזמן ההטמעהתרשים שמראה שבהטמעת Reg-Free COM, מתייחסים לזה כעניין של activation, מפרידים בין נקודות המבט של runtime ו-design-time, בודקים בסביבה נקייה, ומיישרים מראש bitness ו-dependent DLL-ים. אם עוקבים בסדר הזה, קל יותר להימנע מתקלות.מתייחסים לזה כ-activationמפרידים runtime ו-design-timeבודקים בסביבה נקייהמיישרים מראש bitness ו-dependent DLL

איור 17: אם שומרים על ארבע הגישות בסדר הזה, אפשר לצמצם מאוד תקלות בהטמעה.

13. מאמרים קשורים

14. מקורות

מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.

העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.

המאמר קשור ישירות לשירותים הבאים.

שאלות נפוצות

שאלות נפוצות בפניות בנושא המאמר.

מה זה Reg-Free COM?
מנגנון שבו מידע הרישום של COM יושב ב-manifest במקום ב-registry. זה קיצור של Registration-Free COM. בזמן ריצה, ב-resolution של CoCreateInstance או CLSIDFromProgID נבדק קודם ה-activation context, וממנו מזוהה ה-DLL לפי מה שכתוב ב-manifest. ככה אפשר להחזיק COM DLL/OCX כ-private לכל אפליקציה, עם יתרונות כמו הפצה ב-XCOPY, פחות התנגשות גרסאות, ו-uninstall שפחות נשבר.
אם עוברים ל-Reg-Free COM, גם בעיית 32bit/64bit נפתרת?
לא. process של 32bit יכול לטעון רק in-proc COM DLL של 32bit, ו-process של 64bit רק DLL של 64bit. גם עם Reg-Free זה נשאר כמו קודם. בנוסף צריך לטפל בנפרד בהפצה של dependent DLL-ים ו-VC++ runtime, ב-type library, ב-design-time references, ובתלות במידע רישום לא סטנדרטי. מה ש-Reg-Free COM מעלים הוא בעיקר את הכאב שנגרם מרישום גלובלי.
למה קונפיגורציית Reg-Free COM עובדת במחשב הפיתוח אבל לא ביעד ההפצה?
קודם כל כדאי לחשוד שהרישום ב-registry עזר מאחורי הקלעים. אם חסר מידע ב-manifest, ה-COM runtime נופל ל-resolution הרגיל לפי registry, ולכן על מחשב הפיתוח זה עלול לעבוד במקרה בזכות registration מקומי. לכן בודקים Reg-Free COM בסביבה נקייה. אם ההפעלה נכשלת עם 'side-by-side configuration is incorrect', הסיבה בדרך כלל היא manifest לא תואם או dependent DLL חסר, ו-Event Log יחד עם sxstrace הם הדרך הסטנדרטית לחקור.
אפשר להפוך גם קומפוננטת COM שנבנתה ב-.NET 8 ל-Reg-Free COM?
כן. ב-.NET 5+ / .NET 8, EnableComHosting יוצר את *.comhost.dll שנכנסת כ-entry point לחשיפת COM, ואם מוסיפים גם EnableRegFreeCom=true, מתקבל side-by-side manifest ל-Reg-Free COM. עם זאת, Reg-Free COM ואסטרטגיית TLB הן שתי שאלות נפרדות. ב-.NET Core / .NET 5+ ה-TLB לא נוצר מה-assembly באופן טבעי כמו ב-.NET Framework, ולכן אם צריך שימוש typed כמו early binding ב-VBA, עדיף לטפל בנפרד ביצירת ה-TLB, ב-embed שלו וב-registration.

פרופיל הכותב

עמוד היכרות עם כותב המאמר.

Go Komura

מנהל KomuraSoft LLC

מתמחה בפיתוח תוכנה עבור Windows, ייעוץ טכני וחקירת תקלות, בעיקר בפרויקטים עם מערכות קיימות ובאגים שקשה לשחזר.

קישורים ציבוריים

חזרה לבלוג