كيفية إصلاح نص مشوه مع استخدام WriteFile على الأنابيب ؟

StackOverflow https://stackoverflow.com/questions/647723

  •  22-07-2019
  •  | 
  •  

سؤال

لدي التطبيق Win32 أنني القرار و يرسل سلسلة من عملية واحدة إلى أخرى عن طريق توجيه الإخراج المسمى.ومع ذلك ، فإن العملية التي تدعو طلب & readfile على الأنابيب يحصل السلسلة مع بعض البيانات مشوه في ذلك.تقوم بإرجاع عدد البايتات المكتوبة بشكل صحيح, ولكن آخر 8 أحرف أو حتى من السلسلة يتم مشوه.

هنا هو رمز لإنشاء أنبوب, والكتابة إليه:

myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL);
TCHAR title[128];
GetWindowText(foundHwnd, title, 128);
wstring windowTitle(title);
vector<wstring> splitVec;
boost::split(splitVec, windowTitle, boost::algorithm::is_any_of(wstring(L"|")));
WriteFile(myPipe, splitVec[0].c_str(), splitVec[0].size(), &wrote, NULL);

و ها هو الكود الذي يقرأ عليه:

if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) {
    MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK);
    return false;
}

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (myPipe == INVALID_HANDLE_VALUE) {
    MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK);
    return false;
}
    // Other code here...
    TCHAR buf[512];
    DWORD read;
    success = ReadFile(myPipe, buf, 512, &read, NULL);
    if (read > 0)
        MessageBox(NULL, buf, L"Got Data", MB_OK);

عندما MessageBox هو مبين في نهاية السلسلة هو مشوه وليس لدي أي فكرة عن السبب.أي أفكار ؟

وذلك بفضل!

هل كانت مفيدة؟

المحلول

أعتقد أن المفتاح هنا هو التأكد من أن سلاسل فارغة إنهاء إرسال إنهاء الطابع أيضا.لا يجب أن نرسل كامل العازلة إذا كانت الاتصالات المتزامنة أو إذا كنت في PIPE_READMODE_MESSAGE.طلب & readfile سيعود عندما يكون أي عدد محدد من البايتات تم قراءة أو كتابة العملية يكمل على الطرف الآخر من الأنبوب.وأعتقد أن "مشوه" النص هو حقا القمامة في قراءة العازلة على جانب العميل من الأنابيب لأنك لا يحيل السلسلة إنهاء الطابع ، ومن بينها هذا في النص إرسالها إلى مربع الرسالة.إما مسح قراءة العازلة قبل إرسال أو إرسال سلسلة إنهاء الطابع مع الرسالة و أعتقد أنه سوف يعمل من دون النفقات العامة من إرسال كامل العازلة.

هنا عينة العميل من MSDN.لاحظ كيف يرسل العميل بالضبط عدد الأحرف في الرسالة + 1 (بما في ذلك إنهاء حرف) ويتلقى إلى ثابت العازلة من حجم 512.إذا نظرت إلى خادم سبيل المثال, سترى نفس النمط.

نصائح أخرى

بعض الملاحظات على الكود الذي نشر:

  • تحتاج إلى إما 1) صراحة وإرسال null إنهاء بايت أو 2) إلحاق واحدة إلى البيانات تقرأ.
  • منذ كنت تقرأ 512 بايت ، يجب أن تكون أيضا إرسال بالضبط 512 بايت.
  • يمكنك ارسال السلاسل ذات الطول المتغير بدلا من إرسال أول حجم السلسلة ، ثم إرسال العديد من وحدات البايت.بهذه الطريقة عند قراءة البيانات سوف تعرف كم بايت في أن تقرأ سلسلة الفعلي.
  • المشكلة مع ما فعلته سوف ينظر بمجرد إرسال 2 الأشياء على الأنابيب و أنت تقرأ الماضي ما تريد حقا في أول قراءة.
  • إذا كنت تقوم بإرسال فقط 1 الشيء على الأنابيب ، يمكنك الاحتفاظ الخاص بك التعليمات البرمجية ، ولكن إرسال حجم() + 1 عند الكتابة إلى الأنابيب.
  • طلب & readfile / WriteFile كان من المفترض أن ترسل البيانات الثنائية ، وليس بالضرورة السلاسل.حتى تتمكن من جعل وظيفة تسمى ReadString و WriteString التي تطبق اقتراحي حول القراءة/الكتابة الأولى الحجم ثم سلسلة الفعلي.

محاولة شيء من هذا القبيل:

هنا هو رمز لإنشاء أنبوب, والكتابة إليه:

myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL);
TCHAR title[128];
GetWindowText(foundHwnd, title, 128);
WriteFile(myPipe, title, 128*sizeof(TCHAR), &wrote, NULL);//<---In this case we are sending a null terminated string buffer.

و ها هو الكود الذي يقرأ عليه:

if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) {
    MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK);
    return false;
}

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (myPipe == INVALID_HANDLE_VALUE) {
    MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK);
    return false;
}
    // Other code here...
    TCHAR buf[128];
    DWORD read;
    success = ReadFile(myPipe, buf, 128*sizeof(TCHAR), &read, NULL);
    if (read > 0)
        MessageBox(NULL, buf, L"Got Data", MB_OK);

وأنا واجهت هذه المشكلة مع "القمامة في الأنابيب" عند كتابة وظيفة عامة لقراءة المعياري من أي عملية إعدام في موجه الأوامر. لذلك، لم أتمكن من تغيير ما كان يتم كتابتها إلى أنبوب (كما هو مقترح شيوعا)، ويمكن أن يغير فقط في الجانب القراءة. لذلك، أنا "خدع".

إذا لم البيانات أنبوب ينتهي في فاصل لاغيا، أنا محل شار الماضي مع واحد! يبدو أنها تعمل بالنسبة لي. رأيت هذا العمل تماما حيث كانت هناك بلا قيم وحيث لم تكن هناك في نهاية قطع البيانات الخاصة بي.

وأنا قلق بأنني قد تفقد حاسم شار الماضي (وانه من الممكن ان كنت قد!)، ولكن لأغراض بلدي المباشرة، فإن ذلك لن يحدث. قد تفكر في إضافة لاغية بدلا من استبدال نهاية في بعض الظروف ...

وهنا كود SNIPPIT:

const unsigned int MAX_PIPE_PEEKS = 100;
DWORD bytesInPipe = 0;
unsigned int pipePeeks=0;
while( (bytesInPipe==0) && (pipePeeks < MAX_PIPE_PEEKS) )
{
    bSuccess = PeekNamedPipe( g_hChildStd_OUT_Rd, NULL, 0, NULL, 
                              &bytesInPipe, NULL );
    if( !bSuccess ) return bSuccess;  // Bail on critical failure                
    ++pipePeeks;
}
if( bytesInPipe > 0 )
{
    // Read the data written to the pipe (and implicitly clear it)
    DWORD dwRead; 
    CHAR *pipeContents = new CHAR[ bytesInPipe ];    
    bSuccess = ReadFile( g_hChildStd_OUT_Rd, pipeContents, 
                         bytesInPipe, &dwRead, NULL );
    if( !bSuccess || dwRead == 0  )  return FALSE;  // Bail on critical failure              

    // "Cheat" - eliminate garbage at the end of the pipe
    if( pipeContents[ bytesInPipe ] != '\0' )
        pipeContents[ bytesInPipe ] = '\0';
}

وUPDATE:

وبعد إجراء مزيد من التجارب، وجدت أن هذه ليست موثوقة جدا (صدمة، هاه؟). أعتقد أنني على الطريق الصحيح على الرغم من أجل التوصل إلى حل بسيط نسبيا. أي أفكار من أجل الحصول على هذا التصحيح السريع إلى العمل؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top