windows-vs2005b2-20050706
[openafs.git] / src / WINNT / afsapplib / ctl_sockaddr.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include <windows.h>
16 #include <windowsx.h>
17 #include <commctrl.h>
18 #include <winsock2.h>
19 #include <stdlib.h>
20 #include <WINNT/dialog.h>
21 #include <WINNT/resize.h>       // for GetRectInParent()
22 #include <WINNT/subclass.h>
23 #include <WINNT/ctl_spinner.h>
24 #include <WINNT/ctl_sockaddr.h>
25 #include <WINNT/TaLocale.h>
26
27 #ifndef cchRESOURCE
28 #define cchRESOURCE 256
29 #endif
30
31
32 /*
33  * MISCELLANEOUS ______________________________________________________________
34  *
35  */
36
37 #ifndef REALLOC
38 #define REALLOC(_a,_c,_r,_i) SockAddrReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
39 BOOL SockAddrReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
40 {
41    LPVOID pNew;
42    size_t cNew;
43
44    if (cReq <= *pcTarget)
45       return TRUE;
46
47    if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
48       return FALSE;
49
50    if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
51       return FALSE;
52    memset (pNew, 0x00, cbElement * cNew);
53
54    if (*pcTarget != 0)
55       {
56       memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
57       Free (*ppTarget);
58       }
59
60    *ppTarget = pNew;
61    *pcTarget = cNew;
62    return TRUE;
63 }
64 #endif
65
66
67 /*
68  * SOCKADDRS __________________________________________________________________
69  *
70  */
71
72 typedef struct
73    {
74    HWND hSockAddr;
75    HWND hE1;
76    HWND hSep1;
77    HWND hE2;
78    HWND hSep2;
79    HWND hE3;
80    HWND hSep3;
81    HWND hE4;
82    HWND hMinutes;
83
84    WORD idE1;
85    WORD idE2;
86    WORD idE3;
87    WORD idE4;
88
89    SOCKADDR_IN addr;
90
91    BOOL  fCallingBack;
92    } SockAddrInfo;
93
94 static CRITICAL_SECTION  csSockAddr;
95 static SockAddrInfo     *aSockAddr = NULL;
96 static size_t            cSockAddr = 0;
97
98 #define cszSOCKADDRCLASS TEXT("SockAddr")
99
100 BOOL CALLBACK SockAddrProc (HWND hSockAddr, UINT msg, WPARAM wp, LPARAM lp);
101 BOOL CALLBACK SockAddrEditProc (HWND hEdit, UINT msg, WPARAM wp, LPARAM lp);
102 BOOL CALLBACK SockAddrDlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
103
104 void SockAddr_SendCallback (SockAddrInfo *psai, WORD eln, LPARAM lp);
105
106 void SockAddr_OnCreate (SockAddrInfo *psai);
107 void SockAddr_OnDestroy (SockAddrInfo *psai);
108 void SockAddr_OnButtonDown (SockAddrInfo *psai, UINT msg, WPARAM wp, LPARAM lp);
109 BOOL SockAddr_OnGetAddr (SockAddrInfo *psai, WPARAM wp, LPARAM lp);
110 BOOL SockAddr_OnSetAddr (SockAddrInfo *psai, WPARAM wp, LPARAM lp);
111
112 void SockAddr_Edit_OnChange (SockAddrInfo *psai, HWND hEdit);
113 void SockAddr_Edit_OnUpdate (SockAddrInfo *psai, HWND hEdit);
114 void SockAddr_Edit_SetText (SockAddrInfo *psai, HWND hEdit);
115
116 #define cszSOCKSEP TEXT(".")
117
118 BOOL RegisterSockAddrClass (void)
119 {
120    static BOOL fRegistered = FALSE;
121
122    if (!fRegistered)
123       {
124       InitializeCriticalSection (&csSockAddr);
125
126       WNDCLASS wc;
127       memset (&wc, 0x00, sizeof(wc));
128       wc.style = CS_GLOBALCLASS;
129       wc.lpfnWndProc = (WNDPROC)SockAddrProc;
130       wc.hInstance = THIS_HINST;
131       wc.hCursor = LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW));
132       wc.hbrBackground = CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
133       wc.lpszClassName = cszSOCKADDRCLASS;
134
135       if (RegisterClass (&wc))
136          fRegistered = TRUE;
137       }
138
139    return fRegistered;
140 }
141
142
143 void SockAddr_SendCallback (SockAddrInfo *psai, WORD san, LPARAM lp)
144 {
145    if (!psai->fCallingBack)
146       {
147       psai->fCallingBack = TRUE;
148
149       SendMessage (GetParent (psai->hSockAddr),
150                    WM_COMMAND,
151                    MAKELONG ((WORD)GetWindowLong (psai->hSockAddr, GWL_ID), san),
152                    lp);
153
154       psai->fCallingBack = FALSE;
155       }
156 }
157
158
159 BOOL CALLBACK SockAddrProc (HWND hSockAddr, UINT msg, WPARAM wp, LPARAM lp)
160 {
161    SockAddrInfo *psai = NULL;
162
163    EnterCriticalSection (&csSockAddr);
164
165    if (msg == WM_CREATE)
166       {
167       size_t iSockAddr;
168       for (iSockAddr = 0; iSockAddr < cSockAddr; ++iSockAddr)
169          {
170          if (aSockAddr[ iSockAddr ].hSockAddr == NULL)
171             break;
172          }
173       if (iSockAddr >= cSockAddr)
174          {
175          if (!REALLOC (aSockAddr, cSockAddr, 1+iSockAddr, 4))
176             return FALSE;
177          }
178
179       memset (&aSockAddr[ iSockAddr ], 0x00, sizeof(SockAddrInfo));
180       aSockAddr[ iSockAddr ].hSockAddr = hSockAddr;
181
182       psai = &aSockAddr[ iSockAddr ];
183       }
184    else
185       {
186       for (size_t iSockAddr = 0; !psai && iSockAddr < cSockAddr; ++iSockAddr)
187          {
188          if (aSockAddr[ iSockAddr ].hSockAddr == hSockAddr)
189             psai = &aSockAddr[ iSockAddr ];
190          }
191       }
192
193    LeaveCriticalSection (&csSockAddr);
194
195    if (psai != NULL)
196       {
197       switch (msg)
198          {
199          case WM_CREATE:
200             SockAddr_OnCreate (psai);
201             break;
202
203          case WM_DESTROY:
204             SockAddr_OnDestroy (psai);
205             break;
206
207          case WM_RBUTTONDOWN:
208          case WM_LBUTTONDOWN:
209             SockAddr_OnButtonDown (psai, msg, wp, lp);
210             break;
211
212          case WM_SETFOCUS:
213             PostMessage (GetParent(hSockAddr), WM_NEXTDLGCTL, (WPARAM)psai->hE1, TRUE);
214             break;
215
216          case WM_ENABLE:
217             EnableWindow (psai->hE1,   IsWindowEnabled (hSockAddr));
218             EnableWindow (psai->hSep1, IsWindowEnabled (hSockAddr));
219             EnableWindow (psai->hE2,   IsWindowEnabled (hSockAddr));
220             EnableWindow (psai->hSep2, IsWindowEnabled (hSockAddr));
221             EnableWindow (psai->hE3,   IsWindowEnabled (hSockAddr));
222             EnableWindow (psai->hSep3, IsWindowEnabled (hSockAddr));
223             EnableWindow (psai->hE4,   IsWindowEnabled (hSockAddr));
224
225             RECT rSockAddr;
226             GetRectInParent (hSockAddr, &rSockAddr);
227             InvalidateRect (GetParent(hSockAddr), &rSockAddr, TRUE);
228             UpdateWindow (GetParent(hSockAddr));
229             break;
230
231          case SAM_GETADDR:
232             return SockAddr_OnGetAddr (psai, wp, lp);
233
234          case SAM_SETADDR:
235             return SockAddr_OnSetAddr (psai, wp, lp);
236          }
237       }
238
239    return DefWindowProc (hSockAddr, msg, wp, lp);
240 }
241
242
243 void SockAddr_OnCreate (SockAddrInfo *psai)
244 {
245    Subclass_AddHook (GetParent(psai->hSockAddr), SockAddrDlgProc);
246
247    RECT rSockAddr;
248    GetClientRect (psai->hSockAddr, &rSockAddr);
249
250    POINT ptSockAddr = {0,0};
251    ClientToScreen (psai->hSockAddr, &ptSockAddr);
252    ScreenToClient (GetParent (psai->hSockAddr), &ptSockAddr);
253
254    SIZE s888; // size of widest likely triple-digit number
255    SIZE sSockSep; // size of "."
256
257    HDC hdc = GetDC (GetParent (psai->hSockAddr));
258    GetTextExtentPoint (hdc, TEXT("888"), lstrlen(TEXT("888")), &s888);
259    GetTextExtentPoint (hdc, cszSOCKSEP, lstrlen(cszSOCKSEP), &sSockSep);
260    ReleaseDC (GetParent (psai->hSockAddr), hdc);
261
262    LONG cxNumbers = cxRECT(rSockAddr) - (3 * sSockSep.cx);
263    LONG cxE2 = cxNumbers/4;
264    LONG cxE1 = cxNumbers - cxE2 * 3;
265    LONG yy = ptSockAddr.y;
266    LONG cy = cyRECT(rSockAddr);
267
268    cxE2 = min (cxE2, (LONG)( 1.4 * s888.cx ));
269    cxE1 = min (cxE1, (LONG)( 1.4 * s888.cx ));  // don't be TOO wide.
270
271    psai->idE1 = 100+NextControlID (GetParent (psai->hSockAddr));
272    psai->hE1 = CreateWindow (
273                 TEXT("EDIT"),
274                 TEXT(""),
275                 WS_CHILD | WS_TABSTOP | ES_RIGHT | ES_NUMBER | ES_MULTILINE,
276                 ptSockAddr.x, yy, cxE1, cy,
277                 GetParent(psai->hSockAddr),
278                 (HMENU)psai->idE1,
279                 THIS_HINST,
280                 0);
281
282    psai->hSep1 = CreateWindow (
283                 TEXT("STATIC"),
284                 cszSOCKSEP,
285                 WS_CHILD | SS_CENTER,
286                 ptSockAddr.x + cxE1, yy, sSockSep.cx, cy,
287                 GetParent(psai->hSockAddr),
288                 (HMENU)-1,
289                 THIS_HINST,
290                 0);
291
292    psai->idE2 = 1 + psai->idE1;
293    psai->hE2 = CreateWindow (
294                 TEXT("EDIT"),
295                 TEXT(""),
296                 WS_CHILD | WS_TABSTOP | ES_RIGHT | ES_NUMBER | ES_MULTILINE,
297                 ptSockAddr.x + cxE1 + sSockSep.cx, yy, cxE2, cy,
298                 GetParent(psai->hSockAddr),
299                 (HMENU)psai->idE2,
300                 THIS_HINST,
301                 0);
302
303    psai->hSep2 = CreateWindow (
304                 TEXT("STATIC"),
305                 cszSOCKSEP,
306                 WS_CHILD | SS_CENTER,
307                 ptSockAddr.x + cxE1 + sSockSep.cx + cxE2, yy, sSockSep.cx, cy,
308                 GetParent(psai->hSockAddr),
309                 (HMENU)-1,
310                 THIS_HINST,
311                 0);
312
313    psai->idE3 = 1 + psai->idE2;
314    psai->hE3 = CreateWindow (
315                 TEXT("EDIT"),
316                 TEXT(""),
317                 WS_CHILD | WS_TABSTOP | ES_RIGHT | ES_NUMBER | ES_MULTILINE,
318                 ptSockAddr.x + cxE1 + sSockSep.cx*2 + cxE2, yy, cxE2, cy,
319                 GetParent(psai->hSockAddr),
320                 (HMENU)psai->idE3,
321                 THIS_HINST,
322                 0);
323
324    psai->hSep3 = CreateWindow (
325                 TEXT("STATIC"),
326                 cszSOCKSEP,
327                 WS_CHILD | SS_CENTER,
328                 ptSockAddr.x + cxE1 + sSockSep.cx*2 + cxE2*2, yy, sSockSep.cx, cy,
329                 GetParent(psai->hSockAddr),
330                 (HMENU)-1,
331                 THIS_HINST,
332                 0);
333
334    psai->idE4 = 1 + psai->idE3;
335    psai->hE4 = CreateWindow (
336                 TEXT("EDIT"),
337                 TEXT(""),
338                 WS_CHILD | WS_TABSTOP | ES_RIGHT | ES_NUMBER | ES_MULTILINE,
339                 ptSockAddr.x + cxE1 + sSockSep.cx*3 + cxE2*2, yy, cxE2, cy,
340                 GetParent(psai->hSockAddr),
341                 (HMENU)psai->idE4,
342                 THIS_HINST,
343                 0);
344
345    Subclass_AddHook (psai->hE1, SockAddrEditProc);
346    Subclass_AddHook (psai->hE2, SockAddrEditProc);
347    Subclass_AddHook (psai->hE3, SockAddrEditProc);
348    Subclass_AddHook (psai->hE4, SockAddrEditProc);
349
350    HFONT hf = (HFONT)SendMessage (GetParent (psai->hSockAddr), WM_GETFONT, 0, 0);
351    SendMessage (psai->hE1,   WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
352    SendMessage (psai->hSep1, WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
353    SendMessage (psai->hE2,   WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
354    SendMessage (psai->hSep2, WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
355    SendMessage (psai->hE3,   WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
356    SendMessage (psai->hSep3, WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
357    SendMessage (psai->hE4,   WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
358
359    EnableWindow (psai->hE1,   IsWindowEnabled (psai->hSockAddr));
360    EnableWindow (psai->hSep1, IsWindowEnabled (psai->hSockAddr));
361    EnableWindow (psai->hE2,   IsWindowEnabled (psai->hSockAddr));
362    EnableWindow (psai->hSep2, IsWindowEnabled (psai->hSockAddr));
363    EnableWindow (psai->hE3,   IsWindowEnabled (psai->hSockAddr));
364    EnableWindow (psai->hSep3, IsWindowEnabled (psai->hSockAddr));
365    EnableWindow (psai->hE4,   IsWindowEnabled (psai->hSockAddr));
366
367    ShowWindow (psai->hE1,   TRUE);
368    ShowWindow (psai->hSep1, TRUE);
369    ShowWindow (psai->hE2,   TRUE);
370    ShowWindow (psai->hSep2, TRUE);
371    ShowWindow (psai->hE3,   TRUE);
372    ShowWindow (psai->hSep3, TRUE);
373    ShowWindow (psai->hE4,   TRUE);
374
375    RECT rWindow;
376    GetWindowRect (psai->hSockAddr, &rWindow);
377    rWindow.right += (cxE1 + cxE2*3 + sSockSep.cx*3) - cxRECT(rSockAddr);
378
379    SetWindowPos (psai->hSockAddr, NULL, 0, 0, cxRECT(rWindow), cyRECT(rWindow),
380                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
381
382    SOCKADDR_IN addrNew;
383    memset (&addrNew, 0x00, sizeof(addrNew));
384    SockAddr_OnSetAddr (psai, 0, (LPARAM)&addrNew);
385 }
386
387
388 void SockAddr_OnDestroy (SockAddrInfo *psai)
389 {
390    Subclass_RemoveHook (GetParent(psai->hSockAddr), SockAddrDlgProc);
391    psai->hSockAddr = NULL;
392 }
393
394
395 void SockAddr_OnButtonDown (SockAddrInfo *psai, UINT msg, WPARAM wp, LPARAM lp)
396 {
397    DWORD dw = GetMessagePos();
398    POINT pt;
399    pt.x = LOWORD(dw);
400    pt.y = HIWORD(dw);  // in screen coordinates
401
402    RECT rTarget;
403    HWND hTarget = 0;
404
405    GetWindowRect (psai->hE1, &rTarget);
406    if (PtInRect (&rTarget, pt))
407       hTarget = psai->hE1;
408
409    GetWindowRect (psai->hE2, &rTarget);
410    if (PtInRect (&rTarget, pt))
411       hTarget = psai->hE2;
412
413    GetWindowRect (psai->hE3, &rTarget);
414    if (PtInRect (&rTarget, pt))
415       hTarget = psai->hE3;
416
417    GetWindowRect (psai->hE4, &rTarget);
418    if (PtInRect (&rTarget, pt))
419       hTarget = psai->hE4;
420
421    if (hTarget != 0)
422       {
423       PostMessage (hTarget, msg, wp, lp);
424       }
425 }
426
427
428 BOOL SockAddr_OnGetAddr (SockAddrInfo *psai, WPARAM wp, LPARAM lp)
429 {
430    SOCKADDR_IN *pAddr = (SOCKADDR_IN*)lp;
431    *pAddr = psai->addr;
432    return TRUE;
433 }
434
435
436 BOOL SockAddr_OnSetAddr (SockAddrInfo *psai, WPARAM wp, LPARAM lp)
437 {
438    SOCKADDR_IN *pAddr = (SOCKADDR_IN*)lp;
439    psai->addr = *pAddr;
440    SockAddr_Edit_SetText (psai, psai->hE1);
441    SockAddr_Edit_SetText (psai, psai->hE2);
442    SockAddr_Edit_SetText (psai, psai->hE3);
443    SockAddr_Edit_SetText (psai, psai->hE4);
444    return TRUE;
445 }
446
447
448 BOOL CALLBACK SockAddrDlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
449 {
450    PVOID oldProc = Subclass_FindNextHook (hDlg, SockAddrDlgProc);
451    size_t iSockAddr;
452
453    switch (msg)
454       {
455       case WM_CTLCOLOREDIT:
456       case WM_CTLCOLORSTATIC:
457          for (iSockAddr = 0; iSockAddr < cSockAddr; ++iSockAddr)
458             {
459             if (aSockAddr[ iSockAddr ].hSockAddr == NULL)
460                continue;
461             if ( (aSockAddr[ iSockAddr ].hE1   == (HWND)lp) ||
462                  (aSockAddr[ iSockAddr ].hSep1 == (HWND)lp) ||
463                  (aSockAddr[ iSockAddr ].hE2   == (HWND)lp) ||
464                  (aSockAddr[ iSockAddr ].hSep2 == (HWND)lp) ||
465                  (aSockAddr[ iSockAddr ].hE3   == (HWND)lp) ||
466                  (aSockAddr[ iSockAddr ].hSep3 == (HWND)lp) ||
467                  (aSockAddr[ iSockAddr ].hE4   == (HWND)lp) )
468                {
469                COLORREF clr;
470                if (IsWindowEnabled (aSockAddr[ iSockAddr ].hSockAddr))
471                   clr = GetSysColor (COLOR_WINDOW);
472                else
473                   clr = GetSysColor (COLOR_BTNFACE);
474                SetBkColor ((HDC)wp, clr);
475                return (BOOL)CreateSolidBrush (clr);
476                }
477             }
478          break;
479
480       case WM_COMMAND:
481          for (iSockAddr = 0; iSockAddr < cSockAddr; ++iSockAddr)
482             {
483             if (aSockAddr[ iSockAddr ].hSockAddr == NULL)
484                continue;
485             if ( (aSockAddr[ iSockAddr ].idE1 == LOWORD(wp)) ||
486                  (aSockAddr[ iSockAddr ].idE2 == LOWORD(wp)) ||
487                  (aSockAddr[ iSockAddr ].idE3 == LOWORD(wp)) ||
488                  (aSockAddr[ iSockAddr ].idE4 == LOWORD(wp)) )
489                {
490                static BOOL fInHere = FALSE;
491                if (!fInHere)
492                   {
493                   fInHere = TRUE;
494
495                   if (HIWORD(wp) == EN_CHANGE)
496                      {
497                      SockAddr_Edit_OnChange (&aSockAddr[ iSockAddr ], GetDlgItem (hDlg, LOWORD(wp)));
498                      }
499                   else if (HIWORD(wp) == EN_UPDATE)
500                      {
501                      SockAddr_Edit_OnUpdate (&aSockAddr[ iSockAddr ], GetDlgItem (hDlg, LOWORD(wp)));
502                      }
503
504                   fInHere = FALSE;
505                   }
506                break;
507                }
508             }
509          break;
510       }
511
512    if (oldProc)
513       return CallWindowProc ((WNDPROC)oldProc, hDlg, msg, wp, lp);
514    else
515       return DefWindowProc (hDlg, msg, wp, lp);
516 }
517
518
519 BOOL CALLBACK SockAddrEditProc (HWND hEdit, UINT msg, WPARAM wp, LPARAM lp)
520 {
521    SockAddrInfo *psai = NULL;
522
523    EnterCriticalSection (&csSockAddr);
524
525    for (size_t iSockAddr = 0; !psai && iSockAddr < cSockAddr; ++iSockAddr)
526       {
527       if ( (aSockAddr[ iSockAddr ].hE1 == hEdit) ||
528            (aSockAddr[ iSockAddr ].hE2 == hEdit) ||
529            (aSockAddr[ iSockAddr ].hE3 == hEdit) ||
530            (aSockAddr[ iSockAddr ].hE4 == hEdit) )
531          {
532          psai = &aSockAddr[ iSockAddr ];
533          }
534       }
535
536    LeaveCriticalSection (&csSockAddr);
537
538    if (psai)
539       {
540       switch (msg)
541          {
542          case WM_KILLFOCUS:
543             SockAddr_Edit_SetText (psai, hEdit);
544             break;
545
546          case WM_CHAR:
547             if (wp == TEXT('.'))
548                {
549                // advance to the next field
550                PostMessage (GetParent(hEdit), WM_NEXTDLGCTL, 0, 0);
551                return FALSE;
552                }
553             break;
554          }
555       }
556
557    PVOID oldProc = Subclass_FindNextHook (hEdit, SockAddrEditProc);
558    if (oldProc)
559       return CallWindowProc ((WNDPROC)oldProc, hEdit, msg, wp, lp);
560    else
561       return DefWindowProc (hEdit, msg, wp, lp);
562 }
563
564
565 void SockAddr_Edit_OnChange (SockAddrInfo *psai, HWND hEdit)
566 {
567    TCHAR szText[ cchRESOURCE ];
568    GetWindowText (hEdit, szText, cchRESOURCE);
569
570    if ( (hEdit != psai->hE1) ||
571         (psai->addr.sin_addr.s_net) ||
572         (psai->addr.sin_addr.s_host) ||
573         (psai->addr.sin_addr.s_lh) ||
574         (psai->addr.sin_addr.s_impno) ||
575         (szText[0] != TEXT('\0')) )
576       {
577       DWORD dwMin = (hEdit == psai->hE1) ? 1 : 0;
578       DWORD dwNow = (DWORD)atol(szText);
579       DWORD dwMax = (hEdit == psai->hE1) ? 253 : 255;
580
581       dwNow = limit (dwMin, dwNow, dwMax);
582
583       if (hEdit == psai->hE1)
584          psai->addr.sin_addr.s_net = (unsigned char)dwNow;
585       else if (hEdit == psai->hE2)
586          psai->addr.sin_addr.s_host = (unsigned char)dwNow;
587       else if (hEdit == psai->hE3)
588          psai->addr.sin_addr.s_lh = (unsigned char)dwNow;
589       else if (hEdit == psai->hE4)
590          psai->addr.sin_addr.s_impno = (unsigned char)dwNow;
591
592       SOCKADDR_IN addrNew = psai->addr;
593       SockAddr_SendCallback (psai, SAN_CHANGE, (LPARAM)&addrNew);
594       if (memcmp (&addrNew, &psai->addr, sizeof(SOCKADDR_IN)))
595          {
596          SockAddr_OnSetAddr (psai, (WPARAM)0, (LPARAM)&addrNew);
597          }
598       }
599
600 // SockAddr_Edit_SetText (psai, hEdit);
601
602    if ( (hEdit == psai->hE1) &&
603         (psai->addr.sin_addr.s_net) &&
604         (!psai->addr.sin_addr.s_host) &&
605         (!psai->addr.sin_addr.s_lh) &&
606         (!psai->addr.sin_addr.s_impno) )
607       {
608       SockAddr_Edit_SetText (psai, psai->hE2);
609       SockAddr_Edit_SetText (psai, psai->hE3);
610       SockAddr_Edit_SetText (psai, psai->hE4);
611       }
612 }
613
614
615 void SockAddr_Edit_OnUpdate (SockAddrInfo *psai, HWND hEdit)
616 {
617    SOCKADDR_IN addrNew = psai->addr;
618    SockAddr_SendCallback (psai, SAN_UPDATE, (LPARAM)&addrNew);
619 }
620
621
622 void SockAddr_Edit_SetText (SockAddrInfo *psai, HWND hEdit)
623 {
624    DWORD dwNow;
625
626    if ( (!psai->addr.sin_addr.s_net) &&
627         (!psai->addr.sin_addr.s_host) &&
628         (!psai->addr.sin_addr.s_lh) &&
629         (!psai->addr.sin_addr.s_impno) )
630       {
631       SetWindowText (hEdit, TEXT(""));
632       }
633    else
634       {
635       if (hEdit == psai->hE1)
636          dwNow = (DWORD)psai->addr.sin_addr.s_net;
637       else if (hEdit == psai->hE2)
638          dwNow = (DWORD)psai->addr.sin_addr.s_host;
639       else if (hEdit == psai->hE3)
640          dwNow = (DWORD)psai->addr.sin_addr.s_lh;
641       else if (hEdit == psai->hE4)
642          dwNow = (DWORD)psai->addr.sin_addr.s_impno;
643
644       TCHAR szText[ cchRESOURCE ];
645       wsprintf (szText, TEXT("%lu"), dwNow);
646       SetWindowText (hEdit, szText);
647       }
648 }
649