সি ++ এ কীভাবে ফর্ম্যাটমেসেজ () সঠিকভাবে ব্যবহার করব?


90

ছাড়া :

  • এমএফসি
  • এটিএল

এটির FormatMessage()ত্রুটিযুক্ত পাঠ্য পেতে আমি কীভাবে ব্যবহার করতে পারি HRESULT?

 HRESULT hresult = application.CreateInstance("Excel.Application");

 if (FAILED(hresult))
 {
     // what should i put here to obtain a human-readable
     // description of the error?
     exit (hresult);
 }

উত্তর:


134

HRESULTএটির জন্য সিস্টেম থেকে ত্রুটি বার্তা ফিরে পাওয়ার উপযুক্ত উপায় এখানে রয়েছে (এক্ষেত্রে নামকরণ করা হ্রেসোল্ট, বা আপনি এটির সাথে প্রতিস্থাপন করতে পারেন GetLastError()):

LPTSTR errorText = NULL;

FormatMessage(
   // use system message tables to retrieve error text
   FORMAT_MESSAGE_FROM_SYSTEM
   // allocate buffer on local heap for error text
   |FORMAT_MESSAGE_ALLOCATE_BUFFER
   // Important! will fail otherwise, since we're not 
   // (and CANNOT) pass insertion parameters
   |FORMAT_MESSAGE_IGNORE_INSERTS,  
   NULL,    // unused with FORMAT_MESSAGE_FROM_SYSTEM
   hresult,
   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
   (LPTSTR)&errorText,  // output 
   0, // minimum size for output buffer
   NULL);   // arguments - see note 
   
if ( NULL != errorText )
{
   // ... do something with the string `errorText` - log it, display it to the user, etc.

   // release memory allocated by FormatMessage()
   LocalFree(errorText);
   errorText = NULL;
}

এই এবং ডেভিড হানকের উত্তরের মধ্যে প্রধান পার্থক্য হ'ল FORMAT_MESSAGE_IGNORE_INSERTSপতাকা ব্যবহার । কীভাবে সন্নিবেশগুলি ব্যবহার করা উচিত সে সম্পর্কে এমএসডিএন কিছুটা অস্পষ্ট, তবে রেমন্ড চেন উল্লেখ করেছেন যে কোনও সিস্টেমের বার্তাটি পুনরুদ্ধার করার সময় আপনার সেগুলি কখনই ব্যবহার করা উচিত নয় , কারণ সিস্টেমটি কী সন্নিবেশকে প্রত্যাশা করে তা জানার কোনও উপায় নেই।

এফডাব্লুআইডাব্লু, আপনি যদি ভিজ্যুয়াল সি ++ ব্যবহার করেন তবে আপনি _com_errorক্লাসটি ব্যবহার করে আপনার জীবনকে আরও সহজ করে তুলতে পারেন :

{
   _com_error error(hresult);
   LPCTSTR errorText = error.ErrorMessage();
   
   // do something with the error...

   //automatic cleanup when error goes out of scope
}

আমি যতটা অবগত আছি সরাসরি এমএফসি বা এটিএলের অংশ নয় of


8
সাবধান: এই কোডটি একটি Win32 ত্রুটি কোডের জায়গায় hResult ব্যবহার করে: এগুলি আলাদা জিনিস! আপনি যা ঘটেছে তার চেয়ে সম্পূর্ণ ভিন্ন ত্রুটির পাঠ্য পেতে পারেন।
আন্দ্রে বেলোগোর্টসফ

4
দুর্দান্ত পয়েন্ট, @ আন্ড্রেই - এবং সত্যই, ত্রুটিটি যদি একটি win32 ত্রুটি হয় তবে এই রুটিনটি কেবল তখনই সফল হবে যদি এটি একটি সিস্টেম ত্রুটি হয় - একটি ত্রুটি-ত্রুটি-পরিচালনা ব্যবস্থাটি ত্রুটির উত্স সম্পর্কে সচেতন হওয়া দরকার, কোডটি পরীক্ষা করুন ফর্ম্যাটম্যাসেজ কল করার আগে এবং সম্ভবত অন্য উত্সগুলি জিজ্ঞাসা করুন।
শোগ 9

4
@ আন্দ্রেই বেলগোর্টসিফ প্রতিটি ক্ষেত্রে কী ব্যবহার করবেন তা আমি কীভাবে জানতে পারি? উদাহরণস্বরূপ, RegCreateKeyExa প্রদান করে LONG। এর দস্তাবেজগুলি বলছে যে আমি FormatMessageত্রুটিটি পুনরুদ্ধার করতে ব্যবহার করতে পারি তবে আমাকে কাস্ট করতে LONGহবে HRESULT
সিএসএল

ফর্ম্যাটম্যাসেজ () একটি ডিডাবর্ড, @ এসএসএল, একটি স্বাক্ষরবিহীন পূর্ণসংখ্যা গ্রহণ করে যা একটি বৈধ ত্রুটি কোড হিসাবে ধরে নেওয়া হয়। সমস্ত রিটার্ন মান - বা এই বিষয়ে HREilersTS - বৈধ ত্রুটি কোড হবে না; সিস্টেমটি ধরে নিয়েছে আপনি যাচাই করেছেন যে এটি ফাংশনটি কল করার আগে। RegCreateKeyEx এর জন্য দস্তাবেজগুলিকে নির্দিষ্ট করা উচিত যখন প্রত্যাবর্তনের মানটিকে ত্রুটি হিসাবে ব্যাখ্যা করা যায় ... প্রথমে সেই চেকটি সম্পাদন করুন এবং তারপরেই ফর্ম্যাটমেসেজ কল করুন।
শোগ 9

4
এমএসডিএন প্রকৃতপক্ষে এখন একই কোডে তাদের সংস্করণ সরবরাহ করে
ahmd0

14

মনে রাখবেন যে আপনি নিম্নলিখিতগুলি করতে পারবেন না:

{
   LPCTSTR errorText = _com_error(hresult).ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}

ক্লাসটি স্ট্যাকের উপর তৈরি এবং ধ্বংস হওয়ার সাথে সাথে ত্রুটিটি অবৈধ অবস্থানে নির্দেশ করে leaving বেশিরভাগ ক্ষেত্রে এই অবস্থানটিতে ত্রুটিযুক্ত স্ট্রিং থাকবে তবে থ্রেডযুক্ত অ্যাপ্লিকেশনগুলি লেখার সময় সেই সম্ভাবনাটি খুব দ্রুত হ্রাস পাবে।

সুতরাং সর্বদা উপরের শোগ 9 এর উত্তর অনুসারে এটি করুন:

{
   _com_error error(hresult);
   LPCTSTR errorText = error.ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}

7
_com_errorবস্তু স্ট্যাক তৈরি করা হয় উভয় আপনার উদাহরণ। আপনি যে শব্দটির সন্ধান করছেন তা অস্থায়ী । পূর্ববর্তী উদাহরণে, অবজেক্টটি একটি অস্থায়ী যা বিবৃতিটির শেষে ধ্বংস হয়।
রব কেনেডি

হ্যাঁ, মানে। তবে আমি আশা করি বেশিরভাগ লোক কমপক্ষে কোড থেকে এটি নির্ধারণ করতে সক্ষম হবেন। প্রযুক্তিগতভাবে অস্থায়ীতা বিবৃতিটির শেষে ধ্বংস হয় না, তবে ক্রম বিন্দুর শেষে হয়। (যা এই উদাহরণে একই জিনিস তাই এটি কেবল চুলের বিভাজন।)
মারিয়াস

4
আপনি যদি এটি নিরাপদ করতে চান (সম্ভবত খুব দক্ষ না হন ) তবে আপনি এটি সি ++ এ করতে পারেন:std::wstring strErrorText = _com_error(hresult).ErrorMessage();
আহমড0

11

এটা চেষ্টা কর:

void PrintLastError (const char *msg /* = "Error occurred" */) {
        DWORD errCode = GetLastError();
        char *err;
        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                           NULL,
                           errCode,
                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
                           (LPTSTR) &err,
                           0,
                           NULL))
            return;

        static char buffer[1024];
        _snprintf(buffer, sizeof(buffer), "ERROR: %s: %s\n", msg, err);
        OutputDebugString(buffer); // or otherwise log it
        LocalFree(err);
}

অকার্যকর হ্যান্ডললেস্টেরর (হেসল্ট)?
হারুন

4
নিশ্চয় আপনি এই রূপান্তরগুলি নিজেই করতে পারেন।
oefe

@ অ্যাটক্লিন: আপনি যদি কোনও প্যারামিটার থেকে হ্রেসাল্ট ব্যবহার করতে চান তবে আপনার অবশ্যই প্রথম লাইনের দরকার নেই (গেটলাস্টআরার ())।
ডেভিড হানাক

4
গেটলাস্টআরআর এইচআরসাল্ট ফিরিয়ে দেয় না। এটি একটি Win32 ত্রুটি কোড দেয়। নাম মুদ্রণযন্ত্রের নাম পছন্দ করতে পারে কারণ এটি আসলে কিছুই হ্যান্ডেল করে না । এবং অবশ্যই FORMAT_MESSAGE_IGNORE_INSERTS ব্যবহার নিশ্চিত করুন।
রব কেনেডি

আপনার সাহায্যের লোকদের জন্য ধন্যবাদ :) - অনেক প্রশংসিত
অ্যারোন

5

এটি উত্তরগুলির সংখ্যাগরিষ্ঠের চেয়ে আরও একটি সংযোজন, তবে ফাংশনটি LocalFree(errorText)ব্যবহার না HeapFreeকরে:

::HeapFree(::GetProcessHeap(), NULL, errorText);

এমএসডিএন সাইট থেকে :

উইন্ডোজ 10 :
লোকালফ্রি আধুনিক এসডিকে নেই, সুতরাং ফলাফল বাফারটি মুক্ত করতে এটি ব্যবহার করা যাবে না। পরিবর্তে, হিপফ্রি (গেটপ্রসেসহীপ (), বরাদ্দকৃত ম্যাসেজ) ব্যবহার করুন। এই ক্ষেত্রে, এটি মেমরিতে লোকালফ্রি কল করার সমান।

আপডেটটি
আমি খুঁজে পেয়েছি যে LocalFreeএসডিকে 10.0.10240.0 সংস্করণে রয়েছে (উইনবেস.এইচ 1108 লাইন)। তবে উপরের লিঙ্কটিতে সতর্কতাটি এখনও বিদ্যমান।

#pragma region Desktop Family or OneCore Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)

WINBASEAPI
_Success_(return==0)
_Ret_maybenull_
HLOCAL
WINAPI
LocalFree(
    _Frees_ptr_opt_ HLOCAL hMem
    );

#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
#pragma endregion

আপডেট 2
আমি FORMAT_MESSAGE_MAX_WIDTH_MASKসিস্টেম বার্তাগুলিতে লাইন ব্রেকগুলি পরিপাটি করার জন্য পতাকা ব্যবহার করার পরামর্শ দেব ।

এমএসডিএন সাইট থেকে :

FORMAT_MESSAGE_MAX_WIDTH_MASK
ফাংশন বার্তা সংজ্ঞা পাঠ্যে নিয়মিত লাইন বিরতি উপেক্ষা করে। ফাংশনটি হার্ড-কোডড লাইন ব্রেকগুলি বার্তা সংজ্ঞা পাঠ্যে আউটপুট বাফারে সংরক্ষণ করে। ফাংশনটি কোনও নতুন লাইন বিরতি জেনারেট করে না।

আপডেট 3
এমন 2 টি সিস্টেম ত্রুটি কোড রয়েছে যা প্রস্তাবিত পদ্ধতির সাহায্যে সম্পূর্ণ বার্তাটি ফেরত না:

ফর্ম্যাটম্যাসেজ কেবল ERROR_SYSTEM_PROCESSQLMMINATED এবং ERROR_UNHANDLED_EXCEPTION সিস্টেম ত্রুটির জন্য আংশিক বার্তা তৈরি করে?


4

এখানে ডেভিডের ফাংশনের একটি সংস্করণ যা ইউনিকোড পরিচালনা করে

void HandleLastError(const TCHAR *msg /* = "Error occured" */) {
    DWORD errCode = GetLastError();
    TCHAR *err;
    if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                       NULL,
                       errCode,
                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
                       (LPTSTR) &err,
                       0,
                       NULL))
        return;

    //TRACE("ERROR: %s: %s", msg, err);
    TCHAR buffer[1024];
    _sntprintf_s(buffer, sizeof(buffer), _T("ERROR: %s: %s\n"), msg, err);
    OutputDebugString(buffer);
    LocalFree(err);

}


4
নোট করুন যে আপনি _sntprintf_sইউনিকোডের ক্ষেত্রে সঠিক বাফার আকারটি পাস করছেন না । ফাংশনটি অক্ষরের সংখ্যা নেয়, সুতরাং আপনি চান _countofবা পরিবর্তে ARRAYSIZEওরফে । sizeof(buffer) / sizeof(buffer[0])sizeof
থ্যাফব্বা

4

যেহেতু সি ++ ১১, আপনি এর পরিবর্তে স্ট্যান্ডার্ড লাইব্রেরিটি ব্যবহার করতে পারেন FormatMessage:

#include <system_error>

std::string message = std::system_category().message(hr)

2

অন্যান্য উত্তরে যেমন উল্লেখ করা হয়েছে:

  • FormatMessageDWORDএকটি HRESULT(সাধারণত GetLastError()) নয় ফলাফল গ্রহণ করে ।
  • LocalFree বরাদ্দ করা মেমরি মুক্তি প্রয়োজন FormatMessage

আমি উপরোক্ত বিষয়গুলি নিয়েছি এবং আমার উত্তরের জন্য আরও কয়েকটি যুক্ত করেছি:

  • FormatMessageপ্রয়োজনীয় হিসাবে মেমরি বরাদ্দ এবং প্রকাশ করতে একটি শ্রেণীর মধ্যে মোড়ানো rap
  • অপারেটর ওভারলোড ব্যবহার করুন (যেমন operator LPTSTR() const { return ...; }আপনার ক্লাসটি স্ট্রিং হিসাবে ব্যবহৃত হতে পারে
class CFormatMessage
{
public:
    CFormatMessage(DWORD dwMessageId,
                   DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)) :
        m_text(NULL)
    {
        Assign(dwMessageId, dwLanguageId);
    }

    ~CFormatMessage()
    {
        Clear();
    }

    void Clear()
    {
        if (m_text)
        {
            LocalFree(m_text);
            m_text = NULL;
        }
    }

    void Assign(DWORD dwMessageId,
                DWORD dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT))
    {
        Clear();
        DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM
            | FORMAT_MESSAGE_ALLOCATE_BUFFER
            | FORMAT_MESSAGE_IGNORE_INSERTS,
        FormatMessage(
            dwFlags,
            NULL,
            dwMessageId,
            dwLanguageId,
            (LPTSTR) &m_text,
            0,
            NULL);
    }

    LPTSTR text() const { return m_text; }
    operator LPTSTR() const { return text(); }

protected:
    LPTSTR m_text;

};

উপরের কোডটির আরও একটি সম্পূর্ণ সংস্করণ এখানে পান: https://github.com/stephenquan/ FormatMessage

উপরের শ্রেণীর সাথে, ব্যবহারটি সহজভাবে:

    std::wcout << (LPTSTR) CFormatMessage(GetLastError()) << L"\n";

0

নীচের কোডটি হ'ল সি ++ সমতুল্য যা আমি মাইক্রোসফ্টের ত্রুটিযুক্তি () এর বিপরীতে লিখেছি কিন্তু সমস্ত ম্যাক্রোগগুলি এড়াতে এবং ইউনিকোড ব্যবহার করতে কিছুটা পরিবর্তিত হয়েছিল। এখানে ধারণাটি অপ্রয়োজনীয় কাস্ট এবং ম্যালোকগুলি এড়ানো avoid আমি সমস্ত সি ক্যাসেটের হাত থেকে বাঁচতে পারিনি তবে এটিই সবচেয়ে ভাল mus ফর্ম্যাটম্যাসেজডাব্লু () এর সাথে সম্পর্কিত, যার বিন্যাস ফাংশন এবং গেটলাস্টআরার () থেকে ত্রুটি আইডি দ্বারা বরাদ্দ করার জন্য একটি পয়েন্টার প্রয়োজন। স্ট্যাটিক_কাস্টের পরে পয়েন্টারটি স্বাভাবিক ডাব্লুচিকার_ট পয়েন্টারের মতো ব্যবহার করা যায়।

#include <string>
#include <windows.h>

void __declspec(noreturn) error_exit(const std::wstring FunctionName)
{
    // Retrieve the system error message for the last-error code
    const DWORD ERROR_ID = GetLastError();
    void* MsgBuffer = nullptr;
    LCID lcid;
    GetLocaleInfoEx(L"en-US", LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (wchar_t*)&lcid, sizeof(lcid));

    //get error message and attach it to Msgbuffer
    FormatMessageW(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL, ERROR_ID, lcid, (wchar_t*)&MsgBuffer, 0, NULL);
    //concatonate string to DisplayBuffer
    const std::wstring DisplayBuffer = FunctionName + L" failed with error " + std::to_wstring(ERROR_ID) + L": " + static_cast<wchar_t*>(MsgBuffer);

    // Display the error message and exit the process
    MessageBoxExW(NULL, DisplayBuffer.c_str(), L"Error", MB_ICONERROR | MB_OK, static_cast<WORD>(lcid));

    ExitProcess(ERROR_ID);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.