Q&A

  • 멀티캐스팅 UDP 통신에 대해 잘 아시는 분
안녕하세요..한델 회원 여러분...
게시판에 글 올리기는 정말 첨 이네여...
오랫동안 델파이를 안 쓰다가 오랜만에 쓸려구 하니 여러가지 어려움이 있네여..
다름이 아니라 제가 UNIX 에서 UDP 통신용 프로그램을 만들었는데 이것을
Delphi 로 다시 만들라구 그랬더랍니다. 근데 너무 오랜만(전 델1.0부터 3.0)
까정만 써 봐서리)이라 문법두 아리아리 하구 버전도 6로 업 되있더군여..

어렵사리 후배한넘 닥달해서 Delphi 5 를 구해서 설치 하구선 이런 저런 기능을 살펴보던중 놀랍게도 fastNet 이란 탭에서 UDP 용 컴포넌트를 발견 했죠..

근데 이거 어떻게 사용하는 지 영 몰겠더군여..

UNIX 에서 코딩할땐 흔히 하는 SOCKET 만들고 BIND 하구 옵션주구 어쩌구
저쩌구 하는데..특히 멀티 캐스팅(제가필요로하는건 멀티캐스팅용 UDP라) 옵션및 기타등등을 설정하는데

이 컴포넌튼 단순히 IP 와 PORT NO만 수정하게 되 있더군요그래서 소스를 볼까했는데 .pas 로 등록도 안된것 같구..winapi를 쓸까두 생각했는데
좋은 생각 같지가 않군여..혹 이 컴포넌트로 멀티캐스팅 하게 쓰는 방법아시는
분은 꼭 좀 갈켜 주세여...

3  COMMENTS
  • Profile
    한방러쉬 2002.02.20 20:11
    맨윗단에 있는 TSocket 에서 원하는 대로 지정해주면 될것 같은데여...
    아래는 참고 소스 코드 임다...

    -----------------------------------------------------------------
    unit ListenThrd;

    interface

    uses
      Classes, ComCtrls, StdCtrls, Windows, Winsock2;


    const

       BufferSize    = MAXGETHOSTSTRUCT;

    type

    TMCOptions = record
                   Port      : Integer;
                   Address   : String;
                   UseWS2    : Boolean;
                  end;

    TConnData = record
                  NumEvents : DWORD;
                  EventArray : array[1..WSA_MAXIMUM_WAIT_EVENTS] of WSAEvent;
                 end;

    TMulticast = record
                   imr_multiaddr : TInAddr;   // IP multicast address of group */
                   imr_interface : TInAddr;   // local IP address of interface */
                  end;

      TListenThrd = class(TThread)
      private
        { Private declarations }
       FRunning : Boolean;
      protected
        MsgNo                  : Integer;
        EventMsg               : WSAEVENT;
        lpNetworkEvents        : PWSANETWORKEVENTS;
        ConnData               : TConnData;
        Buffers                : array[0..BufferSize - 1] of char;
        Msg,
        StatusMsg              : String;
        Done                   : Boolean;
        ReUseFlag              : BOOL;
        sktBlast               : TSocket;
        Multicast              : TMulticast;
        MCOptions              : TMCOptions;
        LocalAddr,
        RemoteAddr             : TSockAddr;
        Started                : Boolean;
        wsaData                : TWSADATA;
        function Start : Boolean;
        procedure DisplayMsg;
        procedure DisplayStatusMsg;
        procedure ChangeWS;
        procedure ChangeBtnState;
        procedure CleanUp(Sender : TObject);
        procedure HandleSocketEvent;
        procedure GetMsg;
        function  JoinSession : Boolean;
        procedure LeaveSession;
        procedure Execute; override;
      public
        property Running : Boolean read FRunning default FALSE;
        procedure CloseSession;
        constructor Create(Options : TMCOptions);
      end;

    var
    thrdListen : TListenThrd;
    Options    : TMCOptions;

    implementation
    { TListenThrd }

    Uses
    Dialogs, Forms, Main, SysUtils;

    var
      AddrStrSize   : Integer;

    function TListenThrd.Start : Boolean;
    var
    VerReqd : WordRec;
    begin
    with VerReqd do
    begin
      Hi := 2;
      Lo := 2;
    end;
    Result := WSAStartUp(Word(VerReqd), wsaData) = 0;
    end;

    procedure TListenThrd.DisplayMsg;
    begin
      frmMain.memMsg.Lines.Add(Msg);
    end;

    procedure TListenThrd.DisplayStatusMsg;
    begin
    frmMain.memStatusMsg.Lines.Add(StatusMsg);
    end;

    procedure TListenThrd.ChangeWS;
    begin
    MessageBeep(0);
    with frmMain do
      WindowState := wsNormal;
    end;

    procedure TListenThrd.ChangeBtnState;
    begin
    frmMain.bbtnStop.Enabled  := not frmMain.bbtnStop.Enabled;
    frmMain.bbtnStart.Enabled := not frmMain.bbtnStart.Enabled;
    end;


    procedure TListenThrd.CleanUp(Sender : TObject);
    begin
    if Started then
    begin
      closesocket(sktBlast);
      WSACleanUp;
    end;
    end;

    function TListenThrd.JoinSession : Boolean;
    var
    sktRes : Integer;
    sktTemp : TSocket;
    begin
    Result := TRUE;
    case MCOptions.UseWS2 of
      TRUE :  begin
               sktTemp := WSAJoinLeaf(sktBlast, @RemoteAddr, SizeOf(RemoteAddr), NIL, NIL, NIL, NIL, JL_RECEIVER_ONLY);
               if sktTemp = INVALID_SOCKET then
               begin        
                StatusMsg := Concat('Call to WSAJoinLeaf failed! Error ', IntToStr(WSAGetLastError));
                Synchronize(DisplayStatusMsg);
                Result := FALSE;
                Synchronize(ChangeBtnState);
                Exit;
               end;
              end;
      FALSE : begin
               with Multicast do
               begin
                imr_multiaddr.s_addr := inet_addr(PChar(MCOptions.Address));
                imr_interface.s_addr := INADDR_ANY;
               end;
               sktRes := setsockopt(sktBlast,IPPROTO_IP, IP_ADD_MEMBERSHIP, pchar(@Multicast), SizeOf(Multicast));
               if sktRes = SOCKET_ERROR then
               begin
                StatusMsg := Concat('Call to setsockopt failed! Error ', IntToStr(WSAGetLastError));
                Synchronize(DisplayStatusMsg);
                Result := FALSE;
               end;
              end;
    end;// case
    end;

    procedure TListenThrd.LeaveSession;
    var
    sktRes : Integer;
    begin
    if not UseWS2 then
      with Multicast do
      begin
       imr_multiaddr.s_addr := inet_addr(MultiCastAddr);
       imr_interface.s_addr := INADDR_ANY;
      end;
      sktRes := setsockopt(sktBlast, IPPROTO_IP, IP_DROP_MEMBERSHIP, pchar(@Multicast), SizeOf(Multicast));
      if sktRes = SOCKET_ERROR then
      begin
       StatusMsg := Concat('Call to setsockopt failed! Error ', IntToStr(WSAGetLastError));
       Synchronize(DisplayStatusMsg);
      end;
    end;

    procedure TListenThrd.CloseSession;
    begin
    // Leave session ...
    LeaveSession;
    // Terminate the thread by setting the global Done and call
    Done := TRUE;
    // Call WSASetEvent to signal HandleSocketEvent
    WSASetEvent(EventMsg);
    end;

    constructor TListenThrd.Create(Options : TMCOptions);
    var
    sktRes : Integer;
    begin
    inherited Create(TRUE);
    MCOptions := Options;
    FreeOnTerminate := TRUE;
    Started := Start;
    if not Started then
    begin
      StatusMsg := 'Cannot load Winsock 2.0!';
      Synchronize(DisplayStatusMsg);
      Exit;
    end;
    OnTerminate := CleanUp;
    MsgNo := 0;
    with MCOptions do
    begin
    // get a UDP socket
      if UseWS2 then
      begin
    // Convert address string to a value
       RemoteAddr.sin_family := AF_INET;
       AddrStrSize := 16;
       sktRes := WSAStringToAddress(Pchar(MultiCastAddr),AF_INET, NIL, @RemoteAddr, @AddrStrSize);
       if sktRes = SOCKET_ERROR then
       begin
        StatusMsg := Concat('Call to WSAStringToAddress failed! Error ', IntToStr(WSAGetLastError));
        Synchronize(DisplayStatusMsg);
        Exit;
       end;
       sktBlast := WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NIL, 0, WSA_FLAG_OVERLAPPED or
                             WSA_FLAG_MULTIPOINT_C_LEAF or
                             WSA_FLAG_MULTIPOINT_D_LEAF);
      end
      else
       sktBlast := socket(AF_INET, SOCK_DGRAM, 0);
      if sktBlast = SOCKET_ERROR then
      begin
       StatusMsg := Concat('Failed to create UDP socket! Error ', IntToStr(WSAGetLastError));
       Synchronize(DisplayStatusMsg);
       Exit;
      end;
    // Create an event ...
      EventMsg := CreateEvent(NIL, FALSE, FALSE, NIL);
      if EventMsg = WSA_INVALID_EVENT then
      begin
       StatusMsg := Concat('Failed to create Message Event. Error ', IntToStr(WSAGetLastError));
       Synchronize(DisplayStatusMsg);
       Done := TRUE;
       Exit;
      end;
    // Now set up notification ...
      sktRes := WSAEventSelect(sktBlast, EventMsg, FD_READ);
      if sktRes = SOCKET_ERROR then
      begin
       StatusMsg := Concat('Call to WSAEventSelect failed for socket ', IntToStr(sktBlast),'. Error ', IntToStr(WSAGetLastError));
       Synchronize(DisplayStatusMsg);
       closesocket(sktBlast);
       Done := TRUE;
       Exit;
      end;
    // Set up socket options for multicast ...
    // Always reuse socket
      ReUseFlag := TRUE;
      sktRes := setsockopt(sktBlast, SOL_SOCKET, SO_REUSEADDR, @ReUseFlag,
                           SizeOf(ReUseFlag));
      if sktRes = SOCKET_ERROR then
      begin
       StatusMsg := Concat('Call to setsockopt failed! Error ', IntToStr(WSAGetLastError));
       Synchronize(DisplayStatusMsg);
       closesocket(sktBlast);
       Synchronize(ChangeWS);
       Exit;
      end;
    // Name the socket and assign the local port number to receive on
      with LocalAddr do
      begin
       sin_family      := AF_INET;
       sin_addr.s_addr := htonl(INADDR_ANY);
       sin_port        := htons(MCOptions.Port);
      end;
    // bind it!
      sktRes := bind(sktBlast, LocalAddr, SizeOf(TSockAddrIn));
      if sktRes = SOCKET_ERROR then
      begin
       StatusMsg := Concat('Call to bind failed ! Error ', IntToStr(WSAGetLastError));
       Synchronize(DisplayStatusMsg);
       closesocket(sktBlast);
       Exit;
      end;
      if UseWS2 then
      begin
    // swap host to network order ...
       with RemoteAddr do
       begin
        sin_family := PF_INET;
        sktRes := WSAHtons(sktBlast, MCOptions.Port, @sin_port);
        if sktRes = SOCKET_ERROR then
        begin
         StatusMsg := Concat('Call to WSAHtons failed! Error ', IntToStr(WSAGetLastError));
         Synchronize(DisplayStatusMsg);
         closesocket(sktBlast);
         Exit;
        end;
       end;
      end;
    // Join the multicast group
      if not JoinSession then
      begin
       closesocket(sktBlast);
       Exit;
      end;
      StatusMsg := 'Started listening thread ...';
      Synchronize(DisplayStatusMsg);
    end;// with MCOptions
    Resume;
    end;

    procedure TListenThrd.HandleSocketEvent;
    var
    sktRes : Integer;
    begin
    sktRes := WSAEnumNetworkEvents(sktBlast, EventMsg, @Buffers[0]);
    if sktRes = SOCKET_ERROR then
    begin
      StatusMsg := Concat('Call to WSAEnumNetworkEvents failed. Error ',IntToStr(WSAGetLastError));
      Synchronize(DisplayStatusMsg);
      Done := TRUE;
      Exit;
    end;
    lpNetworkEvents := PWSANETWORKEVENTS(@Buffers[0]);
    // Decipher network events ...
    with lpNetworkevents^ do
    begin
    // Is this a FD_READ event?
      if (lNetworkEvents and FD_READ) = FD_READ then
      begin
       if iErrorCode[1] = WSAENETDOWN then
       begin
        StatusMsg := Concat('Network down ... Error ',IntToStr(WSAGetLastError));
        Synchronize(DisplayStatusMsg);
       end else
       begin
        GetMsg;
       end;
      end;
    end;
    end;

    procedure TListenThrd.GetMsg;
    var
    Error: Integer;
    Buff : PWSABUF;
    Flags, NoBytes,
    Size,
    sktRes,
    AddrStrSize : Integer;
    AddrStr : array[0..MAXGETHOSTSTRUCT - 1] of char;
    PortNo : shortint;

    begin
    // Get the message ...
    Buff := NIL;
    Flags := 0;
    AddrStrSize := MAXGETHOSTSTRUCT;
    try
      Buff       := AllocMem(SizeOf(Buffers));
      Buff.Buf   := Buffers;
      Buff.len   := SizeOf(Buffers);
      Size       := SizeOf(RemoteAddr);
      sktRes     := WSARecvFrom(sktBlast, Buff, 1, @NoBytes, @Flags, @RemoteAddr, @Size, NIL, NIL);
      if sktRes = SOCKET_ERROR then
      begin
       Error := WSAGetLastError;
       if Error <> WSAEWOULDBLOCK then
       begin
        StatusMsg := Concat('Call to WSARecvFrom failed! Error ', IntToStr(WSAGetLastError));
        Synchronize(DisplayStatusMsg);
        Done := TRUE;
        WSASetEvent(EventMsg);
       end;
      end else
      begin
       Synchronize(ChangeWS);
       Msg := String(Buff.buf);
       Synchronize(DisplayMsg);
    // Convert address to a readable string ...
       PortNo := 0;
       sktRes := WSAAddressToString(@RemoteAddr, SizeOf(RemoteAddr), NIL, AddrStr, @AddrStrSize);
       if sktRes = SOCKET_ERROR then
       begin
        StatusMsg := Concat('Call to WSAAddressToString failed! Error ', IntToStr(WSAGetLastError));
        Synchronize(DisplayStatusMsg);
       end;
    // Convert from network to host byte order
       sktRes := WSANtohs(sktBlast,RemoteAddr.sin_port, @PortNo);
       if sktRes = SOCKET_ERROR then
       begin
        StatusMsg := Concat('Call to WSANtohs failed! Error ', IntToStr(WSAGetLastError));
        Synchronize(DisplayStatusMsg);
       end else
       begin
        StatusMsg := Concat('Message #', IntToStr(MsgNo), ' received from ', String(AddrStr));
        Synchronize(DisplayStatusMsg);
       end;
      end;
    finally
      FreeMem(Buff);
    end;
    end;


    procedure TListenThrd.Execute;
    var
    WaitStatus : DWORD;
    begin
    with ConnData do
    begin
      NumEvents := 1;
      EventArray[1] := EventMsg;
      Done := FALSE;
      repeat
       WaitStatus := WSAWaitForMultipleEvents(NumEvents, @EventArray, FALSE, WSA_INFINITE, FALSE);
       case WaitStatus of
        WSA_WAIT_FAILED    : begin
                              StatusMsg := Concat('WSA_WAIT_FAILED ... Error ',IntToStr(WSAGetLastError));
                              Synchronize(DisplayStatusMsg);
                              Done := TRUE;
                             end;
        WAIT_IO_COMPLETION : begin
                              StatusMsg := 'WAIT_IO_COMPLETION ...';
                              Synchronize(DisplayStatusMsg);
                             end;
        WSA_WAIT_EVENT_0   : begin
                              StatusMsg := 'WSA_WAIT_EVENT_0 ...';
                              Synchronize(DisplayStatusMsg);
                              if Done then
                              begin// then we are done ...
                               StatusMsg := 'Listening thread terminated ...';
                               Synchronize(DisplayStatusMsg);
                              end else
                              begin
                               Inc(MsgNo);
                               HandleSocketEvent;
                              end;
                             end;
       end;// case
      until Done;
    end;
    end;

    end.

  • Profile
    Mr. Ziker 2002.02.17 19:23
    안녕하세욤!

    UDP는 통신용으로는 적합하지 않다고 생각 합니다.
    그래서 요즘 TCP/IP를 쓰는것이

    UDP는 무조건 보내는 형태이라서 중간에 패킷이 손실 되면
    찾을 길이 없습니다. -.-  이를 보안 한것이 TCP/IP로 알고 있거든요
    TCP/IP는 한 패킷을 보내고, 받은쪽에서 받았다고 메세지가 오면
    다시 한패킷 보내고 이런식인데 반해

    UDP는 말 그대로 주~~~욱 보내는거라 중간에 어떤 패킷이 손실 됬는지
    찾기가 무척 힙듭니다..
    (고수님들 맞죠? ^^;;)

    해서 보통 UDP는 음성 전달용으로 사용 많이 하죠. 음성은 패킷 잃어버려도
    큰 지장이 없지만 바이너리 데이터는 한 패킷만 없어도 CRC에러가 발생합니다


    참고로 FastNet에 있는 UDP는 간단하며, 클라이언트/서버 역활 다 합니다.
    Local Port하고 Remote Port를 같은 값으로 주시고 Remote Host에 아이피를
    적어주시면 됩니다.

    하나더 참고로 인디에서 제공하는 UDP는 서버/클라이언트 구분 합니다.


    그리고 진짜 마지막 -0-
    멀티 태스크 말씀 하시는거 같은데욤.. TCP/IP가 낳을듯 하네요 ^^

    즐코 되세욤!!




  • Profile
    박남준 2002.02.17 21:21
    저녁에 글을 올렸는데 아침에 답변을 보게 되네요.. 답변 감사합니다..^^
    근데 제가 몇 가지 빠트린 것이 있군요..
    우선 제가 할려고 하는 부분은 Client 쪽임다.. Server 쪽은 이미 만들어져 있죠

    UNIX OS 이구여.. 근데 Server 자료가 UDP로 옵니다..물론 님의 말씀이 틀린것은 아닙니다만 굳이 UDP를 쓴이유에 대해서는 제가 Server 쪽 담당이 아니라 별로 드릴 말씀이 없군여 ..중요한 것은 이 Server 쪽에서 멀티캐스팅으로 자룔 뿌린 다는거죠..물론 같은 OS 군으로 Client 는 만들어져 있습니다.

    같은 OS 환경상에서는 큰 문제 없이 작동하겠죠..문제는 제가 이걸 일반 windows 환경의 PC로 받아서 자료를 처리하고 싶더군요..근데 문제가 생기더군요..Demos 디렉토리의 UDP 통신예제에서 IP 는 멀티 그룹 IP를 주고 PORT는 물론 정해진 것을 줬죠..그랬더니 error 가 뜨더군요..물론 PC routing table에는 멀티캐스팅 그룹이 등록되있슴다..

    그래서 제가 생각해보건데(제 짧은생각이자만) UNIX 에서 UDP 소켓을 생성하고 멀티캐스팅할때 옵션을 준다는 거죠..아래와 같이요

    int np_create_multicast_inbound_socket (int                port,
                                            unsigned int       ip_group_addr,
                                            unsigned int       local_ip_addr,
                                            int                max_rx_size,
                                            struct sockaddr_in *udp_socket,
                                            int                *err_no)
    {

      int                          fd;
      int                          s;
      int                          max_buffer_size;
      struct ip_mreq               mreq;

      max_buffer_size = max_rx_size;

      /* Create inbound socket */

      fd = socket (AF_INET, SOCK_DGRAM, 0);

      if (fd == NP_ERR) {
        *err_no = errno;
        np_log_errno ("socket()", "np_create_multicast_inbound_socket",
                    errno);
        return (NP_ERR);
      }

      /* Set maximum receive buffer size. */

      if (max_rx_size == NP_DEFAULT) {
        /* noop, continue */
      }
      else {

        s = setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
                        &max_buffer_size, sizeof(max_buffer_size));

        if (s == NP_ERR) {
          np_log_errno ("setsockopt(), SO_RCVBUF",
                        "np_create_multicast_inbound_socket", errno);
          np_log_info ("CONTINUE", "np_create_multicast_inbound_socket");
        }
      }

      memset (udp_socket, 0, sizeof (struct sockaddr_in));

      /* Join multicast group.   */
      /* Setup interface address */

      udp_socket->sin_port         = port;
      udp_socket->sin_family       = AF_INET;
      udp_socket->sin_addr.s_addr  = ip_group_addr;

      memset (&mreq, 0, sizeof (struct ip_mreq));

      mreq.imr_multiaddr.s_addr    = ip_group_addr;
      mreq.imr_interface.s_addr    = local_ip_addr;

      setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

      if (s == NP_ERR) {
        *err_no = errno;
        np_log_errno ("setsockopt(), IP_ADD_MEMBERSHIP",
                      "np_create_multicast_inbound_socket", errno);
        np_shutdown_socket (fd);
        return (NP_ERR);
      }

      /* Bind multicast address and port number. */

      s = bind (fd, (void *) udp_socket, sizeof (struct sockaddr_in));

      if (s == NP_ERR) {
        *err_no = errno;
        np_log_errno ("bind()", "np_create_multicast_inbound_socket", errno);
        np_shutdown_socket (fd);
        return (NP_ERR);
      }

      *err_no = 0;

      if (tracing_on) {
        sprintf (trace_msg, "SUCCESS GROUP Addr: %s Port: %d",
                 np_inet_ntoa(ip_group_addr), udp_socket->sin_port);
        np_log_trace (trace_msg, "np_create_multicast_inbound_socket()");
      }

      return (fd);

    }

    (죄송함다..델파이 게시판에 C 를 써서..--;;)

    근데 이러한 것들을 UDP 컴포넌트에서는 어떻게 안되겠더군여...
    그래서 혹 아시는 분이 있나해서 여쭤 본겁니다. 그 Componet 가 님께서
    얘기하신 작용외에 어떤 추가적인 부분을 할수 없다면 별수 없이 winsock 을
    써야 겠군여..아무튼 답변 감사합니다..
    • 강정구
    • 2002.02.18 20:27
    • 1 COMMENTS
    • /
    • 0 LIKES
    • * 아자!! *
      2002.02.18 21:40
      소스를 찾아보면 많이 있을것 같은데... 저두 그 부분 구현해볼려구 이곳저곳 찾다가... 비슷한 답변을 ...
    • 이명옥
    • 2002.02.18 20:20
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 허일학
      2002.02.18 20:31
      다음과 같이 하시면 폼의 이동과 크기를 고정 시킬 수 있습니다.. 참고하시길 바랍니다..^^... &n...
    • 설승호
    • 2002.02.18 19:42
    • 4 COMMENTS
    • /
    • 0 LIKES
    • Yellena
      2002.04.12 20:39
      저두 브레이크 포인트가 걸리질 않아요... 어떻게 해야 하나요?
    • gudwhrla
      2002.02.18 21:52
      메인 프로그램에서 dll를 디버깅 할 수 는 없습니다. 거꾸로 하셔야 합니다. Dll 프로젝트로 Open 하...
    • 설승호
      2002.02.18 22:38
      네... 답변은 감사 합니다만... DLL프로젝트를 이미 열구 프로젝트내에서 브래이킹포인트를 걸어 놓은 상...
    • 설승호
      2002.02.18 22:37
      이미 그렇게 한거거덩요.. DLL을 수정할려는거니깐 DLL 프로젝트에서 브래이킹 포인트를 붙인거지여. 런 ...
    • 김기수
      2002.02.18 21:05
      <- Delphi Tips 에서 textfile 로 검색후 첫번째 게시물을 참고 하십시오.
    • 최용일
      2002.02.18 18:44
      안녕하세요. 최용일입니다. 바탕화면이라.... 여기에다가 프로그램 설치하는 경우는 한번도 못봤는데......
    • 허일학
      2002.02.18 18:42
      단순히 외부실행파일을 불러들여 실행할려면 다음가 같이 하시면 될꺼 같은데요..^^.. 참고하시기 바...
    • 우영범
      2002.02.18 18:27
      단순히 기능만 구현하려면 SendStream만으로 가능합니다. 하지만 전송 상황이라든가 에러 처리를 위해서는...
    • 노정윤
    • 2002.02.18 07:04
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 우영범
      2002.02.18 18:22
      ShGetFileInfo API를 이용하면 됩니다. // Get System Image List procedure TfrmRemoteExplorer.GetSy...
    • 조현석
    • 2002.02.18 06:16
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 김규한
      2002.02.18 20:35
      안녕하세요? 저같은 분이시네용~ 혼자 독불장군식으로 막무가내로 배웠는데 ^^; 암튼 책은요. 가남사...
    • 노수경
    • 2002.02.18 05:40
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 최보&#46
    • 2002.02.18 04:11
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 권대웅
      2002.02.18 04:33
      1. FileExists란 함수를 쓰세요! if FileExists('여기에 파일 패스와 이름을 넣고...') then  ...
    • 이승근
    • 2002.02.18 02:39
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 서은구
      2002.02.18 05:50
      제가 아는 선에 답변을 드리도록하죠.. 첫째 as 를 사용하십시요 select  a.코드, a.상호, sum...
    • 김기수
      2002.02.18 01:55
      레코드? 필드? 정확한 질문이 정확한 답변을 얻습니다.
    • 권대웅
      2002.02.18 19:03
      DB의 모든 테이블과 테이블의 필드정보 얻는 간단한 예제입니다. unit Unit1; interface use...
    • 박영수
      2002.02.18 18:18
      예 죄송합니다. 제 입장만 생각했네요. ^^; 필드를 알고 싶습니다. 아신다면 가르쳐주면 정말 고맙겠습니...
    • 이추형
      2002.02.18 18:52
      SQL SERVER는 손 놓은지 여러해가 되어 잘 기억이 나지 않지만 오라클은 유저의 권한이 있다면 다음의 SQL...
    • 허일학
      2002.02.18 01:52
      정확한건 아닙니다만...다음과 같은 형식을 조금응용하시면 원하시는 결과를 얻을 수 있을것이라 생각 ...
    • 김희창
    • 2002.02.17 12:04
    • 2 COMMENTS
    • /
    • 0 LIKES
    • Mr. Ziker
      2002.02.17 17:46
      안녕하세욤! SQL-SERVER에서는 운영체제 자체에 등록된 계정으로 허가를 받아 접속이 가능합니다. 이부...
    • 김희창
      2002.02.18 01:15
      물론 그 계정도 superuser 계정으로 줬습니다.. 덧붙이자면.. TDatabase 의 계정 밑 DB를 묻는 곳에서 p...
    • Mr. Ziker
      2002.02.17 19:15
      안녕하세욤! 받는 부분에서  스트림으로 못 받는거 같은데요.. 보낼때 SendStream으로 보내...
    • 구철수
    • 2002.02.17 09:19
    • 0 COMMENTS
    • /
    • 0 LIKES
    • Mr. Ziker
      2002.02.17 19:45
      안녕하세욤!! 기본적으로 MDI폼에서 Child폼을 생성 할때 동적 생성을 합니다. 그정보는 부모폼에 있...
    • 박남준
    • 2002.02.17 08:43
    • 3 COMMENTS
    • /
    • 1 LIKES
    • 한방러쉬
      2002.02.20 20:11
      맨윗단에 있는 TSocket 에서 원하는 대로 지정해주면 될것 같은데여... 아래는 참고 소스 코드 임다... ...
    • Mr. Ziker
      2002.02.17 19:23
      안녕하세욤! UDP는 통신용으로는 적합하지 않다고 생각 합니다. 그래서 요즘 TCP/IP를 쓰는것이 UDP...
    • 박남준
      2002.02.17 21:21
      저녁에 글을 올렸는데 아침에 답변을 보게 되네요.. 답변 감사합니다..^^ 근데 제가 몇 가지 빠트린 것이...