static void grid_region_rect(grid_t* grid, WORD col0, WORD row0, WORD col1, WORD row1, RECT* rect) { int header_w, header_h; /* Note: Caller may never mix header and ordinary cells in one call, * because the latter is scrolled area, while the headers are not. Hence * it does not make any sense to mix theme together. */ MC_ASSERT(col1 > col0 || col0 == MC_TABLE_HEADER); MC_ASSERT(row1 > row0 || row0 == MC_TABLE_HEADER); header_w = grid_header_width(grid); header_h = grid_header_height(grid); if(col0 == MC_TABLE_HEADER) { rect->left = 0; rect->right = header_w; } else { rect->left = grid_col_x(grid, col0); rect->right = grid_col_x2(grid, col0, rect->left, col1); } if(row0 == MC_TABLE_HEADER) { rect->top = 0; rect->bottom = header_h; } else { rect->top = grid_row_y(grid, row0); rect->bottom = grid_row_y2(grid, row0, rect->top, row1); } }
void* debug_realloc(const char* fname, int line, void* mem, size_t size) { void* new_mem; new_mem = debug_malloc(fname, line, size); if(MC_ERR(new_mem == NULL)) return NULL; /* Copy contents from the old memory chunk */ if(mem != NULL) { mem_info_t* mi; mi = mem_hashtable[MEM_HASHTABLE_INDEX(mem)]; while(mi->mem != mem) { if(MC_ERR(mi == NULL)) { /* Not registered? */ MC_TRACE("%s:%d: \tdebug_realloc(%p): Attempting to realloc " "non-allocated memory.", fname, line, mem); MC_ASSERT(1 == 0); } mi = mi->next; } memcpy(new_mem, mem, MC_MIN(size, mi->size)); debug_free(fname, line, mem); } return new_mem; }
static BSTR html_bstr(const void* from_str, int from_type) { WCHAR* str_w; BSTR str_b; if(from_str == NULL) { /* According to MSDN, BSTR should never be NULL. */ from_str = L""; from_type = MC_STRW; } if(from_type == MC_STRW) { str_w = (WCHAR*) from_str; } else { char* str_a; MC_ASSERT(from_type == MC_STRA); str_a = (char*) from_str; str_w = (WCHAR*) mc_str(str_a, from_type, MC_STRW); if(MC_ERR(str_w == NULL)) { MC_TRACE("html_bstr: mc_str() failed."); return NULL; } } str_b = html_SysAllocString(str_w); if(MC_ERR(str_b == NULL)) MC_TRACE("html_bstr: SysAllocString() failed."); if(str_w != from_str) free(str_w); return str_b; }
static BSTR html_bstr(const void* from_str, int from_type) { WCHAR* str_w; BSTR str_b; if(from_str == NULL) return NULL; if(from_type == MC_STRW) { str_w = (WCHAR*) from_str; if(str_w[0] == L'\0') return NULL; } else { char* str_a; MC_ASSERT(from_type == MC_STRA); str_a = (char*) from_str; if(str_a[0] == '\0') return NULL; str_w = (WCHAR*) mc_str(str_a, from_type, MC_STRW); if(MC_ERR(str_w == NULL)) { MC_TRACE("html_bstr: mc_str() failed."); return NULL; } } str_b = html_SysAllocString(str_w); if(MC_ERR(str_b == NULL)) MC_TRACE("html_bstr: SysAllocString() failed."); if(from_type == MC_STRA) free(str_w); return str_b; }
void debug_init(void) { InitializeCriticalSection(&mem_lock); /* We guard the heap with our own locking as we need the critical section * around it anyway. Hence HEAP_NO_SERIALIZE. */ mem_heap = HeapCreate(HEAP_NO_SERIALIZE, 1024 * 16 * sizeof(mem_info_t), 0); MC_ASSERT(mem_heap != NULL); }
static void grid_paint_header_cell(grid_t* grid, WORD col, WORD row, table_cell_t* cell, HDC dc, RECT* rect, int index, DWORD style) { table_cell_t tmp; table_cell_t* tmp_cell = &tmp; TCHAR buffer[16]; DWORD fabricate; /* Paint header background. */ if(grid->theme_header != NULL) { mcDrawThemeBackground(grid->theme_header, dc, HP_HEADERITEM, HIS_NORMAL, rect, NULL); } else { DrawEdge(dc, rect, BDR_RAISEDINNER, BF_MIDDLE | BF_RECT); } /* The 'dead' cell cannot have any contents. */ if(index < 0) return; /* Retrieve (or fabricate) cell to be painted. */ fabricate = (style & (MC_GS_COLUMNHEADERMASK | MC_GS_ROWHEADERMASK)); if(!fabricate) { /* Make copy so we can reset alignment flags below w/o side effects. */ if(cell != NULL) memcpy(&tmp, cell, sizeof(table_cell_t)); else tmp_cell = NULL; } else { if(fabricate == MC_GS_COLUMNHEADERNUMBERED || fabricate == MC_GS_ROWHEADERNUMBERED) { _stprintf(buffer, _T("%d"), index + 1); tmp.text = buffer; } else { MC_ASSERT(fabricate == MC_GS_COLUMNHEADERALPHABETIC || fabricate == MC_GS_ROWHEADERALPHABETIC); tmp.text = grid_alphabetic_number(buffer, index); } tmp.flags = (cell != NULL ? cell->flags : 0); tmp.is_value = FALSE; } /* If the header does not say explicitly otherwise, force centered * alignment for the header cells. */ if((tmp.flags & VALUE_PF_ALIGNMASKHORZ) == VALUE_PF_ALIGNDEFAULT) tmp.flags |= VALUE_PF_ALIGNCENTER; if((tmp.flags & VALUE_PF_ALIGNMASKVERT) == VALUE_PF_ALIGNVDEFAULT) tmp.flags |= VALUE_PF_ALIGNVCENTER; /* Paint header contents. */ grid_paint_cell(grid, col, row, tmp_cell, dc, rect); }
void* debug_malloc(const char* fname, int line, size_t size) { BYTE* buffer; void* mem; mem_info_t* mi; /* We never attempt to allocate zero bytes in mCtrl */ MC_ASSERT(size > 0); /* Allocate */ buffer = (BYTE*) malloc(size + sizeof(head_guard) + sizeof(tail_guard)); if(MC_ERR(buffer == NULL)) { MC_TRACE("%s:%d: \tdebug_malloc(%lu) failed.", fname, line, (ULONG)size); return NULL; } /* Setup over/underrun guards */ memcpy(buffer, head_guard, sizeof(head_guard)); memcpy(buffer + sizeof(head_guard) + size, tail_guard, sizeof(tail_guard)); /* Fill the memory chunk with some non-zero bytes * (this can help to debug (mis)uses of uninitialized memory) */ mem = (void*)(buffer + sizeof(head_guard)); memset(mem, 0xff, size); /* Register info about the allocated memory */ EnterCriticalSection(&mem_lock); mi = (mem_info_t*) HeapAlloc(mem_heap, 0, sizeof(mem_info_t)); MC_ASSERT(mi != NULL); mi->next = mem_hashtable[MEM_HASHTABLE_INDEX(mem)]; mem_hashtable[MEM_HASHTABLE_INDEX(mem)] = mi; mi->mem = mem; mi->size = size; mi->fname = fname; mi->line = line; LeaveCriticalSection(&mem_lock); DEBUG_TRACE("%s:%d: \tdebug_malloc(%lu) -> %p", fname, line, mi->size, mem); return mem; }
/* We dig into the raw resources instead of using LoadStringW() with nBufferMax * set to zero. * * See http://blogs.msdn.com/b/oldnewthing/archive/2004/01/30/65013.aspx. * * This allows us to do two useful things: * -- Verify easily the string is zero-terminated (the assertion). * -- Implement a fall-back to English, as translations can be potentially * incomplete. */ const TCHAR* mc_str_load(UINT id) { #ifndef UNICODE #error mc_str_load() is not (yet?) implemented for ANSI build. #endif const UINT lang_id[2] = { MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) }; TCHAR* rsrc_id = MAKEINTRESOURCE(id/16 + 1); int str_num = (id & 15); HRSRC rsrc; HGLOBAL handle; WCHAR* str; UINT len; int i, j; for(i = 0; i < MC_SIZEOF_ARRAY(lang_id); i++) { rsrc = FindResourceEx(mc_instance, RT_STRING, rsrc_id, lang_id[i]); if(MC_ERR(rsrc == NULL)) goto not_found; handle = LoadResource(mc_instance, rsrc); if(MC_ERR(handle == NULL)) goto not_found; str = (WCHAR*) LockResource(handle); if(MC_ERR(str == NULL)) goto not_found; for(j = 0; j < str_num; j++) str += 1 + (UINT) *str; len = (UINT) *str; if(MC_ERR(len == 0)) goto not_found; str++; /* Verify string resources are '\0'-terminated. This is not default * behavior of RC.EXE as well as windres.exe. For windres.exe we need * to have resources in the form "foo bar\0". For RC.EXE, we need to * use option '/n' to terminate the strings as RC.EXE even strips final * '\0' from the string even when explicitly specified. */ MC_ASSERT(str[len - 1] == L'\0'); return str; not_found: MC_TRACE("mc_str_load: String %u missing [language 0x%x].", id, (DWORD)(lang_id[i] == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ? LANGIDFROMLCID(GetThreadLocale()) : lang_id[i])); } return _T(""); }
void EXCO_Directory::InitializeHook() { // Hook so the directory doesn't point to 'My Documents' Detours::X86::DetourFunctionClass((PBYTE)0x0044C120, &GetModDirectory); // Current server directory DWORD bufferLen = GetCurrentDirectoryA(ARRAYSIZE(ourModDirectory), ourModDirectory); MC_ASSERT(bufferLen > 0); // Append the 'mods' folder path strcat_s(ourModDirectory, "\\mods\\"); }
static void module_fini_modules(module_t** modules, int n) { int i; mc_mutex_lock(&mod_mutex); for(i = n-1; i >= 0; i--) { MC_ASSERT(modules[i]->refs > 0); modules[i]->refs--; if(modules[i]->refs == 0) modules[i]->fn_fini(); } mc_mutex_unlock(&mod_mutex); }
static void module_fini_modules(module_t** modules, int n) { int i; EnterCriticalSection(&mod_lock); for(i = n-1; i >= 0; i--) { MC_ASSERT(modules[i]->refs > 0); modules[i]->refs--; if(modules[i]->refs == 0) modules[i]->fn_fini(); } LeaveCriticalSection(&mod_lock); }
static void grid_refresh(void* view, void* detail) { grid_t* grid = (grid_t*) view; table_refresh_detail_t* rd = (table_refresh_detail_t*) detail; RECT rect; MC_ASSERT(rd != NULL); switch(rd->event) { case TABLE_CELL_CHANGED: if(!grid->no_redraw) { grid_cell_rect(grid, rd->param[0], rd->param[1], &rect); InvalidateRect(grid->win, &rect, TRUE); } break; case TABLE_REGION_CHANGED: if(!grid->no_redraw) { grid_region_rect(grid, rd->param[0], rd->param[1], rd->param[2], rd->param[3], &rect); InvalidateRect(grid->win, &rect, TRUE); } break; case TABLE_COLCOUNT_CHANGED: if(grid->col_widths != NULL) grid_alloc_col_widths(grid, grid->col_count, rd->param[1], TRUE); grid->col_count = rd->param[1]; grid_setup_scrollbars(grid, TRUE); if(!grid->no_redraw) { /* TODO: optimize by invalidating minimal rect (new cols) and scrolling rightmost columns */ InvalidateRect(grid->win, NULL, TRUE); } break; case TABLE_ROWCOUNT_CHANGED: if(grid->row_heights != NULL) grid_alloc_row_heights(grid, grid->row_count, rd->param[1], TRUE); grid->row_count = rd->param[1]; grid_setup_scrollbars(grid, TRUE); if(!grid->no_redraw) { /* TODO: optimize by invalidating minimal rect (new rows) and scrolling bottommost rows */ InvalidateRect(grid->win, NULL, TRUE); } break; } }
void debug_fini(void) { int i; int n = 0; size_t size = 0; mem_info_t* mi; /* Generate report about memory leaks */ EnterCriticalSection(&mem_lock); for(i = 0; i < MEM_HASHTABLE_SIZE; i++) { for(mi = mem_hashtable[i]; mi != NULL; mi = mi->next) { if(n == 0) { MC_TRACE(""); MC_TRACE("debug_fini: LEAK REPORT:"); MC_TRACE("debug_fini: --------------------------------------------------"); #ifdef _WIN64 MC_TRACE("debug_fini: Address Size Where"); #else MC_TRACE("debug_fini: Address Size Where"); #endif MC_TRACE("debug_fini: --------------------------------------------------"); } #ifdef _WIN64 MC_TRACE("debug_fini: 0x%16p %8lu %s:%d", mi->mem, mi->size, mi->fname, mi->line); #else MC_TRACE("debug_fini: 0x%8p %8lu %s:%d", mi->mem, mi->size, mi->fname, mi->line); #endif n++; size += mi->size; } } LeaveCriticalSection(&mem_lock); if(n > 0) { MC_TRACE("debug_fini: --------------------------------------------------"); MC_TRACE("debug_fini: Lost %lu bytes in %d leaks.", size, n); MC_TRACE(""); } MC_ASSERT(n == 0); /* Uninitialize */ HeapDestroy(mem_heap); DeleteCriticalSection(&mem_lock); }
void view_list_uninstall_view(view_list_t* vlist, void* view) { view_node_t* node = vlist->head; view_node_t* prev = NULL; while(node->view != view) { MC_ASSERT(node != NULL); prev = node; node = node->next; } if(prev) prev->next = node->next; else vlist->head = node->next; free(node); }
void table_destroy(table_t* table) { TABLE_TRACE("table_destroy(%p)", table); MC_ASSERT(table->refs == 0); if(table->cells) { int i, n; n = table->col_count + table->row_count + table->col_count * table->row_count; for(i = 0; i < n; i++) table_cell_clear(&table->cells[i]); free(table->cells); } view_list_fini(&table->vlist); free(table); }
int view_list_install_view(view_list_t* vlist, void* view, view_refresh_t refresh) { view_node_t* node; /* View can be installed only once in the list */ #ifdef DEBUG for(node = vlist->head; node != NULL; node = node->next) MC_ASSERT(node->view != view); #endif node = (view_node_t*) malloc(sizeof(view_node_t)); if(MC_ERR(node == NULL)) { MC_TRACE("view_install: malloc() failed."); return -1; } node->view = view; node->refresh = refresh; node->next = vlist->head; vlist->head = node; return 0; }
static void button_paint_icon(HWND win, button_t* button, HDC dc) { HICON icon; RECT rect; RECT content; int state; SIZE size; UINT flags; HFONT font, old_font; int old_bk_mode; COLORREF old_text_color; HRGN old_clip; /* When theming is not used, we keep all the work on COMCTL32 button * implementation. */ MC_ASSERT(button->theme != NULL); GetClientRect(win, &rect); icon = (HICON) MC_SEND(win, BM_GETIMAGE, IMAGE_ICON, 0); font = (HFONT) MC_SEND(win, WM_GETFONT, 0, 0); if(font == NULL) font = GetStockObject(SYSTEM_FONT); old_font = SelectObject(dc, font); old_bk_mode = GetBkMode(dc); old_text_color = GetTextColor(dc); old_clip = get_clip(dc); /* Draw background */ if(button->style & WS_DISABLED) { state = PBS_DISABLED; } else { LRESULT s = MC_SEND(win, BM_GETSTATE, 0, 0); if(s & BST_PUSHED) state = PBS_PRESSED; else if(s & BST_HOT) state = PBS_HOT; else if(button->style & BS_DEFPUSHBUTTON) state = PBS_DEFAULTED; else state = PBS_NORMAL; } if(mcIsThemeBackgroundPartiallyTransparent(button->theme, BP_PUSHBUTTON, state)) mcDrawThemeParentBackground(win, dc, &rect); mcDrawThemeBackground(button->theme, dc, BP_PUSHBUTTON, state, &rect, &rect); /* Get content rectangle of the button and clip DC to it */ mcGetThemeBackgroundContentRect(button->theme, dc, BP_PUSHBUTTON, state, &rect, &content); IntersectClipRect(dc, content.left, content.top, content.right, content.bottom); /* Draw focus rectangle */ if(MC_SEND(win, BM_GETSTATE, 0, 0) & BST_FOCUS) { if(!button->hide_focus) DrawFocusRect(dc, &content); } /* Draw the contents (i.e. the icon) */ if(icon != NULL) { mc_icon_size(icon, &size); flags = DST_ICON; if(button->style & WS_DISABLED) flags |= DSS_DISABLED; DrawState(dc, NULL, NULL, (LPARAM) icon, 0, (rect.right + rect.left - size.cx) / 2, (rect.bottom + rect.top - size.cy) / 2, size.cx, size.cy, flags); } /* Revert DC into original state */ SelectObject(dc, old_font); SetBkMode(dc, old_bk_mode); SetTextColor(dc, old_text_color); SelectObject(dc, old_clip); }
static int table_resize_helper(table_t* table, int col_pos, int col_delta, int row_pos, int row_delta) { size_t size; table_cell_t* cols; table_cell_t* rows; table_cell_t* cells; table_region_t copy_src[4]; table_region_t copy_dst[4]; table_region_t init_dst[3]; table_region_t free_src[3]; int copy_count, init_count, free_count; int col_count, row_count; int i; table_refresh_detail_t refresh_detail; TABLE_TRACE("table_resize_helper(%p, %d, %d, %d, %d)", table, col_pos, col_delta, row_pos, row_delta); if(col_delta == 0 && row_delta == 0) { /* noop */ return 0; } col_count = table->col_count + col_delta; row_count = table->row_count + row_delta; if(col_delta == 0) col_pos = col_count; if(row_delta == 0) row_pos = row_count; /* Allocate buffer for resized table */ size = col_count * sizeof(table_cell_t) + row_count * sizeof(table_cell_t) + (col_count*row_count) * sizeof(table_cell_t); if(size > 0) { cells = (table_cell_t*) malloc(size); if(MC_ERR(cells == NULL)) { MC_TRACE("table_resize: malloc() failed"); return -1; } cols = cells + (col_count * row_count); rows = cols + col_count; } else { cells = NULL; cols = NULL; rows = NULL; } /* Analyze which region of the original cells shall be freed, which shall * be reused in the reallocated buffer, and which in the new buffer need * initialization. */ #define REGSET(reg, c0, r0, c1, r1) \ do { reg.col0 = c0; reg.row0 = r0; \ reg.col1 = c1; reg.row1 = r1; } while (0) if(col_delta >= 0 && row_delta >= 0) { /* * +---+-+---+ * +---+---+ | 0 | | 1 | * | 0 | 1 | +---+-+---+ * +---+---+ ---> | | * | 2 | 3 | +---+-+---+ * +---+---+ | 2 | | 3 | * +---+-+---+ */ REGSET(copy_src[0], 0, 0, col_pos, row_pos); REGSET(copy_dst[0], 0, 0, col_pos, row_pos); REGSET(copy_src[1], col_pos, 0, table->col_count, row_pos); REGSET(copy_dst[1], col_pos + col_delta, 0, col_count, row_pos); REGSET(copy_src[2], 0, row_pos, col_pos, table->row_count); REGSET(copy_dst[2], 0, row_pos + row_delta, col_pos, row_count); REGSET(copy_src[3], col_pos, row_pos, table->col_count, table->row_count); REGSET(copy_dst[3], col_pos + col_delta, row_pos + row_delta, col_count, row_count); copy_count = 4; REGSET(init_dst[0], col_pos, 0, col_pos + col_delta, row_pos); REGSET(init_dst[1], 0, row_pos, col_count, row_pos + row_delta); REGSET(init_dst[2], col_pos, row_pos + row_delta, col_pos + col_delta, row_count); init_count = 3; free_count = 0; } else if(col_delta >= 0 && row_delta < 0) { /* * +---+---+ * | 0 | 1 | +---+-+---+ * +---+---+ | 0 | | 1 | * | | ---> +---+ +---+ * +---+---+ | 2 | | 3 | * | 2 | 3 | +---+-+---+ * +---+---+ */ REGSET(copy_src[0], 0, 0, col_pos, row_pos); REGSET(copy_dst[0], 0, 0, col_pos, row_pos); REGSET(copy_src[1], col_pos, 0, table->col_count, row_pos); REGSET(copy_dst[1], col_pos + col_delta, 0, col_count, row_pos); REGSET(copy_src[2], 0, row_pos - row_delta, col_pos, table->row_count); REGSET(copy_dst[2], 0, row_pos, col_pos, row_count); REGSET(copy_src[3], col_pos, row_pos - row_delta, table->col_count, table->row_count); REGSET(copy_dst[3], col_pos + col_delta, row_pos, col_count, row_count); copy_count = 4; REGSET(init_dst[0], col_pos, 0, col_pos + col_delta, row_count); init_count = 1; REGSET(free_src[0], 0, row_pos, table->col_count, row_pos - row_delta); free_count = 1; } else if(col_delta < 0 && row_delta >= 0) { /* * +---+---+ * +---+-+---+ | 0 | 1 | * | 0 | | 1 | +---+---+ * +---+ +---+ ---> | | * | 2 | | 3 | +---+---+ * +---+-+---+ | 2 | 3 | * +---+---+ */ REGSET(copy_src[0], 0, 0, col_pos, row_pos); REGSET(copy_dst[0], 0, 0, col_pos, row_pos); REGSET(copy_src[1], col_pos - col_delta, 0, table->col_count, row_pos); REGSET(copy_dst[1], col_pos, 0, col_count, row_pos); REGSET(copy_src[2], 0, row_pos, col_pos, table->row_count); REGSET(copy_dst[2], 0, row_pos + row_delta, col_pos, row_count); REGSET(copy_src[3], col_pos - col_delta, row_pos, table->col_count, table->row_count); REGSET(copy_dst[3], col_pos, row_pos + row_delta, col_count, row_count); copy_count = 4; REGSET(init_dst[0], 0, row_pos, col_count, row_pos + row_delta); init_count = 1; REGSET(free_src[0], col_pos, 0, col_pos - col_delta, table->row_count); free_count = 1; } else { MC_ASSERT(col_delta < 0 && row_delta < 0); /* * +---+-+---+ * | 0 | | 1 | +---+---+ * +---+-+---+ | 0 | 1 | * | | ---> +---+---+ * +---+-+---+ | 2 | 3 | * | 2 | | 3 | +---+---+ * +---+-+---+ */ REGSET(copy_src[0], 0, 0, col_pos, row_pos); REGSET(copy_dst[0], 0, 0, col_pos, row_pos); REGSET(copy_src[1], col_pos - col_delta, 0, table->col_count, row_pos); REGSET(copy_dst[1], col_pos, 0, col_count, row_pos); REGSET(copy_src[2], 0, row_pos - row_delta, col_pos, table->row_count); REGSET(copy_dst[2], 0, row_pos, col_pos, row_count); REGSET(copy_src[3], col_pos - col_delta, row_pos - row_delta, table->col_count, table->row_count); REGSET(copy_dst[3], col_pos, row_pos, col_count, row_count); copy_count = 4; init_count = 0; REGSET(free_src[0], col_pos, 0, col_pos - col_delta, row_pos); REGSET(free_src[1], 0, row_pos, table->col_count, row_pos - row_delta); REGSET(free_src[2], col_pos, row_pos - row_delta, col_pos - col_delta, table->row_count); free_count = 3; } #undef REGSET /* Copy cells to be reused */ if(table->cells != NULL && cells != NULL) { for(i = 0; i < copy_count; i++) { MC_ASSERT(copy_src[i].col1-copy_src[i].col0 == copy_dst[i].col1-copy_dst[i].col0); MC_ASSERT(copy_src[i].row1-copy_src[i].row0 == copy_dst[i].row1-copy_dst[i].row0); if(col_delta == 0) { memcpy(&cells[copy_dst[i].row0 * col_count], &table->cells[copy_src[i].row0 * col_count], (copy_src[i].row1-copy_src[i].row0) * (copy_src[i].col1-copy_src[i].col0) * sizeof(table_cell_t)); } else { WORD row_src, row_dst; for(row_src = copy_src[i].row0, row_dst = copy_dst[i].row0; row_src < copy_src[i].row1; row_src++, row_dst++) { memcpy(&cells[row_dst * col_count + copy_dst[i].col0], &table->cells[row_src * table->col_count + copy_src[i].col0], (copy_src[i].col1-copy_src[i].col0) * sizeof(table_cell_t)); } } } } /* Init new cells in the new buffer */ if(cells != NULL) { for(i = 0; i < init_count; i++) { if(col_delta == 0) { memset(&cells[col_count * init_dst[i].row0], 0, col_count * (init_dst[i].row1-init_dst[i].row0) * sizeof(table_cell_t)); } else { WORD row; for(row = init_dst[i].row0; row < init_dst[i].row1; row++) { memset(&cells[row * col_count + init_dst[i].col0], 0, (init_dst[i].col1-init_dst[i].col0) * sizeof(table_cell_t)); } } } } /* Free bogus cells in the old buffer */ if(table->cells != NULL) { for(i = 0; i < free_count; i++) { WORD col, row; for(row = free_src[i].row0; row < free_src[i].row1; row++) { for(col = free_src[i].col0; col < free_src[i].col1; col++) { table_cell_clear(&table->cells[row * table->col_count + col]); } } } } /* Handle column headers */ if(cols != NULL && table->cols != NULL) { memcpy(&cols[0], &table->cols[0], col_pos * sizeof(table_cell_t)); if(col_delta > 0) memcpy(&cols[col_pos + col_delta], &table->cols[col_pos], (table->col_count - col_pos) * sizeof(table_cell_t)); else if(col_delta < 0) memcpy(&cols[col_pos], &table->cols[col_pos - col_delta], (col_count - col_pos) * sizeof(table_cell_t)); } if(cols != NULL && col_delta > 0) memset(&cols[col_pos], 0, col_delta * sizeof(table_cell_t)); if(table->cols != NULL && col_delta < 0) { WORD col; for(col = col_pos; col < col_pos - col_delta; col++) table_cell_clear(&table->cols[col]); } /* Handle row headers */ if(rows != NULL && table->rows != NULL) { memcpy(&rows[0], &table->rows[0], row_pos * sizeof(table_cell_t)); if(row_delta > 0) memcpy(&rows[row_pos + row_delta], &table->rows[row_pos], (table->row_count - row_pos) * sizeof(table_cell_t)); else if(row_delta < 0) memcpy(&rows[row_pos], &table->rows[row_pos - row_delta], (row_count - row_pos) * sizeof(table_cell_t)); } if(rows != NULL && row_delta > 0) memset(&rows[row_pos], 0, row_delta * sizeof(table_cell_t)); if(table->rows != NULL && row_delta < 0) { WORD row; for(row = row_pos; row < row_pos - row_delta; row++) table_cell_clear(&table->rows[row]); } /* Install the new buffer */ if(table->cells != NULL) free(table->cells); table->cols = cols; table->rows = rows; table->cells = cells; table->col_count = col_count; table->row_count = row_count; /* Refresh */ if(col_delta != 0) { refresh_detail.event = TABLE_COLCOUNT_CHANGED; refresh_detail.param[0] = table->col_count - col_delta; refresh_detail.param[1] = table->col_count; refresh_detail.param[2] = col_pos; table_refresh(table, &refresh_detail); } if(row_delta != 0) { refresh_detail.event = TABLE_ROWCOUNT_CHANGED; refresh_detail.param[0] = table->row_count - row_delta; refresh_detail.param[1] = table->row_count; refresh_detail.param[2] = row_pos; table_refresh(table, &refresh_detail); } return 0; }
static LRESULT CALLBACK menubar_ht_proc(int code, WPARAM wp, LPARAM lp) { if(code >= 0) { MSG* msg = (MSG*)lp; menubar_t* mb = menubar_ht_mb; MC_ASSERT(mb != NULL); switch(msg->message) { case WM_MENUSELECT: menubar_ht_sel_menu = (HMENU)msg->lParam; menubar_ht_sel_item = LOWORD(msg->wParam); menubar_ht_sel_flags = HIWORD(msg->wParam); MENUBAR_TRACE("menubar_ht_proc: WM_MENUSELECT %p %d", menubar_ht_sel_menu, menubar_ht_sel_item); break; case WM_MOUSEMOVE: { POINT pt = msg->pt; int item; MapWindowPoints(NULL, mb->win, &pt, 1); item = MENUBAR_SENDMSG(mb->win, TB_HITTEST, 0, (LPARAM)&pt); if(menubar_ht_last_pos.x != pt.x || menubar_ht_last_pos.y != pt.y) { menubar_ht_last_pos = pt; if(item != mb->pressed_item && 0 <= item && item < MENUBAR_SENDMSG(mb->win, TB_BUTTONCOUNT, 0, 0)) { MENUBAR_TRACE("menubar_ht_proc: Change dropdown by mouse move " "[%d -> %d]", mb->pressed_item, item); menubar_ht_change_dropdown(mb, item, FALSE); } } break; } case WM_KEYDOWN: case WM_SYSKEYDOWN: switch(msg->wParam) { case VK_MENU: case VK_F10: menubar_ht_change_dropdown(mb, -1, TRUE); return 0; case VK_LEFT: if(menubar_ht_sel_menu == NULL || menubar_ht_sel_menu == GetSubMenu(mb->menu, mb->pressed_item)) { int item = mb->pressed_item - 1; if(item < 0) item = MENUBAR_SENDMSG(mb->win, TB_BUTTONCOUNT, 0, 0) - 1; MENUBAR_TRACE("menubar_ht_proc: Change dropdown by VK_LEFT"); if(item != mb->pressed_item) menubar_ht_change_dropdown(mb, item, TRUE); menubar_update_ui_state(mb, TRUE); } break; case VK_RIGHT: if(menubar_ht_sel_menu == NULL || !(menubar_ht_sel_flags & MF_POPUP) || (menubar_ht_sel_flags & (MF_GRAYED | MF_DISABLED))) { int item = mb->pressed_item + 1; if(item >= MENUBAR_SENDMSG(mb->win, TB_BUTTONCOUNT, 0, 0)) item = 0; MENUBAR_TRACE("menubar_ht_proc: Change dropdown by VK_RIGHT"); if(item != mb->pressed_item) menubar_ht_change_dropdown(mb, item, TRUE); menubar_update_ui_state(mb, TRUE); } break; } break; } } return CallNextHookEx(menubar_ht_hook, code, wp, lp); }
static void grid_get_dispinfo(grid_t* grid, WORD col, WORD row, table_cell_t* cell, grid_dispinfo_t* di, DWORD mask) { MC_NMGDISPINFO info; MC_ASSERT((mask & ~(MC_TCMF_TEXT | MC_TCMF_VALUE | MC_TCMF_FLAGS)) == 0); /* Use what can be taken from the cell. */ if(cell != NULL) { if(cell->text != MC_LPSTR_TEXTCALLBACK) { di->text = (cell->is_value ? NULL : cell->text); mask &= ~MC_TCMF_TEXT; } di->value = (cell->is_value ? cell->value : NULL); di->flags = cell->flags; mask &= ~(MC_TCMF_VALUE | MC_TCMF_FLAGS); if(mask == 0) return; } /* For the rest data, fire MC_GN_GETDISPINFO notification. */ info.hdr.hwndFrom = grid->win; info.hdr.idFrom = GetWindowLong(grid->win, GWL_ID); info.hdr.code = (grid->unicode_notifications ? MC_GN_GETDISPINFOW : MC_GN_GETDISPINFOA); info.wColumn = col; info.wRow = row; info.cell.fMask = mask; /* Set info.cell members to meaningful values. lParam may be needed by the * app to find the requested data. Other members should be set to some * defaults to deal with broken apps which do not set the asked members. */ if(cell != NULL) { info.cell.pszText = NULL; info.cell.hValue = NULL; info.cell.lParam = cell->lp; info.cell.dwFlags = cell->flags; } else { info.cell.pszText = NULL; info.cell.hValue = NULL; info.cell.lParam = 0; info.cell.dwFlags = 0; } MC_SEND(grid->notify_win, WM_NOTIFY, 0, &info); /* If needed, convert the text from parent to the expected format. */ if(mask & MC_TCMF_TEXT) { if(grid->unicode_notifications == MC_IS_UNICODE) di->text = info.cell.pszText; else di->text = mc_str(info.cell.pszText, (grid->unicode_notifications ? MC_STRW : MC_STRA), MC_STRT); } else { /* Needed even when not asked for because of grid_free_dispinfo() */ di->text = NULL; } /* Small optimization: We do not ask about the corresponding bits in the * mask for these. If not set, the assignment does no hurt and we save few * instructions. */ di->value = info.cell.hValue; di->flags = info.cell.dwFlags; }
void debug_free(const char* fname, int line, void* mem) { mem_info_t* mi_prev = NULL; mem_info_t* mi; BYTE* head; BYTE* tail; MC_ASSERT(mem != NULL); EnterCriticalSection(&mem_lock); /* Find memory info for the memory chunk */ mi = mem_hashtable[MEM_HASHTABLE_INDEX(mem)]; while(TRUE) { if(MC_ERR(mi == NULL)) { /* Not registered? */ MC_TRACE("%s:%d: \tdebug_free(%p): Attempting to release " "non-allocated memory.", fname, line, mem); MC_ASSERT(1 == 0); } if(mi->mem == mem) break; mi_prev = mi; mi = mi->next; } DEBUG_TRACE("%s:%d: \tdebug_free(%p) [size=%lu]", fname, line, mem, mi->size); /* Check that the over/underrun guards are intact */ head = ((BYTE*)mem) - sizeof(head_guard); tail = ((BYTE*)mem) + mi->size; if(memcmp(head, head_guard, sizeof(head_guard)) != 0) { MC_TRACE("%s:%d: \tdebug_free(%p) detected buffer underrun " "[guard={%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x}, " "size=%lu]. Was allocated here: %s:%d", fname, line, mem, head[0], head[1], head[2], head[3], head[4], head[5], head[6], head[7], head[8], head[9], head[10], head[11], head[12], head[13], head[14], head[15], mi->size, mi->fname, mi->line); MC_ASSERT(2 == 0); } if(memcmp(tail, tail_guard, sizeof(tail_guard)) != 0) { MC_TRACE("%s:%d: \tdebug_free(%p) detected buffer overrun " "[guard={%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x}, " "size=%lu]. Was allocated here: %s:%d", fname, line, mem, tail[0], tail[1], tail[2], tail[3], tail[4], tail[5], tail[6], tail[7], tail[8], tail[9], tail[10], tail[11], tail[12], tail[13], tail[14], tail[15], mi->size, mi->fname, mi->line); MC_ASSERT(3 == 0); } /* Rewrite all the memory with 'invalid-memory' mark, including the guards. * (this can help to debug (mis)uses of released memory) */ memset(head, 0xee, mi->size + 2 * sizeof(head_guard)); /* Unregister the memory info */ if(mi_prev != NULL) mi_prev->next = mi->next; else mem_hashtable[MEM_HASHTABLE_INDEX(mem)] = mi->next; HeapFree(mem_heap, 0, mi); LeaveCriticalSection(&mem_lock); /* Finally we can free it */ free(head); }