#include <windows.h>
#include <windowsx.h>
#include <winsock.h>
#include <commctrl.h>
#include "resource.h"

// -----------------------------------------------------
// Описание функций
// -----------------------------------------------------

// Функция главного окна
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Функция для обработки сообщения WM_CREATE
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);

// Функция для обработки сообщения WM_DESTROY
void WndProc_OnDestroy(HWND hWnd);

// Функция для обработки сообщения WM_COMMAND
void WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify);

// Функция для обработки сообщения WM_SIZE
void WndProc_OnSize(HWND hWnd, UINT state, int cx, int cy);

// Установка соединения
void SetConnection(HWND hWnd);

// Передача сообщения
void SendMsg(HWND hWnd);

// Порт сервера
#define SERV_PORT 5000

#define IDS_STATUSBAR 802

// -----------------------------------------------------
// Глобальные переменные
// -----------------------------------------------------

// Идентификатор приложения
HINSTANCE hInst;

// Название приложения
char szAppName[] = "WClientUDP";

// Заголовок главного окна приложения
char szAppTitle[] = "Windows Socket UDP Client Demo";

// Идентификатор органа управления Statusbar
HWND hwndSb;

// Сокет клиента
SOCKET srv_socket;

// Адрес сервера
SOCKADDR_IN dest_sin;

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------

int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;

  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
  	// Если окно приложения было свернуто в пиктограмму,
	  // восстанавливаем его
    if(IsIconic(hWnd))
	  ShowWindow(hWnd, SW_RESTORE);

    // Выдвигаем окно приложения на передний план
	  SetForegroundWindow(hWnd);
    return FALSE;
  }

  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON_SM), IMAGE_ICON, 16, 16, 0);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0);
  
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
  wc.lpszClassName = szAppName;

  // Вызываем функцию RegisterClassEx, которая выполняет
  // регистрацию окна
  if(!RegisterClassEx(&wc))
    if(!RegisterClass((LPWNDCLASS)&wc.style))
	  return FALSE;
    
  InitCommonControls();
  
  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW,
   	 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------

LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hWnd, WM_CREATE, WndProc_OnCreate);
    HANDLE_MSG(hWnd, WM_COMMAND, WndProc_OnCommand);
    HANDLE_MSG(hWnd, WM_SIZE, WndProc_OnSize);
    HANDLE_MSG(hWnd, WM_DESTROY, WndProc_OnDestroy);

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

// -----------------------------------------------------
// Функция WndProc_OnCreate
// -----------------------------------------------------

BOOL WndProc_OnCreate(HWND hWnd, 
                      LPCREATESTRUCT lpCreateStruct)
{
  int rc;
  WSADATA WSAData;
  char szTemp[128];

  // Инициализация и проверка версии Windows Sockets
  rc = WSAStartup(MAKEWORD(1, 1), &WSAData);
  if(rc != 0)
  {
    MessageBox(NULL, "WSAStartup Error", "Error", MB_OK);
    return FALSE;
  }

  // Отображаем описание и версию системы Windows Sockets
  // в окне органа управления Statusbar
  wsprintf(szTemp, "Server use %s %s", 
    WSAData.szDescription,WSAData.szSystemStatus);

  hwndSb = CreateStatusWindow(WS_CHILD | WS_VISIBLE 
    | WS_BORDER | SBARS_SIZEGRIP, 
    szTemp, hWnd, IDS_STATUSBAR);

  return TRUE;
}

// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------

#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
  // Освобождение ресурсов, полученных для
  // работы с Windows Sockets
  WSACleanup();

  // Завершение цикла обработки сообщений
  PostQuitMessage(0);
  return FORWARD_WM_DESTROY(hWnd, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnSize
// -----------------------------------------------------

#pragma warning(disable: 4098)
void 
WndProc_OnSize(HWND hWnd, UINT state, int cx, int cy)
{
  SendMessage(hwndSb, WM_SIZE, cx, cy);
  return FORWARD_WM_SIZE(hWnd, state, cx, cy, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------

#pragma warning(disable: 4098)
void 
WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  switch (id)
  {
    case IDM_EXIT:

      // Уничтожение главного окна прилоджения
      DestroyWindow(hWnd);
      break;

    case IDM_CONNECT:
      
      // Установка соединения с сервером
      SetConnection(hWnd);
      break;

    case IDM_SEND:
      
      // Посылка сообщения серверу
      SendMsg(hWnd);
      break;

	default:
      MessageBox(NULL, "Unknown command", "Error", MB_OK);
  }

  return FORWARD_WM_COMMAND(hWnd, id, hwndCtl,
    codeNotify, DefWindowProc);
}

// -----------------------------------------------------
// Функция SetConnection
// -----------------------------------------------------

void SetConnection(HWND hWnd)
{
  PHOSTENT phe;
	
  // Создаем сокет 
  srv_socket = socket(AF_INET, SOCK_DGRAM, 0);
  if(srv_socket == INVALID_SOCKET)
  {
    MessageBox(NULL, "socket Error", "Error", MB_OK);
    return;
  }


  // Связываем адрес IP с сокетом  
  dest_sin.sin_family = AF_INET;
  dest_sin.sin_addr.s_addr = INADDR_ANY;
  dest_sin.sin_port = 0;
   
  if(bind(srv_socket, (LPSOCKADDR)&dest_sin, 
    sizeof(dest_sin)) == SOCKET_ERROR)
  {
    // При ошибке закрываем сокет
    closesocket(srv_socket);
    MessageBox(NULL, "bind Error", "Error", MB_OK);
    return;
  }
  
  // Устанавливаем адрес IP и номер порта
  dest_sin.sin_family = AF_INET;

  // Определяем адрес узла

  // Адрес локального узла для отладки
  phe = gethostbyname("localhost");
  
  // Адрес удаленного узла
  //  phe = gethostbyname("maxsinev");
  
  if(phe == NULL)
  {
    closesocket(srv_socket);
    MessageBox(NULL, "gethostbyname Error", "Error", MB_OK);
    return;
  }

  // Копируем адрес узла
  memcpy((char FAR *)&(dest_sin.sin_addr), phe->h_addr,
	  phe->h_length);

  // Другой способ указания адреса узла
  //  dest_sin.sin_addr.s_addr = inet_addr("200.200.200.201");

  // Копируем номер порта
  dest_sin.sin_port = htons(SERV_PORT);

  // В случае успеха выводим сообщение об установке
  // соединения с узлом
  SendMessage(hwndSb, SB_SETTEXT, 0, 
    (LPARAM)"Connected");
}

// -----------------------------------------------------
// Функция SendMsg
// -----------------------------------------------------

void SendMsg(HWND hWnd)
{
	char szBuf[80];
	lstrcpy(szBuf, "Test string");

  // Посылаем сообщение
  sendto(srv_socket, szBuf, lstrlen(szBuf), 0,
    (PSOCKADDR)&dest_sin, sizeof(dest_sin));

}
