מה זה Reg-Free COM - שימוש ב-COM בלי רישום
· עודכן בתאריך: · Go Komura · COM, Reg-Free COM, Registration-Free COM, פיתוח Windows, טכנולוגיה ישנה
בפרויקטים של COM / ActiveX / OCX, אותה בעיה חוזרת בכל הפצה ועדכון.
- נדרש
regsvr32 - לרוב נדרשות הרשאות מנהל
- התנגשות עם גרסה אחרת שהתקינה אפליקציה אחרת
- הסרת התקנה שגוררת גם מוצר אחר
- עובד במחשב הפיתוח, לא עובד בסביבה נקייה
מה שיכול לצמצם משמעותית את הטרחה הזו הוא Reg-Free COM. עם זאת, למרות השם, זה לא “קסם שמוחק את כל הטרחה של COM”. מה שנעלם הוא בעיקר הטרחה שנגררת מרישום גלובלי. bitness, DLL-ים תלויים, ספריית טיפוסים, וקושי מודל ה-thread לא נעלמים.
flowchart TB
accTitle: מה נעלם ומה נשאר ב-Reg-Free COM
accDescr: תרשים שמראה שב-Reg-Free COM מה שנעלם בעיקר הוא הטרחה שנגררת מרישום גלובלי, ואילו bitness, DLL-ים תלויים, ספריית טיפוסים וקושי מודל ה-thread לא נעלמים.
rf1["Reg-Free COM"] --> rf2["פחות טרחת רישום גלובלי"]
rf1 --> rf3["גם קושי שנשאר"]
rf3 -.-> rf4["bitness / DLL תלוי / ספריית טיפוסים"]
איור 1: לא קסם - מצפים בנפרד לטרחה שנעלמת ולטרחה שנשארת.
המאמר הזה מסדר את Reg-Free COM בעיקר בהקשר של שימוש ב-COM DLL / OCX כמוגבל לאפליקציה בודדת (private) באפליקציית שולחן עבודה ל-Windows.
קהל היעד והנחות היסוד
המאמר נכתב עבור מפתחים שמפיצים אפליקציית שולחן עבודה ל-Windows שמשתמשת ב-COM DLL / OCX קיימים, ורוצים להיפטר מ-regsvr32 ומהרשאות מנהל. ההנחה היא שנתקלתם לפחות פעם אחת ביסודות COM (CLSID, ProgID, CoCreateInstance, שרת in-proc). אם זה עדיין לא ברור, מהיר יותר לקרוא קודם את “מה זה COM / ActiveX / OCX - הסבר על ההבדלים והקשרים”.
חלק ההליכים משתמש ב-mt.exe וב-sxstrace מ-Windows SDK, ולכן ההנחה היא סביבה עם Visual Studio או Windows SDK מותקנים.
1. קודם כל - המסקנה (בקצרה)
אם אומרים את זה בגסות אך שימושית, זה כך:
- Reg-Free COM היא דרך שבה מידע הרישום של COM מוחזק ב-manifest ולא ב-registry
- בזמן ריצה, בפתרון של
CoCreateInstanceאוCLSIDFromProgID, קודם נבדק activation context - לכן, אפשר להחזיק COM DLL / OCX כ-private לכל אפליקציה
- היתרונות העיקריים הם קלות הפצה ב-XCOPY, הימנעות מהתנגשות גרסאות, הסרת התקנה שפחות נשברת
- עם זאת, בעיית 32bit / 64bit לא נעלמת. אין דרך לעקוף את זה בכתיבת manifest
- כמו כן, יש צורך לחשוב בנפרד על DLL-ים תלויים, ספריית טיפוסים, הפניה בזמן תכנון, תלות ברישום לא סטנדרטי
- בפועל, זה מתאים מאוד ל-מצבים שרוצים להניח בצד רכיב COM ייעודי לאפליקציה
בקיצור, Reg-Free COM היא מנגנון שמחזיר את הפעלת COM (activation) לרמת אפליקציה בודדת.
flowchart TB
accTitle: מקום מידע הרישום משתנה
accDescr: תרשים שמראה ש-Reg-Free COM מחזיקה את מידע הרישום של COM ב-manifest ולא ב-registry, ומכיוון שבפתרון של CoCreateInstance וכדומה נבדק קודם ה-activation context, אפשר להחזיק רכיבי COM כ-private לכל אפליקציה.
mg1["מידע הרישום ב-manifest"] --> mg2["בפתרון, activation context נבדק קודם"]
mg2 --> mg3["אפשר להחזיק רכיבי COM כ-private לאפליקציה"]
mg3 -.-> mg4["קל יותר להפיץ ב-XCOPY ולהימנע מהתנגשות"]
איור 2: המהות היא שכניסת הפתרון עוברת מ-registry ל-manifest.
מפת הידע של המאמר
Reg-Free COM הוא מנגנון שמחזיק את מידע רישום ה-COM ב-manifest ולא ב-registry, ובזמן ריצה בודק תחילה את ה-activation context כדי לפתור את ה-DLL. מניפסט היישום מצהיר על side-by-side assembly שהוא תלוי בו, ומניפסט הרכיב מחזיק מידע כמו CLSID ו-ProgID שבמקור היה ב-registry - בחלוקת התפקידים הזו, משבצים עם mt.exe ועוקבים אחרי כשל פתרון עם sxstrace. עם זאת, דרישת התאמת bitness בין 32 ל-64 לא נפתרת, וגם הטיפול ב-DLL תלוי ובספריית טיפוסים נשאר כסוגיה נפרדת, ולכן זה מתאים להפיכת נכסי שולחן עבודה קיימים כמו VB6, MFC ו-WinForms למקומיים לאפליקציה, אך פחות מתאים למצבים שדורשים שיתוף COM ברמת המכונה כולה. ב-.NET 5+/.NET 8, יוצרים comhost עם EnableComHosting, ואם מפעילים EnableRegFreeCom אפשר לייצא side-by-side manifest עבור Reg-Free COM.
flowchart LR
accTitle: מפת הידע של Reg-Free COM
accDescr: תרשים שמראה ש-Reg-Free COM מחזיק את מידע הרישום של COM ב-manifest ולא ב-registry ופותר DLL דרך בדיקת activation context בזמן ריצה תחילה, את חלוקת התפקידים בין מניפסט היישום למניפסט הרכיב, הרכב עם mt.exe וחקירת כשל עם sxstrace, והקשר ל-comhost של .NET 5+.
reg_free_com["Reg-Free COM (COM ללא רישום)"]
activation_context["הקשר הפעלה (activation context)"]
win32_application_manifest["מניפסט היישום (Win32 side-by-side)"]
component_manifest["מניפסט רכיב (assembly manifest)"]
side_by_side_assembly["side-by-side assembly"]
bitness_match_requirement["דרישת התאמת bitness"]
regsvr32["regsvr32"]
type_library["ספריית טיפוסים (TLB)"]
mt_exe["mt.exe (כלי המניפסטים)"]
sxstrace["sxstrace"]
assembly_searching_sequence["סדר החיפוש של private assembly"]
dotnet[".NET (מ-Core ואילך)"]
comhost["COM host(*.comhost.dll)"]
enable_com_hosting["EnableComHosting"]
enable_regfreecom["EnableRegFreeCom"]
vb6["Visual Basic 6.0(VB6)"]
clsid["CLSID(Class ID)"]
progid["ProgID(Programmatic Identifier)"]
com["COM (Component Object Model)"]
activex["ActiveX"]
ocx["OCX"]
mfc["MFC(Microsoft Foundation Classes)"]
windows_forms["Windows Forms"]
machine_wide_com_sharing["שיתוף COM ברמת המכונה כולה"]
reg_free_com -->|"משתמש ב"| activation_context
reg_free_com -->|"משתמש ב"| win32_application_manifest
reg_free_com -->|"משתמש ב"| component_manifest
win32_application_manifest -->|"מחייב"| side_by_side_assembly
component_manifest -->|"מממש את"| side_by_side_assembly
reg_free_com -->|"מחייב"| bitness_match_requirement
reg_free_com -.->|"יורש את"| regsvr32
component_manifest -.->|"משתמש ב"| type_library
reg_free_com -->|"מוגדר באמצעות"| mt_exe
reg_free_com -->|"נבדק באמצעות"| sxstrace
component_manifest -->|"מוגדר באמצעות"| mt_exe
reg_free_com -->|"מחייב"| assembly_searching_sequence
dotnet -.->|"משתמש ב"| comhost
comhost -->|"מחייב"| enable_com_hosting
comhost -->|"מוגדר באמצעות"| enable_regfreecom
enable_regfreecom -->|"מממש את"| reg_free_com
vb6 -.->|"משתמש ב"| type_library
component_manifest -->|"משתמש ב"| clsid
component_manifest -.->|"משתמש ב"| progid
reg_free_com -->|"משתמש ב"| com
reg_free_com -->|"משתמש ב"| activex
reg_free_com -->|"משתמש ב"| ocx
reg_free_com -->|"מענה מומלץ ל"| vb6
reg_free_com -->|"מענה מומלץ ל"| mfc
reg_free_com -->|"מענה מומלץ ל"| windows_forms
reg_free_com -->|"שימוש לא מומלץ ל"| machine_wide_com_sharing
בתרשים, קו מלא מציין קשר שמתקיים תמיד וקו מקווקו מציין קשר מותנה (תנאי ההתקיימות מפורטים בהסבר של כל קשר בעמוד המפורט). רשימת כל הקשרים (סך הכול 26, עם אסמכתה ורמת ודאות) והגדרות המושגים המרכזיים מרוכזות בעמוד המפורט של מפת הידע (ביפנית). נתונים: JSON-LD / Turtle
2. Reg-Free COM כפי שמדובר עליו במאמר הזה
Reg-Free COM הוא קיצור של Registration-Free COM. לפעמים נכתב גם “COM ללא צורך ברישום”.
ה”אין צורך ברישום” כאן פירושו לא להסתמך באופן מלא על רישום גלובלי ב-registry דרך HKCR / CLSID / InprocServer32 וכדומה, כדי להשתמש ב-COM.
זה לא אומר שCOM עצמו נעלם, ולא שה-GUID כבר לא נחוץ.
מה שבמאמר הזה עוסקים בו בעיקר הוא:
- COM DLL נייטיבי
- שרת COM מבוסס ATL
- ActiveX / OCX
- Interop COM מבוסס .NET Framework
- חשיפה דרך COM host של .NET 5+ / .NET 8
מנגד, שתי הנקודות שרוצים להדגיש במאמר הזה הן:
- Reg-Free COM עוסקת ב”הפעלה” (activation)
- הפצת מידע הטיפוס והגדרת הפניה בזמן תכנון עלולים להישאר כסוגיה נפרדת
אם מערבבים בין אלה, השיח נעשה עמום.
flowchart TB
accTitle: שתי הסוגיות שאסור לערבב
accDescr: תרשים שמראה ש-Reg-Free COM עוסק בהפעלה, ושהפצת מידע הטיפוס והגדרת הפניה בזמן תכנון נשארים כסוגיה נפרדת, ולכן ערבוב ביניהם מעכר את השיח.
pt1["Reg-Free COM"] --> pt2["סוגיה של הפעלה"]
pt3["הפצת טיפוסים / הפניה בזמן תכנון"] --> pt4["נשארת כסוגיה נפרדת"]
pt2 -.-> pt5["ערבוב מעכר את השיח"]
pt4 -.-> pt5
איור 3: סוגיית זמן הריצה וסוגיית זמן התכנון מטופלות בנפרד מלכתחילה.
3. סידור ראשוני בתמונה אחת
לפני שנכנסים לתרשים, נקבע קודם 4 מונחים שחוזרים לאורך המאמר.
| מונח | משמעות |
|---|---|
| activation context | מבנה נתונים בזמן ריצה שמחזיק “איזו גרסה של איזה assembly ה-thread הזה משתמש בו כרגע”. CoCreateInstance בודק את זה לפני ה-registry |
| side-by-side assembly | מנגנון ב-Windows שמאפשר לרכיב עם אותו שם, בגרסאות שונות, להתקיים יחד באותה מכונה. מזוהה דרך manifest, ו-assemblyIdentity הוא התג המזהה |
| מניפסט היישום | XML שמצמידים לצד ה-EXE, שמציין “באיזה side-by-side assembly זה תלוי” |
| מניפסט רכיב (assembly manifest) | XML שמצמידים לצד הרכיב, שמציין “אילו קבצים ה-assembly הזה כולל, ואילו מחלקות COM הוא חושף”. מידע שבמקור היה ב-registry עובר לכאן |
ה-activation context מוחזק לכל thread בנפרד. COM מעביר את ה-activation context של ה-thread היוצר אל ה-thread המארח לפני שהוא קורא ל-LoadLibrary או ל-DllGetClassObject, ולכן לא נדרשת הכנה מיוחדת מצד הקורא.
עם זאת, מהיר יותר לראות תחילה את התמונה הכללית בתרשים אחד.
flowchart LR
accTitle: התמונה הכללית של Reg-Free COM
accDescr: תרשים שמראה שהאפליקציה מפנה דרך מניפסט היישום ומניפסט הרכיב אל ה-DLL, ובמקביל האפליקציה משתמשת ב-activation context כדי לפתור את קריאת ה-COM ולהגיע לאותו DLL בלי registry.
APP["MyApp.exe"] --> AM["מניפסט היישום"]
AM --> DEP["dependentAssembly"]
DEP --> CM["מניפסט הרכיב"]
CM --> META["file / comClass / typelib"]
META --> DLL["VendorControl.dll / .ocx"]
APP --> ACTX["Activation Context"]
ACTX --> COM["CLSIDFromProgID / CoCreateInstance"]
COM --> DLL
איור 4: עוקבים מ-manifest האפליקציה ל-manifest הרכיב, ומגיעים ל-DLL בלי להשתמש ב-registry.
ב-COM רגיל, כשקוראים ל-CoCreateInstance, עוברים דרך ה-registry כדי לקבוע איזה DLL לטעון.
ב-Reg-Free COM, לפני זה נבדק ה-activation context שפעיל כרגע, ומתוכו נפתר לפי מידע ה-manifest שכתוב שם.
בגלל זה, קל יותר שאפליקציה A ואפליקציה B על אותה מכונה יחזיקו גרסאות שונות של אותה משפחת רכיבי COM. זה מחזיר קצת אחורה את תרבות השיתוף של COM לכיוון מקומי לאפליקציה.
4. למה הפצת COM רגילה נוטה להיות כבדה
הפצת COM רגילה כבדה לא כי COM עצמו רע, אלא בגלל ההנחה של רישום גלובלי.
כדי להשתמש במחלקת COM, נדרש בערך המידע הבא.
| מידע | תפקיד |
|---|---|
| CLSID | GUID שמזהה את המחלקה באופן ייחודי |
| ProgID | שם נוח לבני אדם |
| InprocServer32 | איזה DLL לטעון |
| ThreadingModel | הנחה כמו Apartment / Both |
| TypeLib | מידע טיפוס |
כשאלה נכנסים ל-registry, זה נוח ברמת המכונה כולה, כי קל לשתף בין כמה אפליקציות.
אבל בפועל, השיתוף הזה מתגלה כבעייתי.
- ההתקנה של מוצר אחד דורסת את רישום COM של מוצר אחר
- ההסרה “חושבת” שהיא מסירה רק את שלה, ושוברת COM משותף
- רישום שקיים במקרה במחשב הפיתוח, לא קיים במחשב הייצור
- רישום 32bit ו-64bit לא תואמים, והתופעה בלבד נראית מוזרה
כלומר, מודל ההפצה, ולא COM עצמו, הוא מה שמטריד אנשים לעיתים קרובות. Reg-Free COM הוא מנגנון שמצמצם את הסבל הזה במודל ההפצה.
flowchart TB
accTitle: איך שיתוף גלובלי מתגלה כבעייתי
accDescr: תרשים שמראה שמידע רישום COM שנכנס ל-registry נוח לשיתוף ברמת המכונה, אבל בפועל השיתוף הזה מתגלה כבעייתי דרך דריסות ממוצרים אחרים, גרירה בהסרת התקנה, ופער בין סביבות, כך שמודל ההפצה מטריד יותר מ-COM עצמו.
gs1["מידע רישום ברמת המכונה"] --> gs2["נוח לשימוש בכמה אפליקציות"]
gs1 --> gs3["בפועל השיתוף מתגלה כבעייתי"]
gs3 -.-> gs4["דריסה / גרירה / פער סביבות"]
gs3 --> gs5["מודל ההפצה מטריד"]
איור 5: הבעיה האמיתית היא לא COM עצמו, אלא ההנחה של רישום גלובלי.
5. איך המנגנון של Reg-Free COM עובד
5.1 מניפסט היישום כותב את התלות
ראשית, צד האפליקציה כותב במניפסט היישום באיזה side-by-side assembly היא תלויה.
את ה-manifest הזה אפשר:
- למקם ליד ה-EXE כמו
MyApp.exe.manifest - לשבץ בתוך ה-EXE כמשאב
בפועל, אם רוצים להקל על הפצה והחלפה - קובץ חיצוני; אם עדיפות לחוסן ופשטות הפצה - שיבוץ.
יש לציין שאם יש גם קובץ חיצוני וגם שיבוץ, ה-manifest שבמערכת הקבצים מקבל עדיפות.
5.2 מניפסט הרכיב כותב את מידע ה-COM
בשלב הבא, צד COM מחזיק ב-manifest הרכיב מידע שבמקור היה ב-registry.
מה שנכנס לכאן, למשל, הוא:
comClassclsidprogidthreadingModeltypelib- אם צריך, גם proxy / stub או window class
כלומר, זה מייצג את הרעיון של לתאר את פני ה-COM עם XML במקום registry.
את ה-manifest הזה אפשר להרכיב:
- כקובץ נפרד מה-DLL
- כשיבוץ בתוך ה-DLL כמשאב
בפועל, שיבוץ בתוך ה-DLL כ-private assembly נוטה פחות להיכשל. תפעול עם קובץ נפרד קל להבנה, אבל קל למעוד בהתאמה בין שם הקובץ ל-assemblyIdentity, במיקום ההצבה, או בקובץ שנשכח מהעתקה.
flowchart TB
accTitle: איך מחזיקים את מניפסט הרכיב
accDescr: תרשים שמראה שמידע כמו comClass, clsid, typelib שבמקור היה ב-registry, מניפסט הרכיב מחזיק אותו כ-XML, ואפשר לבחור בין קובץ נפרד מה-DLL לבין שיבוץ בתוך ה-DLL כמשאב, כאשר בפועל השיבוץ נוטה פחות להיכשל.
cm1["מידע שהיה ב-registry, ב-XML"] --> cm2["מוצב כקובץ נפרד"]
cm1 --> cm3["משובץ בתוך ה-DLL"]
cm2 -.-> cm4["קל למעוד בהעתקה שכוחה וכדומה"]
cm3 -.-> cm5["בפועל נוטה פחות להיכשל"]
איור 6: תוכן המידע זהה, אבל אופן ההצבה קובע את שיעור הכשלים.
5.3 בזמן ריצה, נבדק קודם ה-activation context
כאן טמון הלב של Reg-Free COM.
כשהאפליקציה קוראת ל-CLSIDFromProgID או ל-CoCreateInstance, ה-COM runtime בודק את ה-activation context הפעיל.
אם קיים שם המידע הנדרש להמרה מ-ProgID ל-CLSID, ומ-CLSID ל-DLL, הפתרון מתבצע בלי להשתמש ב-registry.
לעומת זאת, אם המידע הנדרש חסר ב-manifest, זה נופל לפתרון הרגיל המבוסס על רישום. בגלל ההתנהגות הזו, נוצרת מלכודת שבה המחשב עובד במקרה במחשב הפיתוח. חשבתם שהצלחתם להפוך את זה ל-Reg-Free, אבל בפועל זה נעזר ברישום מקומי.
זהו הבור הכי מרושע של Reg-Free COM.
flowchart TB
accTitle: המלכודת שנופלת לפתרון מבוסס רישום
accDescr: תרשים שמראה שבפתרון של CoCreateInstance נבדק קודם ה-activation context, אבל אם חסר מידע ב-manifest, זה נופל לפתרון הרגיל המבוסס על רישום, ולכן נוצרת מלכודת שבה זה עובד במקרה במחשב הפיתוח בזכות רישום מקומי.
ac1["הפתרון בודק קודם את activation context"] --> ac2{"יש מספיק מידע ב-manifest?"}
ac2 -->|"יש"| ac3["פתרון בלי registry"]
ac2 -->|"אין"| ac4["נופל לפתרון מבוסס רישום"]
ac4 -.-> ac5["מלכודת: עובד במקרה במחשב הפיתוח"]
איור 7: ה-fallback השקט הוא הבור הגדול ביותר במנגנון הזה.
6. מה טוב בזה
היתרונות של Reg-Free COM ברורים למדי בפועל.
6.1 קל להפיץ ב-XCOPY
אפשר למקם את כל הקבצים הנדרשים יחד בתיקיית האפליקציה, כך שהתקנה ורישום נעשים קלים יותר.
כמובן, כתיבה תחת Program Files היא עדיין עניין של הרשאות, אבל לפחות עבודת המנהל שנדרשת לרישום COM קל יותר לצמצם.
6.2 קל יותר לצמצם התנגשות גרסאות
גם אם יש כמה גרסאות של רכיב COM על אותה מכונה, קל יותר להפריד את הגרסה שכל אפליקציה משתמשת בה. קל יותר להימנע מתקלה של “ההתנהגות השתנתה פתאום בגלל התקנה של מוצר אחר”.
6.3 לרוב אין צורך לשנות משמעותית קוד קיים
Reg-Free COM לא משנה מהיסוד את אופן הקריאה של הקוד הקיים, אלא היא מנגנון שמשנה את אופן הפתרון.
לכן, אם זה מסתדר, אפשר להטמיע את זה כמעט בלי לגעת בקוד ה-CoCreateInstance.
6.4 מחיקה וחזרה אחורה נעשים קלים יותר
מכיוון שזה מוגבל לאפליקציה, עדכון וחזרה לגרסה קודמת נעשים ישירים יותר. במונחים קיצוניים, קל יותר לחשוב במונחי החלפת תיקייה שלמה.
flowchart TB
accTitle: היתרון בהגבלה לרמת אפליקציה
accDescr: תרשים שמראה שהגבלת רכיבי COM לרמת אפליקציה מולידה יתרונות כמו קלות הפצה ב-XCOPY, צמצום התנגשות גרסאות, הטמעה כמעט בלי לגעת בקוד הקיים, ופשטות במחיקה ובחזרה אחורה.
cl1["מגבילים לרמת אפליקציה"] --> cl2["קל להפיץ ב-XCOPY"]
cl1 --> cl3["מצמצם התנגשות גרסאות"]
cl2 -.-> cl5["אפשר להחליף תיקייה שלמה"]
cl3 -.-> cl4["כמעט בלי לגעת בקוד הקריאה"]
איור 8: כל היתרונות צומחים מתכונה אחת - ההגבלה.
7. מקרים שמתאימים ומקרים שלא
7.1 מקרים שמתאימים
במקרים הבאים, Reg-Free COM חזק למדי.
| מצב | התאמה |
|---|---|
| רוצים לצרף COM DLL / OCX ייעודי לאפליקציה | טוב מאוד |
| רוצים להחזיק כמה גרסאות באותו PC | טוב מאוד |
| רוצים להימנע מתקלת רישום של רכיב ספק חיצוני | טוב |
| רוצים להשתמש ב-ActiveX / OCX כ-private באפליקציית שולחן עבודה קיימת | טוב |
| רוצים להקל על ההפצה בלי לשנות משמעותית את הקריאה הקיימת | טוב |
בדרך כלל, זה מתאים ל-אפליקציות עסקיות בשולחן עבודה, כלי חיבור לציוד, ונכסים קיימים של VB6 / MFC / WinForms.
7.2 מקרים שלא מתאימים, או שכדאי לבדוק בזהירות
מצד שני, יש גם מקרים שכדאי לבדוק בזהירות.
| מצב | הערה |
|---|---|
| רוצים לשתף COM ברמת המכונה כולה | היתרון של Reg-Free חלש |
| ה-bitness לא תואם | Reg-Free לא פותר את זה |
| תלות חזקה במידע רישום לא סטנדרטי או בהתקנה ייחודית | קשה להפוך ל-manifest |
| הפצת DLL תלוי או VC++ runtime לא מסודרת | זה ייתקע במקום אחר בכל מקרה |
| כלי תכנון או הגדרת הפניה ב-IDE מניחים registry | נדרש תכנון תפעול נפרד |
בפרט, הנקודה האחרונה חשובה. Reg-Free COM עוזרת ל-הפעלה בזמן ריצה, אבל לא משנה במחי יד את מה שכלי ההגדרה בזמן תכנון מניח.
flowchart TB
accTitle: זמן ריצה נעזר, זמן תכנון נשאר
accDescr: תרשים שמראה ש-Reg-Free COM עוזרת להפעלה בזמן ריצה, אבל אם כלי או IDE להגדרת הפניה בזמן תכנון מניחים registry, זה לא משתנה כך סתם, ונדרש תכנון תפעול נפרד.
rt1["הפעלה בזמן ריצה"] --> rt2["Reg-Free עוזרת"]
dt1["UI להגדרת הפניה בזמן תכנון"] --> dt2["לפעמים מניח registry"]
dt2 -.-> dt3["נדרש תכנון תפעול נפרד"]
איור 9: גם כשהמנגנון שמפעיל מסודר, המנגנון שמפתחים נשאר צריך סידור נפרד.
8. אי-הבנות נפוצות
8.1 עם Reg-Free COM, בעיית ה-bitness נעלמת
לא נעלמת. תהליך 32bit יכול לטעון רק COM DLL מסוג in-proc של 32bit, ותהליך 64bit רק DLL של 64bit. זה נשאר כמות שהיה גם עם Reg-Free.
8.2 עם Reg-Free COM, ה-registry כבר לא נבדק בכלל
גם זה לא נכון. אם חסר מידע נדרש ב-manifest, זה נופל לפתרון הרגיל המבוסס על רישום. בגלל זה, הצלחה במחשב הפיתוח לא בהכרח אומרת שהרכב ה-Reg-Free נכון.
8.3 עם Reg-Free COM, גם עניין ספריית הטיפוסים נפתר אוטומטית
זה נכון רק בחצי.
אפשר לכתוב גם מידע typelib ב-manifest, אבל הגדרת הפניה ב-VBA, #import ב-C++, יצירת הפניה בזמן תכנון בצד .NET - הטיפול במידע הטיפוס לרוב עדיין דורש תכנון נפרד.
Reg-Free COM היא בעיקר סוגיה של איך לגרום לזה להתחיל לרוץ. איך מפתחים עם טיפוסים הוא הנושא הבא.
flowchart TB
accTitle: הסדר בין נושא ההפעלה לנושא הטיפוסים
accDescr: תרשים שמראה שגם אם אפשר לכתוב מידע typelib ב-manifest, הטיפול במידע הטיפוס - הגדרת הפניה ב-VBA, import ב-C++, יצירת interop ב-.NET - עדיין דורש תכנון נפרד, ו-Reg-Free COM עוסקת קודם כל בהפעלה, ופיתוח עם טיפוסים הוא הנושא הבא.
st1["מגדירים Reg-Free COM"] --> st2["קודם כל, גורמים לזה לרוץ"]
st2 --> st3["בשלב הבא, איך מפתחים עם טיפוסים"]
st3 -.-> st4["הגדרת הפניה ב-VBA / import / יצירת interop"]
איור 10: היכולת לכתוב typelib והשלמת ניהול מידע הטיפוסים הן שני דברים שונים.
8.4 עם Reg-Free COM, כל ActiveX / OCX עובד ישירות
גם זה מסוכן. אם הרכיב מבוסס על מידע רישום COM סטנדרטי, קל להתקדם, אבל אם יש הגדרת registry ייחודית, התקנה נוספת, עיבוד רישוי, או תלות חזקה בקבוצת מודולים אחרת, הפיכה ל-Reg-Free הופכת פתאום לקשה.
8.5 Reg-Free COM דומה לחלוטין בין .NET Framework ל-.NET 8
יש דמיון, אבל שרשרת הכלים שונה למדי.
ההקשר של .NET Framework + RegAsm וההקשר של .NET 5+ / .NET 8 + comhost הם אותו COM, אבל התשתית שונה.
9. ההבדל בין נייטיב / .NET Framework / .NET 5+ / .NET 8
זה קל להתבלבל בו, ולכן ננתח את זה בנפרד פעם אחת.
| משפחה | סידור בגסות |
|---|---|
| COM DLL / OCX נייטיבי | בסיסי לחשוב עליו במונחי מניפסט יישום + מניפסט רכיב |
| Interop COM מבוסס .NET Framework | בנוסף למניפסט היישום בסגנון 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 נייטיבי, נוסף manifest אחד. המגבלה של השם ומזהה המשאב מסעיף 10.4 חלה באותה מידה גם על ה-component manifest כאן.
9.2 חשיפת COM ב-.NET 5+ / .NET 8
ב-.NET 5+ / .NET 8, הכניסה לחשיפת COM הופכת ל-*.comhost.dll.
בנוסף, אם מוסיפים EnableRegFreeCom=true, מיוצא side-by-side manifest עבור Reg-Free COM.
הטיפול במידע הטיפוסים כסוגיה נפרדת כפי שתואר בסעיף 8.3, אבל ב-.NET Core / .NET 5+ הדבר משתנה עוד יותר. מכיוון שזה לא עולם שבו TLB נוצר באופן טבעי מה-assembly כמו בתקופת .NET Framework, אם נדרש שימוש עם טיפוסים, יש לבנות בנפרד את יצירת ה-TLB, שיבוצו ורישומו. השלבים המדויקים מסוכמים ב-“שימוש ב-DLL של .NET 8 מ-VBA עם טיפוסים - חשיפת COM ו-TLB ב-dscom”.
flowchart TB
accTitle: Reg-Free COM ב-.NET 5 ואילך
accDescr: תרשים שמראה שב-.NET 5 ואילך, EnableComHosting יוצר את comhost.dll כניסה לחשיפת COM, EnableRegFreeCom מייצא side-by-side manifest עבור Reg-Free COM, אבל יצירה ורישום של TLB דורשים בנייה נפרדת.
dn1["בנייה עם EnableComHosting"] --> dn2["comhost.dll הופך לכניסה"]
dn2 --> dn3["מפעילים EnableRegFreeCom"]
dn3 --> dn4["מיוצא manifest עבור Reg-Free"]
dn4 -.-> dn5["הטיפול ב-TLB דורש בנייה נפרדת"]
איור 11: ב-.NET 8, שתי מאפיינים מכינים את התשתית, אבל מידע הטיפוס דורש עבודה נפרדת.
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
בדוגמה למעלה, ההנחה היא שהמניפסט של הרכיב מוצב כקובץ נפרד. אפשר גם לשבץ אותו בתוך ה-DLL, אבל אז חלים מגבלות קבועות על שם ה-assembly ומזהה המשאב. ההליך המלא מובא בסעיף 10.4.
10.2 תמונת מניפסט היישום
<?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 תמונת מניפסט הרכיב
<?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 שהרכיב חושף בפועל.
flowchart TB
accTitle: דרישת ההתאמה בין שני המניפסטים
accDescr: תרשים שמראה שה-dependentAssembly בצד האפליקציה וה-assemblyIdentity בצד הרכיב חייבים להתאים בשם ובגרסה, ואם יש פער, זה הופך לכישלון הפעלה שהסיבה לו לא נראית ממראה השגיאה.
mm1["dependentAssembly בצד האפליקציה"] --> mm3{"השם והגרסה תואמים?"}
mm2["assemblyIdentity בצד הרכיב"] --> mm3
mm3 -->|"תואם"| mm4["הפתרון מצליח"]
mm3 -->|"לא תואם"| mm5["כישלון הפעלה בלי סיבה נראית"]
איור 12: יותר מפרטי ה-XML, מה שקובע חיים ומוות הוא התאמת שני התגים.
10.4 איפה מציבים ואיך משבצים את ה-manifest
זו הנקודה שהכי קל להיתקע בה בפועל בהליך. אם מציבים כקובץ נפרד או משבצים בקובץ הבינארי, השם המותר משתנה.
side-by-side מחפש private assembly בתיקיית האפליקציה בסדר הזה.
- תיקיית WinSxS
<appdir>\<assemblyname>.DLL<appdir>\<assemblyname>.manifest<appdir>\<assemblyname>\<assemblyname>.DLL<appdir>\<assemblyname>\<assemblyname>.manifest
אם נמצא DLL עם שם זהה לשם ה-assembly, החיפוש נעצר שם. מכאן, יש רק שתי אפשרויות ישימות.
| הצבה | שם ה-assembly | קובץ | מזהה משאב לשיבוץ |
|---|---|---|---|
| קובץ נפרד | שם שונה משם ה-DLL. לדוגמה: Vendor.CameraControl.Asm |
Vendor.CameraControl.Asm.manifest ליד ה-DLL |
לא משובץ |
| שיבוץ ב-DLL | יכול להיות זהה לשם ה-DLL. לדוגמה: Vendor.CameraControl |
רק Vendor.CameraControl.dll |
1 |
כלומר, אם משתמשים בשם Vendor.CameraControl.Asm כמו בדוגמאות 10.2 ו-10.3, זה תפעול לקובץ נפרד. אם עוברים לשיבוץ, משנים את ה-name של assemblyIdentity ל-Vendor.CameraControl, ומיישרים גם את dependentAssembly לאותו שם.
flowchart TB
accTitle: המנגנון שבו החיפוש נעצר
accDescr: תרשים שמראה ש-side-by-side מחפש private assembly בסדר מ-WinSxS ואילך בתיקיית האפליקציה, ואם נמצא DLL עם שם זהה לשם ה-assembly, החיפוש נעצר שם, ולכן בתפעול של קובץ נפרד צריך שהשם יהיה שונה משם ה-DLL.
se1["מתחילים חיפוש private assembly"] --> se2["מחפשים DLL עם שם זהה ל-assembly"]
se2 -->|"נמצא"| se3["החיפוש נעצר שם"]
se2 -->|"לא נמצא"| se4["מחפשים קובץ manifest עם אותו שם"]
se3 -.-> se5["בתפעול של קובץ נפרד, מבדילים את השם"]
איור 13: מגבלת מתן השם נובעת מהעובדה שהחיפוש נעצר באמצע.
יש עוד מגבלה שקל לטעות בה. מניפסט הרכיב לא ניתן להכניס כמשאב ב-EXE. מה שניתן להכניס ל-EXE הוא מניפסט היישום.
לשיבוץ משתמשים ב-mt.exe (כלי המניפסטים) מ-Windows SDK. הריצו אותו מ-Developer Command Prompt של Visual Studio.
rem 1. לפני השיבוץ, קודם עוברים בדיקת syntax
mt.exe -manifest MyApp.exe.manifest -validate_manifest
mt.exe -manifest Vendor.CameraControl.manifest -validate_manifest
rem 2. משבצים את מניפסט היישום לתוך ה-EXE
mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;#1
rem 3. משבצים את מניפסט הרכיב לתוך ה-DLL (מזהה משאב 1)
mt.exe -manifest Vendor.CameraControl.manifest -outputresource:Vendor.CameraControl.dll;#1
rem 4. מוציאים ובודקים אם השיבוץ הצליח
mt.exe -inputresource:Vendor.CameraControl.dll;#1 -out:extracted.manifest
אם משווים את extracted.manifest שהוצא בפקודה הרביעית ל-XML המקורי, אפשר לזהות “חשבתי ששיבצתי, אבל זה לא נכנס”.
flowchart TB
accTitle: הליך השיבוץ עם mt.exe
accDescr: תרשים שמראה שב-mt.exe, קודם עוברים בדיקת syntax עם validate_manifest, משבצים את מניפסט היישום ל-EXE, את מניפסט הרכיב ל-DLL עם מזהה משאב 1, ולבסוף מוציאים ומשווים ל-XML המקורי.
mt1["עוברים בדיקת syntax"] --> mt2["משבצים את צד האפליקציה ל-EXE"]
mt2 --> mt3["משבצים את צד הרכיב ל-DLL (מזהה 1)"]
mt3 --> mt4["מוציאים ומשווים ל-XML המקורי"]
איור 14: השיבוץ מתבצע כהליך אחד שכולל גם את הבדיקה.
יש שתי הערות ל-mt.exe.
- הקבצים שה-manifest מפנה אליהם חייבים להיות באותה תיקייה כמו ה-manifest. אם כתוב
<file name="Vendor.CameraControl.dll">, יש להציב את ה-DLL הזה ליד ה-manifest לפני ההרצה. אם פלט הבנייה ומיקום ניהול ה-manifest מופרדים, זה ייתקע כאן - אם משמיטים את מזהה המשאב ב-
-outputresource, נעשה שימוש ב-CREATEPROCESS_MANIFEST_RESOURCE(= 1). כדי לא להסתמך על 1 בלי כוונה, עדיף לציין;#1במפורש - זה קריא יותר
אם רוצים רק להחליף שיבוץ קיים, אפשר להשתמש ב--updateresource:<קובץ>;#1. זה שקול לזה שמעבירים את אותם ארגומנטים ל--inputresource ול--outputresource.
10.5 הליך בדיקה כולל סביבה נקייה
ל-Reg-Free COM כמעט אין משמעות ל”עבד במחשב הפיתוח”. תמיד נשארת האפשרות שזה רק בזכות רישום מקומי ב-registry. בודקים בסדר הזה.
- בונים, ומרכזים את כל חבילת ההפצה בתיקייה אחת. EXE, manifest, COM DLL, DLL תלוי, VC++ runtime, ואפילו DLL של proxy / stub
- מכינים סביבת בדיקה. אידיאלי שזו סביבה שה-COM הזה מעולם לא נרשם בה. Windows Sandbox מאפשר לנסות בכל פעם ממצב נקי לגמרי
- בסביבה הזו, קודם מוודאים שה-COM הרלוונטי לא רשום. אם הפקודה למטה מחזירה שגיאה שהמפתח לא נמצא, זה סימן שלא נרשם
- מעתיקים את התיקייה ומפעילים ישירות. בלי להריץ מתקין ובלי
regsvr32 - מוודאים שגם יצירת אובייקט COM עוברת. רק ההפעלה לא בודקת רכיבים שנוצרים באיחור. מפעילים בפועל את המסך או הפונקציה שבה
CoCreateInstanceמתבצע - אם נכשל, אוספים לוג לפי ההליך בסעיף 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, זה משפיע גם עליו, ולכן בטוח יותר להכין סביבה נקייה.
flowchart TB
accTitle: תהליך הבדיקה בסביבה נקייה
accDescr: תרשים שמראה שמרכזים את חבילת ההפצה בתיקייה אחת, מכינים סביבת בדיקה נקייה שהCOM הרלוונטי לא נרשם בה, מוודאים קודם שהוא לא רשום, מעתיקים ומפעילים ישירות, ומריצים עד לפונקציה שבה מתבצע CoCreateInstance.
cv1["מרכזים את חבילת ההפצה"] --> cv2["מכינים סביבת בדיקה נקייה"]
cv2 --> cv3["מוודאים קודם שהוא לא רשום"]
cv3 --> cv4["מעתיקים ומפעילים ישירות"]
cv4 --> cv5["מריצים עד לפונקציה שבה יש יצירת COM"]
cv5 -.->|"אם נכשל"| cv6["אוספים לוג וחוקרים"]
איור 15: שילוב בדיקת אי-הרישום מוציא מהבדיקה את מקרה “עובד במקרה”.
11. מוקשים נפוצים
11.1 עובד במחשב הפיתוח, לא עובד ביעד ההפצה
מה שכדאי לחשוד בו ראשית הוא הדפוס שבו בעצם רישום ה-registry עזר בסתר. בטוח יותר לבצע את בדיקת Reg-Free COM בסביבה נקייה אם אפשר.
11.2 ההפעלה נכשלת עם “side-by-side configuration is incorrect”
הבעיה הזו קורית בגלל אי-התאמה ב-manifest, חוסר ב-DLL תלוי, חוסר ב-VC++ runtime, או פער בארכיטקטורה.
מכיוון שהודעת השגיאה עצמה לא ידידותית, מקובל לחקור עם Event Log ו-sxstrace.
ה-Event Log נפתח דרך מציג האירועים > יומני Windows > Application, ומחפשים שגיאה שהמקור שלה SideBySide. שם רואים איזה assembly נכשל בפתרון.
sxstrace נאסף תוך שחזור הכישלון. עדיף לפתוח את שורת הפקודה כמנהל.
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, אפשר לזהות זאת דרך “שם הקובץ שחיפש”.
flowchart TB
accTitle: איך חוקרים שגיאת side-by-side
accDescr: תרשים שמראה שכשההפעלה נכשלת עם side-by-side configuration is incorrect, בודקים ב-Event Viewer שגיאה עם מקור SideBySide, מתחילים trace עם sxstrace, משחזרים את הכישלון, ואחרי העצירה ממירים עם parse וקוראים היכן הייתה אי-התאמה.
sx1["בודקים SideBySide ב-Event Viewer"] --> sx2["מתחילים trace עם sxstrace"]
sx2 --> sx3["מפעילים את האפליקציה ומשחזרים את הכישלון"]
sx3 --> sx4["עוצרים וממירים עם parse"]
sx4 --> sx5["קוראים היכן היה חיפוש ואי-התאמה"]
איור 16: לא מתעכבים על הודעת השגיאה החיצונית - עוקבים אחרי דרך הפתרון עם לוג ו-trace.
11.3 ההתאמה בין component manifest ל-application manifest נשברת
- ה-name שונה
- ה-version שונה
- ה-processorArchitecture שונה
- ה-manifest שחשבו שהעתיקו הוא בעצם ישן
הפערים האלה נראים קטנים למראה עין, אבל בזמן ההפעלה משפיעים משמעותית.
11.4 שוכחים למקם DLL תלוי
אם מסתפקים בבדיקת Vendor.CameraControl.dll בלבד ומרגישים בטוחים, חסרים Vendor.Helper.dll שנקרא מתוכו, VC++ runtime, ו-DLL של proxy / stub.
Reg-Free COM מצמצם את בעיית רישום ה-COM, אבל לא מוחק את בעיית פתרון התלות הנייטיבית.
11.5 דוחים את ניהול ספריית הטיפוסים והגדרת ההפניה
גם אם ה-runtime activation עובר, אם יש דרישות כמו:
- רוצים קישור מוקדם מ-VBA
- רוצים
#importב-C++ - רוצים יצירת interop בזמן תכנון בצד .NET
נדרשת דרך לחלק את מידע הטיפוס. Reg-Free COM לא מסדרת את זה אוטומטית לגמרי, ולכן חשוב לחשוב בנפרד על runtime ו-design-time.
12. סיכום
אם אומרים את Reg-Free COM במשפט אחד, זה מנגנון שמעביר את מידע רישום ה-COM מרמת המכונה כולה לרמת אפליקציה בודדת.
בזכות זה, יש יתרונות כמו:
- קל להגביל COM DLL / OCX לרמה מקומית לאפליקציה
- קל יותר לצמצם התנגשות גרסאות
- קל יותר לפשט הפצה וחזרה אחורה
מצד שני, אלה עדיין חשובים:
- 32bit / 64bit
- DLL תלוי
- TLB / הגדרת הפניה
- תלות ברישום לא סטנדרטי
- בדיקה בסביבה נקייה
לכן, הגישה הבסיסית להטמעת Reg-Free COM היא כך.
- מקבלים את זה כסוגיה של activation
- מפרידים בין נקודות המבט של runtime ו-design-time
- בודקים בסביבה נקייה
- מתאימים מראש bitness ו-DLL-ים תלויים
אם עוקבים אחר הסדר הזה, קל בהרבה להימנע מתקלות.
flowchart TB
accTitle: הגישה הבסיסית בזמן ההטמעה
accDescr: תרשים שמראה שבהטמעת Reg-Free COM, מקבלים את זה כסוגיה של activation, מפרידים בין נקודות המבט של runtime ו-design-time, בודקים בסביבה נקייה, ומתאימים מראש bitness ו-DLL-ים תלויים - אם עוקבים בסדר הזה, קל יותר להימנע מתקלות.
bs1["מקבלים כסוגיית activation"] --> bs2["מפרידים runtime ו-design-time"]
bs2 --> bs3["בודקים בסביבה נקייה"]
bs3 --> bs4["מתאימים מראש bitness ו-DLL תלוי"]
איור 17: אם שומרים על ארבע הגישות בסדר הזה, אפשר לצמצם מאוד תקלות בהטמעה.
13. מאמרים קשורים
- מה זה COM / ActiveX / OCX - הסבר על ההבדלים והקשרים
- איך לטפל היום ב-ActiveX / OCX - טבלת החלטה בין לשמר, לעטוף ולהחליף
- שימוש ב-DLL של .NET 8 מ-VBA עם טיפוסים - חשיפת COM ו-TLB ב-dscom
14. מקורות
- Microsoft Learn - Registration-Free COM オブジェクトの作成
- Microsoft Learn - アプリケーション マニフェスト
- Microsoft Learn - Assembly Manifests (מגבלת מזהה המשאב והשם בזמן שיבוץ)
- Microsoft Learn - Assembly Searching Sequence (סדר החיפוש של private assembly)
- Microsoft Learn - Manifest File Schema
- Microsoft Learn - Mt.exe
- Microsoft Learn - 登録を必要としない COM 相互運用機能 (.NET Framework)
- Microsoft Learn - COM への .NET Core コンポーネントの公開
- Microsoft Learn - sxstrace
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
בניית פלט דוחות Excel - COM, Open XML, תבנית
פלט דוחות Excel משתנה מהותית לפי השאלה אם מפעילים את Excel אוטומטית, יוצרים xlsx ישירות, או משמרים VBA קיים. המאמר מסדר את קריטריוני הבחי...
מה זה COM / ActiveX / OCX — הסבר מרוכז על ההבדלים והקשרים
מהו COM, מהו ActiveX ומהו OCX — סקירה מעשית של ההבדלים והקשרים ביניהם, הזיקה ל-OLE, איפה זה נמצא בשימוש, ואיך כדאי להתייחס לזה היום.
איך מתייחסים היום ל-ActiveX / OCX — טבלת החלטה: לשמר, לעטוף או להחליף
כשמוצאים ActiveX / OCX, מסודר כאן איך לבחור בין לשמר, לעטוף או להחליף — כולל 32bit / 64bit, רישום, תלות בדפדפן ותחזוקת ספקים.
מבוא ל-Media Foundation — מבינים את ה-API מנקודת המבט של COM
המאמר מסביר מה זה Media Foundation, יחד עם המונחים הבסיסיים של ה-API למדיה ב-Windows כמו COM, HRESULT, IMFSourceReader ו-MFT, בסדר שכדא...
ידע בסיסי על STA/MTA ב-COM — מודל השרשור ואיך נמנעים מתקיעה
המאמר מסכם את הידע הבסיסי על STA/MTA ב-COM, כולל מודל ה-Apartment, ת'רד ה-UI, לולאת ההודעות, מרשלינג, ואת אופן ההימנעות מתקיעה.
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
העברת ActiveX
החלטות אם לשמר, לעטוף או להחליף רכיבי COM / ActiveX / OCX.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
פיתוח יישומי Windows
נושא שקשור ישירות למימוש אפליקציית שולחן עבודה ל-Windows, כולל הפצת COM DLL / OCX, הרכב ה-manifest, bitness ו-DLL-ים תלויים.
ייעוץ טכני וסקירת תכנון
מתאים גם לסידור ההחלטה בין אימוץ Reg-Free COM לבין שימור תפעול מבוסס רישום, ואיך מפרידים בין ספריית טיפוסים להפניה בזמן תכנון.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- מה זה Reg-Free COM?
- מנגנון שבו מידע הרישום של COM מוחזק ב-manifest ולא ב-registry, קיצור של Registration-Free COM. בזמן ריצה, בפתרון של CoCreateInstance או CLSIDFromProgID נבדק קודם ה-activation context, ומתוכו מפוענח ה-DLL לפי מידע ה-manifest שכתוב שם. כך אפשר להחזיק COM DLL/OCX כ-private לכל אפליקציה, ויש יתרונות כמו קלות הפצה ב-XCOPY, הימנעות מהתנגשות גרסאות, והתקנה מחדש שפחות נשברת.
- אם עוברים ל-Reg-Free COM, גם בעיית 32bit/64bit נפתרת?
- לא נפתרת. תהליך 32bit יכול לטעון רק COM DLL מסוג in-proc של 32bit, ותהליך 64bit רק DLL של 64bit. גם ב-Reg-Free זה נשאר כמות שהיה. בנוסף, יש לחשוב בנפרד על הפצת DLL-ים תלויים ו-VC++ runtime, ספריית טיפוסים, הגדרת הפניה בזמן תכנון, ותלות במידע רישום לא סטנדרטי. מה ש-Reg-Free COM מוחק הוא בעיקר הטרחה שנגררת מרישום גלובלי.
- למה הרכב Reg-Free COM עובד במחשב הפיתוח אבל לא ביעד ההפצה?
- מה שכדאי לחשוד בו ראשית הוא דפוס שבו בעצם הרישום ב-registry עזר בסתר. אם חסר מידע ל-manifest, ה-COM runtime נופל לפתרון המבוסס על רישום, ולכן במחשב הפיתוח זה עלול לעבוד במקרה בזכות רישום מקומי. לכן, בדיקת Reg-Free COM בטוחה יותר בסביבה נקייה. אם ההפעלה נכשלת עם 'side-by-side configuration is incorrect', הסיבה היא בדרך כלל אי-התאמה ב-manifest או חוסר ב-DLL תלוי, ו-Event Log יחד עם sxstrace הם הדרך המקובלת לחקור.
- אפשר להפוך גם רכיב COM שנבנה עם .NET 8 ל-Reg-Free COM?
- כן, אפשר. ב-.NET 5+ / .NET 8, EnableComHosting יוצר את *.comhost.dll שמשמש כניסה לחשיפת COM, ואם מוסיפים גם EnableRegFreeCom=true, מיוצא side-by-side manifest עבור Reg-Free COM. עם זאת, Reg-Free COM ואסטרטגיית TLB הן שתי סוגיות נפרדות. ב-.NET Core / .NET 5+ ה-TLB לא נוצר באופן טבעי מה-assembly כפי שהיה ב-.NET Framework, ולכן אם נדרש שימוש עם טיפוסים כמו קישור מוקדם ב-VBA, בטוח יותר לסדר בנפרד את יצירת ה-TLB, שיבוצו ורישומו.