الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

مساعدة فى تصميم FrameWork

مغلق
بدأه justnow في 28 سبتمبر 2004 · 2 رد · 652 مشاهدة · في قسم برمجة الألعاب و الرسوميات العام
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم

الاخوة الاعضاء فى منتدى الجرافيكس

اقوم الان بتصميم Frame كل البرامج التى

اكتبها ب Direct3D9.0 لكن وا جهتنى مشكلة

واحدة, هى ان عند تصغير النافذة تقوم بتعليق

الجهاز. ارفق لكم الملف.

#2

لم استطع ارفاق الملف لذا ها هو

#include "windows.h"
#include "d3d9.h"
#include "d3dx9.h"
#include "dxerr9.h"




/*******************************************************/
/***************Direct3D Objects Here*******************/
LPDIRECT3D9 g_pD3D                = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice    = NULL;
/*******************************************************/
/*******************************************************/


/*******************************************************/
/***************ALL Normal Variables *******************/
HWND g_hApplicationWindow;

/*******************************************************/
/*******************************************************/

void    AppLoop();
void    AppShutDown();


HRESULT InitD3D();
HRESULT Render();
HRESULT ValidateDevice();
HRESULT RestoreDeviceObjects();
HRESULT InvalidateDeviceObjects();

HRESULT D3DError(HRESULT hrCode, int nLine, char* szFile, char* szExtraInfo);

#define SAFE_RELEASE(X) (X)->Release(); (X) = NULL

struct D3DCURRENTSETTINGS
{
	int                   m_nDeviceHeight;
	int                   m_nDeviceWidth;
	float                 m_fScreenAspect;
	BOOL                  m_bWindowed;
	BOOL                  m_bMultiSampling;
	D3DFORMAT             m_D3DFormat;
	D3DPRESENT_PARAMETERS m_PresentParams;

	BOOL SetAspect()
	{
  if(m_nDeviceHeight == 0) return FALSE;

  m_fScreenAspect = (float)m_nDeviceWidth/(float)m_nDeviceHeight;
  return TRUE;
	}

};

D3DCURRENTSETTINGS g_D3DSettings;


LRESULT CALLBACK MsgProc(HWND hWnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{

	case WM_CLOSE:
  ::DestroyWindow(hWnd);
  return 0;
  break;


	case WM_DESTROY:
  ::PostQuitMessage(0);
  return 0;

	case WM_SIZE:
  {
 	 if( g_pD3DDevice != NULL && wParam != SIZE_MINIMIZED )
 	 {
    InvalidateDeviceObjects();

    g_D3DSettings.m_PresentParams.BackBufferWidth  = LOWORD(lParam);
    g_D3DSettings.m_PresentParams.BackBufferHeight = HIWORD(lParam);

    HRESULT rslt = g_pD3DDevice->Reset( &g_D3DSettings.m_PresentParams );
                if( FAILED(rslt) )
                {
                    D3DError(rslt,__LINE__,__FILE__,"Failed To Reet the device during resizing");
   	 ::PostQuitMessage(0);
                }

    RestoreDeviceObjects();
 	 }
 	 return DefWindowProc(hWnd,uMsg,wParam,lParam);
  }


	default:
  return DefWindowProc(hWnd,uMsg,wParam,lParam);
  
	}

}


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
      // Register the window class
      WNDCLASSEX wc;

      ZeroMemory(&wc, sizeof(WNDCLASSEX));
      wc.cbSize=sizeof(WNDCLASSEX);                       // size of the window struct in bytes
      wc.style=CS_HREDRAW | CS_VREDRAW | CS_OWNDC;        // window styles to use
      wc.lpfnWndProc=MsgProc;                             // function name of event handler
      wc.hInstance=hInstance;                             // handle to this apps instance
      wc.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);// background colour of window
      wc.hIcon= LoadIcon(NULL, IDI_APPLICATION);          // icon for the app window
      wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);         // icon when minimized to taskbar
      wc.hCursor=LoadCursor(NULL, IDC_ARROW);             // cursor to use for this window
      wc.lpszClassName="MY_WINDOW_CLASS_NAME";            // name for this class

      RegisterClassEx( &wc );

      // Create the application's window
   g_D3DSettings.m_nDeviceWidth = 600;
   g_D3DSettings.m_nDeviceHeight= 400;

   g_D3DSettings.SetAspect();


      g_hApplicationWindow = CreateWindow("MY_WINDOW_CLASS_NAME", "MY WINDOW TITLE",
          WS_OVERLAPPEDWINDOW, 100, 100, 640, 480,
          NULL, NULL, wc.hInstance, NULL );

      // Show the window
      ShowWindow( g_hApplicationWindow, nCmdShow );
      UpdateWindow( g_hApplicationWindow );

  HRESULT rslt = InitD3D();
  if(FAILED(rslt))
  {
   D3DError(rslt,__LINE__,__FILE__,"InitD3D Failed");
   return rslt;
  }

      // Enter the message loop
      MSG msg;
      ZeroMemory( &msg, sizeof(msg) );
      while( msg.message!=WM_QUIT )
      {
          if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
          {
              TranslateMessage( &msg );
              DispatchMessage( &msg );
          }
          else
          {
              AppLoop();
          }
      }

   AppShutDown();
   

      UnregisterClass( "MY_CLASS_NAME", wc.hInstance );
      return 0;

}


HRESULT InitD3D()
{
	g_pD3D=Direct3DCreate9(D3D_SDK_VERSION);

	if(g_pD3D==NULL)
	{
  return E_FAIL;
	}


	// Populate our struct with how we want to set up D3D...
	g_D3DSettings.m_bWindowed=TRUE;
	g_D3DSettings.m_bMultiSampling=FALSE;
	g_D3DSettings.m_D3DFormat=D3DFMT_X8R8G8B8;

	////////////////////////////////////////////////////
	/////////////Time To Prepare Our Device/////////////

	D3DPRESENT_PARAMETERS d3dpp;
	D3DDISPLAYMODE        d3ddm;

	g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm);

	ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
	d3dpp.BackBufferWidth  = g_D3DSettings.m_nDeviceWidth;
	d3dpp.BackBufferHeight  = g_D3DSettings.m_nDeviceHeight;
	d3dpp.BackBufferFormat = g_D3DSettings.m_bWindowed ? d3ddm.Format : g_D3DSettings.m_D3DFormat;
	d3dpp.hDeviceWindow=g_hApplicationWindow;
	d3dpp.Windowed=g_D3DSettings.m_bWindowed;
	d3dpp.BackBufferCount=1;	
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;


	if(g_D3DSettings.m_bMultiSampling)
	{
  
  if( SUCCEEDED(g_pD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
                d3dpp.BackBufferFormat, 
                g_D3DSettings.m_bWindowed, 
                D3DMULTISAMPLE_2_SAMPLES, NULL)))
  {
 	 d3dpp.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
  }
  else
 	 d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
	}
	else
  d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;

	d3dpp.EnableAutoDepthStencil=TRUE;
	d3dpp.AutoDepthStencilFormat=D3DFMT_D16;
	d3dpp.FullScreen_RefreshRateInHz=0;
	d3dpp.PresentationInterval = g_D3DSettings.m_bWindowed ? 0 : D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

	HRESULT rslt=g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hApplicationWindow,
       D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice);
	if(FAILED(rslt))
	{
  rslt=g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hApplicationWindow,
           D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice);
  if(FAILED(rslt))
  {
 	 return E_FAIL;
  }
	}

	g_D3DSettings.m_PresentParams=d3dpp;
	if(g_D3DSettings.m_bWindowed)
  g_D3DSettings.m_D3DFormat=d3dpp.BackBufferFormat;


	return RestoreDeviceObjects();

}
HRESULT Render()
{
	if(!g_pD3DDevice) return E_FAIL;
	HRESULT rslt = ValidateDevice();
	if(FAILED(rslt)) return rslt;


	g_pD3DDevice->Clear(0,0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,55), 0.0f, 0);

	rslt = g_pD3DDevice->BeginScene();
	if(FAILED(rslt)) return rslt;

	g_pD3DDevice->EndScene();

	g_pD3DDevice->Present(NULL,NULL,NULL,NULL);

	return S_OK;
}

HRESULT ValidateDevice()
{
	HRESULT rslt = g_pD3DDevice->TestCooperativeLevel();
	if(FAILED(rslt))
	{
  if(rslt == D3DERR_DEVICELOST)
 	 return E_FAIL;

  if(rslt == D3DERR_DEVICENOTRESET)
  {
 	 InvalidateDeviceObjects();

 	 g_pD3DDevice->Reset(&g_D3DSettings.m_PresentParams);

 	 RestoreDeviceObjects();
  }
	}
	return S_OK;
}

HRESULT RestoreDeviceObjects()
{
	return S_OK;
}

HRESULT InvalidateDeviceObjects()
{
	return S_OK;
}


void AppLoop()
{
	HRESULT rslt;
	rslt = Render();
	if(FAILED(rslt)) D3DError(rslt,__LINE__,__FILE__,"Render() Has Failed");
}

void AppShutDown()
{
	InvalidateDeviceObjects();

	SAFE_RELEASE(g_pD3D);
	SAFE_RELEASE(g_pD3DDevice);
  
}


HRESULT D3DError(HRESULT hrCode, int nLine, char* szFile, char* szExtraInfo)
{
	::OutputDebugString("--------------------------D3DError Has  Been Called---------------------------\n");
	char pszError[256];
	wsprintf(pszError, "The following error occurred on line %d of %s\n", nLine, szFile);
	::OutputDebugString(pszError);
	::OutputDebugString(DXGetErrorString9(hrCode));
	::OutputDebugString("\n");
	if(szExtraInfo)
	{
  ::OutputDebugString("Extra information: ");
  ::OutputDebugString(szExtraInfo);
  ::OutputDebugString("\n");
	}

	return hrCode;
}
#3

السلام عليكم ,,

نأسف على التأخير ,,

المشكلة أن حلقة الرسائل عندما لايكون هناك أي حدث في صف الرسائل ,, تستدعى الدالة AppLoop() ,, ليعمل البرنامج ,, والمشكلة أنه اذا لم يكن هناك دالة في بلوك ال else في كما في الكود التالي ,, سيعلق البرنامج ,,

if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
         {
             TranslateMessage( &msg );
             DispatchMessage( &msg );
         }
         else
         {
    
         }

كودك المكتوب كالتالي :

if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
         {
             TranslateMessage( &msg );
             DispatchMessage( &msg );
         }
         else
         {
 	 
             AppLoop();
      
         }

حيث أن بلوك ال else فيه استدعاء لتنفيذ ال AppLoop ,, وعند تصغير البرنامج فان الدالة AppLoop لن تفعل شيئا في الواقع لأنه لاتوجد مساحة للعرض كما فهمت أنا ولم أتعمق في الكود أصلا ,,

لكن يكفي أن تسكت البرنامج وقت تصغير البرنامج لكي لايفعل شيئا ويعود ليعمل فور تكبير النافذة مباشرة ,, لأنه في الواقع لايفعل شيئا حقا عند تصغير النافذة فكتبت الكود التالي في بلوك ال else :

if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
         {
             TranslateMessage( &msg );
             DispatchMessage( &msg );
         }
         else
         {
    if(!minimized)
             AppLoop();
    else Sleep(10);
    
         }

حيث المتغير minimized يصبح true عند تصغير البرنامج ثم يصبح false عندما يعود للوضع الطبيعي مرة أخرى ,,

خذ الكود النهائي :

#include "windows.h"
#include "d3d9.h"
#include "d3dx9.h"
//#include "dxerr9.h"
#pragma comment(lib,"d3d9.lib")
//#pragma comment(lib,"d3dX9.lib")


bool minimized=false;
/*******************************************************/
/***************Direct3D Objects Here*******************/
LPDIRECT3D9 g_pD3D                = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice    = NULL;
/*******************************************************/
/*******************************************************/


/*******************************************************/
/***************ALL Normal Variables *******************/
HWND g_hApplicationWindow;

/*******************************************************/
/*******************************************************/

void    AppLoop();
void    AppShutDown();


HRESULT InitD3D();
HRESULT Render();
HRESULT ValidateDevice();
HRESULT RestoreDeviceObjects();
HRESULT InvalidateDeviceObjects();

HRESULT D3DError(HRESULT hrCode, int nLine, char* szFile, char* szExtraInfo);

#define SAFE_RELEASE(X) (X)->Release(); (X) = NULL

struct D3DCURRENTSETTINGS
{
int                   m_nDeviceHeight;
int                   m_nDeviceWidth;
float                 m_fScreenAspect;
BOOL                  m_bWindowed;
BOOL                  m_bMultiSampling;
D3DFORMAT             m_D3DFormat;
D3DPRESENT_PARAMETERS m_PresentParams;

BOOL SetAspect()
{
 if(m_nDeviceHeight == 0) return FALSE;

 m_fScreenAspect = (float)m_nDeviceWidth/(float)m_nDeviceHeight;
 return TRUE;
}

};

D3DCURRENTSETTINGS g_D3DSettings;


LRESULT CALLBACK MsgProc(HWND hWnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{

case WM_CLOSE:
 ::DestroyWindow(hWnd);
 return 0;
 break;


case WM_DESTROY:
 ::PostQuitMessage(0);
 return 0;

case WM_SIZE:
 {
  
  if( g_pD3DDevice != NULL && wParam != SIZE_MINIMIZED )
  {minimized=false;
   InvalidateDeviceObjects();

   g_D3DSettings.m_PresentParams.BackBufferWidth  = LOWORD(lParam);
   g_D3DSettings.m_PresentParams.BackBufferHeight = HIWORD(lParam);

   HRESULT rslt = g_pD3DDevice->Reset( &g_D3DSettings.m_PresentParams );
               if( FAILED(rslt) )
               {
                   D3DError(rslt,__LINE__,__FILE__,"Failed To Reet the device during resizing");
    ::PostQuitMessage(0);
               }

   RestoreDeviceObjects();
  }

  if(wParam==SIZE_MINIMIZED)
  {
   minimized=true;
  }

  if(wParam==SIZE_MAXIMIZED)
  {
   
  }


  return DefWindowProc(hWnd,uMsg,wParam,lParam);
 }


default:
 return DefWindowProc(hWnd,uMsg,wParam,lParam);

}

}


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
     // Register the window class
     WNDCLASSEX wc;

     ZeroMemory(&wc, sizeof(WNDCLASSEX));
     wc.cbSize=sizeof(WNDCLASSEX);                       // size of the window struct in bytes
     wc.style=CS_HREDRAW | CS_VREDRAW | CS_OWNDC;        // window styles to use
     wc.lpfnWndProc=MsgProc;                             // function name of event handler
     wc.hInstance=hInstance;                             // handle to this apps instance
     wc.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);// background colour of window
     wc.hIcon= LoadIcon(NULL, IDI_APPLICATION);          // icon for the app window
     wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);         // icon when minimized to taskbar
     wc.hCursor=LoadCursor(NULL, IDC_ARROW);             // cursor to use for this window
     wc.lpszClassName="MY_WINDOW_CLASS_NAME";            // name for this class

     RegisterClassEx( &wc );

     // Create the application's window
  g_D3DSettings.m_nDeviceWidth = 600;
  g_D3DSettings.m_nDeviceHeight= 400;

  g_D3DSettings.SetAspect();


     g_hApplicationWindow = CreateWindow("MY_WINDOW_CLASS_NAME", "MY WINDOW TITLE",
         WS_OVERLAPPEDWINDOW, 100, 100, 640, 480,
         NULL, NULL, wc.hInstance, NULL );

     // Show the window
     ShowWindow( g_hApplicationWindow, nCmdShow );
     UpdateWindow( g_hApplicationWindow );

 HRESULT rslt = InitD3D();
 if(FAILED(rslt))
 {
  D3DError(rslt,__LINE__,__FILE__,"InitD3D Failed");
  return rslt;
 }

     // Enter the message loop
     MSG msg;
     ZeroMemory( &msg, sizeof(msg) );
     while( msg.message!=WM_QUIT )
     {
         if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
         {
             TranslateMessage( &msg );
             DispatchMessage( &msg );
         }
         else
         {
    if(!minimized)
             AppLoop();
    else Sleep(10);
    
         }
     }

  AppShutDown();
  

     UnregisterClass( "MY_CLASS_NAME", wc.hInstance );
     return 0;

}


HRESULT InitD3D()
{
g_pD3D=Direct3DCreate9(D3D_SDK_VERSION);

if(g_pD3D==NULL)
{
 return E_FAIL;
}


// Populate our struct with how we want to set up D3D...
g_D3DSettings.m_bWindowed=TRUE;
g_D3DSettings.m_bMultiSampling=FALSE;
g_D3DSettings.m_D3DFormat=D3DFMT_X8R8G8B8;

////////////////////////////////////////////////////
/////////////Time To Prepare Our Device/////////////

D3DPRESENT_PARAMETERS d3dpp;
D3DDISPLAYMODE        d3ddm;

g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm);

ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
d3dpp.BackBufferWidth  = g_D3DSettings.m_nDeviceWidth;
d3dpp.BackBufferHeight  = g_D3DSettings.m_nDeviceHeight;
d3dpp.BackBufferFormat = g_D3DSettings.m_bWindowed ? d3ddm.Format : g_D3DSettings.m_D3DFormat;
d3dpp.hDeviceWindow=g_hApplicationWindow;
d3dpp.Windowed=g_D3DSettings.m_bWindowed;
d3dpp.BackBufferCount=1; 
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;


if(g_D3DSettings.m_bMultiSampling)
{

 if( SUCCEEDED(g_pD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
               d3dpp.BackBufferFormat, 
               g_D3DSettings.m_bWindowed, 
               D3DMULTISAMPLE_2_SAMPLES, NULL)))
 {
  d3dpp.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
 }
 else
  d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
}
else
 d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;

d3dpp.EnableAutoDepthStencil=TRUE;
d3dpp.AutoDepthStencilFormat=D3DFMT_D16;
d3dpp.FullScreen_RefreshRateInHz=0;
d3dpp.PresentationInterval = g_D3DSettings.m_bWindowed ? 0 : D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

HRESULT rslt=g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hApplicationWindow,
      D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice);
if(FAILED(rslt))
{
 rslt=g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hApplicationWindow,
          D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice);
 if(FAILED(rslt))
 {
  return E_FAIL;
 }
}

g_D3DSettings.m_PresentParams=d3dpp;
if(g_D3DSettings.m_bWindowed)
 g_D3DSettings.m_D3DFormat=d3dpp.BackBufferFormat;


return RestoreDeviceObjects();

}
HRESULT Render()
{


if(!g_pD3DDevice) return E_FAIL;
HRESULT rslt = ValidateDevice();
if(FAILED(rslt)) return rslt;
g_pD3DDevice->Clear(0,0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,55), 0.0f, 0);

rslt = g_pD3DDevice->BeginScene();
if(FAILED(rslt)) return rslt;
g_pD3DDevice->EndScene();

g_pD3DDevice->Present(NULL,NULL,NULL,NULL);


return S_OK;
}

HRESULT ValidateDevice()
{
HRESULT rslt = g_pD3DDevice->TestCooperativeLevel();
if(FAILED(rslt))
{
 if(rslt == D3DERR_DEVICELOST)
  return E_FAIL;

 if(rslt == D3DERR_DEVICENOTRESET)
 {
  InvalidateDeviceObjects();

  g_pD3DDevice->Reset(&g_D3DSettings.m_PresentParams);

  RestoreDeviceObjects();
 }
}
return S_OK;
}

HRESULT RestoreDeviceObjects()
{
return S_OK;
}

HRESULT InvalidateDeviceObjects()
{
return S_OK;
}


void AppLoop()
{
HRESULT rslt;
rslt = Render();
if(FAILED(rslt)) D3DError(rslt,__LINE__,__FILE__,"Render() Has Failed");
}

void AppShutDown()
{
InvalidateDeviceObjects();

SAFE_RELEASE(g_pD3D);
SAFE_RELEASE(g_pD3DDevice);

}


HRESULT D3DError(HRESULT hrCode, int nLine, char* szFile, char* szExtraInfo)
{
::OutputDebugString("--------------------------D3DError Has  Been Called---------------------------\n");
char pszError[256];
wsprintf(pszError, "The following error occurred on line %d of %s\n", nLine, szFile);
::OutputDebugString(pszError);
//::OutputDebugString(DXGetErrorString9(hrCode));
::OutputDebugString("\n");
if(szExtraInfo)
{
 ::OutputDebugString("Extra information: ");
 ::OutputDebugString(szExtraInfo);
 ::OutputDebugString("\n");
}

return hrCode;
}

شغله مباشرة في برنامج وندوز لأن المكتبات مرفقة في الكود نفسه باستخدام الموجه Pragma comment

banner_60_468.gif

NOTHING IS IMPOSSIBLE

هذا الموضوع مغلق.

مواضيع مشابهة