Разрешение ссылки

Как я могу очистить это?

std::wstring LinkResolve::ResolveLink( const std::wstring& source ) const
{
    HRESULT errorCheck;
 wchar_t linkTarget[MAX_PATH];
 wchar_t expandedTarget[MAX_PATH];
 wchar_t arguments[INFOTIPSIZE];
    ATL::CComPtr<IPersistFile> ipf;
    errorCheck = ipf.CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER);
    if (!SUCCEEDED(errorCheck))
    {
        throw _com_error(errorCheck);
    }
    errorCheck = ipf->Load(source.c_str(), 0);
    ATL::CComPtr<IShellLink> shellLink;
    errorCheck = ipf->QueryInterface(&shellLink);
    if (!SUCCEEDED(errorCheck))
    {
        throw _com_error(errorCheck);
    }
    errorCheck = shellLink->Resolve(0, SLR_NO_UI);
    if (!SUCCEEDED(errorCheck))
    {
        throw _com_error(errorCheck);
    }
    errorCheck = shellLink->GetPath(linkTarget, MAX_PATH, 0, SLGP_RAWPATH);
    if (!SUCCEEDED(errorCheck))
    {
        throw _com_error(errorCheck);
    }
    ExpandEnvironmentStringsW(linkTarget, expandedTarget, MAX_PATH);
    errorCheck = shellLink->GetArguments(arguments, INFOTIPSIZE);
    if (SUCCEEDED(errorCheck))
    {
        return std::wstring(expandedTarget) + L" " + arguments;
    }
    else
    {
        return expandedTarget;
    }
}
36 голосов | спросил Billy ONeal 27 Jam1000000amThu, 27 Jan 2011 10:26:21 +030011 2011, 10:26:21

6 ответов


56

Лично я бы написал простую функцию:

void ThrowOnFail( HRESULT hrcode )
{
    if (FAILED(hrcode))
        throw _com_error(hrcode);
}

Затем вызовы функций становятся:

ThrowOnFail( ipf.CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER) );
ThrowOnFail( ipf->Load(source.c_str(), 0) );
ATL::CComPtr<IShellLink> shellLink;
ThrowOnFail( ipf->QueryInterface(&shellLink) );
ThrowOnFail( shellLink->Resolve(0, SLR_NO_UI) );
ThrowOnFail( shellLink->GetPath(linkTarget, MAX_PATH, 0, SLGP_RAWPATH) );

Кстати, вы пропустили проверку errorCheck после Load. Это легче обнаружить с помощью функции проверки.

ответил CB Bailey 27 Jam1000000amThu, 27 Jan 2011 10:41:45 +030011 2011, 10:41:45
18

Если я нахожу, что сам повторяю одно и то же снова и снова, я обычно помещаю его в действие. Даже если эта функция в вашем случае проста:

void check(HRESULT result) {
    if (FAILED(result)) {
        throw _com_error(result);
    }
}

Я думаю, что код выглядит довольно прямо, если вы повторно используете код проверки ошибок. Я не знаком с API, который вы используете, поэтому я не могу комментировать, есть ли другой способ его использования, который может привести к созданию более чистого кода.

ответил Arlaharen 27 Jam1000000amThu, 27 Jan 2011 10:40:39 +030011 2011, 10:40:39
6

По крайней мере, при использовании DirectX я использую макрос.

#define D3DCALL(a) { auto __ = a; if (FAILED(__)) DXTrace(__FILE__, __LINE__, __, WIDEN(#a), TRUE); }

Вы можете полюбить и использовать тип с оператором = (HRESULT), чтобы выполнить проверку.

ответил DeadMG 27 Jam1000000amThu, 27 Jan 2011 10:42:57 +030011 2011, 10:42:57
3

Я помню что-то вроде этого раньше:

class XHR
{
public:
   XHR() {};
   ~XHR() {};

   operator HRESULT() { return hr };

   HRESULT& operator =(const HRESULT& rhs)
   {
       hr = rhs;
       if (FAILED(hr)
          throw _com_error(hr);
   }

private:
   HRESULT hr;
}

Затем вы можете написать:

std::wstring LinkResolve::ResolveLink( const std::wstring& source ) const
{
    XHR errorCheck;   // instead of HRESULT errorCheck

    wchar_t linkTarget[MAX_PATH];
    wchar_t expandedTarget[MAX_PATH];
    wchar_t arguments[INFOTIPSIZE];
    ATL::CComPtr<IPersistFile> ipf;


    errorCheck = ipf.CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER);
    errorCheck = ipf->Load(source.c_str(), 0);

    ATL::CComPtr<IShellLink> shellLink;

    errorCheck = ipf->QueryInterface(&shellLink);
    errorCheck = shellLink->Resolve(0, SLR_NO_UI);
    errorCheck = shellLink->GetPath(linkTarget, MAX_PATH, 0, SLGP_RAWPATH);

    ExpandEnvironmentStringsW(linkTarget, expandedTarget, MAX_PATH);

    try {
       errorCheck = shellLink->GetArguments(arguments, INFOTIPSIZE);
       return std::wstring(expandedTarget) + L" " + arguments;
    }
    catch (const XHR&)
    {
        return expandedTarget;
    }
}

Поэтому в любое время, когда HRESULT указывает на сбой, он автоматически преобразует его в _com_error для вас и бросает.

ответил MarkS 11 J0000006Europe/Moscow 2011, 22:40:43
1

Ошибки проверки не все одинаковы. иногда вы действуете на специальных возвращенных HResults. иногда есть ELSE. когда-нибудь вы хотите зарегистрировать ошибку, иногда вы этого не делаете.

Кроме того - хотя и вряд ли будет актуальным в мире com /atl - вызов функции имеет свои затраты на производительность.

, поэтому я предпочитаю использовать, если после вызова вместо вызова функции. Сколько вы экономите? набрав 10 символов?

ответил Dani 27 Jam1000000amThu, 27 Jan 2011 11:14:40 +030011 2011, 11:14:40
1

Я думаю, что вы можете сделать многое из этого, используя Поддержка компилятора com вот пример.

#import "CLSID:lnkfile" //use the clsid of the ShellLink class.

IPersistFilePtr ptr = IPersistFilePtr.CreateInstance(...);

_com_ptr_t::CreateInstance() генерирует исключение (типа _com_error, если вызов завершается с ошибкой)

Все остальные ifs в вашем коде могут быть заменены с помощью интеллектуальных указателей, созданных с помощью #import. Я знаю, что я немного скуден по деталям, но прошло много времени с тех пор, как я коснулся COM.

ответил Sandeep Datta 27 Jpm1000000pmThu, 27 Jan 2011 16:59:01 +030011 2011, 16:59:01

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132