התו שכמעט חיסל את התוכנה שלי

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

התוכנה הזו, שפרסמתי בזמנו בפורומים שונים של מייקרים, אמנם לא הפכה ללהיט בינלאומי היסטרי, אבל שירתה אותי היטב בכל מיני הזדמנויות. אחד הדברים שהיא עושה זה לסרוק את ה-Registry של Windows ולשאוב ממנו את שמות ה-COM Ports שזמינים כרגע, בדומה למה שקורה מתחת למכסה המנוע של התפריט Tools->Port בסביבת הפיתוח של ארדואינו. לאחרונה, קרה כמה פעמים שחיברתי לוח ארדואינו למחשב, והצלחתי גם להעלות אליו קוד, אבל דווקא התוכנה שלי לא זיהתה נכון את הפורט. במקום משהו כמו "COM5" הופיעה לי מחרוזת ריקה, וכשניסיתי להתחבר בכל זאת, התוכנה התרסקה.

איתור הבעיה

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

ב-regedit (היישום שאסור בשום פנים להתעסק איתו בלי להבין מה עושים, כי אפשר לחרב דרכו בטעות את כל מערכת ההפעלה), ה-Port של לוח הארדואינו הבעייתי נראה כמו בצילום המסך הבא, בשורת הנתונים השנייה בחלונית הימנית. השם של ה"מפתח" (Key) הוא \Device\Serial, והערך שלו (מטיפוס מחרוזת) הוא COM4. התוכנה שלי, שנכתבה בשפת פסקל בסביבת הפיתוח Lazarus, נעזרת במחלקה (class) מובנית בשם TRegistry שיודעת לבקש מ-Windows את שמות המפתחות בתיקיה הרלוונטית, ולאחזר ערך לכל שם. לפחות, זה מה שהיא עשתה בעבר. למה עכשיו היא מאחזרת מחרוזת ריקה במקום COM4?

הרישום התמים-למראה של הפורט ב-Registry
הרישום התמים-למראה של הפורט ב-Registry

כשחיברתי לוח ארדואינו נוסף למחשב, שם המפתח החדש שהופיע היה USBSER001, והתוכנה שלי הצליחה לקרוא את הערך המתאים לו בלי בעיה. תוכנת בדיקה קטנה ונפרדת שכתבתי במיוחד לצורך העניין, בסביבת הפיתוח המסחרית Delphi, זיהתה את שני הערכים כמו שצריך. ליתר ביטחון הפעלתי שוב את קובץ ה-EXE המקורי שקימפלתי לפני שנתיים, כדי לוודא לא מדובר באיזשהו שינוי שעשיתי בתוכנית. גם הוא הראה לי מחרוזת ריקה. כלומר, משהו השתנה ב-Windows, והמשהו הזה משגע ספציפית תוכנות שנכתבו עם Lazarus, ספציפית עם לוחות ארדואינו מסוימים. מה זה יכול להיות?

הדבר הראשון ששמתי לב אליו, אם כי הוא לא קידם אותי לשום מקום, זה שהארדואינו הסורר לא היה מקורי אלא תואם סיני, עם שבב USB-to-UART מדגם CH340G. רמז גדול הרבה יותר הופיע כשהתחלתי לדבג לעומק והסתכלתי על שם המפתח כפי שהוא נקלט בתוכנית שלי. הדיבאגר הציג לי את המחרוזת שמופיעה ב-regedit – בתוספת סימן שאלה בסוף. כידוע, סימני שאלה מופיעים לפעמים כשתווים מוצגים בקידוד לא נכון, אז אולי יש תו סמוי בשם של המפתח? ניסיתי לבדוק ב-regedit במצב "בינארי" ולא ראיתי שום בייט יוצא דופן (את זה אני לא מבין עד עכשיו), אבל כשלחצתי על rename לשם המפתח, עמדתי בקצה השם ולחצתי Backspace פעם אחת, נמחק משהו שלא היה גלוי לעין. ויותר מזה, באותו רגע התוכנה שלי כן הצליחה לקרוא את המחרוזת COM4.

כפתרון כללי לבעיה זה היה די חסר טעם, כי הערך המקורי צץ שוב ברגע שניתקתי את הארדואינו וחיברתי מחדש (הוא בטח מגיע מהדרייבר של CH340 ל-Windows). מצד שני, לפחות ידעתי עכשיו שזה המקור: תו "בלתי נראה" שלא נקרא נכון. בדיקה נוספת של מחרוזת השם ב-Delphi העלתה שזהו התו BPH ב-Unicode. עם זאת, Lazarus וקומפיילר הפסקל FPC אמורים לדעת להתמודד עם Unicode, אז מה הקטע?

מציאת הפתרון

הצגתי את השאלה בפורומים של FPC/Lazarus, ומהר מאוד מישהו הגיע עם התשובה: הקוד של TRegistry ספציפית לא תומך ב-Unicode, זו בעיה שכבר דווחה ומישהו אפילו כתב קוד מתוקן. FPC/Lazarus הם פרויקטים בקוד פתוח, אז צריך רק להוריד את התיקון ולקמפל הכול מחדש.

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

המחלקות השונות שמתווספות לליבה של הקומפיילר FPC, וליתר דיוק קובצי הקוד שמכילים אותן, נקראים packages. במקרה הנוכחי אנחנו מדברים על package שנקראת fcl-registry. הקבצים העדכניים שלה נמצאים כאן. אם לא אכפת לכם להסתכן קצת, אפשר להעתיק אותם ישירות לתיקיית ה-source של FPC במחשב, שנמצאת ב- \lazarus\fpc\3.0.4\source\packages\fcl-registry (ה-3.0.4 היא גרסת הקומפיילר).

עכשיו, לפי המדריך הזה, עלינו להכין את הקבצים האלה לקראת קימפול-מחדש של הקומפיילר כולו. זהו שלב ביניים, שמתבצע על ידי הרצה של הקומפיילר (fpc.exe) על הקבצים שהעתקנו שיש להם את הסיומת pp. :

fpc registry.pp

fpc xmlreg.pp

פעולה זו יוצרת קובצי exe חדשים באותה תיקייה. אחרי זה נבצע בנייה(?) של קובצי הקומפיילר, בעזרת הפקודה

fpmake.exe build –globalunitdir=[…]\lazarus\fpc\3.0.4

(כמובן, להחליף את […] בתחילת הנתיב הנכונה למחשב שלכם).

אפשר להוסיף, למען הסדר הטוב, גם

fpmake clean

ולסיום נריץ את ההתקנה הסופית של כל ה-packages:

fpmake.exe install –globalunitdir=[…]\lazarus\fpc\3.0.4 –prefix=[…]\lazarus\fpc\3.0.4 –baseinstalldir=[…]\lazarus\fpc\3.0.4

עכשיו הקומפיילר fpc עצמו, שמשמש את סביבת הפיתוח Lazarus, יהיה מעודכן עם הקוד החדש, יתמוך ב-Unicode ב-Registry והתוכנה המסכנה שלי תוכל סופסוף לקרוא את המחרוזת "COM4" ולעבוד עם תואם הארדואינו הסיני הארור.

מחשבות לאחר מעשה

אם ה-Registry עצמו תומך ב-Unicode, ברור שגם קומפיילר עדכני שמתעסק איתו צריך לתמוך ב-Unicode. במובן זה הייתה כאן פאשלה של מפתחי FPC, רגע של חוסר תשומת לב או משהו כזה, וטוב שיצרו תיקון (אפילו אם ההתקנה שלו לא טריוויאלית, עד שהתיקון ישולב בגרסה הרשמית הבאה).

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

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

להרשמה
הודע לי על
2 תגובות
מהכי חדשה
מהכי ישנה לפי הצבעות
Inline Feedbacks
הראה את כל התגובות

חבוב,
נשמע שהגיע הזמן ללמוד ג'אווה