GetLastError () দ্বারা ফিরে আসা ত্রুটি কোড থেকে ত্রুটি বার্তাটি কীভাবে পাবেন?


144

উইন্ডোজ এপিআই কল করার পরে, আমি কীভাবে পাঠ্য আকারে শেষ ত্রুটি বার্তাটি পেতে পারি?

GetLastError() একটি পাঠ্য বার্তা নয়, একটি পূর্ণসংখ্যা মান প্রদান করে।


ভিজ্যুয়াল স্টুডিওতে সরঞ্জাম বিভাগে একটি এক্সে ত্রুটি অনুসন্ধানের জন্য এটি ব্যবহার করা হয় যা এটি খুব ভাল করে যখন আপনার কেবলমাত্র ডিবাগিংয়ের জন্য ত্রুটি থেকে বার্তা প্রয়োজন।
কোল্ডগেট

@ কোল্ডগেট: ডিবাগিংয়ের জন্য কেবল একটি @err,hrঘড়ি যুক্ত করা অনেক সহজ এবং ডিবাগারটি স্বয়ংক্রিয়ভাবে শেষ ত্রুটি কোডটিকে একটি মানব-পঠনযোগ্য উপস্থাপনায় রূপান্তরিত করে। ,hrবিন্যাস সুনির্দিষ্টভাবে উল্লেখ করা কোনো অভিব্যক্তি অবিচ্ছেদ্য মান মূল্যায়ন করে, যেমন একটি জন্য কাজ করে 5,hrঘড়ি প্রদর্শন করা হবে "ERROR_ACCESS_DENIED। অ্যাক্সেস অস্বীকৃত হয়"
IInspectable

4
GetLastError()ডকুমেন্টেশন থেকে : " সিস্টেম ত্রুটি কোডগুলির জন্য একটি ত্রুটি স্ট্রিং প্রাপ্ত করতে, FormatMessage()ফাংশনটি ব্যবহার করুন । " এমএসডিএন - তে সর্বশেষ-ত্রুটি কোডটি পুনরুদ্ধার করুন দেখুন ।
রেমি Lebeau

উত্তর:


151
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
std::string GetLastErrorAsString()
{
    //Get the error message, if any.
    DWORD errorMessageID = ::GetLastError();
    if(errorMessageID == 0)
        return std::string(); //No error message has been recorded

    LPSTR messageBuffer = nullptr;
    size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);

    std::string message(messageBuffer, size);

    //Free the buffer.
    LocalFree(messageBuffer);

    return message;
}

4
আমি বিশ্বাস করি যে আপনাকে আসলে (LPSTR)&messageBufferএই ক্ষেত্রেটি পাস করতে হবে , অন্যথায় ফর্ম্যাটমেসেজএর কোনও বরাদ্দ বাফারের দিকে নির্দেশ করতে তার মান পরিবর্তন করতে পারে না।
কাইলোটন

4
ওহ, বাহ, হ্যাঁ, এটা খুব অদ্ভুত। এটি কীভাবে পয়েন্টারটি সংশোধন করবে? তবে এটি পয়েন্টারের ঠিকানা (পয়েন্টার-টু-এ-পয়েন্টার) প্রেরণ করা হচ্ছে, তবে এটি নিয়মিত পয়েন্টারে কাস্ট করা ... Win32 অদ্ভুততা। শীর্ষস্থানীয়দের জন্য ধন্যবাদ, এটি আমার নিজের কোড বেসে স্থির করুন (এবং আমার উত্তর)। খুব সূক্ষ্ম ধরা।
জামিন গ্রে

4
আপনাকে অনেক ধন্যবাদ, আপনার উদাহরণটি এমএসডিএন-এর চেয়ে অনেক পরিষ্কার। আরও বেশি, এমএসডিএন থেকে আসা একটি এমনকি সংকলন করতে পারেনি। এটিতে কিছু strsafe.hশিরোনাম অন্তর্ভুক্ত রয়েছে , এটি মোটেও নিরাপদ নয়, এটি winuser.hএবং এর মধ্যে একটি সংকলক ত্রুটির একটি গুচ্ছ ঘটায় winbase.h
হাই-অ্যাঞ্জেল

4
কিছু ত্রুটি আইডি সমর্থিত নয়। উদাহরণস্বরূপ, 0x2EE7, ERROR_INTERNET_NAME_NOT_RESOLVED ফর্ম্যাটমেজ: 0x13D কল করার সময় একটি নতুন ত্রুটি ঘটায়, সিস্টেম% 2 এর জন্য মেসেজ ফাইলে 0x% 1 বার্তা নম্বরটির জন্য বার্তা পাঠাতে পারে না।
ব্রেন্ট

4
এই বাস্তবায়ন সংক্রান্ত সমস্যাগুলি: 1 GetLastErrorসম্ভবত খুব দেরি বলা হয়। 2কোনও ইউনিকোড সমর্থন নেই। 3ব্যতিক্রম সুরক্ষা গ্যারান্টি কার্যকর না করে ব্যতিক্রম ব্যবহার।
IInspectable

66

কিছু মন্তব্য বিবেচনায় নিতে আপডেট (11/2017)।

সহজ উদাহরণ:

wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
               NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
               buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

4
@ হাই-অ্যাঞ্জেল - উদাহরণটি ধরে নিয়েছে যে আপনি ইউনিকোডি সংজ্ঞায়িত সংস্থার সাথে সংকলন করছেন। 'ফরম্যাটমেজেজ' আসলে ম্যাক্রো যা আনসি / এমবিসিএস ক্যারেক্টার বাফারগুলির জন্য হয় 'ফর্ম্যাটম্যাসেজএ' বা ইউটিএফ 16 / ইউনিকোডে বাফারদের জন্য 'ফর্ম্যাটম্যাসেজডাব্লু' তে প্রসারিত হয়, অ্যাপ্লিকেশনটি কীভাবে সংকলিত হয় তার উপর নির্ভর করে। আউটপুট বাফার টাইপের (wchar_t) সাথে মেলে এমন সংস্করণটি স্পষ্টভাবে প্রার্থনা করতে আমি উপরের উদাহরণটি সম্পাদনা করার স্বাধীনতা নিয়েছি।
বুড়ো

4
FORMAT_MESSAGE_IGNORE_INSERTS যুক্ত করুন: "আপনি যদি ফর্ম্যাট স্ট্রিংয়ের নিয়ন্ত্রণে না রাখেন তবে% 1 কে সমস্যা তৈরির হাত থেকে রক্ষা করতে আপনাকে অবশ্যই FORMAT_MESSAGE_IGNORE_INSERTS পাস করতে হবে" " ব্লগস.এমএসএনএন.মাইক্রোসফট.ল্ডনেউথিং
ড্যান্টন

4
এই বাস্তবায়ন সহ সমস্যাগুলি: 1গুরুত্বপূর্ণ FORMAT_MESSAGE_IGNORE_INSERTSপতাকাটি নির্দিষ্ট করতে ব্যর্থ । 2 GetLastErrorসম্ভাব্যভাবে অনেক দেরি করা হয়েছে। 3256 কোড ইউনিটে ম্যাসেজের নির্বিচারে সীমাবদ্ধতা। 4পরিচালনা করার ক্ষেত্রে কোনও ত্রুটি নেই।
IInspectable

4
আকারে (বুফ) অ্যারেজেস (বুফ) হওয়া উচিত কারণ ফর্ম্যাটম্যাসেজ টিএমএইচআরসে বাফারের আকারের প্রত্যাশা করে, বাইটে নয়।
কাই

4
আমরা এর 256পরিবর্তে ব্যবহার করতে পারি না (sizeof(buf) / sizeof(wchar_t)? এটা গ্রহণযোগ্য এবং নিরাপদ না?
ব্যাটলটেষ্টেড


17

GetLastError একটি সংখ্যাসূচক ত্রুটি কোডটি দেয়। বর্ণনামূলক ত্রুটি বার্তাটি পেতে (উদাহরণস্বরূপ, কোনও ব্যবহারকারীর কাছে প্রদর্শন করতে), আপনি ফর্ম্যাটম্যাসেজ কল করতে পারেন :

// This functions fills a caller-defined character buffer (pBuffer)
// of max length (cchBufferLength) with the human-readable error message
// for a Win32 error code (dwErrorCode).
// 
// Returns TRUE if successful, or FALSE otherwise.
// If successful, pBuffer is guaranteed to be NUL-terminated.
// On failure, the contents of pBuffer are undefined.
BOOL GetErrorMessage(DWORD dwErrorCode, LPTSTR pBuffer, DWORD cchBufferLength)
{
    if (cchBufferLength == 0)
    {
        return FALSE;
    }

    DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                 NULL,  /* (not used with FORMAT_MESSAGE_FROM_SYSTEM) */
                                 dwErrorCode,
                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                 pBuffer,
                                 cchBufferLength,
                                 NULL);
    return (cchMsg > 0);
}

সি ++ তে আপনি স্টাডি :: স্ট্রিং ক্লাসটি ব্যবহার করে ইন্টারফেসটি যথেষ্ট সহজ করতে পারবেন:

#include <Windows.h>
#include <system_error>
#include <memory>
#include <string>
typedef std::basic_string<TCHAR> String;

String GetErrorMessage(DWORD dwErrorCode)
{
    LPTSTR psz{ nullptr };
    const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                                         | FORMAT_MESSAGE_IGNORE_INSERTS
                                         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                                       NULL, // (not used with FORMAT_MESSAGE_FROM_SYSTEM)
                                       dwErrorCode,
                                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                       reinterpret_cast<LPTSTR>(&psz),
                                       0,
                                       NULL);
    if (cchMsg > 0)
    {
        // Assign buffer to smart pointer with custom deleter so that memory gets released
        // in case String's c'tor throws an exception.
        auto deleter = [](void* p) { ::LocalFree(p); };
        std::unique_ptr<TCHAR, decltype(deleter)> ptrBuffer(psz, deleter);
        return String(ptrBuffer.get(), cchMsg);
    }
    else
    {
        auto error_code{ ::GetLastError() };
        throw std::system_error( error_code, std::system_category(),
                                 "Failed to retrieve error message string.");
    }
}

দ্রষ্টব্য: এই ফাংশনগুলি HRESULT মানগুলির জন্যও কাজ করে। কেবলমাত্র প্রথম প্যারামিটারটি DWORD dwErrorCode থেকে HRESULT hResult এ পরিবর্তন করুন। কোডের বাকি অংশটি অপরিবর্তিত থাকতে পারে।


এই প্রয়োগগুলি বিদ্যমান উত্তরের তুলনায় নিম্নলিখিত উন্নতি সরবরাহ করে:

  • নমুনা কোডটি সম্পূর্ণ করুন, কেবলমাত্র কল করার জন্য এপিআই-এর কোনও রেফারেন্স নয়।
  • সি এবং সি ++ উভয় বাস্তবায়ন সরবরাহ করে।
  • ইউনিকোড এবং এমবিসিএস প্রকল্প উভয় ক্ষেত্রেই কাজ করে।
  • একটি ইনপুট প্যারামিটার হিসাবে ত্রুটি কোড নেয়। এটি গুরুত্বপূর্ণ, যেহেতু কোনও থ্রেডের শেষ ত্রুটি কোডটি কেবলমাত্র সংজ্ঞায়িত পয়েন্টগুলিতে বৈধ। একটি ইনপুট প্যারামিটার কলারকে নথিভুক্ত চুক্তি অনুসরণ করতে দেয়।
  • যথাযথ ব্যতিক্রম সুরক্ষা কার্যকর করে। স্পষ্টতই ব্যতিক্রমগুলি ব্যবহার করে এমন সমস্ত সমাধানগুলির থেকে পৃথক, এই প্রয়োগটি রিটার্ন মান নির্মানের সময় কোনও ব্যতিক্রম ছড়িয়ে পড়লে মেমরি ফাঁস হবে না।
  • FORMAT_MESSAGE_IGNORE_INSERTSপতাকাটির যথাযথ ব্যবহার । আরও তথ্যের জন্য FORMAT_MESSAGE_IGNORE_INSERTS পতাকাটির গুরুত্ব দেখুন ।
  • যথাযথ ত্রুটি পরিচালনা / ত্রুটি প্রতিবেদন করা, অন্য উত্তরগুলির মতো কিছু নয় যা নিঃশব্দে ত্রুটিগুলি উপেক্ষা করে।


এই উত্তরটি স্ট্যাক ওভারফ্লো ডকুমেন্টেশন থেকে অন্তর্ভুক্ত করা হয়েছে। নিম্নলিখিত ব্যবহারকারীরা উদাহরণটিতে অবদান রেখেছেন: স্ট্যাকপ্টর , অজয় , কোডি গ্রে II , IInspectable


4
নিক্ষেপ করার পরিবর্তে std::runtime_error, আমি ব্যর্থ কলের পরে ফেরতের মানটি std::system_error(lastError, std::system_category(), "Failed to retrieve error message string.")কোথায় lastErrorহবে তা নিক্ষেপ করার পরামর্শ দিই । GetLastError()FormatMessage()
zett42

FormatMessageসরাসরি আপনার সি সংস্করণ ব্যবহার করে কী সুবিধা ?
মিখা উইডেনম্যান

@ মিমি: এটি জিজ্ঞাসার মতো: "সি-তে ফাংশনগুলির সুবিধা কী?" ফাংশন বিমূর্ততা সরবরাহ করে জটিলতা হ্রাস করে। এই ক্ষেত্রে, বিমূর্ততা 7 থেকে 3 পরামিতিগুলির সংখ্যা হ্রাস করে, সামঞ্জস্যপূর্ণ পতাকা এবং পরামিতিগুলি পেরিয়ে এপিআইয়ের নথিভুক্ত চুক্তি প্রয়োগ করে এবং নথিভুক্ত ত্রুটির প্রতিবেদনের যুক্তিকে এনকোড করে। এটি একটি সংক্ষিপ্ত ইন্টারফেস সরবরাহ করে, শব্দার্থবিজ্ঞান অনুমান করা সহজ সহ, আপনাকে ডকুমেন্টেশন পড়ার জন্য 11 মিনিটের বিনিয়োগের প্রয়োজনকে ছাড়িয়ে দেয় ।
IInspectable

আমি এই উত্তরটি পছন্দ করি, এটি খুব স্পষ্ট যে কোডের সঠিকতার প্রতি যত্নবান মনোযোগ দেওয়া হয়েছে। আমার দুটি প্রশ্ন আছে। 1) ডকুমেন্টেশনের পরামর্শ অনুসারে আপনি ::HeapFree(::GetProcessHeap(), 0, p)মুছে ফেলার ক্ষেত্রে কেন ব্যবহার করবেন ::LocalFree(p)? 2) আমি বুঝতে পারি যে ডকুমেন্টেশনটি এটি এইভাবে করতে বলে, তবে reinterpret_cast<LPTSTR>(&psz)কঠোরভাবে আলিয়াসিং বিধি লঙ্ঘন করে না ?
তেহ জো ই

@ টেক: মতামতের জন্য আপনাকে ধন্যবাদ প্রশ্ন 1): সত্য, আমি জানি না এটি নিরাপদ কিনা। কাকে বা কেন কলটি HeapFreeচালু করা হয়েছিল তা আমি মনে করি না , যদিও এটি এখনও ডকুমেন্টেশনের একটি বিষয় ছিল। আমাকে তদন্ত করতে হবে (যদিও ডকুমেন্টেশনটি পরিষ্কার বলে মনে হচ্ছে, এটি নিরাপদ নয় )। প্রশ্ন 2): এটি দ্বিগুণ। একটি এমবিসিএস কনফিগারেশনের জন্য, LPTSTRএকটি উপনাম char*। Castালাই সর্বদা নিরাপদ। ইউনিকোড কনফিগারেশনের জন্য, wchar_t*কোনও হারে কাস্টিং করা মৎসকর। এটি সি তে নিরাপদ কিনা তা আমি জানি না, তবে এটি সম্ভবত সি ++ তে নেই। আমাকেও এটি তদন্ত করতে হবে।
IInspectable


13

সাধারণভাবে, আপনার ব্যবহার করা দরকার FormatMessage উইন 32 ত্রুটি কোড থেকে পাঠ্যে রূপান্তর করতে হবে।

এমএসডিএন ডকুমেন্টেশন থেকে :

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

ফরম্যাটমেসেজের ঘোষণা:

DWORD WINAPI FormatMessage(
  __in      DWORD dwFlags,
  __in_opt  LPCVOID lpSource,
  __in      DWORD dwMessageId, // your error code
  __in      DWORD dwLanguageId,
  __out     LPTSTR lpBuffer,
  __in      DWORD nSize,
  __in_opt  va_list *Arguments
);

8

আপনি যদি সি # ব্যবহার করছেন তবে আপনি এই কোডটি ব্যবহার করতে পারেন:

using System.Runtime.InteropServices;

public static class WinErrors
{
    #region definitions
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr LocalFree(IntPtr hMem);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern int FormatMessage(FormatMessageFlags dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer, uint nSize, IntPtr Arguments);

    [Flags]
    private enum FormatMessageFlags : uint
    {
        FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100,
        FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200,
        FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000,
        FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000,
        FORMAT_MESSAGE_FROM_HMODULE = 0x00000800,
        FORMAT_MESSAGE_FROM_STRING = 0x00000400,
    }
    #endregion

    /// <summary>
    /// Gets a user friendly string message for a system error code
    /// </summary>
    /// <param name="errorCode">System error code</param>
    /// <returns>Error string</returns>
    public static string GetSystemMessage(int errorCode)
    {
        try
        {
            IntPtr lpMsgBuf = IntPtr.Zero;

            int dwChars = FormatMessage(
                FormatMessageFlags.FORMAT_MESSAGE_ALLOCATE_BUFFER | FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM | FormatMessageFlags.FORMAT_MESSAGE_IGNORE_INSERTS,
                IntPtr.Zero,
                (uint) errorCode,
                0, // Default language
                ref lpMsgBuf,
                0,
                IntPtr.Zero);
            if (dwChars == 0)
            {
                // Handle the error.
                int le = Marshal.GetLastWin32Error();
                return "Unable to get error code string from System - Error " + le.ToString();
            }

            string sRet = Marshal.PtrToStringAnsi(lpMsgBuf);

            // Free the buffer.
            lpMsgBuf = LocalFree(lpMsgBuf);
            return sRet;
        }
        catch (Exception e)
        {
            return "Unable to get error code string from System -> " + e.ToString();
        }
    }
}

আমি নিশ্চিত করেছি যে এই কোডটি কাজ করে। টিএস এই উত্তর গ্রহণ করা উচিত নয়?
swdev

4
যদি এটি আরও নিক্ষেপের জন্য প্রয়োজনীয় হয় তবে এটি সি # তে Win32Exception এর সাথে করার সহজ উপায় রয়েছে
সার্জ

4
@ এসডেদেব: সি বা সি ++ থাকা কোনও প্রশ্নের উত্তর কেন কেউ সি # তে গ্রহণ করবেন ? যেমনটি দাঁড়িয়েছে, এই উত্তরটি জিজ্ঞাসা করা প্রশ্নের সমাধানও করে না।
IInspectable

4
ঠিক আছে, আমি মনে করি না এই প্রস্তাবিত উত্তরে ভোট দিয়েছি। আমি @ swdev এর যুক্তিতে সুস্পষ্ট ত্রুটি সম্বোধন করেছি। তবে যেহেতু আপনি আমাকে বিশ্বাস করবেন না, এখন আমি তা আপনাকে প্রমাণ করতে যাচ্ছি: এখানে, আরেকটি ডাউন-ভোট দিন। এটি আমার কাছ থেকে, কারণ এই উত্তরটি - যদিও এটি একটি ভিন্ন প্রশ্ন দেওয়াতে কার্যকর হতে পারে - যে প্রশ্নটি জিজ্ঞাসা করা হচ্ছিল তা সহজভাবে কার্যকর নয়।
IInspectable

4
"আমি অনুমান করি যে আপনার কাছে সুস্পষ্টর বাইরে অফার করার জন্য সহায়ক অন্তর্দৃষ্টি রয়েছে" - আসলে আমার কাছে রয়েছে
IInspectable

5

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

#include <system_error>

std::string GetLastErrorAsString(){
    DWORD errorMessageID = ::GetLastError();
    if (errorMessageID == 0) {
        return std::string(); //No error message has been recorded
    } else {
        return std::system_category().message(errorMessageID);
    }
}

এখানে কেবল একটি ক্ষুদ্র উইন্ডো রয়েছে যেখানে কলিং GetLastErrorঅর্থবহ ফলাফল দেয়। এটি সি ++ হওয়ার সাথে সাথে, এখানে কেবলমাত্র নিরাপদ বিকল্পটি হ'ল কলারকে সর্বশেষ ত্রুটি কোড সরবরাহ করতে হবে। এটি অবশ্যই সহায়তা করে না, যে কোডটি GetLastError দুটি বার কল উপস্থাপন করেছিল । এছাড়াও, সুবিধাজনক হলেও, সি ++ 'বিস্তৃত অক্ষর সমর্থনের অন্তর্নিহিত অভাব error_categoryইন্টারফেসটি সর্বজনীনভাবে কার্যকর করতে ব্যর্থ । এটি কেবল C ++ 'মিস করা সুযোগের দীর্ঘ ইতিহাসে যুক্ত করে।
IInspectable

অকেজো কল সম্পর্কে ভাল পয়েন্ট GetLastError। তবে আমি GetLastErrorএখানে কল করা বা কলকারীকে কল করার মধ্যে পার্থক্য দেখছি না । সি ++ এবং উইচার সম্পর্কে: আশা ত্যাগ করবেন না, মাইক্রোসফ্ট অ্যাপ্লিকেশনগুলিকে কেবল ইউটিএফ -8 হওয়ার অনুমতি দিতে শুরু করছে ।
ক্রোনিয়াল

"আমি কোন পার্থক্য দেখুন" - নিম্নলিখিত কল সাইটে বিবেচনা করুন: log_error("error", GetLastErrorAsString());। এছাড়াও বিবেচনা করুন যে log_errorপ্রথম আর্গুমেন্ট টাইপ হয় std::string। (অদৃশ্য) রূপান্তর ক্যাটার কলটি GetLastErrorআপনাকে যে বিন্দুতে ডেকেছে সেখান থেকে একটি অর্থবোধক মান ক্যাপচার করার জন্য আপনার গ্যারান্টিটি সরিয়ে ফেলেছে ।
IInspectable

আপনি কেন মনে করেন যে std :: স্ট্রিং কনস্ট্রাক্টর একটি Win32 ফাংশন কল করে?
ক্রোনিয়াল

4
mallocHeapAllocপ্রক্রিয়া গাদা জন্য কল । প্রক্রিয়া হিপ বর্ধনযোগ্য। এটি হত্তয়া দরকার হয় তবে এটা শেষ পর্যন্ত ডাকব VirtualAlloc , যা নেই কলিং থ্রেড এর শেষ ত্রুটি কোড সেট। এখন এটি পুরোপুরি বিন্দুটি হারিয়েছে, যা: সি ++ একটি খনি ক্ষেত্র field এই প্রয়োগটি কেবল এতে যুক্ত করে, অন্তর্নিহিত গ্যারান্টি সহ একটি ইন্টারফেস সরবরাহ করে এটি কেবল বাঁচতে পারে না। যদি আপনি বিশ্বাস করেন যে কোনও সমস্যা নেই, তবে প্রস্তাবিত সমাধানটির যথার্থতা প্রমাণ করা আপনার পক্ষে সহজ হওয়া উচিত । শুভকামনা।
IInspectable

4

আপনার যদি ইউনিকোডের পাশাপাশি এমবিসিএস সমর্থন করতে হয় তবে মিঃসি 64 এর উত্তরটি যথেষ্ট নয় enough বাফারকে অবশ্যই টিসিএইচএআর হিসাবে ঘোষণা করতে হবে এবং এলপিটিআরটিএসে প্রেরণ করতে হবে। নোট করুন যে এই কোডটি ত্রুটি বার্তায় মাইক্রোসফ্ট সংযোজন করে এমন বিরক্তিকর নতুন লাইনের সাথে কাজ করে না।

CString FormatErrorMessage(DWORD ErrorCode)
{
    TCHAR   *pMsgBuf = NULL;
    DWORD   nMsgLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        reinterpret_cast<LPTSTR>(&pMsgBuf), 0, NULL);
    if (!nMsgLen)
        return _T("FormatMessage fail");
    CString sMsg(pMsgBuf, nMsgLen);
    LocalFree(pMsgBuf);
    return sMsg;
}

এছাড়াও, ব্রিভিটির জন্য আমি নিম্নলিখিত পদ্ধতিটি দরকারী বলে মনে করি:

CString GetLastErrorString()
{
    return FormatErrorMessage(GetLastError());
}

যদি CStringক্যাটার একটি ব্যতিক্রম ছুঁড়ে মারে, এই প্রয়োগটি কল দ্বারা বরাদ্দ হওয়া মেমরি ফাঁস করে দেয় FormatMessage
IInspectable

সত্য, তবে আমি বহু বছর ধরে এই কোডটি ব্যবহার করেছি এবং এটি কখনও সমস্যা হয়নি। কেবলমাত্র যে ক্ষেত্রে সিএসট্রিং কর্টর নিক্ষেপ করতে পারে তা হ'ল মেমরি বরাদ্দ করতে ব্যর্থতা এবং মাইক্রোসফ্ট সরবরাহিত সামগ্রী সহ বেশিরভাগ এমএফসি কোড - আপনার পছন্দ মতো মেমরির শর্তগুলি পরিচালনা করে না। ভাগ্যক্রমে বেশিরভাগ পিসিতে এখন এত বেশি মেমরি রয়েছে যে আপনি এটি ব্যবহার করতে বেশ কঠোর পরিশ্রম করতে হবে। অস্থায়ী সিএসট্রিংয়ের উদাহরণ তৈরি করে এমন কোনও ব্যবহার (সিএসট্রিং ফিরিয়ে দেওয়া সহ) এই ঝুঁকিটি চালায়। এটি ঝুঁকি / সুবিধাযুক্ত বাণিজ্য। এছাড়াও এটি যদি কোনও বার্তা হ্যান্ডলারে ঘটে তবে ব্যতিক্রম ধরা পড়বে।
শিকারের শিকার

এই মন্তব্য বেশিরভাগই ভুল, দুঃখিত। "এটি আমার সাথে কখনও ঘটেনি" এটি হ'ল একটি দুর্বল বিন্দু, বিশেষত যখন আপনি জানেন কীভাবে কোডটি ব্যর্থ হতে পারে। কোনও প্রক্রিয়াতে বরাদ্দ প্রাপ্ত অ্যাড্রেস স্পেসে মেমরির পরিমাণের কোনও প্রভাব নেই। র‌্যাম কেবল একটি পারফরম্যান্স অপ্টিমাইজেশন। অনুলিপি-এলিজেন কোনও অস্থায়ী বরাদ্দকে বাধা দেয়, যখন এনআরভিওকে অনুমতি দেওয়ার জন্য কোড লেখা হয়। কোনও বার্তা হ্যান্ডলারে ব্যতিক্রম ধরা আছে বা না তা প্রক্রিয়া নির্ভরতা এবং বাহ্যিক সেটিংসের উপর নির্ভর করে। আমি একটি উত্তর জমা দিয়েছি যা দেখায় যে, ঝুঁকি ব্যবস্থাপনার অসুবিধার দিকে যায় না।
IInspectable

এছাড়াও, অস্থায়ী নির্মাণে স্মৃতিশক্তি হারিয়ে যাওয়ার ঝুঁকি হ'ল মোট। এই মুহুর্তে সমস্ত সংস্থান মুক্ত করা হয়েছে এবং এর কোনও খারাপ কিছুই আসবে না।
IInspectable

4
না আমি দুঃখিত এই কোডটি আপনার পক্ষে কার্যকর নয়। তবে টিবিএইচ এটি আমার সমস্যার তালিকার তুলনায় বেশ কম।
শিকারের শিকার 21

3
void WinErrorCodeToString(DWORD ErrorCode, string& Message)
{
char* locbuffer = NULL;
DWORD count = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, ErrorCode,
    0, (LPSTR)&locbuffer, 0, nullptr);
if (locbuffer)
{
    if (count)
    {
        int c;
        int back = 0;
        //
        // strip any trailing "\r\n"s and replace by a single "\n"
        //
        while (((c = *CharPrevA(locbuffer, locbuffer + count)) == '\r') ||
            (c == '\n')) {
            count--;
            back++;
        }

        if (back) {
            locbuffer[count++] = '\n';
            locbuffer[count] = '\0';
        }

        Message = "Error: ";
        Message += locbuffer;
    }
    LocalFree(locbuffer);
}
else
{
    Message = "Unknown error code: " + to_string(ErrorCode);
}
}

আপনি কিছু ব্যাখ্যা যোগ করতে পারেন?
রবার্ট

4
এই বাস্তবায়ন সহ সমস্যাগুলি: 1কোনও ইউনিকোড সমর্থন নেই। 2ত্রুটি বার্তার অনুপযুক্ত বিন্যাস। যদি কলারকে ফিরে আসা স্ট্রিংটি প্রক্রিয়া করার প্রয়োজন হয় তবে এটি কেবল এটি করতে পারে। আপনার প্রয়োগটি কোনও বিকল্প ছাড়াই কলারকে ছেড়ে দেয়। 3ব্যতিক্রম ব্যবহার তবে সঠিক ব্যতিক্রমী সুরক্ষার অভাব। std::stringঅপারেটররা ব্যতিক্রম ছুঁড়ে ফেলার ক্ষেত্রে , বরাদ্দ করা বাফারটি FormatMessageফাঁস হয়ে যায়। কলারকে রেফারেন্সের মাধ্যমে কোনও জিনিস পাস করার পরিবর্তে 4কেন কেবল একটি ফেরত দেওয়া হবে না std::string?
IInspectable

0

আমি এটি এখানে রেখে দেব কারণ আমার এটি পরে ব্যবহার করতে হবে। এটি একটি ছোট বাইনারি সামঞ্জস্যপূর্ণ সরঞ্জামের জন্য উত্স যা সমাবেশ, সি এবং সি ++ তে সমানভাবে ভাল কাজ করবে।

GetErrorMessageLib.c (getErrorMessageLib.dll তে সংকলিত)

#include <Windows.h>

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
__declspec(dllexport)
int GetErrorMessageA(DWORD dwErrorCode, LPSTR lpResult, DWORD dwBytes)
{    
    LPSTR tmp;
    DWORD result_len;

    result_len = FormatMessageA (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPSTR)&tmp,
        0,
        NULL
    );        

    if (result_len == 0) {
        return -1;
    }

    // FormatMessage's return is 1 character too short.
    ++result_len;

    strncpy(lpResult, tmp, dwBytes);

    lpResult[dwBytes - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_len <= dwBytes) {
        return 0;
    } else {
        return result_len;
    }
}

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
__declspec(dllexport)
int GetErrorMessageW(DWORD dwErrorCode, LPWSTR lpResult, DWORD dwBytes)
{   
    LPWSTR tmp;
    DWORD nchars;
    DWORD result_bytes;

    nchars = dwBytes >> 1;

    result_bytes = 2 * FormatMessageW (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPWSTR)&tmp,
        0,
        NULL
    );    

    if (result_bytes == 0) {
        return -1;
    } 

    // FormatMessage's return is 1 character too short.
    result_bytes += 2;

    wcsncpy(lpResult, tmp, nchars);
    lpResult[nchars - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_bytes <= dwBytes) {
        return 0;
    } else {
        return result_bytes * 2;
    }
}

ইনলাইন সংস্করণ (GetErrorMessage.h):

#ifndef GetErrorMessage_H 
#define GetErrorMessage_H 
#include <Windows.h>    

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
static inline int GetErrorMessageA(DWORD dwErrorCode, LPSTR lpResult, DWORD dwBytes)
{    
    LPSTR tmp;
    DWORD result_len;

    result_len = FormatMessageA (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPSTR)&tmp,
        0,
        NULL
    );        

    if (result_len == 0) {
        return -1;
    }

    // FormatMessage's return is 1 character too short.
    ++result_len;

    strncpy(lpResult, tmp, dwBytes);

    lpResult[dwBytes - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_len <= dwBytes) {
        return 0;
    } else {
        return result_len;
    }
}

/***
 * returns 0 if there was enough space, size of buffer in bytes needed
 * to fit the result, if there wasn't enough space. -1 on error.
 */
static inline int GetErrorMessageW(DWORD dwErrorCode, LPWSTR lpResult, DWORD dwBytes)
{   
    LPWSTR tmp;
    DWORD nchars;
    DWORD result_bytes;

    nchars = dwBytes >> 1;

    result_bytes = 2 * FormatMessageW (
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        dwErrorCode,
        LANG_SYSTEM_DEFAULT,
        (LPWSTR)&tmp,
        0,
        NULL
    );    

    if (result_bytes == 0) {
        return -1;
    } 

    // FormatMessage's return is 1 character too short.
    result_bytes += 2;

    wcsncpy(lpResult, tmp, nchars);
    lpResult[nchars - 1] = 0;
    LocalFree((HLOCAL)tmp);

    if (result_bytes <= dwBytes) {
        return 0;
    } else {
        return result_bytes * 2;
    }
}

#endif /* GetErrorMessage_H */

ডায়নামিক ইউজকেস (ধরে নেওয়া হয়েছে যে ত্রুটি কোডটি বৈধ, অন্যথায় একটি -1 চেক প্রয়োজন):

#include <Windows.h>
#include <Winbase.h>
#include <assert.h>
#include <stdio.h>

int main(int argc, char **argv)
{   
    int (*GetErrorMessageA)(DWORD, LPSTR, DWORD);
    int (*GetErrorMessageW)(DWORD, LPWSTR, DWORD);
    char result1[260];
    wchar_t result2[260];

    assert(LoadLibraryA("GetErrorMessageLib.dll"));

    GetErrorMessageA = (int (*)(DWORD, LPSTR, DWORD))GetProcAddress (
        GetModuleHandle("GetErrorMessageLib.dll"),
        "GetErrorMessageA"
    );        
    GetErrorMessageW = (int (*)(DWORD, LPWSTR, DWORD))GetProcAddress (
        GetModuleHandle("GetErrorMessageLib.dll"),
        "GetErrorMessageW"
    );        

    GetErrorMessageA(33, result1, sizeof(result1));
    GetErrorMessageW(33, result2, sizeof(result2));

    puts(result1);
    _putws(result2);

    return 0;
}

নিয়মিত ব্যবহারের ক্ষেত্রে (ধরে নেওয়া হয়েছে ত্রুটি কোডটি বৈধ, অন্যথায় -1 রিটার্ন চেক প্রয়োজন):

#include <stdio.h>
#include "GetErrorMessage.h"
#include <stdio.h>

int main(int argc, char **argv)
{
    char result1[260];
    wchar_t result2[260];

    GetErrorMessageA(33, result1, sizeof(result1));
    puts(result1);

    GetErrorMessageW(33, result2, sizeof(result2));
    _putws(result2);

    return 0;
}

উদাহরণস্বরূপ MinGW32 এর মতো অ্যাসেম্বলি gnu ব্যবহার করে (আবার ধরে নেওয়া হয়েছে যে ত্রুটি কোডটি বৈধ, অন্যথায় -1 চেক প্রয়োজন)।

    .global _WinMain@16

    .section .text
_WinMain@16:
    // eax = LoadLibraryA("GetErrorMessageLib.dll")
    push $sz0
    call _LoadLibraryA@4 // stdcall, no cleanup needed

    // eax = GetProcAddress(eax, "GetErrorMessageW")
    push $sz1
    push %eax
    call _GetProcAddress@8 // stdcall, no cleanup needed

    // (*eax)(errorCode, szErrorMessage)
    push $200
    push $szErrorMessage
    push errorCode       
    call *%eax // cdecl, cleanup needed
    add $12, %esp

    push $szErrorMessage
    call __putws // cdecl, cleanup needed
    add $4, %esp

    ret $16

    .section .rodata
sz0: .asciz "GetErrorMessageLib.dll"    
sz1: .asciz "GetErrorMessageW"
errorCode: .long 33

    .section .data
szErrorMessage: .space 200

ফলাফল: The process cannot access the file because another process has locked a portion of the file.


4
এটি সত্যিই দরকারী কিছু যুক্ত করে না। সর্বোপরি, এটি FormatMessageকোনও আপাত কারণ ছাড়াই এএনএসআই সংস্করণটিকে কল করে এবং নির্বিচারে নিজেকে বিনা কারণে বিনা কারণে 80 টি চরিত্রের মধ্যে সীমাবদ্ধ করে। আমি ভীত, এটি সহায়ক নয়।
IInspectable

আপনি ঠিক বলেছেন আমি আশা করছিলাম যে ইউনিকোড সংস্করণটির অভাব সম্পর্কে কেউ খেয়াল করবে না। আমি জিনুতে ইউনিকোড স্ট্রিং কীভাবে সংজ্ঞায়িত করব এবং আমার সমাধানটি সংশোধন করব তা পরীক্ষা করব। অসততা সম্পর্কে দুঃখিত।
দিমিত্রি

ঠিক আছে ইউনিকোড সংস্করণ শেষ। এবং এটি স্বেচ্ছাচারী কারণ নয়; সমস্ত ত্রুটি বার্তাগুলি হয় 80 টিরও কম অক্ষরের, বা পড়ার মতো নয় এবং ত্রুটি বার্তার চেয়ে ত্রুটি কোডটি আরও গুরুত্বপূর্ণ। এমন কোনও মানক ত্রুটি বার্তা নেই যা 80 টি অক্ষরের বেশি হয় তাই এটি একটি নিরাপদ অনুমান, এবং যখন তা হয় না, এটি মেমরি ফাঁস করে না।
দিমিত্রি

4
"সমস্ত ত্রুটি বার্তাগুলি হয় 80 টিরও কম অক্ষরের চেয়ে কম বা পড়ার মতো নয়" - এটি ভুল। ERROR_LOCK_VIOLATION(33) এর জন্য ত্রুটি বার্তাটি হ'ল: "প্রক্রিয়াটি ফাইলটি অ্যাক্সেস করতে পারে না কারণ অন্য একটি প্রক্রিয়া ফাইলের একটি অংশ লক করেছে।" যদি আপনি কোনও সমস্যা সমাধান করতে এবং ডায়াগনস্টিক লগ ফাইলটিতে এটি সন্ধান করার চেষ্টা করেন তবে এটি উভয়রই স্পষ্টতই 80 টি অক্ষরের চেয়ে বেশি লম্বা এবং পঠনযোগ্য। এই উত্তরটি বিদ্যমান উত্তরের চেয়ে কোনও উল্লেখযোগ্য মান যুক্ত করে না।
IInspectable

এটি কোনও কম বোকা। এটি কেবল কম প্রায়ই ব্যর্থ হয়। বাফার আকার সম্পর্কে অ্যাসেমব্লিলিটি বাস্তবায়ন ব্যতীত (200 টি অক্ষরের জন্য জায়গা থাকার দাবি করা, যখন এটির জন্য কেবলমাত্র 100 স্থান রয়েছে)। আবার, এটি উল্লেখযোগ্য কিছু যোগ করে না, এটি ইতিমধ্যে অন্য কোনও উত্তরে নেই। বিশেষত, এটি এই উত্তরের চেয়ে খারাপ । বুলেট তালিকাটি দেখুন এবং পর্যালোচনা করুন, আপনার প্রস্তাবিত বাস্তবায়নের বিষয়টি কোনটি ইস্যু করেছে তার শীর্ষে just
IInspectable
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.