פתרון ארכיטקטורות וחוזי WinAPI¶
משתנה שאינו נמצא נשאר בצורתו המקורית לפי חוזה ההרחבה. זו אינה בהכרח שגיאת API. אם המוצר דורש שכל משתנה יהיה קיים, צריך להוסיף בדיקת משמעות נפרדת במקום לפרש כל תוצאה שהכילה סימני אחוז ככשל מערכת.
מתאם בדיקה פשוט יכול להפריד את הלולאה מפונקציית המערכת. הקטע הבא מדגים callback שמחזיר בכל ניסיון גודל גדול יותר; הוא אינו מחליף את כל ה־wrapper אלא את פעולת המדידה והמילוי שלו.
struct GrowingResult {
DWORD operator()(const wchar_t*, wchar_t*, DWORD capacity) const {
return capacity == 0 ? 4 : capacity + 1;
}
};
הבדיקה צריכה להזריק את האובייקט לתוך אותו אלגוריתם, ולוודא שהוא מגיע לכשל אחרי מספר הניסיונות שהוגדר. אין צורך לייצר race אמיתי במשתני הסביבה כדי לבדוק את מדיניות הגידול.
ב־Windows x64 גם long וגם DWORD הם בני ארבעה בתים, בעוד pointer הוא בן שמונה. ב־x86 pointer הוא בן ארבעה. התוצאה אינה תלויה רק בגודל RAM או בארכיטקטורת החומרה המארחת, אלא ביעד הבנייה ובסביבת התהליך.
| פעולה | חוזה שצריך לשמור |
|---|---|
| פתיחת קובץ באמצעות CreateFileW | הכשל הוא INVALID_HANDLE_VALUE; הצלחה שמחזיקה handle מחייבת CloseHandle |
| יצירת event באמצעות CreateEventW | הכשל הוא null; הצלחה מחייבת CloseHandle |
| קבלת נתיב module | הקיבולת נמדדת ביחידות wchar_t; ערך הצלחה רגיל אינו כולל null, וצריך לזהות חיתוך לפי החוזה |
| הרחבת משתני סביבה | הגודל והערך המוחזר נמדדים ביחידות טקסט; תוצאה מלאה כוללת null |
הטבלה היא נקודת התחלה לקריאת תיעוד, ולא תחליף לפרטי המקרים המיוחדים. בפרט, GetModuleFileNameW דורשת תשומת לב לתוצאה שווה לקיבולת, והחוזה ההיסטורי שלה אינו זהה בכל גרסת Windows.
הבדיקה הנכונה של HRESULT היא FAILED(hr) לזיהוי כשל. לאחר מכן אפשר לבדוק hr == S_FALSE כדי לטפל במשמעות הספציפית. הצלחה יכולה לומר שהפעולה הסתיימה בלי שינוי, או שתנאי מסוים אינו מתקיים, בהתאם ל־API.
הפתרון לא מעביר HRESULT אל GetLastError. מקור השגיאה הוא הערך שחזר מהפעולה, והמרה בין משפחות קודים דורשת מנגנון מתועד.