Функция чтения статуса UPSmart 1.4
SQInteger Read_UPS(HSQUIRRELVM v) { const int paUPS = 0x0076f604; // pointer to array HWND hwnd; // handle for UPSmart window HANDLE hUPS; // handle for UPSmart process DWORD upsProcessId; // UPSmart process Id struct UPS { __declspec( align( 16)) float vac_in; // Current input Voltage __declspec( align( 16)) float reserved_1; __declspec( align( 16)) float vac_out; // Current output Voltage __declspec( align( 16)) float max_load; // Current output Load Level __declspec( align( 16)) float vac_hz; // Current input frequency __declspec( align( 16)) float vdc_battery; // Battery Voltage __declspec( align( 16)) float temperature; // Current Temperature; __declspec( align( 16)) float reserved_2; __declspec( align( 16)) float reserved_3; } ups; hwnd = FindWindow( NULL, "UPSmart"); // Find the UPSmart window if( hwnd == NULL) return 0; // Nothing, if program not running if( GetWindowThreadProcessId( hwnd, &upsProcessId) == NULL) return 0; // Nothing, if process not openned hUPS = OpenProcess( PROCESS_VM_READ, FALSE, upsProcessId); if( hUPS == NULL) // Try for process memory read is OK? return 0; // Nothing, if error ReadProcessMemory( hUPS, ( void *)paUPS, &ups, sizeof ups, NULL); CloseHandle( hUPS); sq_settop( v, 1); sq_pushroottable( v); sq_newtable( v); // Create the structured table with named values sq_pushstring( v, "vac_in", -1), sq_pushinteger( v, ups.vac_in), sq_rawset( v, -3); sq_pushstring( v, "reserved_1", -1), sq_pushinteger( v, ups.reserved_1), sq_rawset( v, -3); sq_pushstring( v, "vac_out", -1), sq_pushinteger( v, ups.vac_out), sq_rawset( v, -3); sq_pushstring( v, "are_load", -1), sq_pushinteger( v, ups.max_load), sq_rawset( v, -3); sq_pushstring( v, "vac_hz", -1), sq_pushinteger( v, ups.vac_hz), sq_rawset( v, -3); sq_pushstring( v, "vdc_battery", -1),sq_pushinteger( v, ups.vdc_battery), sq_rawset( v, -3); sq_pushstring( v, "celsius", -1), sq_pushinteger( v, ups.celsius), sq_rawset( v, -3); sq_pushstring( v, "reserved_2", -1), sq_pushinteger( v, ups.reserved_2), sq_rawset( v, -3); sq_pushstring( v, "reserved_3", -1), sq_pushinteger( v, ups.reserved_3), sq_rawset( v, -3); return 1; // One element are returns }
Если для нормального линейного вращения координат имеется
float sine = sin(PI / 180.0), cose = cos( PI / 180.0); // Prepare for rotation by 1 degree float x = 127.0, y = 0.0, tmp; // Init // Main cycle { tmp = x * cose - y * sine; y = y * cose + x * sine; x = tmp; }
, возможно в частности заменить алгоритмом Брезенхэма
long px1 = 150, py1 = 0, pz; //////////////////////////////////////////////////////////// // Bresenham circle algorithm x,y-coordinate rotation // //////////////////////////////////////////////////////////// void Bres_Rotation(long &x, long &y, long &d) { static long dx, dy; if( y > 0 && x >= 0) dx = +1, dy = -1; else if( y <= 0 && x > 0) dx = -1, dy = -1; else if( y < 0 && x <= 0) dx = -1, dy = +1; else if( y >= 0 && x < 0) dx = +1, dy = +1; if( !x || !y) { d = - 2 * abs( x + y); if( !y) x += dx; } if( d < 0 && 2 * ( d + abs( y)) - 1 <= 0) { if( dx * dy < 1) d += 1 + 2 * abs( x += dx); else d += 1 + 2 * abs( y += dy); } else if( d > 0 && 2 * ( d - abs( x)) - 1 > 0) { if( dx * dy < 1) d += 1 - 2 * abs( y += dy); else d += 1 - 2 * abs( x += dx); } else if( dx * dy < 1) d += 2 * ( abs( x += dx) - abs( y += dy)); else d += 2 * ( abs( y += dy) - abs( x += dx)); } ... ... WinMain tester ... case WM_TIMER: hdc = GetDC( hWnd); SetPixel( hdc, 250 + px, 250 + py, 0xFFFFFF); Bres_Rotation( px, py, pz); SetPixel( hdc, 250 + px, 250 + py, 0x000000); ReleaseDC( hWnd, hdc); break;
, мною разработан ненормальный способ
long xp1 = 150, yp1 = 0, xx1, yy1, ss1 = 0; // Use it long xp2 = 0, yp2 = -175, xx2, yy2, ss2 = 0; // as sample /////////////////////////////////////////////////////////////// // Step Rotation - Rotation the x and y by simple operations // // Auto initialize - s = 0, x != 0 || y != 0 // // xx, yy - squares of x, y // /////////////////////////////////////////////////////////////// void StepRotation(long &x, long &y, long &xx, long &yy, long &s) { if( s == 0 && x != 0) xx = x * x, yy = y = 0, s = xx; else if( s == 0 && y != 0) xx = x = 0, yy = y * y, s = yy; if( x >= 0 && y > 0 && x > y) { yy += ++ y * 2 - 1; if( xx + yy > s) xx -= -- x * 2 + 1; } else if( x > 0 && y >= 0 && x <= y) { xx -= -- x * 2 + 1; if( xx + yy <= s) yy += ++ y * 2 - 1; } else if( x <= 0 && y > 0 && -x < y) { if( xx + yy > s) yy -= -- y * 2 + 1; xx -= -- x * 2 + 1; } else if( x < 0 && y >= 0 && -x >= y) { yy -= -- y * 2 + 1; if( xx + yy <= s) xx -= -- x * 2 + 1; } else if( x <= 0 && y < 0 && -x > -y) { if( xx + yy > s) xx += ++ x * 2 - 1; yy -= -- y * 2 + 1; } if( x < 0 && y <= 0 && -x <= -y) { xx += ++ x * 2 - 1; if( xx + yy <= s) yy -= -- y * 2 + 1; } else if( x >= 0 && y < 0 && x < -y) { if( xx + yy > s) yy += ++ y * 2 - 1; xx += ++ x * 2 - 1; } else if( x > 0 && y <= 0 && x >= -y) { yy += ++ y * 2 - 1; if( xx + yy <= s) xx += ++ x * 2 - 1; } } ... ... WinMain tester ... case WM_TIMER: hdc = GetDC( hWnd); SetPixel( hdc, 250 + xp1, 250 - yp1, 0xFFFFFF); SetPixel( hdc, 250 + xp2, 250 - yp2, 0xFFFFFF); StepRotation( xp1, yp1, xx1, yy1, ss1); StepRotation( xp2, yp2, xx2, yy2, ss2); if( ss1 > 50) -- ss1; // Draw Spiral SetPixel( hdc, 250 + xp1, 250 - yp1, 0); SetPixel( hdc, 250 + xp2, 250 - yp2, 0); ReleaseDC( hWnd, hdc); break;
, который можно использовать в алгоритме черчения дуги.
Интересный побочный эффект: скорость движения у прямых углов заметно падает.
Как вариант, для компенсации этого следует как-то добавить дополнительные итерации.
Алгоритм писался с расчётом на перенос под Verilog.
BOOL CrossLine(long x1, long y1, long x2, long y2, long x3, long y3, long x4, long y4, long &x, long &y) { long dx1 = x2 - x1; long dy1 = y2 - y1; long dx2 = x4 - x3; long dy2 = y4 - y3; x = dy1 * dx2 - dy2 * dx1; if( !x || !dx2) return false; y = x3 * y4 - y3 * x4; x = ( ( x1 * y2 - y1 * x2) * dx2 - y * dx1) / x; y = ( dy2 * x - y) / dx2; return ( ( x1 <= x && x2 >= x) || ( x2 <= x && x1 >= x)) && ( ( x3 <= x && x4 >= x) || ( x4 <= x && x3 >= x)); }
Бывают случаи, когда нужно получить точный клон меню стороннего окна, чтобы дистанционно им управлять:
char Mode = -1; // Input: Any window menu handle to clone // Output: New popup menu HMENU BuildMenu(HMENU hMnu) { HMENU hMenu; MENUITEMINFO mmi; char mnuText[4096]; int i = 0; hMenu = CreatePopupMenu( ); // Творим новое меню ++ Mode; do { ZeroMemory( &mmi, sizeof( MENUITEMINFO)); // Формируем структуру mmi.cbSize = sizeof( MENUITEMINFO); // Иначе будет тихая ошибка mmi.dwTypeData = mnuText; mmi.cch = sizeof( mnuText); mmi.fMask = MIIM_TYPE | MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU; if( !GetMenuItemInfo( hMnu, i, TRUE, &mmi)) // Проверяем, получилось ли? break; if( !( mmi.hSubMenu = BuildMenu( mmi.hSubMenu))) mmi.fMask &= ~MIIM_SUBMENU; InsertMenuItem( hMenu, i, TRUE, &mmi); // Трассируем вложенные меню } while( ++ i > 0); -- Mode; return i ? hMenu : NULL; }
Команды окну посылаются самым обычным способом: PostMessage|SendMessage (hWindow, WM_COMMAND, wParam, lParam)
Для корректного построения меню необходимо в начале выполнять SendMessage(hWindow, WM_INITMENU, WPARAM(GetMenu(hWindow)), NULL)
Задумался я над тем, а сколько же тиков тактовой частоты пожирает тот или иной фрагмент моего кода? Особенно на ассемблере. Причём, простой перестановкой всего двух инструкций в нескольких местах я добился сокращения тиков на ⅓.
Вот, собственно, фрагмент
__int64 ticks; TCHAR szInfo[256]; RECT rt; ... case WM_TIMER: SetPriorityClass(GetCurrentProcess( ), HIGH_PRIORITY_CLASS); // Никаких тормозов _asm { push 1024 // 1024 итераций, чтобы конвейрей стал стабильнее movd mm3,ebp movd mm2,esp // Запоминаем указатели, мало ли, какой код тестить будем L1: rdtsc movd mm7,edx movd mm6,eax // Текущий показатель тиков для выравнивания rdtsc movd mm5,edx movd mm4,eax // Показатель тиков для анализа кода #include "dbg.h" // Указываем файл с фрагментом нашего кода rdtsc movd ecx,mm4 movd ebx,mm5 movd esi,mm6 movd edi,mm7 sub eax,ecx sbb edx,ebx // Вычисляем тики, потраченные на выполнение тест-кода sub ecx,esi sbb ebx,edi // Выравниваем учитыванием затрат на саму RDTSC sub eax,ecx sbb edx,ebx // Если инклад пуст, тут получаем НОЛЬ movd esp,mm2 dec dword ptr[esp] jne L1 // Нужно восстановить стек и проверить вновь, так как конвейер pop ecx // ещё чем-то занимался и показания будут рандомными movd ebp,mm3 mov dword ptr[ticks],eax; mov dword ptr[ticks+4],edx; } SetPriorityClass( GetCurrentProcess( ), IDLE_PRIORITY_CLASS); GetClientRect( hWnd, &rt); hdc = GetDC( hWnd); wsprintf( szInfo, "%013li ", ticks); DrawText( hdc, szInfo, -1, &rt, 0); ReleaseDC( hWin, hdc); break;
Тем самым, я занялся изучением оптимизации на уровне распараллеливания именно на своём процессоре.
P.S.: Данный код был написан специально для анализа отдельных фрагментов алгоритма заливки.
В технологиях меня раздражают две крайности:
1) Великое множество информационных структур*, в котором вслепую разобраться нереально;
2) Избыточная альтернатива XML.
* - Имеются ввиду заголовки файлов мультимедия, чанки видео файлов и т.п.
Так как я работаю на Windows, все мои оценочные задумки опираются так или иначе на идеологию Microsoft. А именно...
Мне нравятся форматы документации CHM и HLP. Но мне не нравится, что для полноценного создания и редактирования этих файлов нужны специализированные утилиты (как htm2chm).
Мне нравится формат GIF. Но мне не нравится, что большинство программ ограничены и имеют триал-версии (как Gif Movie Gear).
Работая с Total Commander'ом и плагинами для прямой навигации в CHM и GIF как с папками файлов, я подумал, а почему бы не разработать кросс-формат, как XML? Так как я всё же не могу задавать выдержку между фреймами в gif-анимации.
Идея проста. Самый универсальный, открытый и де-факто формат уже устоялся: tar / tar+gzip.
По аналогии с форматом JAR Java-приложений, взять привычку представлять файлы любого содержания (PDF, DJVU, MPEG, PNG и т.д.) как обыкновенный tar. Т.е. использовать tar как контейнер, внутри которого могут содержаться десятки или тысячи файлов с фреймами, палитрами, сэмплами или сценариями.
Иными словами, можно было бы написать кросс-утилиту, которая любой файл (от S3M до DLL) конвертирует в tar'абарский, с которым уже работаем сами любыми удобными утилитами. Внутри - обязательно xml-структура (или альтернатива), где расписано всё (от последовательности gif-кадров, avi chunk'ов, до отдельных функции lib-библиотеки).
Внутри будут представлены опять-таки tar'абарские chunk'и и всё остальное в сжатом виде (как есть). Просто будет возможность докопаться вплоть до отдельного кадра в его сжатом виде.
Допустим, мы рас'tar'абарили avi-фильм. Получим tar-архив, внутри которого содержится xml-древо с ветками LIST:hdrl, avih, strl, JUNK, dmlh и т.д. Также вложен другой tar-архив LIST:movi, содержащий другие Chunk-tar-архивы с stream-данными.
Тем самым, ни в коем случае, как это можно ошибочно представить, avi-запись не рас'tar'абарится до космического размера с распаковкой всех кадров. Размер вырастит на долю процентов, в зависимости от количества веток и tar'заголовков под них. Все данные будут оставаться как есть. Просто они извлекутся из общей кучи контейнера.
Так, tar'абарский процесс прежде всего разворачивает все структурные ветки. Но никак не занимается их декомпрессией. Подобные утилиты исследования структуры можно найти, например, в VirtualDub (Hex-редактор, опция RIFF chunk tree).
Примеры
*.bmp
<Bitmap> <BITMAPFILEHEADER> <char name='bfType' value='BM' /> <ulong name='bfSize' value='sizeof(this.parent)' /> <short name='bfReserved1' value='0x0000' /> <short name='bfReserved2' value='0x0000' /> <short name='bfOffBits' value='&this.parent.Data' /> </BITMAPFILEHEADER> <BITMAPINFOHEADER> <ulong name='biSize' value='ulong(sizeof(this))' /> <long name='biWidth' value='long(32)' /> <long name='biHeight' value='long(32)' /> <short name='biPlanes' value='short(1)' /> <short name='biBitCount' value='short(1)' /> <ulong name='biCompression' value='ulong(0)' /> <ulong name='biSizeImage' value='ulong(sizeof(this.parent.Data))' /> <long name='biXPelsPerMeter' value='long(0)' /> <long name='biYPelsPerMeter' value='long(0)' /> <long name='biClrUsed' value='long(0)' /> <long name='biClrImportant' value='long(0)' /> </BITMAPINFOHEADER> <char name='Data' value='file("/p32x32.bit")' /> </Bitmap>
Причем тут вращение, это растеризация окружности
Чето слишком сложно, abs выкини, считать надо только от 0 до 45 град, остальное симметриями вокруг X, Y и сменой местами
Тема в архиве.