از بلاگر: گرفتن خروجی Console در نرم‌افزارهای با رابط گرافیکی در ویندوز

انتقال از بلاگر، ارسال در جمعه ۱۷ سپتامبر ۲۰۱۰ ساعت ۱:۱۱
چند روز پیش متوجه شدم کدی شبیه به:

printf(“Hello!”);

یا:

std::cout<< “Hello!”;

که در نرم‌افزاری با رابط گرافیکی «Gui Application» به کار رفته بود خروجی مورد انتظار را وقتی نرم‌افزار در خط فرمان اجرا می‌شود ایجاد نمی‌کند، خیلی عجیب بود! از آنجا که قبلا این نرم‌افزار را در لینوکس استفاده کرده بودم و چنین اشکالی را در آنجا ندیده بودم کاملا مطمئن بودم هر چه هست مربوط به ویندوز است، از آنجا که این نرم‌افزار بر روی سکوی Qt نوشته شده بود رفتم به دنبال راه‌حلی در دنیای Qt و بعد از کمی جستجو به سرعت فهمیدم که با استفاده از دستور:

CONFIG += console

در فایل پروژه به هدفم می‌رسم و نرم‌افزار دارای خروجی بر روی Console خواهد شد، اما اشکال کار در این است که با دابل کلیک بر روی فایل اجرایی نرم‌افزار علاوه بر رابط گرافیکی نرم‌افزار یک صفحه ترمینال هم باز خواهد شد، که به هیچ‌وجه مورد نظر من نبود!
پس به دنبال راه حل گشتم، در ادامه این پست راه حلی برای این منظور ارایه می‌کنم، این روش از APIهای ویندوز استفاده می‌کند و مستقل از Qt است،
تمام کد به صورت زیر است:

HWND hWnd = GetForegroundWindow();
DWORD PID;
GetWindowThreadProcessId(hWnd, &PID);
if( AttachConsole(PID) )
{
      freopen(“CON”, “w”, stdout);
      freopen(“CON”, “w”, stderr);
      freopen(“CONIN$”, “r”, stdin);
      printf(“Hello!”);
      FreeConsole();
}
else
{
      //error handling, Console is not attached!
}

در اینجا فرض کرده‌ایم پنجره فعال و جلوتر همان پنجره ترمینالی است که نرم‌افزار را از طریق آن اجرا کرده‌ایم، و می‌خواهیم بر روی آن خروجی داشته باشیم. تابع GetWindowThreadProcessId با گرفتن HANDLE پنجره مورد نظر یعنی hWnd در متغیر PID مقدار Process Identifier ترمینال را ذخیره می‌کند، و سپس تابع اصلی این مجموعه کد یعنی AttachConsole سعی می‌کند Console را به Processی که PID آن داده شده است ضمیمه کند و در صورت موفقیت مقداری ناصفر برمی‌گرداند. در این مرحله اگر Console با موفقیت ضمیمه شده باشد با سه بار به کار بردن دستور freopen، ورودی و خروجی‌های استاندارد را به Console ضمیمه شده Redirect می‌کنیم، و از اینجا به بعد تمام خروجی‌ها را بر روی ترمینال مورد نظر خواهیم داشت.
در آخر بوسیله FreeConsole می‌توانیم Console ضمیمه شده را آزاد کنیم.
متاسفانه این روش یک اشکال دارد و آن اینکه بعد از استفاده از دستورات freopen در هر صورت خروجی را بر روی ترمینال خواهیم داشت!! یعنی دستورات زیر خروجی مورد نظر را به ما نمی‌دهد:

myapp.exe > myapp_out.txt
myapp.exe | find “he”

البته یک راه حل این مشکل کد زیر است:

HWND hWnd = GetForegroundWindow();
DWORD PID;
GetWindowThreadProcessId(hWnd, &PID);
if( AttachConsole(PID) )
{
      printf(“Hello!”); //output for Pipe and Redirect to a file
      freopen(“CON”, “w”, stdout);
      freopen(“CON”, “w”, stderr);
      freopen(“CONIN$”, “r”, stdin);
      printf(“Hello!”); //outpot for Terminal
      FreeConsole();
}
else
{
       //error handling, Console is not attached!
}

یعنی باید قبل از دستورات freopen نیز یک بار از دستورات خروجی استفاده کنیم.

یک فکر در “از بلاگر: گرفتن خروجی Console در نرم‌افزارهای با رابط گرافیکی در ویندوز”

  1. بابا سید دمت گرم، نمیدونستم سایت زدی………..!

    رضی

    @صادق:
    به به! قدم رنجه فرمودیین!
    این کلبه خرابه هم اسمش وبلاگه، بابا سایتمون کجا بود.

امکان ثبت دیدگاه وجود ندارد.