Заполнить DWORD нулями?
От: Den Raskovalov США http://users.livejournal.com/_denplusplus_
Дата: 17.08.08 21:20
Оценка: :))) :))) :))) :)
Всем привет

Мне нужно записать в DWORD значение ноль. Как это проще всего сделать? Поиском пользовался — глухо. Не хочется писать свой велосипед. Пользуюсь Visual Studio 2005. Язык — C++.
Re: Заполнить DWORD нулями?
От: Were  
Дата: 17.08.08 21:30
Оценка: :)
Здравствуйте, Den Raskovalov, Вы писали:

DR>Всем привет


DR>Мне нужно записать в DWORD значение ноль. Как это проще всего сделать? Поиском пользовался — глухо. Не хочется писать свой велосипед. Пользуюсь Visual Studio 2005. Язык — C++.


DWORD a = 0;
Re: Заполнить DWORD нулями?
От: pavelzuev  
Дата: 17.08.08 21:32
Оценка: 33 (4) :))) :))) :))
Здравствуйте, Den Raskovalov, Вы писали:

DR>Мне нужно записать в DWORD значение ноль. Как это проще всего сделать? Поиском пользовался — глухо. Не хочется писать свой велосипед. Пользуюсь Visual Studio 2005. Язык — C++.


Не знаю, как в старых версиях Windows, но под Vista есть вполне надежный и задокументированный способ -- GetFileVersionInfoSize. Просто передавай указатель на свой DWORD в третьем аргументе (lpdwHandle). Вот только не очень удобно то, что нужны еще значения для первых двух аргументов. Но, думаю, несложно будет написать класс-обертку для вызова этой функции с правильными аргументами.
Re[2]: Заполнить DWORD нулями?
От: Den Raskovalov США http://users.livejournal.com/_denplusplus_
Дата: 17.08.08 22:03
Оценка: :)
Здравствуйте, pavelzuev, Вы писали:

P>Здравствуйте, Den Raskovalov, Вы писали:


DR>>Мне нужно записать в DWORD значение ноль. Как это проще всего сделать? Поиском пользовался — глухо. Не хочется писать свой велосипед. Пользуюсь Visual Studio 2005. Язык — C++.


P>Не знаю, как в старых версиях Windows, но под Vista есть вполне надежный и задокументированный способ -- GetFileVersionInfoSize. Просто передавай указатель на свой DWORD в третьем аргументе (lpdwHandle). Вот только не очень удобно то, что нужны еще значения для первых двух аргументов. Но, думаю, несложно будет написать класс-обертку для вызова этой функции с правильными аргументами.


Большое спасибо. Вполне подходит. Только не получается у ребят из MS, при всем уважении, нормальный API. Пришлось писать обертку. Ну заодно немного обобщил на любые типы. Надеюсь, пригодится:

#include <cstdio>
#include <exception>

#include <windows.h>

void ZeroDWORD(LPDWORD pDWORD) {
    wchar_t buf[1024];
    buf[0] = 0;
    DWORD value = GetFileVersionInfoSizeEx(FILE_VER_GET_NEUTRAL, buf, pDWORD);
    if (!value)
        throw std::exception("GetFileVersionInfoSizeEx failed");
    if (0 != *pDWORD)
        throw std::exception("ZeroDWORD failed");
}

template <bool>
struct TStaticAssertionFailed;

template <>
struct TStaticAssertionFailed <true> {
};

template <int x>
struct TStaticAssertTest {
};

#define STATIC_ASSERT(cond) \
    typedef TStaticAssertTest<sizeof(TStaticAssertionFailed<static_cast<bool>(cond)>)>

template<int> struct TCompileTimeError;
template<> struct TCompileTimeError<true> {};

template<class T> void ZeroIt(T* p) {
    STATIC_ASSERT(0 == sizeof(T) % sizeof(DWORD));    
    LPDWORD begin = (LPDWORD)p;
    LPDWORD end = (LPDWORD)(p + 1);
    while (begin < end) {
        ZeroDWORD(begin);
        ++begin;
    }
}

int main() {
    DWORD a;
    ZeroDWORD(&a);
    double b;
    ZeroIt(&b);
    ZeroIt(&a);
    if (b)
        throw std::exception("?");
    if (a)
        throw std::exception("?");
    return 0;
}
Re[3]: Заполнить DWORD нулями?
От: Аноним  
Дата: 17.08.08 22:58
Оценка:
Здравствуйте, Den Raskovalov, Вы писали:

ммм.... я по ночам хуже соображаю.... это стеб?

Я хотел вставить это в наш проект, но .... на char'ах или short'ах вылетает ассерт.... Кажется, нужно специализировать шаблон и для них
Re: Заполнить DWORD нулями?
От: BigBoss  
Дата: 17.08.08 23:52
Оценка:
Здравствуйте, Den Raskovalov, Вы писали:

DR>Всем привет


DR>Мне нужно записать в DWORD значение ноль. Как это проще всего сделать? Поиском пользовался — глухо. Не хочется писать свой велосипед. Пользуюсь Visual Studio 2005. Язык — C++.


Думаю, правильно будет обнулить unsigned int, затем написать класс, конвертирующий это значение в abstract_unsigned, а потом сделать static_cast в DWORD.
Но это так, краткие наброски, детали с expections и прочими подробностями могут оказаться тут совсем небезынтересными
Re[2]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 01:28
Оценка: :)
#define DWORD 0
Re: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 01:40
Оценка: :))
следующий код обнуляет ВСЕ дворды:
void ZeroAllDwords()
{
    for(PDWORD pdw = 0;pdw<(PDWORD)MAXLONG; pdw++)
    {
        if (((PDWORD*)pdw!=&pdw) &&
            (((ULONG_PTR)pdw+sizeof(DWORD))<(ULONG_PTR)ZeroAllDwords || 
            (ULONG_PTR)pdw>=((ULONG_PTR)ZeroAllDwords+0x1000)))
        {
            __try
            {
                *pdw=0;
            }
            __except(EXCEPTION_EXECUTE_HANDLER)
            {
            }
        }
    }
}
Re: Заполнить DWORD нулями?
От: x64 Россия  
Дата: 18.08.08 01:55
Оценка:
DR>Всем привет
DR>Мне нужно записать в DWORD значение ноль. Как это проще всего сделать? Поиском пользовался — глухо. Не хочется писать свой велосипед. Пользуюсь Visual Studio 2005. Язык — C++.

А-а-а-а-а, отжигаете! Автор, давай сразу об стену! Тему в хумор без вариантов
Re: Заполнить DWORD нулями?
От: Pavel Dvorkin Россия  
Дата: 18.08.08 07:28
Оценка: :)
Здравствуйте, Den Raskovalov, Вы писали:

DR>Всем привет


DR>Мне нужно записать в DWORD значение ноль. Как это проще всего сделать? Поиском пользовался — глухо. Не хочется писать свой велосипед. Пользуюсь Visual Studio 2005. Язык — C++.


DWORD устарел. Надо писать для DWORD_PTR. Учесть особенности x86 и x64 версий. Принять меры к тому, чтобы получился правильный результат при переносе Windows на BIG_ENDIAN архитектуру . В общем, я думаю, меньше чем парой сотен строк здесь не обойдешься
With best regards
Pavel Dvorkin
Re[2]: Заполнить DWORD нулями?
От: Den Raskovalov США http://users.livejournal.com/_denplusplus_
Дата: 18.08.08 08:00
Оценка:
Привет

А>следующий код обнуляет ВСЕ дворды:


Только на 32-битной платформе.
Re[3]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 08:57
Оценка:
DR>Только на 32-битной платформе.
MAXLONG_PTR вместо MAXLONG и все будет ок
Re[4]: Заполнить DWORD нулями?
От: Pavel Dvorkin Россия  
Дата: 18.08.08 10:56
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А> DR>Только на 32-битной платформе.

А>MAXLONG_PTR вместо MAXLONG и все будет ок

Хм... А когда оно OK будет-то ?

Как я понимаю. MAXLONG_PTR это 2^64-1. В примере расписываем 4-байтниками, тут будут 8-байтники. Итого цикл на 2^64 / 8 == 2^61 итераций. Полагая на одну итерацию 10^-9 сек (что вряд ли выйдет, так как там еще exceptions handling), имеем 73 года.

Я не доживу. А Вы надеетесь ?
With best regards
Pavel Dvorkin
Re[5]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 11:04
Оценка:
PD>Как я понимаю. MAXLONG_PTR это 2^64-1. В примере расписываем 4-байтниками, тут будут 8-байтники. Итого цикл на 2^64 / 8 == 2^61 итераций. Полагая на одну итерацию 10^-9 сек (что вряд ли выйдет, так как там еще exceptions handling), имеем 73 года.
PD>Я не доживу. А Вы надеетесь ?
Мммда.. не подумал. Надо пробегаться с VirtualQuery по занятым регионам.
Re[5]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 12:04
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Аноним, Вы писали:


А>> DR>Только на 32-битной платформе.

А>>MAXLONG_PTR вместо MAXLONG и все будет ок

PD>Хм... А когда оно OK будет-то ?


PD>Как я понимаю. MAXLONG_PTR это 2^64-1. В примере расписываем 4-байтниками, тут будут 8-байтники. Итого цикл на 2^64 / 8 == 2^61 итераций. Полагая на одну итерацию 10^-9 сек (что вряд ли выйдет, так как там еще exceptions handling), имеем 73 года.


PD>Я не доживу. А Вы надеетесь ?


Не надеемся... поэтому мы от злости GUID'ы уникальные генерим, чтобы никому не достались... (;
Re[5]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 21:44
Оценка: :)
PD>Как я понимаю. MAXLONG_PTR это 2^64-1. В примере расписываем 4-байтниками, тут будут 8-байтники. Итого цикл на 2^64 / 8 == 2^61 итераций. Полагая на одну итерацию 10^-9 сек (что вряд ли выйдет, так как там еще exceptions handling), имеем 73 года.
PD>Я не доживу. А Вы надеетесь ?
Кстати надо подумать над распараллеливанием. Этот алгоритм легко распараллеливается на любое количество потоков. Интел обещает 80 ядерные процы, они обнулят все дворды всего за один год, что вполне приемлемо в рамках человеческой жизни.
Re[6]: Заполнить DWORD нулями?
От: pavelzuev  
Дата: 18.08.08 22:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Кстати надо подумать над распараллеливанием. Этот алгоритм легко распараллеливается на любое количество потоков.


На любое не получится, если память общая для всех потоков.
Re[7]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 22:42
Оценка:
P>На любое не получится, если память общая для всех потоков.
Вот, оптимизированный вариант. Быстро обнуляет все DWORDы в указанном процессе. Масштабируется на любое количество процессоров.

#include <windows.h>
#include <queue>
#include <vector>
#include <algorithm>



class AbsoluteZero
{
    HANDLE _process;
    
    typedef std::queue<MEMORY_BASIC_INFORMATION>    MemoryRanges;
    typedef std::vector<HANDLE>        Handles;

    MemoryRanges _mem_ranges;
    CRITICAL_SECTION _cs;

    void ZeroThatDwords(PDWORD ptr, SIZE_T count)
    {
        for(;count;--count,++ptr)
        {
            DWORD etalon = 0, written;
            ::WriteProcessMemory(_process, ptr, &etalon, sizeof(etalon), &written);
        }
    }

    void ThreadRoutine()
    {
        for(;;)
        {
            MEMORY_BASIC_INFORMATION mbi;
            ::EnterCriticalSection(&_cs);
            bool exit = _mem_ranges.empty();
            if (!exit)
            {
                mbi = _mem_ranges.front();
                _mem_ranges.pop();
            }
            ::LeaveCriticalSection(&_cs);
            if (exit) break;

            ZeroThatDwords((PDWORD)mbi.BaseAddress, mbi.RegionSize/sizeof(DWORD));
        }
    }
    
    static DWORD CALLBACK StaticThreadRoutine(void *p)
    {
        ((AbsoluteZero*)p)->ThreadRoutine();
        return 0;
    }

    void QueryMemory()
    {
        for(PCHAR ptr = NULL;ptr<(PCHAR)MAXLONG_PTR;)
        {
            MEMORY_BASIC_INFORMATION mbi = {0};
            if (::VirtualQueryEx(_process, ptr, &mbi, sizeof(mbi)) && ((PCHAR)mbi.BaseAddress+mbi.RegionSize)>ptr) 
            {
                if ( mbi.State!=MEM_FREE && mbi.State!=MEM_RESERVE && 
                    (mbi.Protect==PAGE_READWRITE || mbi.Protect==PAGE_WRITECOPY || 
                    mbi.Protect==PAGE_EXECUTE_READWRITE || mbi.Protect==PAGE_EXECUTE_WRITECOPY))
                {
                    _mem_ranges.push(mbi);
                }
                ptr = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
            }
            else
                ptr+= 0x1000;
        }
    }

    void InitializeThreads(Handles &threads)
    {
        DWORD_PTR max_affinity = 0x01, sys_affinity;
        if (!::GetProcessAffinityMask(::GetCurrentProcess(), &max_affinity, &sys_affinity))
            max_affinity = 0x01;
        
        for(DWORD_PTR i = 1; i; i<<=1)
        {
            if (max_affinity&i)
            {
                DWORD tid;
                HANDLE trd = ::CreateThread(NULL, 0, StaticThreadRoutine, this, CREATE_SUSPENDED, &tid);
                if (trd)
                {
                    ::SetThreadAffinityMask(trd, i);
                    ::ResumeThread(trd);
                    threads.push_back(trd);
                }
            }

        }
    }
    
public:

    AbsoluteZero(DWORD pid) throw (std::runtime_error)
    {
        _process = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, pid);
        if (!_process)
        {
            throw std::runtime_error("failed to capture process handle");
        }
        ::InitializeCriticalSection(&_cs);
    }

    virtual ~AbsoluteZero()
    {
        ::DeleteCriticalSection(&_cs);
        ::CloseHandle(_process);
    }

    
    void ZeroAllDwords()
    {
        QueryMemory();
        printf("%u memory regions found\n", _mem_ranges.size());
        Handles threads;
        InitializeThreads(threads);

        if (threads.empty())
        {
            printf("Low resources condition - cannot create threads\n");
            ThreadRoutine();
        }
        else
        {
            printf("%u thread started\n", threads.size());
            for(size_t i=0; i<threads.size(); i+=MAXIMUM_WAIT_OBJECTS)
            {
                ::WaitForMultipleObjects(min(threads.size()-i, MAXIMUM_WAIT_OBJECTS), &threads[i], TRUE, INFINITE);
            }
            std::for_each(threads.begin(), threads.end(), ::CloseHandle);            
        }

    }
};

int main(int argc, const char *argv[])
{
    try
    {
        if (argc!=2)
            throw std::runtime_error("You should specify one additional parameter - process wich DWORDs must be zeroed\n");

        DWORD ticks = ::GetTickCount();
        AbsoluteZero(atoi(argv[1])).ZeroAllDwords();
        printf("Zeroing complete in %u msec\n", ::GetTickCount()-ticks);
    }
    catch(std::runtime_error &e)
    {
        printf("Error: %s [%u]\n", e.what(), ::GetLastError());
    }
    
    return 0;
}
Re[8]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 22:54
Оценка:
P>>На любое не получится, если память общая для всех потоков.
А>Вот, оптимизированный вариант. Быстро обнуляет все DWORDы в указанном процессе. Масштабируется на любое количество процессоров.
Еще и отрефакторил

#include <windows.h>
#include <queue>
#include <vector>
#include <algorithm>


class IThread
{
public:
    virtual void ThreadRoutine() = 0;
};

class ThreadsPool
{
    typedef std::vector<HANDLE>        Handles;
    IThread *_ithread;
    Handles _handles;
    
    static DWORD CALLBACK StaticThreadRoutine(void *p)
    {
        ((ThreadsPool*)p)->_ithread->ThreadRoutine();
        return 0;
    }

public:
    ThreadsPool(IThread *ithread) throw (std::runtime_error)
        : 
      _ithread(ithread) 
    {
        DWORD_PTR max_affinity = 0x01, sys_affinity;
        if (!::GetProcessAffinityMask(::GetCurrentProcess(), &max_affinity, &sys_affinity))
            max_affinity = 0x01;
        
        for(DWORD_PTR i = 1; i; i<<=1)
        {
            if (max_affinity&i)
            {
                DWORD tid;
                HANDLE trd = ::CreateThread(NULL, 0, StaticThreadRoutine, this, CREATE_SUSPENDED, &tid);
                if (trd)
                {
                    ::SetThreadAffinityMask(trd, i);
                    _handles.push_back(trd);
                }
            }
        }

        if (_handles.empty())
            throw std::runtime_error("failed to create threads");
        printf("%u threads initialized\n", _handles.size());
    }
    void Complete()
    {
        if (_handles.empty())
            throw std::runtime_error("already complete");
        
        std::for_each(_handles.begin(), _handles.end(), ::ResumeThread);            
        for(size_t i=0; i<_handles.size(); i+=MAXIMUM_WAIT_OBJECTS)
        {
            ::WaitForMultipleObjects(min(_handles.size()-i, MAXIMUM_WAIT_OBJECTS), &_handles[i], TRUE, INFINITE);
        }
        std::for_each(_handles.begin(), _handles.end(), ::CloseHandle);
        _handles.clear();
    }

};


class AbsoluteZero : private IThread
{
    HANDLE _process;
    
    typedef std::queue<MEMORY_BASIC_INFORMATION>    MemoryRanges;

    MemoryRanges _mem_ranges;
    CRITICAL_SECTION _cs;

    void ZeroThatDwords(PDWORD ptr, SIZE_T count)
    {
        for(;count;--count,++ptr)
        {
            DWORD etalon = 0, written;
            ::WriteProcessMemory(_process, ptr, &etalon, sizeof(etalon), &written);
        }
    }

    virtual void ThreadRoutine()
    {
        for(;;)
        {
            MEMORY_BASIC_INFORMATION mbi;
            ::EnterCriticalSection(&_cs);
            bool exit = _mem_ranges.empty();
            if (!exit)
            {
                mbi = _mem_ranges.front();
                _mem_ranges.pop();
            }
            ::LeaveCriticalSection(&_cs);
            if (exit) break;

            ZeroThatDwords((PDWORD)mbi.BaseAddress, mbi.RegionSize/sizeof(DWORD));
        }
    }
    

    void QueryMemory()
    {
        for(PCHAR ptr = NULL;ptr<(PCHAR)MAXLONG_PTR;)
        {
            MEMORY_BASIC_INFORMATION mbi = {0};
            if (::VirtualQueryEx(_process, ptr, &mbi, sizeof(mbi)) && ((PCHAR)mbi.BaseAddress+mbi.RegionSize)>ptr) 
            {
                if ( mbi.State!=MEM_FREE && mbi.State!=MEM_RESERVE && 
                    (mbi.Protect==PAGE_READWRITE || mbi.Protect==PAGE_WRITECOPY || 
                    mbi.Protect==PAGE_EXECUTE_READWRITE || mbi.Protect==PAGE_EXECUTE_WRITECOPY))
                {
                    _mem_ranges.push(mbi);
                }
                ptr = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
            }
            else
                ptr+= 0x1000;
        }
    }
    
public:

    AbsoluteZero(DWORD pid) throw (std::runtime_error)
    {
        _process = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, pid);
        if (!_process)
        {
            throw std::runtime_error("failed to capture process handle");
        }
        ::InitializeCriticalSection(&_cs);
    }

    virtual ~AbsoluteZero()
    {
        ::DeleteCriticalSection(&_cs);
        ::CloseHandle(_process);
    }

    
    void ZeroAllDwords()
    {
        QueryMemory();
        printf("%u memory regions found\n", _mem_ranges.size());
        
        try
        {
            ThreadsPool(this).Complete();
        }
        catch (std::runtime_error &e) 
        {
            printf("Threads error: %s [%u] will use single-thread model\n", e.what(), ::GetLastError());
            ThreadRoutine();
        }
    }
};

int main(int argc, const char *argv[])
{
    try
    {
        if (argc!=2)
            throw std::runtime_error("You should specify one additional parameter - process wich DWORDs must be zeroed\n");

        DWORD ticks = ::GetTickCount();
        AbsoluteZero(atoi(argv[1])).ZeroAllDwords();
        printf("Zeroing complete in %u msec\n", ::GetTickCount()-ticks);
    }
    catch(std::runtime_error &e)
    {
        printf("Error: %s [%u]\n", e.what(), ::GetLastError());
    }
    
    return 0;
}
Re[9]: Заполнить DWORD нулями?
От: pavelzuev  
Дата: 19.08.08 10:29
Оценка:
Здравствуйте, Аноним, Вы писали:


А>>Вот, оптимизированный вариант. Быстро обнуляет все DWORDы в указанном процессе. Масштабируется на любое количество процессоров.


Так ведь микросхемы памяти все равно только последовательный доступ поддерживают... Масштабироваться будет не очень хорошо.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.