C ++ Redefinition Header Files (winsock2.h)


143

ฉันจะป้องกันไม่ให้รวมไฟล์ส่วนหัวสองครั้งได้อย่างไร ปัญหาคือฉันรวมถึงในMyClass.hจากนั้นฉันรวมMyClass.hในหลายไฟล์ดังนั้นจึงมีหลายครั้งและเกิดข้อผิดพลาดในการกำหนดใหม่ วิธีการป้องกัน

ฉันใช้ #pragma เพียงครั้งเดียวแทนที่จะใช้ยามและฉันเดาว่าไม่เป็นไร

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

// methods
public:
 MyClass(unsigned short port);
 virtual ~MyClass(void);
};

แก้ไข:ข้อผิดพลาดเล็กน้อยที่ฉันได้รับ

c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(91) : warning C4005: 'AF_IPX' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(460) : see previous definition of 'AF_IPX'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(124) : warning C4005: 'AF_MAX' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(479) : see previous definition of 'AF_MAX'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(163) : warning C4005: 'SO_DONTLINGER' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(402) : see previous definition of 'SO_DONTLINGER'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(206) : error C2011: 'sockaddr' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(485) : see declaration of 'sockaddr'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2143: syntax error : missing '}' before 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2143: syntax error : missing ';' before 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2059: syntax error : 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C2143: syntax error : missing ';' before '}'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(518) : warning C4005: 'IN_CLASSA' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(287) : see previous definition of 'IN_CLASSA'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(524) : warning C4005: 'IN_CLASSB' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(293) : see previous definition of 'IN_CLASSB'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(530) : warning C4005: 'IN_CLASSC' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(299) : see previous definition of 'IN_CLASSC'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(541) : warning C4005: 'INADDR_ANY' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(304) : see previous definition of 'INADDR_ANY'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(543) : warning C4005: 'INADDR_BROADCAST' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(306) : see previous definition of 'INADDR_BROADCAST'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(577) : error C2011: 'sockaddr_in' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(312) : see declaration of 'sockaddr_in'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(132) : error C2011: 'fd_set' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(68) : see declaration of 'fd_set'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(167) : warning C4005: 'FD_SET' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(102) : see previous definition of 'FD_SET'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(176) : error C2011: 'timeval' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(111) : see declaration of 'timeval'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(232) : error C2011: 'hostent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(167) : see declaration of 'hostent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(245) : error C2011: 'netent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(180) : see declaration of 'netent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(252) : error C2011: 'servent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(187) : see declaration of 'servent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(264) : error C2011: 'protoent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(199) : see declaration of 'protoent'

4
คุณใช้ #pragma หนึ่งครั้งดังนั้นควรรวมไว้เพียงครั้งเดียว
Naveen

1
คอมไพเลอร์ของคุณไม่รองรับ pragma เพียงครั้งเดียวเหรอ?
Svetlozar Angelov

ฉันกำลังใช้ Visual Studio 2008 อยู่ทำไม <winsock2.h> รวมสองครั้ง
akif

1
มันอาจจะรวมสองครั้งจากบางส่วนของส่วนหัวรวมจาก MyClass.h
Svetlozar Angelov

5
winsock2 และ winsock มีโครงสร้างทั่วไป คุณต้องรวมเพียงหนึ่งของพวกเขาไม่ใช่ทั้งสอง
Svetlozar Angelov

คำตอบ:


234

ปัญหานี้เกิดขึ้นเมื่อรวม<windows.h>ก่อนหน้า<winsock2.h>นี้ ลองจัดเรียงรายการรวมของคุณที่<windows.h>รวมไว้หลัง<winsock2.h>หรือกำหนด_WINSOCKAPI_ก่อน:

#define _WINSOCKAPI_    // stops windows.h including winsock.h
#include <windows.h>
// ...
#include "MyClass.h"    // Which includes <winsock2.h>

ดูสิ่งนี้ด้วย


ฉันไม่ได้รวม <windows.h> เลยฉันรู้ว่า <winsock2.h> ทำเพื่อฉัน
akif

2
สำหรับฉันรหัสของคุณรวบรวมตกลงด้วยเฉพาะ<winsock2.h>ใน MSVC2008 <windows.h>การรวมทำให้เกิดข้อผิดพลาดในการคอมไพล์เหมือนที่คุณระบุ
pingw33n

<windows.h> ถูกรวมอยู่ใน stdafx.h หรือไม่
Colin Desmond

1
วิธีนี้แก้ไขปัญหาสำหรับฉันใน VS 2010 ด้วย SDK 7.1 ขอบคุณ pingw33n!
adamfisk

ฉันมี#include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>คำสั่งและได้รับ winsock2 ไม่พบไฟล์ h รวมแล้ว#define _WINSOCKAPI_ ข้างต้นทั้ง 3 ยังคงมีข้อผิดพลาดเดียวกัน
Ava

75

เป็นคนอื่น ๆ ชี้ให้เห็นปัญหาที่เกิดขึ้นคือเมื่อจะรวมก่อนwindows.h WinSock2.hเพราะมีwindows.h winsock.hคุณไม่สามารถใช้ทั้งสองและWinSock2.hwinsock.h

Solutions:

  • รวมก่อนWinSock2.h windows.hในกรณีของส่วนหัวที่คอมไพล์แล้วคุณควรแก้ที่นั่น ในกรณีของโครงการที่เรียบง่ายมันเป็นเรื่องง่าย อย่างไรก็ตามในโครงการขนาดใหญ่ (โดยเฉพาะอย่างยิ่งเมื่อเขียนโค้ดแบบพกพาโดยไม่มีส่วนหัวที่คอมไพล์แล้ว) อาจเป็นเรื่องยากมากเพราะเมื่อรวมส่วนหัวของคุณเข้าด้วยWinSock2.hแล้วwindows.hสามารถรวมอยู่ในไฟล์ส่วนหัว / การใช้งานอื่น ๆ

  • กำหนดไว้WIN32_LEAN_AND_MEANก่อนwindows.hหรือกว้างโครงการ แต่มันจะแยกสิ่งอื่น ๆ ที่คุณอาจต้องการและคุณควรรวมไว้ด้วยตัวคุณเอง

  • กำหนดไว้_WINSOCKAPI_ก่อนwindows.hหรือกว้างโครงการ แต่เมื่อคุณรวมWinSock2.hคุณจะได้รับคำเตือนการกำหนดนิยามมาโครใหม่

  • ใช้windows.hแทนWinSock2.hเมื่อwinsock.hมีเพียงพอสำหรับโครงการของคุณ (ในกรณีส่วนใหญ่จะเป็น) ซึ่งอาจส่งผลให้เวลาการรวบรวมนานขึ้น แต่จะแก้ไขข้อผิดพลาด / คำเตือนใด ๆ


14
WIN32_LEAN_AND_MEANเป็นคำตอบสำหรับฉันรถถังมากมาย
Jonatan Cloutier

เกี่ยวกับการ_WINSOCK_แก้ปัญหา: คุณไม่ควรเตือนมาโคร redefinition หากคำจำกัดความทั้งสองเหมือนกัน ข้อผิดพลาดทั่วไปคือคนเพิ่มคำนิยามให้กับโครงการโดยไม่ต้องตั้งค่าใด ๆ และคาดว่าคำนิยามที่ว่างเปล่า อย่างไรก็ตามหากคุณเพิ่ม-D_WINSOCK_ในบรรทัด cmd มันจะถูกตั้งค่า_WINSOCK_เป็น 1 ในการสร้างคำจำกัดความที่ว่างเปล่า-D_WINSOCK_=จะต้องผ่าน
Paweł Stankowski

หากคุณใช้#define _WINSOCKAPI_คุณอาจต้องใช้#define _WINSOCK_DEPRECATED_NO_WARNINGSทั้งนี้ขึ้นอยู่กับสถานการณ์ของคุณ
Lorien Brune

16

โอ้ - ความอัปลักษณ์ของ Windows ... ลำดับการรวมมีความสำคัญที่นี่ คุณต้องรวม winsock2.h ก่อน windows.h เนื่องจาก windows.h อาจรวมอยู่ในส่วนหัวของคุณ precompiled (stdafx.h) คุณจะต้องรวม winsock2.h จากที่นั่นด้วย:

#include <winsock2.h>
#include <windows.h>

14

โดยใช้ "หัวยาม":

#ifndef MYCLASS_H
#define MYCLASS_H

// This is unnecessary, see comments.
//#pragma once

// MyClass.h

#include <winsock2.h>

class MyClass
{

// methods
public:
    MyClass(unsigned short port);
    virtual ~MyClass(void);
};

#endif

2
ฉันเดาว่าฉันผิด (4 upvotes ก่อนหน้านี้) แต่ฉันคิดว่าการใช้ยามรักษาการณ์นั้นเหมือนกับ pragma เพียงครั้งเดียวคุณทำให้พวกเขาทั้งสองเหรอ?
Svetlozar Angelov

1
ฉันมี #pragma ครั้งหนึ่งซึ่ง afaik เป็นการ์ดส่วนหัวที่เหมือนกัน
30745

2
@Angelov: ใช่นั่นคือสิ่งที่ฉันพูดพวกเขาเป็นสิ่งเดียวกัน ปัญหาไม่ได้อยู่กับไฟล์ส่วนหัวของฉัน แต่ฉันคิดว่า <winsock2.h> ตัวเองไม่มีการ์ดส่วนหัวหรืออาจเป็นอย่างอื่น
akif

1
โดย definition #pragma ขึ้นอยู่กับคอมไพเลอร์ (ไม่ใช่มาตรฐาน) อาจไม่ทำงานกับคอมไพเลอร์ทั้งหมด ฉันรู้ว่า visual studio ยอมรับ #pargma หนึ่งครั้ง ฉันไม่แน่ใจว่าถ้า gcc ทำ ฉันรู้ว่ารวมถึงยามทำงานเสมอ ฉันใช้ทั้ง #pragma หนึ่งครั้งและรวมการ์ดเพื่อความสามารถในการป้องกันสูงสุด ดูเหมือนว่า MSVC มีการจัดการ #pragma ที่เหมาะสมที่สุดและ gcc ได้เพิ่มประสิทธิภาพการจัดการของยามรวม ความแตกต่างเพียงอย่างเดียวกับส่วนหัวมาตรฐานของฉันคือ #praga หนึ่งครั้งอยู่นอกหน่วยป้องกัน
KitsuneYMG

1
คำสั่ง '#pragma' ถูกระบุไว้ในมาตรฐาน ANSI เพื่อให้มีผลตามที่กำหนดไว้โดยพลการ ในตัวประมวลผลล่วงหน้าของ GNU C '#pragma' พยายามครั้งแรกเพื่อเรียกใช้เกม 'โกง'; หากล้มเหลวจะพยายามเรียกใช้เกม 'แฮ็ค'; หากล้มเหลวก็จะพยายามรัน GNU Emacs ที่แสดงหอคอยแห่งฮานอย หากสิ่งนั้นล้มเหลวรายงานข้อผิดพลาดร้ายแรง ไม่ว่าในกรณีใดการประมวลผลล่วงหน้าไม่ดำเนินการต่อ - Richard M. Stallman ผู้
ประมวลผลล่วงหน้า

7

ฉันพบปัญหานี้เมื่อพยายามดึงแพ็คเกจของบุคคลที่สามซึ่งเห็นได้ชัดว่ารวมถึง windows.h บางแห่งที่อยู่ในส่วนหัว การกำหนด_WINSOCKAPI_ในระดับโครงการนั้นง่ายกว่ามาก (ไม่ต้องพูดถึงการบำรุงรักษามาก) กว่าลุยซุปและแก้ไขปัญหารวมถึง


1
บน Qt ในไฟล์. pro จะมีลักษณะดังนี้: DEFINES += _WINSOCKAPI_
phyatt

@ รางวัล: คุณควรเปลี่ยนเป็นคำตอบถ้าคุณไม่ฉันจะ!
Leif Gruenwoldt

@LeifGruenwoldt ไปเลย! ดีใจที่ฉันสามารถช่วย
phyatt

6

ใน VS 2015 สิ่งต่อไปนี้จะทำงาน:

#define _WINSOCKAPI_

ในขณะที่ต่อไปนี้จะไม่:

#define WIN32_LEAN_AND_MEAN

6

ฉันจะตรวจสอบ recursive รวมถึงผมเห็นไฟล์ส่วนหัวซึ่งรวมถึง (ซ้ำ) บาง#include "windows.h"และและการเขียน#include "Winsock.h" #include "Winsock2.h"ในไฟล์นี้ฉันเพิ่ม#include "Winsock2.h"เป็นรายการแรก

เพียงแค่เรื่องของความอดทนรวมถึงดูที่หนึ่งโดยหนึ่งและสร้างคำสั่งนี้เป็นครั้งแรก #include "Winsock2.h"แล้ว#include "windows.h"


5

ฉันพบลิงค์windows.h และ winsock2.h นี้ซึ่งเป็นทางเลือกที่ใช้งานได้ดีสำหรับฉัน:

#define _WINSOCKAPI_    // stops windows.h including winsock.h
#include <windows.h>
#include <winsock2.h>

ฉันมีปัญหาในการค้นหาว่าปัญหาเกิดขึ้นที่ใดโดยการเพิ่ม #define นั้นฉันสามารถสร้างได้โดยไม่ต้องค้นหาออก


4

ฉันจะไม่ใช้เพียงแค่ FILENAME_H แต่

#ifndef FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD
#define FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD

//code stuff
#endif // FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD

ฉันใช้ guid ของ postfix เสมอ ฉันเจอฐานรหัสที่แย่มากเมื่อหลายปีก่อนที่มีไฟล์ส่วนหัวที่แตกต่างกันซึ่งมีชื่อไฟล์เหมือนกันและมีตัวป้องกัน ไฟล์ที่เป็นปัญหาได้กำหนดคลาสด้วยชื่อเดียวกัน หากใช้เฉพาะเนมสเปซ บางโครงการรวบรวมบางอย่างไม่ได้ การใช้การ์ดที่ไม่ซ้ำกันเป็นส่วนหนึ่งของการแก้ปัญหาในการแยกส่วนหัวและเนื้อหาของพวกเขา

บน Windows ที่มี Visual Studio ให้ใช้ guidgen.exe บน Linux uuidgen -t


4

ฉันพบปัญหาเดียวกันและนี่คือสิ่งที่ฉันค้นพบ:

จากส่วนการส่งออกนี้ -

c: \ program files \ microsoft sdks \ windows \ v6.0a \ include \ ws2def.h (91): คำเตือน C4005: 'AF_IPX': นิยามใหม่ของแมโคร
c: \ program files \ microsoft sdks \ windows \ v6.0a \ include \ winsock.h (460): ดูคำจำกัดความก่อนหน้าของ 'AF_IPX'

- ดูเหมือนว่าทั้ง ws2def.h และ winsock.h ได้รวมอยู่ในโซลูชันของคุณแล้ว

หากคุณดูไฟล์ ws2def.h มันเริ่มต้นด้วยความคิดเห็นดังต่อไปนี้ -

/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:

    ws2def.h

Abstract:

    This file contains the core definitions for the Winsock2
    specification that can be used by both user-mode and 
    kernel mode modules.

    This file is included in WINSOCK2.H. User mode applications
    should include WINSOCK2.H rather than including this file
    directly. This file can not be included by a module that also
    includes WINSOCK.H.

Environment:

    user mode or kernel mode

--*/

ให้ความสนใจกับบรรทัดสุดท้าย - "ไฟล์นี้ไม่สามารถรวมโดยโมดูลที่มี WINSOCK.H"

ยังคงพยายามแก้ไขปัญหาโดยไม่ทำการเปลี่ยนแปลงรหัส

แจ้งให้เราทราบหากนี่เหมาะสม


2

คุณควรใช้เฮดเดอร์การ์ด

วางบรรทัดเหล่านั้นที่ด้านบนของไฟล์ส่วนหัว

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

และที่ด้านล่าง

#endif

1
#pragma หนึ่งครั้งและรวมถึงผู้พิทักษ์ก็เหมือนกันใช่ไหม
akif

พวกมันไม่เหมือนกัน - ตัวป้องกันส่วนหัวจะป้องกันการรวมไฟล์ไว้ในระดับตัวประมวลผลก่อนอีกทั้งยังเห็นได้ชัดว่าพกพาสะดวกกว่า #pragma หนึ่งครั้ง
Timo Geusch

1
ฉันหมายความว่าพวกเขาถูกสร้างขึ้นเพื่อวัตถุประสงค์เดียวกัน :)
akif

2
#pragma ครั้งเดียวไม่ใช่แบบมาตรฐาน afaik
ntcong

2

#pragma onceขึ้นอยู่กับเส้นทางแบบเต็มของชื่อไฟล์ ดังนั้นสิ่งที่คุณน่าจะเป็นคือมีสำเนาเหมือนกันสองชุดคือ MyClass.h หรือ Winsock2.h ในไดเรกทอรีที่ต่างกัน


ลิงก์สัญลักษณ์หรือจุดเชื่อมต่อ NTFS จะทำให้ระบบหยุดทำงาน
Thomi

1

#pragma onceแม้ในคอมไพเลอร์ MS และไม่รองรับคอมไพเลอร์อื่น ๆ อีกมากมาย อย่างที่คนอื่น ๆ พูดถึงการใช้ยามรวมเป็นวิธีที่จะไป อย่าใช้#pragma onceเลยเพราะจะทำให้ชีวิตของคุณง่ายขึ้นมาก


3
โชคไม่ดีที่ฉันเห็นว่ามียามรวมศูนย์ไม่เรียบร้อยไม่ว่าตำแหน่งที่พิมพ์ผิดหมายถึงการ์ดไม่ทำงานจริงหรือไฟล์ที่ชื่อเดียวกันในไดเรกทอรีต่าง ๆ ใช้โทเค็นเดียวกันหรือตำแหน่งที่ใช้โทเค็นเริ่มต้นด้วยสองครั้ง ขีดล่างหรือขีดล่างแล้วใช้ตัวพิมพ์ใหญ่ (และด้วยเหตุนี้จึงไม่ใช่แบบพกพาเหมือนกับ #pragma หนึ่งครั้ง) ดังนั้นสำหรับโค้ดที่ไม่สามารถพกพาได้โดยเนื้อแท้เหมือนกับทุกอย่างที่ใช้ winsock.h ฉันไม่ได้รับการรบกวนอย่างมากจาก #pragma เมื่อถึงจุดที่คุณบอกว่ามันเป็นสิ่งสกปรก เมื่อใดที่ล้มเหลวนอกจากจะไม่รองรับเลย?
Steve Jessop

3
เมื่อใช้#pragma onceคอมไพเลอร์จะใช้ชื่อโหนดไฟล์ส่วนหัวเป็นรหัสเฉพาะ สิ่งนี้อาจล้มเหลวได้หากคุณมีลิงค์สัญลักษณ์หรือจุดเชื่อมต่อ NTFS ในแผนผังแหล่งที่มาของคุณ (มากกว่าที่คุณคิด) หรือแม้ว่าคุณจะมีไฟล์ชื่อเดียวกันในระบบอื่นรวมถึงไดเรกทอรี (สิ่งนี้เกิดขึ้นกับฉันก่อนเมื่อฉันมี เวอร์ชัน 1 และเวอร์ชัน 2 ของไลบรารีเดียวกันที่ติดตั้งกับสองระบบที่แตกต่างกันรวมถึงพา ธ ) บรรทัดล่าง: สำหรับฉันฉันชอบที่จะควบคุมได้มากขึ้นและใช้ชีวิตอยู่กับความผิดพลาดของการเป็นครั้งคราวแทนที่จะเชื่อใจนักแปลที่จะทำเพื่อฉัน
Thomi


1

ในโครงการของฉัน (ฉันใช้ VS 2008 SP1) ทำงานวิธีแก้ไขปัญหาถัดไป:

ไฟล์ส่วนหัว:

//myclass.h
#pragma once
#define _WINSOCKAPI_
#include <windows.h>

คลาส Cpp:

//myclass.cpp
#include "Util.h"
#include "winsock2class.h"
#pragma comment(lib, "Ws2_32.lib")

โดยที่ #include "winsock2class.h" หมายถึงคลาสที่ใช้งาน winsock2.h:

//winsock2class.h
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")

0

จริงๆแล้วฉันพบปัญหาที่ฉันต้องกำหนด winsock2.h เนื่องจากการรวมครั้งแรกดูเหมือนว่าจะมีปัญหาอื่น ๆ ที่รวมถึงจากแพ็คเกจอื่น ๆ หวังว่าสิ่งนี้จะเป็นประโยชน์กับคนที่พบปัญหาเดียวกันไม่ใช่เฉพาะ windows.h แต่ทุกอย่างรวมอยู่ด้วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.