Einen Link auflösen - Follow-up

947
Billy ONeal

Ein ähnlicher Code, den ich kürzlich gepostet habe als:

Einen Link auflösen

Ich habe ein anderes Stück Code, das nicht so leicht in eine Methode extrahiert werden kann:

#define THROW_LAST_WINDOWS_ERROR()\
    WindowsApi::Exception::Throw(::GetLastError(), __FILE__,  __LINE__)

#define THROW_MANUAL_WINDOWS_ERROR(x)\
    WindowsApi::Exception::Throw(x, __FILE__,  __LINE__)

Process CreateNormalProcess(
    ProcessSnapshot *parent,
    const UNICODE_STRING& name, 
    const unsigned __int32 pid,
    const std::vector<ToolHelpThread>& threads
    )
{
    std::wstring nameStr(name.Buffer, name.Length/sizeof(wchar_t));
    std::wstring commandLine;
    std::wstring mainModulePath;
    std::wstring error;
    std::vector<Module> modules;
    try
    {
        using WindowsApi::Dll::NtDll;
        using WindowsApi::AutoArray;
        HANDLE hProc = OpenProcess(
            PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE,
            pid);
        if (hProc == 0)
        {
            THROW_LAST_WINDOWS_ERROR();
        }

        //Populate the process environment block
        NtDll ntDll;
        PEB peb;
        AutoArray procInfoBuf = ntDll.NtQueryInformationProcess(
            ProcessBasicInformation,
            hProc,
            sizeof(PROCESS_BASIC_INFORMATION)
            );
        BOOL rpmError = ReadProcessMemory(
            hProc,
            procInfoBuf.GetAs<PROCESS_BASIC_INFORMATION>()->PebBaseAddress,
            &peb,
            sizeof(peb),
            0);
        if (rpmError == 0)
        {
            THROW_LAST_WINDOWS_ERROR();
        }

        RTL_USER_PROCESS_PARAMETERS procParameters;
        rpmError = ReadProcessMemory(hProc,
            peb.ProcessParameters,
            &procParameters,
            sizeof(procParameters),
            0);
        if (rpmError == 0)
        {
            THROW_LAST_WINDOWS_ERROR();
        }

        commandLine.assign(ReadRemoteUnicodeString(hProc,
            procParameters.CommandLine));
        mainModulePath.assign(ReadRemoteUnicodeString(hProc,
            procParameters.ImagePathName));

        PEB_LDR_DATA ldrData;
        rpmError = ReadProcessMemory(hProc,
            peb.Ldr,
            static_cast<void *>(&ldrData),
            sizeof(PEB_LDR_DATA),
            0);
        if (rpmError == 0)
        {
            THROW_LAST_WINDOWS_ERROR();
        }

        void * endPointer = static_cast<void *>
            (reinterpret_cast<char *>(peb.Ldr) + (reinterpret_cast<char *>(&ldrData.InLoadOrderModuleList) - reinterpret_cast<char *>(&ldrData)));
        void * currentListEntry = ldrData.InLoadOrderModuleList.Flink;
        while (currentListEntry != endPointer)
        {
            LDR_MODULE loaderModule;
            rpmError = ReadProcessMemory(
                hProc,
                currentListEntry,
                &loaderModule,
                sizeof(loaderModule),
                0);
            if (rpmError == 0)
            {
                THROW_LAST_WINDOWS_ERROR();
            }
            std::wstring moduleName = ReadRemoteUnicodeString(hProc, loaderModule.FullDllName);
            modules.push_back(Module(
                moduleName,
                loaderModule.BaseAddress,
                loaderModule.SizeOfImage
                ));
            currentListEntry = loaderModule.InLoadOrderModuleList.Flink;
        }

        CloseHandle(hProc);
    }
    catch (const ErrorAccessDeniedException&)
    {
        error.assign(L"ERROR: Could not access additional information because access "
            L"was denied while attempting to open the process. Are you admin? Do you "
            L"have SeDebugPrivilege?");
    }
    catch (const ErrorInvalidParameterException&)
    {
        error.assign(L"ERROR: The process terminated before additional information "
            L"could be extracted");
    }
    catch (const ErrorPartialCopyException&)
    {
        error.assign(L"ERROR: Couldn't copy a data structure from this process. Either "
            L"the process terminated before information extraction, or you are running "
            L"the 32 bit version of pevFind on a 64 bit machine.");
    }

    if (!error.empty())
    {
        if (nameStr.empty())
        {
            nameStr = error;
        }
        if (commandLine.empty())
        {
            commandLine = error;
        }
        if (mainModulePath.empty())
        {
            mainModulePath = error;
        }
    }

    return Process(
        parent,
        pid,
        nameStr, 
        commandLine,
        mainModulePath,
        threads,
        modules);
}

Das Problem hier ist zweifach:

  1. Ich kann die duplizierten if-Blöcke nicht in eine Methode extrahieren, da sie das __FILE__und einbetten müssen __LINE__.
  2. Ich kann die bedingte Prüfung nicht in ein Makro einfügen, da die kontrollierte Methode mehrere Zeilen umfasst:

    MYMACRO(
        Function(
        Call,
        Spanning,
        Multiple,
        Lines));
    

    scheint nicht richtig zu expandieren.

Antworten
9
Sie suchen also nach einer Möglichkeit, das "if" und den kontrollierten Block in einem einzigen Makro zu platzieren? John Dibling vor 10 Jahren 0
@ John: Das wäre eine Lösung für das Problem. Ich möchte nur die wiederholten IFs loswerden - wie ist das keine große Sache. Billy ONeal vor 10 Jahren 0

5 Antworten auf die Frage

7
John Dibling

Wenn die Frage ist, wie man so etwas nimmt:

HANDLE hProc = OpenProcess(
            PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE,
            pid);
        if (hProc == 0)
        {
            THROW_LAST_WINDOWS_ERROR();
        }

Um es auf einen Einzeiler zu reduzieren, verwende ich normalerweise ein verifyMakro:

template<class Eval> RetVal Verify(Eval eval, static const string& file, unsigned line)
{
  if( !eval )
    throw MyException(error_string, file, line);
  else 
    return eval;
}

#define verify(EVAL) (Verify(EVAL, __FILE__, __LINE__))

// ...

HANDLE hProc = verify( OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid ));
Schön, aber würden Sie nicht "VERIFY" anstelle von "Verify" verwenden? Makros sind immer noch Gefahrenstellen, und die Kappen sind ein nützlicher Hinweis. Roddy vor 10 Jahren 0
5
DeadMG

Der MYMACRO-Aufruf sollte in Ordnung sein.

#define D3DCALL(a) { auto __ = a; if (FAILED(__)) DXTrace(__FILE__, __LINE__, __, WIDEN(#a), TRUE); }
D3DCALL(D3DXCreateSphere(
    D3DDev.get(),
    radius,
    slices,
    slices,
    &retval->Mesh._Myptr,
    &retval->Adjacency._Myptr
));

Ich verwende dies ständig in meinem eigenen Quellcode. Sie erhalten Probleme, wenn Sie versuchen, den Makroaufruf bedingt zu kompilieren.

1
indyK1ng

Diese Antwort ist nicht die beste, aber Sie können für jedes Mal, wenn Sie rpmError einen Wert zuweisen, eine neue Variable erstellen und eine if -Anweisung verwenden, bei der die letzte eine Prüfung auf Wert 0 ist.

Hinweis: Dies funktioniert nicht, wenn es unbedingt erforderlich ist, dass diese Fehler vor der nächsten Überprüfung ausgelöst werden.

Nicht wahr. Dies würde an verschiedenen Stellen zu undefiniertem Verhalten führen. Billy ONeal vor 10 Jahren 0
1
greatwolf

Würde so etwas von Charles Antwort aus Ihrem ursprünglichen Beitrag angepasst?

#define THROW_LAST_WINDOWS_ERROR(condition) ThrowOnFail(condition, __FILE__, __LINE__)

void ThrowOnFail(const BOOL condition, LPCSTR file_name, const int file_line)
{
  if (!condition)
    WindowsApi::Exception::Throw(::GetLastError(), file_name, file_line);
}

Die Fehlerbehandlung würde dann etwa so aussehen:

THROW_LAST_WINDOWS_ERROR(ReadProcessMemory(hProc,
                                           procInfoBuf.GetAs<PROCESS_BASIC_INFORMATION>()->PebBaseAddress,
                                           &peb,
                                           sizeof(peb),
                                           0));
THROW_LAST_WINDOWS_ERROR(ReadProcessMemory(hProc,
                                           peb.Ldr,
                                           static_cast<void *>(&ldrData),
                                           sizeof(PEB_LDR_DATA),
                                           0));
// ...
    while (currentListEntry != endPointer)
    {
        LDR_MODULE loaderModule;

        THROW_LAST_WINDOWS_ERROR(ReadProcessMemory(
            hProc,
            currentListEntry,
            &loaderModule,
            sizeof(loaderModule),
            0));

    // ...
    } 
1
MSN

Sie sollten auch eine Variante haben, um Rückgabewerte explizit zu testen. Zum Beispiel CreateFilewird zurückgeben, INVALID_HANDLE_VALUEwas ist !=0.

EDIT: Ah, ich glaube, ich verstehe die Frage jetzt. Sie möchten wissen, wie Sie dies erreichen können:

int x= foo();
if (x==error) { blah(); }

in einem Makro.

Am einfachsten ist es, die Variablendeklaration und die Variableneinstellung aufzuteilen:

int x;
if ((x= foo())==error) { blah(); }

die Sie dann in ein Makro einwickeln können:

#define MYMACRO(x) if ((x)==error) { blah(); }

welche können Sie dann verwenden als:

int x;
MYMACRO(x= foo());