Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.51/41: Рейтинг темы: голосов - 41, средняя оценка - 4.51
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633

Петзольд. Тема DDE-(Dynamic Data Exchange)

03.11.2023, 16:35. Показов 10272. Ответов 93

Студворк — интернет-сервис помощи студентам
Здравствуйте! Не хочет работать программа из книги Петзольда. Тема, Dynamic Data Exchange, если честно, то саму тему не понял, соответственно, и ошибку найти не могу. Вот код:
Когда запускаю клиента, то бывает, что одно значение, численность штата меняется, а следом ошибка Failure on WM_DDE_ADVISE!, не знаю в чём дело.
Тут нужно выложит ещё и файлы ресурсов, но тогда когда будет совсем уж много, возможно, что кто-нибудь в теме разбирается и поможет, код то простой, если понимаешь что к чему, но если нужно выложу все файлы.

DDEPOP1 - Это сервер.
SHOWPOP1 - Это клиент.

DDEPOP1
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
//DDEPOP1.CPP
 
#include<windows.h>
#include<tchar.h>
 
#include<dde.h>
#include<string.h>
 
#include<stdio.h>
 
#include "ddepop1.h"
#include "..\..\..\..\..\Library\_my_header_files\RegisterClass\RegClass.h"
 
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ServerProc(HWND, UINT, WPARAM, LPARAM);
BOOL    CALLBACK TimerEnumProc(HWND, LONG);
BOOL    CALLBACK CloseEnumProc(HWND, LONG);
BOOL             PostDataMessage(HWND, HWND, int, BOOL, BOOL, BOOL);
 
const TCHAR szMainClass[] = TEXT("DdePop1");
const TCHAR szTitle[] = TEXT("DDE population server.");
 
HINSTANCE hInstance = NULL;
 
const TCHAR szServerName[] = TEXT("DdePop1.Server");
 
 
typedef struct
{
    unsigned int fAdvise : 1;
    unsigned int fDeferUpd : 1;
    unsigned int fAckReq : 1;
    unsigned int dummy : 13;
    long         lPopPrev;
} POPADVISE;
 
#define ID_TIMER           1 
#define ID_TIMEOUT         3000 
 
 
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
    LPTSTR szCmdLine, int nCmdShow)
{
    hInstance = hInst;
    MSG msg = { 0 };
    HWND hwnd = NULL;
 
 
    RWC wc(hInst, WndProc, szMainClass); //Класс в котором происходит регистрация класса окна.
    wc.set_icon(hInst, szMainClass);
    if (!wc.reg_class())
        return FALSE;
 
    wc.set_wndproc(ServerProc);
    wc.set_wndextra(2 * sizeof(DWORD));
    wc.set_icon(NULL, IDI_APPLICATION);
    wc.set_class(szServerName);
    if (!wc.reg_class())
        return FALSE;
 
 
    if (!(hwnd = CreateWindow(szMainClass, szTitle,
        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
        CW_USEDEFAULT, 0,
        CW_USEDEFAULT, 0,
        NULL, (HMENU)NULL, hInstance, NULL)))
    {
        return FALSE;
    }
 
    //Initialize 'pop' structure
    InitPops();
 
    SetTimer(hwnd, ID_TIMER, 5000, NULL);
 
 
    ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
    UpdateWindow(hwnd);
 
    for (; GetMessage(&msg, NULL, 0, 0);)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
 
    KillTimer(hwnd, ID_TIMER);
    wc.unreg_class();
    //UnregisterClass(hInstance, szMainClass);
    return msg.wParam;
}
 
 
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static TCHAR szTopic[] = TEXT("US_Population");
    ATOM   aApp, aTop;
    HWND  hwndClient, hwndServer;
 
    switch (msg)
    {
    case WM_DDE_INITIATE:
    {
        //wParam          -- sending window handle
        //LOWORD(lParam)  -- application atom
        //HIWORD(lParam)  -- topic atom 
 
        hwndClient = (HWND)wParam;
        aApp = GlobalAddAtom(szMainClass);
        aTop = GlobalAddAtom(szTopic);
 
        //Check for matching atoms, create window, and acknowledge 
        if ((LOWORD(lParam) == NULL || LOWORD(lParam) == aApp) &&
            (HIWORD(lParam) == NULL || HIWORD(lParam) == aTop))
        {
            hwndServer = CreateWindow(szServerName, NULL,
                WS_CHILD, 0, 0, 0, 0,
                hwnd, NULL, hInstance, NULL);
            SetWindowLong(hwndServer, 0, (LONG)hwndClient);
            SendMessage((HWND)wParam, WM_DDE_ACK,
                (WPARAM)hwndServer, MAKELPARAM(aApp, aTop));
        }
        else  //Otherwise, delete the atoms just created
        {
            GlobalDeleteAtom(aApp);
            GlobalDeleteAtom(aTop);
        }
 
        return 0;
    }
    case WM_TIMER:
    case WM_TIMECHANGE:
    {
        //Calculate new current populations
 
        CalcPops();
 
        //Notify all child windows 
 
        EnumChildWindows(hwnd, &TimerEnumProc, 0L);
 
        return 0;
    }
    case WM_QUERYOPEN:
    {
        return 0;
    }
    case WM_CLOSE:
    {
        //Notify all child windows 
        EnumChildWindows(hwnd, &CloseEnumProc, 0L);
        break;  //for default processing
    }
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        return 0;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
 
LRESULT CALLBACK ServerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    ATOM  aItem;
    TCHAR szItem[10];
    DDEACK DdeAck;
    DDEADVISE* pDdeAdvise;
    DWORD dwTime;
    GLOBALHANDLE hPopAdvise, hDdeAdvise, hCommands, hDdePoke;
    UINT uiLow, uiHi;
    HWND hwndClient;
    MSG iMsg;
    POPADVISE* pPopAdvise;
    WORD  cfFormat, wStatus;
 
    switch (msg)
    {
    case WM_CREATE:
    {
        //Allocate memory for POPADVISE structures
        hPopAdvise = GlobalAlloc(GHND, NUM_STATES * sizeof(POPADVISE));
        if (hPopAdvise == NULL)
            DestroyWindow(hwnd);
        else
            SetWindowLong(hwnd, 4, (LONG)hPopAdvise);
 
        return 0;
    }
    case WM_DDE_REQUEST:
    {
        //wParam            -- sending window handle 
        //LOWORD(lParam)    -- data format
        //HIWORD(lParam)    -- item atom 
 
        hwndClient = (HWND)wParam;
        cfFormat = LOWORD(lParam);
        aItem = HIWORD(lParam);
 
        //Check for matching format and data item
        if (cfFormat == CF_UNICODETEXT)
        {
            GlobalGetAtomName(aItem, szItem, sizeof(szItem));
            int i;
            for (i = 0; i < NUM_STATES; ++i)
                if (_tcscmp(szItem, pop[i].szState) == 0)
                    break;
 
            if (i < NUM_STATES)
            {
                GlobalDeleteAtom(aItem);
                PostDataMessage(hwnd, hwndClient, i,
                    FALSE, FALSE, TRUE);
                return 0;
            }
        }
 
        //Negative acknowledge if no match 
        DdeAck.bAppReturnCode = 0;
        DdeAck.reserved = 0;
        DdeAck.fBusy = FALSE;
        DdeAck.fAck = FALSE;
 
        wStatus = *((WORD*)&DdeAck);
 
        if (!PostMessage(hwndClient, WM_DDE_ACK, (WPARAM)hwnd,
            PackDDElParam(WM_DDE_ACK, wStatus, aItem)))
        {
            GlobalDeleteAtom(aItem);
        }
 
        return 0;
    }
    case WM_DDE_ADVISE:
    {
        //wParam   --  sending window handle
        //lParam   --  DDEADVISE memory handle & item atom 
 
        UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLow, &uiHi);
        FreeDDElParam(WM_DDE_ADVISE, lParam);
 
        hwndClient = (HWND)wParam;
        hDdeAdvise = (GLOBALHANDLE)uiLow;
        aItem = (ATOM)uiHi;
 
        pDdeAdvise = (DDEADVISE*)GlobalLock(hDdeAdvise);
        if (!pDdeAdvise)
        {
            MessageBox(hwnd, TEXT("Can't memory alloc 'GlobalLock'"),
                TEXT("ERROR: DDEPOP1 --> WM_DDE_ADVISE"),
                MB_OK | MB_ICONSTOP);
            return 0;
        }
        //Check for matching format and data item
        if (pDdeAdvise->cfFormat == CF_UNICODETEXT)
        {
            GlobalGetAtomName(aItem, szItem, sizeof(szItem));
            int i;
            for (i = 0; i < NUM_STATES; ++i)
                if (_tcscmp(szItem, pop[i].szState) == 0)
                    break;
 
            //Fill in the POPADVISE structure and acknowledge 
            if (i < NUM_STATES)
            {
                hPopAdvise = (GLOBALHANDLE)GetWindowLong(hwnd, 4);
                pPopAdvise = (POPADVISE*)GlobalLock(hPopAdvise);
 
                if (!pPopAdvise)
                {
                    MessageBox(hwnd, TEXT("Can't memory alloc 'GlobalLock'"),
                        TEXT("ERROR: DDEPOP1 --> WM_DDE_ADVISE"),
                        MB_OK | MB_ICONSTOP);
                    return 0;
                }
 
                pPopAdvise[i].fAdvise = TRUE;
                pPopAdvise[i].fDeferUpd = pDdeAdvise->fDeferUpd;
                pPopAdvise[i].fAckReq = pDdeAdvise->fAckReq;
                //pPopAdvise[i].fAckReq = pDdeAdvise->fAckReq;
                pPopAdvise[i].lPopPrev = pop[i].lPop;
 
                GlobalUnlock(hDdeAdvise);
                GlobalFree(hDdeAdvise);
 
                DdeAck.bAppReturnCode = 0;
                DdeAck.reserved = 0;
                DdeAck.fBusy = FALSE;
                DdeAck.fAck = TRUE;
 
                wStatus = *((WORD*)&DdeAck);
 
                if (!PostMessage(hwndClient, WM_DDE_ACK,
                    (WPARAM)hwnd,
                    PackDDElParam(WM_DDE_ACK, wStatus, aItem)))
                {
                    GlobalDeleteAtom(aItem);
                }
                else
                {
                    PostDataMessage(hwnd, hwndClient, i,
                        pPopAdvise[i].fDeferUpd,
                        pPopAdvise[i].fAckReq,
                        FALSE);
                }
                GlobalUnlock(hPopAdvise);
                return 0;
            }
 
        }
        //Otherwise, post a negative WM_DDE_ACK 
        GlobalUnlock(hDdeAdvise);
 
        DdeAck.bAppReturnCode = 0;
        DdeAck.reserved = 0;
        DdeAck.fBusy = FALSE;
        DdeAck.fAck = FALSE;
 
        wStatus = *((WORD*)&DdeAck);
 
        if (!PostMessage(hwndClient, WM_DDE_ACK,
            (WPARAM)hwnd,
            PackDDElParam(WM_DDE_ACK, wStatus, aItem)))
        {
            GlobalFree(hDdeAdvise);
            GlobalDeleteAtom(aItem);
        }
 
        return 0;
    }
    case WM_DDE_UNADVISE:
    {
        //wParam           -- sending window handle 
        //LOWORD(lParam)   -- data format 
        //HIWORD(lParam)   -- item atom
        hwndClient = (HWND)wParam;
        cfFormat = LOWORD(lParam);
        aItem = HIWORD(lParam);
 
        DdeAck.bAppReturnCode = 0;
        DdeAck.reserved = 0;
        DdeAck.fBusy = FALSE;
        DdeAck.fAck = TRUE;
 
        hPopAdvise = (GLOBALHANDLE)GetWindowLong(hwnd, 4);
        pPopAdvise = (POPADVISE*)GlobalLock(hPopAdvise);
 
        //Check for matching format and data item
        if (cfFormat == CF_UNICODETEXT || cfFormat == NULL)
        {
            if (aItem == (ATOM)NULL)
                for (int i = 0; i < NUM_STATES; ++i)
                    pPopAdvise[i].fAdvise = FALSE;
            else
            {
                GlobalGetAtomName(aItem, szItem, sizeof(szItem));
                int i;
                for (i = 0; i < NUM_STATES; ++i)
                    if (_tcscmp(szItem, pop[i].szState) == 0)
                        break;
 
                if (i < NUM_STATES)
                    pPopAdvise[i].fAdvise = FALSE;
                else
                    DdeAck.fAck = FALSE;
            }
        }
        else
            DdeAck.fAck = FALSE;
 
        //Acknowledge either positively or negatively
        wStatus = *((WORD*)&DdeAck);
 
        if (!PostMessage(hwndClient, WM_DDE_ACK, (WPARAM)hwnd,
            PackDDElParam(WM_DDE_ACK, wStatus, aItem)))
        {
            if (aItem != (ATOM)NULL)
                GlobalDeleteAtom(aItem);
        }
 
        GlobalUnlock(hPopAdvise);
 
        return 0;
    }
    case WM_DDE_EXECUTE:
    {
        //Post negative acknowledge 
        hwndClient = (HWND)wParam;
        hCommands = (GLOBALHANDLE)lParam;
 
        DdeAck.bAppReturnCode = 0;
        DdeAck.reserved = 0;
        DdeAck.fBusy = FALSE;
        DdeAck.fAck = FALSE;
 
        wStatus = *((WORD*)&DdeAck);
 
        if (!PostMessage(hwndClient, WM_DDE_ACK, (WPARAM)hwnd,
            PackDDElParam(WM_DDE_ACK, wStatus,
                (UINT)hCommands)))
        {
            GlobalFree(hCommands);
        }
        return 0;
    }
    case WM_DDE_POKE:
    {
        //Post negative acknowledge 
        UnpackDDElParam(WM_DDE_POKE, lParam, &uiLow, &uiHi);
        FreeDDElParam(WM_DDE_POKE, lParam);
        hwndClient = (HWND)wParam;
        hDdePoke = (GLOBALHANDLE)uiLow;
        aItem = (ATOM)uiHi;
 
        DdeAck.bAppReturnCode = 0;
        DdeAck.reserved = 0;
        DdeAck.fBusy = FALSE;
        DdeAck.fAck = FALSE;
 
        wStatus = *((WORD*)&DdeAck);
 
        if (!PostMessage(hwndClient, WM_DDE_ACK, (WPARAM)hwnd,
            PackDDElParam(WM_DDE_ACK, wStatus, aItem)))
        {
            GlobalFree(hDdePoke);
            GlobalDeleteAtom(aItem);
        }
        return 0;
    }
    case WM_DDE_TERMINATE:
    {
        //Respond with another WM_DDE_TERMINATE msg 
        hwndClient = (HWND)wParam;
        PostMessage(hwndClient, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
        DestroyWindow(hwnd);
        return 0;
    }
    case WM_TIMER:
    {
        //Post WM_DDE_DATA msgs for changed populations 
        hwndClient = (HWND)GetWindowLong(hwnd, 0);
        hPopAdvise = (GLOBALHANDLE)GetWindowLong(hwnd, 4);
        pPopAdvise = (POPADVISE*)GlobalLock(hPopAdvise);
 
        for (int i = 0; i < NUM_STATES; ++i)
            if (pPopAdvise[i].fAdvise)
                if (pPopAdvise[i].lPopPrev != pop[i].lPop)
                {
                    if (!PostDataMessage(hwnd, hwndClient, i,
                        pPopAdvise[i].fDeferUpd,
                        pPopAdvise[i].fAckReq,
                        FALSE))
                        {
                        //pPopAdvise[i].lPopPrev = pop[i].lPop;
                        break;
                        }
 
                    pPopAdvise[i].lPopPrev = pop[i].lPop;
                }
        GlobalUnlock(hPopAdvise);
        return 0;
    }
    case WM_CLOSE:
    {
        //Post a WM_DDE_TERMINATE msg to the client 
        hwndClient = (HWND)GetWindowLong(hwnd, 0);
        PostMessage(hwndClient, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
 
        dwTime = GetCurrentTime();
        while (GetCurrentTime() - dwTime < ID_TIMEOUT)
        {
            if (PeekMessage(&iMsg, hwnd, WM_DDE_TERMINATE,
                WM_DDE_TERMINATE, PM_REMOVE))
                break;
        }
        DestroyWindow(hwnd);
        return 0;
    }
    case WM_DESTROY:
    {
        hPopAdvise = (GLOBALHANDLE)GetWindowLong(hwnd, 4);
        GlobalFree(hPopAdvise);
        return 0;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
 
BOOL CALLBACK TimerEnumProc(HWND hwnd, LPARAM lParam)
{
    SendMessage(hwnd, WM_TIMER, 0, 0L);
    return TRUE;
}
 
BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
    SendMessage(hwnd, WM_CLOSE, 0, 0L);
    return TRUE;
}
 
BOOL PostDataMessage(HWND hwndServer, HWND hwndClient, int iState,
    BOOL fDeferUpd, BOOL fAckReq, BOOL fResponse)
{
    ATOM aItem;
    TCHAR szPopulation[16];
    DDEACK  DdeAck;
    DDEDATA* pDdeData;
    DWORD dwTime;
    GLOBALHANDLE hDdeData;
    MSG msg;
    WORD wStatus;
 
    aItem = GlobalAddAtom(pop[iState].szState);
 
    //Allocate a DDEDATA structure if not deferred update
 
    if (fDeferUpd)
    {
        hDdeData = NULL;
    }
    else
    {
        _stprintf_s(szPopulation, 16, TEXT("%ld\r\n"), pop[iState].lPop);
        hDdeData = GlobalAlloc(GHND | GMEM_DDESHARE,
            sizeof(DDEDATA) + (_tcslen(szPopulation)));
        pDdeData = (DDEDATA*)GlobalLock(hDdeData);
        if (!pDdeData)
            return FALSE;
 
 
        pDdeData->fResponse = fResponse;
        pDdeData->fRelease = TRUE;
        pDdeData->fAckReq = fAckReq;
        pDdeData->cfFormat = CF_UNICODETEXT;
 
        _tcscpy_s((PTSTR)pDdeData->Value, 16, szPopulation);
 
        GlobalUnlock(hDdeData);
    }
 
    //Post the WM_DDE_DATA msg 
    if (!PostMessage(hwndClient, WM_DDE_DATA, (WPARAM)hwndServer,
        PackDDElParam(WM_DDE_DATA, (UINT)hDdeData, aItem)))
    {
        if (hDdeData != NULL)
            GlobalFree(hDdeData);
 
        GlobalDeleteAtom(aItem);
        return FALSE;
    }
 
    //Wait for the acknowledge msg if it's requested 
    if (fAckReq)
    {
        DdeAck.fAck = FALSE;
 
        dwTime = GetCurrentTime();
 
        while (GetCurrentTime() - dwTime < ID_TIMEOUT)
        {
            if (PeekMessage(&msg, hwndServer, WM_DDE_ACK, WM_DDE_ACK,
                PM_REMOVE))
            {
                wStatus = LOWORD(msg.lParam);
                DdeAck = *((DDEACK*)&wStatus);
                aItem = HIWORD(msg.lParam);
                GlobalDeleteAtom(aItem);
                break;
            }
        }
        if (DdeAck.fAck == FALSE)
        {
            if (hDdeData != NULL)
                GlobalFree(hDdeData);
            return FALSE;
        }
    }
    return TRUE;
}



SHOWPOP1
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
//SHOWPOP1.CPP
 
#include<windows.h>
#include<tchar.h>
 
#include<dde.h>
#include<string.h>
 
#include "showpop1.h"
 
#include "D:\\Library\_my_header_files\RegisterClass\RegClass.h"
BOOL RegClass(WNDPROC, LPCTSTR, UINT);
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
 
const TCHAR szMainClass[] = TEXT("ShowPop1");
const TCHAR szTitle[] = TEXT("DDE Client - US population.");
 
HINSTANCE hInstance = NULL;
 
#define WM_USER_INITIATE   (WM_USER + 1) 
#define DDE_TIMEOUT        3000 
 
 
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
    LPTSTR szCmdLine, int nCmdShow)
{
    hInstance = hInst;
    MSG msg = { 0 };
    HWND hwnd = NULL;
 
    //if(!RegClass(WndProc, szMainClass, COLOR_WINDOW))
        //return FALSE;
 
    RWC wc(hInst, WndProc, szMainClass);
    wc.set_icon(hInst, szMainClass);
    if (!wc.reg_class())
        return FALSE;
 
 
 
    if (!(hwnd = CreateWindow(szMainClass, szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0,
        CW_USEDEFAULT, 0,
        NULL, (HMENU)NULL, hInstance, NULL)))
    {
        return FALSE;
    }
 
 
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
 
    SendMessage(hwnd, WM_USER_INITIATE, 0, 0L);
 
    for (; GetMessage(&msg, NULL, 0, 0);)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
 
 
    wc.unreg_class();
    //UnregisterClass(hInstance, szMainClass);
    return msg.wParam;
}
 
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static BOOL fDoingInitiate = TRUE;
    static TCHAR szServerApp[] = TEXT("DdePop1"),
        szTopic[] = TEXT("US_Population");
    static char szServerAppA[] = "DdePop1",
        szTopicA[] = "US_Population";
    static HWND hwndServer = NULL;
    static long cxChar, cyChar;
    ATOM   aApp, aTop, aItem;
    TCHAR  szBuffer[24], szPopulation[16], szItem[16];
    DDEACK DdeAck;
    DDEDATA* pDdeData;
    DDEADVISE* pDdeAdvise;
    DWORD dwTime;
    GLOBALHANDLE hDdeAdvise, hDdeData;
    MSG iMsg;
    WORD wStatus;
 
    switch (msg)
    {
    case WM_CREATE:
    {
        TEXTMETRIC tm;
        HDC hdc = GetDC(hwnd);
        GetTextMetrics(hdc, &tm);
        cxChar = tm.tmAveCharWidth;
        cyChar = tm.tmHeight + tm.tmExternalLeading;
 
        ReleaseDC(hwnd, hdc);
        return 0;
    }
    case WM_USER_INITIATE:
    {
        //Broadcast WM_DDE_INITIATE iMsg
        aApp = GlobalAddAtom(szServerApp);
        aTop = GlobalAddAtom(szTopic);
 
        SendMessage(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwnd,
            MAKELONG(aApp, aTop));
 
        //If no response, try loading DDEPOP first
        if (hwndServer == NULL)
        {
            WinExec(szServerAppA, SW_SHOWMINNOACTIVE);
            SendMessage(HWND_BROADCAST, WM_DDE_INITIATE,
                (WPARAM)hwnd, MAKELONG(aApp, aTop));
        }
 
        //Delete the atoms 
        GlobalDeleteAtom(aApp);
        GlobalDeleteAtom(aTop);
        fDoingInitiate = FALSE;
 
        //If still no response, display message box 
 
        if (hwndServer == NULL)
        {
            MessageBox(hwnd,
                TEXT("Cannot connect with DDEPOP1.EXE!"),
                szMainClass, MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
 
        //Post WM_DDE_ADVISE iMsgs
        int i;
        for (i = 0; i < NUM_STATES; ++i)
        {
            hDdeAdvise = GlobalAlloc(GHND | GMEM_DDESHARE,
                sizeof(DDEADVISE));
            if (!hDdeAdvise)
            {
                MessageBox(hwnd,
                    TEXT("Can't memory alloc 'GlobalAlloc'"),
                    szMainClass, MB_OK);
                return 0;
            }
            pDdeAdvise = (DDEADVISE*)GlobalLock(hDdeAdvise);
            if (!pDdeAdvise)
            {
                MessageBox(hwnd,
                    TEXT("Can't memory alloc 'GlobalLock'"),
                    szMainClass, MB_OK);
                return 0;
            }
            pDdeAdvise->fAckReq = TRUE;
            pDdeAdvise->fDeferUpd = FALSE;
            pDdeAdvise->cfFormat = CF_UNICODETEXT;
 
            GlobalUnlock(hDdeAdvise);
 
            aItem = GlobalAddAtom(pop[i].szAbb);
 
            if (!PostMessage(hwndServer, WM_DDE_ADVISE,
                (WPARAM)hwnd,
                PackDDElParam(WM_DDE_ADVISE,
                    (UINT)hDdeAdvise, aItem)))
            {
                GlobalFree(hDdeAdvise);
                GlobalDeleteAtom(aItem);
                break;
            }
            DdeAck.fAck = FALSE;
 
            dwTime = GetCurrentTime();
 
            while (GetCurrentTime() - dwTime < DDE_TIMEOUT)
            {
                if (PeekMessage(&iMsg, hwnd, WM_DDE_ACK,
                    WM_DDE_ACK, PM_REMOVE))
                {
                    GlobalDeleteAtom(HIWORD(iMsg.lParam));
 
                    wStatus = LOWORD(iMsg.lParam);
 
                    DdeAck = *((DDEACK*)&wStatus);
 
                    if (DdeAck.fAck == FALSE)
                    {
                        GlobalFree(hDdeAdvise);
                    }
                    break;
                }
            }
 
            if (DdeAck.fAck == FALSE)
                break;
 
            while (PeekMessage(&iMsg, hwnd, WM_DDE_FIRST,
                WM_DDE_LAST, PM_REMOVE))
            {
                DispatchMessage(&iMsg);
            }
        }
        if (i < NUM_STATES)
        {
            MessageBox(hwnd, TEXT("Failure on WM_DDE_ADVISE!"),
                szMainClass, MB_ICONEXCLAMATION | MB_OK);
        }
        return 0;
    }
    case WM_DDE_ACK:
    {
        //In response to WM_DDE_INITIATE, save server window 
        unsigned int uiLow, uiHi;
        if (fDoingInitiate)
        {
            UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi);
            if (!FreeDDElParam(WM_DDE_ACK, lParam))
            {
                DWORD er = GetLastError();
                DWORD eer = er;
            }
            hwndServer = (HWND)wParam;
            GlobalDeleteAtom((ATOM)uiLow);
            GlobalDeleteAtom((ATOM)uiHi);
        }
        return 0;
    }
    case WM_DDE_DATA:
    {
        //wParam  -- sending window handle
        //lParam  -- DDEDATA memory handle & item atom
        unsigned int uiLow, uiHi;
        UnpackDDElParam(WM_DDE_DATA, lParam, &uiLow, &uiHi);
        FreeDDElParam(WM_DDE_DATA, lParam);
 
        hDdeData = (GLOBALHANDLE)uiLow;
        pDdeData = (DDEDATA*)GlobalLock(hDdeData);
        aItem = (ATOM)uiHi;
 
        //Initialize DdeAck structure 
        DdeAck.bAppReturnCode = 0;
        DdeAck.reserved = 0;
        DdeAck.fBusy = FALSE;
        DdeAck.fAck = FALSE;
 
        //Check for matching format and data item 
        if (pDdeData->cfFormat == CF_UNICODETEXT)
        {
            GlobalGetAtomName(aItem, szItem, sizeof(szItem));
            int i;
            for (i = 0; i < NUM_STATES; ++i)
                if (_tcscmp(szItem, pop[i].szAbb) == 0)
                    break;
 
            if (i < NUM_STATES)
            {
                _tcscpy_s(szPopulation, 16, (TCHAR*)pDdeData->Value);
                pop[i].lPop = _tstol(szPopulation);
                InvalidateRect(hwnd, NULL, FALSE);
 
                DdeAck.fAck = TRUE;
            }
        }
 
        //Acknowledge if necessary
        if (pDdeData->fAckReq == TRUE)
        {
            wStatus = *((WORD*)&DdeAck);
            if (!PostMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd,
                PackDDElParam(WM_DDE_ACK, wStatus,
                    aItem)))
            {
                GlobalDeleteAtom(aItem);
                GlobalUnlock(hDdeData);
                GlobalFree(hDdeData);
                return 0;
            }
        }
        else
        {
            GlobalDeleteAtom(aItem);
        }
 
        //Clean Up
        if (pDdeData->fRelease == TRUE || DdeAck.fAck == FALSE)
        {
            GlobalUnlock(hDdeData);
            GlobalFree(hDdeData);
        }
        else
        {
            GlobalUnlock(hDdeData);
        }
        return 0;
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
 
        int x, y;
        for (int i = 0; i < NUM_STATES; ++i)
        {
            if (i < (NUM_STATES + 1) / 2)
            {
                x = cxChar;
                y = i * cyChar;
            }
            else
            {
                x = 44 * cxChar;
                y = (i - (NUM_STATES + 1) / 2) * cyChar;
            }
 
            TextOut(hdc, x, y, szBuffer,
                _stprintf_s(szBuffer, 24, TEXT("%-20s"),
                    (PTSTR)pop[i].szState));
            x += 36 * cxChar;
 
            SetTextAlign(hdc, TA_RIGHT | TA_TOP);
 
            TextOut(hdc, x, y, szBuffer,
                _stprintf_s(szBuffer, 24, TEXT("%10ld"),
                    pop[i].lPop));
            SetTextAlign(hdc, TA_LEFT | TA_TOP);
        }
        EndPaint(hwnd, &ps);
        return 0;
    }
    case WM_DDE_TERMINATE:
    {
        //Respond with another WM_DDE_TERMINATE iMsg 
        PostMessage(hwndServer, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
        hwndServer = NULL;
        return 0;
    }
    case WM_CLOSE:
    {
        if (hwndServer == NULL)
            break;
 
        //Post WM_DDE_UNADVISE iMsg
        PostMessage(hwndServer, WM_DDE_UNADVISE, (WPARAM)hwnd,
            MAKELONG(CF_UNICODETEXT, NULL));
 
        dwTime = GetCurrentTime();
 
        while (GetCurrentTime() - dwTime < DDE_TIMEOUT)
        {
            if (PeekMessage(&iMsg, hwnd, WM_DDE_ACK, WM_DDE_ACK,
                PM_REMOVE))
                break;
        }
 
        //Post WM_DDE_TERMINATE iMsg 
        PostMessage(hwndServer, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
 
        dwTime = GetCurrentTime();
 
        while (GetCurrentTime() - dwTime < DDE_TIMEOUT)
        {
            if (PeekMessage(&iMsg, hwnd, WM_DDE_TERMINATE,
                WM_DDE_TERMINATE, PM_REMOVE))
                break;
        }
        break; //for default processing
    }
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        return 0;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}



В этом участке кода ошибка:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
case WM_USER_INITIATE:
    {
        //Broadcast WM_DDE_INITIATE iMsg
        aApp = GlobalAddAtom(szServerApp);
        aTop = GlobalAddAtom(szTopic);
 
        SendMessage(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwnd,
            MAKELONG(aApp, aTop));
 
        //If no response, try loading DDEPOP first
        if (hwndServer == NULL)
        {
            WinExec(szServerAppA, SW_SHOWMINNOACTIVE);
            SendMessage(HWND_BROADCAST, WM_DDE_INITIATE,
                (WPARAM)hwnd, MAKELONG(aApp, aTop));
        }
 
        //Delete the atoms 
        GlobalDeleteAtom(aApp);
        GlobalDeleteAtom(aTop);
        fDoingInitiate = FALSE;
 
        //If still no response, display message box 
 
        if (hwndServer == NULL)
        {
            MessageBox(hwnd,
                TEXT("Cannot connect with DDEPOP1.EXE!"),
                szMainClass, MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
 
        //Post WM_DDE_ADVISE iMsgs
        int i;
        for (i = 0; i < NUM_STATES; ++i)
        {
            hDdeAdvise = GlobalAlloc(GHND | GMEM_DDESHARE,
                sizeof(DDEADVISE));
            if (!hDdeAdvise)
            {
                MessageBox(hwnd,
                    TEXT("Can't memory alloc 'GlobalAlloc'"),
                    szMainClass, MB_OK);
                return 0;
            }
            pDdeAdvise = (DDEADVISE*)GlobalLock(hDdeAdvise);
            if (!pDdeAdvise)
            {
                MessageBox(hwnd,
                    TEXT("Can't memory alloc 'GlobalLock'"),
                    szMainClass, MB_OK);
                return 0;
            }
            pDdeAdvise->fAckReq = TRUE;
            pDdeAdvise->fDeferUpd = FALSE;
            pDdeAdvise->cfFormat = CF_UNICODETEXT;
 
            GlobalUnlock(hDdeAdvise);
 
            aItem = GlobalAddAtom(pop[i].szAbb);
 
            if (!PostMessage(hwndServer, WM_DDE_ADVISE,
                (WPARAM)hwnd,
                PackDDElParam(WM_DDE_ADVISE,
                    (UINT)hDdeAdvise, aItem)))
            {
                GlobalFree(hDdeAdvise);
                GlobalDeleteAtom(aItem);
                break;
            }
            DdeAck.fAck = FALSE;
 
            dwTime = GetCurrentTime();
 
            while (GetCurrentTime() - dwTime < DDE_TIMEOUT)
            {
                if (PeekMessage(&iMsg, hwnd, WM_DDE_ACK,
                    WM_DDE_ACK, PM_REMOVE))
                {
                    GlobalDeleteAtom(HIWORD(iMsg.lParam));
 
                    wStatus = LOWORD(iMsg.lParam);
 
                    DdeAck = *((DDEACK*)&wStatus);
 
                    if (DdeAck.fAck == FALSE)
                    {
                        GlobalFree(hDdeAdvise);
                    }
                    break;
                }
            }
 
            if (DdeAck.fAck == FALSE)
                break;
 
            while (PeekMessage(&iMsg, hwnd, WM_DDE_FIRST,
                WM_DDE_LAST, PM_REMOVE))
            {
                DispatchMessage(&iMsg);
            }
        }
        if (i < NUM_STATES) //Здесь она сообщает, что что-то не так. 
        {
                    
            MessageBox(hwnd, TEXT("Failure on WM_DDE_ADVISE!"),
                szMainClass, MB_ICONEXCLAMATION | MB_OK);
        }
        return 0;
    }
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
03.11.2023, 16:35
Ответы с готовыми решениями:

Чем заменить Dynamic Data Exchange (DDE) из VB6
Здравствуйте. На vb6 очень удобная вещь - Dynamic Data Exchange (DDE) для обмена данными между приложениями, на vb2005 уже не...

научите пользоваться Dynamic Data Display
прошу научите) с самого начала! -как добавить библиотеку в проект? -появятся ли контролы какие-то или нет? (простите возможно это...

Отображение графика в Dynamic Data Display
Добрый день. Не могу добиться отображения данных на графике. P.S. Plotter.AddLineGraph отказывается работать P.P.S. c#...

93
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
17.11.2023, 09:04
Студворк — интернет-сервис помощи студентам

Не по теме:

Цитата Сообщение от Liss29 Посмотреть сообщение
Этот способ используется в современных операционных системах
DDE в 2016.

Цитата Сообщение от learn.microsoft.com
Чтобы предотвратить автоматическое обновление ссылок из Excel (включая DDE, OLE и внешние ссылки на ячейки или определенные ссылки на имена), обратитесь к следующей таблице, чтобы задать строку версии раздела реестра для каждой версии:
Code
1
2
3
4
5
Версия Office     Строка версии раздела <реестра>
Office 2007     12.0
Office 2010     14.0
Office 2013     15.0
Office 2016     16.0
Чтобы отключить функцию DDE в пользовательском интерфейсе:

Перейдите к внешнему>>>> содержимому параметров центра управления безопасностью "Параметры файлового центра управления безопасностью", задайте параметры безопасности для ссылок на книги, чтобы отключить автоматическое обновление ссылок на книги.

Чтобы отключить функцию DDE с помощью редактора реестра, добавьте следующий раздел реестра:

Code
1
2
3
4
    Расположение: HKEY_CURRENT_USER\Software\Microsoft\Office\<version>\Excel\Security
    Имя: WorkbookLinkWarnings
    Тип значения: DWORD
    Значение: 2
Примечание

Влияние устранения рисков:

Отключение этой функции может помешать динамическим обновлениям электронных таблиц Excel, если они отключены в реестре. Данные могут быть не полностью актуальными, так как они больше не обновляются автоматически через динамический канал. Чтобы обновить лист, пользователь должен запустить веб-канал вручную. Кроме того, пользователь не будет получать запросы на напоминание об обновлении листа вручную.
https://learn.microsoft.com/ru... dde-fields
Картинка попытки использования DDE из соцсети microsoft



Добавлено через 1 час 15 минут
Это зачем в сервере?
Цитата Сообщение от Liss29 Посмотреть сообщение
C++
335
336
337
338
            MessageBox(hwnd, 
                TEXT("WM_DDE_ASVISE (pPopAdvise.cfFormat != CF_TEXT)"),
                TEXT("ERROR: DDEPOP1_A.exe"),
                MB_OK | MB_ICONSTOP);
Клиент может попросить данные в формате, который хочет, и необязательно начинать с CF_TEXT.
Диагностические сообщения можно сохранять в файл, лог отладчика(OutputDebugString()), журнал или присоединить windows console и писать туда.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
17.11.2023, 15:30  [ТС]
Обрабатывать ACK в основном цикле сообщений тогда, когда до него дойдёт очередь. Если в назначенный срок ответ на WM_DDE_ADVISE не придёт, то считать, что подписка не удалась.

Пока клиент не ответит на WM_DDE_DATA, не посылать ему новые уведомления, а помечать новые изменённые элементы, как ожидающие посылки WM_DDE_DATA клиенту, когда тот освободится.
Что делать то нужно в цикле обработки сообщений?
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
17.11.2023, 15:56
Для начала совсем убрать вложенные циклы получения и обработки сообщений из WndProc() клиента.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
18.11.2023, 11:44  [ТС]
Цитата Сообщение от politoto Посмотреть сообщение
Для начала совсем убрать вложенные циклы получения и обработки сообщений из WndProc() клиента.
Ну, убрать то их не сложно, остаётся вопрос, как всё это будет работать?! Я полагаю, что в таком случае данный цикл(задержка) должен переместиться в сообщение WM_DDE_ACK, раз задержка всё равно нужна. В основном цикле обработки сообщений, нужно, видимо, установить факт прихода сообщения WM_DDE_ACK и отправить его на обработку в сообщение WM_DDE_ACK(тавтология какая-то). Но в сообщении WM_USER_INITIATE всё равно будут ставиться(отправляться) в очередь сообщений сервера сообщения WM_DDE_ADVISE, значит, нужно запомнить время отправки сообщения, если запоминать его в переменной dwTime, как это делалось до этого, то при следующей итерации цикла и, соответственно, посылки очередного сообщения, предыдущее значение переменной dwTime затрётся, и временной интервал задержки будет вычислен не верно. Что делать?! Создать массив под начальные значения переменных вычисления временного интервала, но это решение так себе, если не сказать больше.
В сообщении WM_DDE_ACK нужно определить вовремя ли пришло сообщение, попадает ли оно во временной интервал, если да, то проверить поле fAck структуры DDEACK, если ложь, то оповестить пользователя о том, что что-то пошло не так, если fAck истинно, то тут..., в WM_USER_INITIATE, если поле fAck истинно, то в этом сообщении вызывается в цикле PeekMessage с целью выявить сообщения DDE из диапазона, следом за подтверждением DDEACK должно прийти сообщение WM_DDE_DATA, так что его и ждёт это цикл, я так думаю, соответственно, если цикл задержки и обработки структуры DDEACK убран, то и этот цикл так же оттуда удалён, нужен ли он здесь вообще?
C++
1
2
3
4
5
while (PeekMessage (&msg, hwnd, WM_DDE_FIRST,
                                        WM_DDE_LAST, PM_REMOVE))
       {
             DispatchMessage (&msg) ;
        }
Надеюсь, что описал понятно, хотя ясного понимания того, что нужно делать, нет.
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
18.11.2023, 21:47
Цитата Сообщение от Liss29 Посмотреть сообщение
убрать то их не сложно, остаётся вопрос, как всё это будет работать?!
На этот вопрос прощего всего ответить, если закомментировать или удалить ненужное, собрать программу, запустить и посмотреть, как она будет работать.

Добавлено через 2 часа 34 минуты
Цитата Сообщение от Liss29 Посмотреть сообщение
если цикл задержки и обработки структуры DDEACK убран, то и этот цикл так же оттуда удалён, нужен ли он здесь вообще?
Не нужен, конечно. В цикле, который выполняется в WndProc(), вызывается DispatchMessage(), который, в свою очередь, вызывает WndProc() для обработки сообщений единственного окна приложения-клиента. В рекурсивном вызове WndProc() нет ничего необычного, но здесь в этом нет необходимости.
Он был нужен, потому что сервер мог ждать обработки сообщений, поставленных в очередь клиента, до завершения обработчика WM_USER_INITIATE, который в примере вызывается до начала основного цикла сообщений:
Цитата Сообщение от Liss29 Посмотреть сообщение
C++
50
51
52
53
54
55
SendMessage(hwnd, WM_USER_INITIATE, 0, 0L);
while (GetMessage(&msg, NULL, 0, 0))
 {
 TranslateMessage(&msg);
 DispatchMessage(&msg);
 }
Цитата Сообщение от Liss29 Посмотреть сообщение
цикл(задержка) должен переместиться в сообщение WM_DDE_ACK, раз задержка всё равно нужна.
Задержки и программные блокировки до прихода сообщения не нужны, а могут быть и вредны, как мы уже убедились, потому что иногда могут приводить к взамной блокировке, о которой говорилось в Главе 14 второго тома книги Чарлза (Режимы многозадачности: Коллизии, возникающие при использовании потоков).
1
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
18.11.2023, 22:05
Цитата Сообщение от Liss29 Посмотреть сообщение
будут ставиться(отправляться) в очередь сообщений сервера сообщения WM_DDE_ADVISE, значит, нужно запомнить время отправки сообщения, если запоминать его в переменной dwTime, как это делалось до этого, то при следующей итерации цикла и, соответственно, посылки очередного сообщения, предыдущее значение переменной dwTime затрётся,
Между постановкой в очередь сервера первого и последнего запроса в нашем случае проходит не больше нескольких миллисекунд, поэтому практически достаточно запомнить время последнего запроса.
Поставить себе напоминалку на DDE_TIMEOUT и уйти пить кофе: обрабатывать в основном цикле текущие сообщения, и регистрировать приходящие в очередь WM_DDE_ACK от сервера, управляя ресурсами так, как это описано в документации DDE. По истечении DDE_TIMEOUT проверить, если ли запросы, на которые ещё не поступили подтверждения от сервера.
Если пользователь сможет в любой момент добавлять и управлять DDE-ссылками на внешние данные, то, конечно, отслеживать состояние ссылок и в целом "бесед"(conversation) с серверами нужно будет отдельно для каждой ссылки.
Миниатюры
Петзольд. Тема DDE-(Dynamic Data Exchange)  
1
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
19.11.2023, 11:05  [ТС]
Цитата Сообщение от politoto Посмотреть сообщение
Поставить себе напоминалку на DDE_TIMEOUT и уйти пить кофе: обрабатывать в основном цикле текущие сообщения, и регистрировать приходящие в очередь WM_DDE_ACK от сервера, управляя ресурсами так, как это описано в документации DDE. По истечении DDE_TIMEOUT проверить, если ли запросы, на которые ещё не поступили подтверждения от сервера.
Как такой вариант решения, близок к тому, что вы имеете ввиду?
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
DWORD dwCountOfMessagesDdeAck = 0;
 
 
while(GetMessage(&msg, NULL, 0, 0))
{
    if(msg.message == WM_DDE_ACK)
    {
        if((msg.time - dwTime) > DDE_TIMEOUT)
        {
            if(dwCountOfMessagesDdeAck != DDE_STATES)
            {
                //ERROR MESSAGE
            }
        }   
        else 
            ++dwCountOfMessagesDdeAck;
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_USET_INITIATE:
        {
            //hDdeAdvise = GlobalAlloc(GHND, sizeof(DDEADVISE));
            //pDdeAdvise = GlobalLock(hDdeAdvise);
            //.........
            if(!PostMessage(hwndServer, WM_DDE_ASVISE, (WPARAM)hwnd,
                            PackDDElParam(WM_DDE_ADVISE, 
                                          hDdeAdvise, aAtom)))
            {
                GlobalFree(hDdeAdvise);
                GlobalDeleteAtom(aAtom);
                return 0;
            }
            
            dwTimeBeg = GetCurrentTime();
            
            //.........
            //GlobalUnlock(hDdeAdvise);
            //GlobalFree(hDdeAdvise);
        }
        case WM_DDE_ACK:
        {
            if(fDoingInitiate)
            {
                 uiLow = LOWORD(lParam); 
                 uiHi = HIWORD(lParam);
                 hwndServer = (HWND)wParam;
                 GlobalDeleteAtom((ATOM)uiLow);
                 GlobalDeleteAtom((ATOM)uiHi);
            }
            else
            {
                UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi);
                FreeDDElParam(WM_DDE_ACK, lParam);
                
                GlobalDeleteAtom((ATOM)uiHi);
                //WORD wStatus = *(DDEACK*)&uiLow;
            }
            return 0;
        }
    }
}
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
19.11.2023, 21:41
Цитата Сообщение от Liss29 Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
12
if(msg.message == WM_DDE_ACK)
 {
 if((msg.time - dwTime) > DDE_TIMEOUT)
 {
 if(dwCountOfMessagesDdeAck != DDE_STATES)
 {
 //ERROR MESSAGE
 }
 } 
 else 
 ++dwCountOfMessagesDdeAck;
 }
До //ERROR MESSAGE дело не дойдёт, если после dwTime + DDE_TIMEOUT так и не придёт ни одного WM_DDE_ACK.
Регистрация сообщений должна работать. Если хотите обрабатывать сообщения вне WndProc(), нужно проверять, кому (и от кого) сообщение. Для WM_DDE_ACK нужно анализировать статус, так как сообщение может быть и отказом.

Регистрацию подтверждений подписки можно также перенести в обработчик WM_DDE_ACK в WndProc()
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
        case WM_DDE_ACK:
        {
            if(fDoingInitiate)
            { if ( InSendMessage() ) // WM_DDE_INITIATE должен подтверждаться с помощью SendMessage()
/*
обработка подтверждения WM_DDE_INITIATE
*/
             }
            else if ( ! InSendMessage() ) // все остальные подтверждения должны выполняться с помощью PostMessage()
            {
/*
             убеждаемся, что wParam это HWND сервера, с которым мы общаемся
             если сообщение неизвестно от кого, можно и не пытаться анализировать и освобождать lParam
             лучше примириться с утечкой, но избежать аварийного завершения программы
*/
                UINT_PTR uiHi, uiLow;
                UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi);
                FreeDDElParam(WM_DDE_ACK, lParam);
 
/*                
             проверяем, что uiHi - атом элемента, которым мы интересовались
             проверям, что uiHi - подтверждение, а не отказ, и, если это так,
             отмечаем в pop[i], соответсвующем атому, что подписка успешно подтверждена
*/
                GlobalDeleteAtom((ATOM)uiHi);
                  
            }
            return 0;
        }
0
Отпрыск ChatGPT
 Аватар для Azawa
266 / 31 / 4
Регистрация: 18.06.2019
Сообщений: 155
20.11.2023, 00:04
DDE в 2023 (эмодзи черепа)

Добавлено через 2 минуты
Вон в ссылке повыше в теме Реймонд Чен сказал, дде всё с 1997.

Добавлено через 1 минуту
Вы некромант?
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
20.11.2023, 00:31  [ТС]
Цитата Сообщение от politoto Посмотреть сообщение
InSendMessage()
Это что за функция?
C++
1
2
3
4
5
BOOL InSendMessage()
{
    DWORD st = GetQueueStatus(QS_SENDMESSAGE);
    return (HIWORD(st) == QS_SENDMESSAGE);
}
Цитата Сообщение от politoto Посмотреть сообщение
dwTime + DDE_TIMEOUT
Если не прав, не верно вычисляю, так и скажите, а то нужно задумываться ещё и над этим.

Цитата Сообщение от politoto Посмотреть сообщение
лучше примириться с утечкой
Что серьёзно?! Примириться с утечкой...

Цитата Сообщение от politoto Посмотреть сообщение
что uiHi - подтверждение, а не отказ
Думаю, вы имели ввиду uiLow, а не uiHi.

Цитата Сообщение от politoto Посмотреть сообщение
Регистрация сообщений должна работать
Что подразумевается под регистрацией сообщений?
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
20.11.2023, 08:47
Цитата Сообщение от Liss29 Посмотреть сообщение
вы имели ввиду uiLow, а не uiHi.
Конечно, Вы правы. Окопипастался.
Цитата Сообщение от Liss29 Посмотреть сообщение
Что подразумевается под регистрацией сообщений?
Этот подсчёт
C++
16
            ++dwCountOfMessagesDdeAck;
Цитата Сообщение от Liss29 Посмотреть сообщение
Если не прав, не верно вычисляю, так и скажите
Дело не в расчёте.
Если, например, из GetMessage() вообще не придёт ни одного WM_DDE_ACK, то это никогда не выполнится:
C++
8
9
10
11
12
13
14
       if((msg.time - dwTime) > DDE_TIMEOUT)
        {
            if(dwCountOfMessagesDdeAck != DDE_STATES)
            {
                //ERROR MESSAGE
            }
        }
Добавлено через 12 минут
Цитата Сообщение от Liss29 Посмотреть сообщение
вы имели ввиду uiLow, а не uiHi.
Конечно, Вы правы. Окопипастался.
Цитата Сообщение от Liss29 Посмотреть сообщение
Что подразумевается под регистрацией сообщений?
Этот подсчёт
C++
16
            ++dwCountOfMessagesDdeAck;
Цитата Сообщение от Liss29 Посмотреть сообщение
Если не прав, не верно вычисляю, так и скажите
Дело не в расчёте.
Если, например, из GetMessage() вообще не придёт ни одного WM_DDE_ACK, то это никогда не выполнится:
C++
8
9
10
11
12
13
14
       if((msg.time - dwTime) > DDE_TIMEOUT)
        {
            if(dwCountOfMessagesDdeAck != DDE_STATES)
            {
                //ERROR MESSAGE
            }
        }
Цитата Сообщение от Liss29 Посмотреть сообщение
InSendMessage()
Это что за функция?
TRUE==InSendMessage() внутри WndProc() означает, что обрабатывается сообщение "вне очереди" из других потоков( и процессов), отправленное с помощью SendMessage()
https://learn.microsoft.com/ru... endmessage
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
20.11.2023, 13:40  [ТС]
Цитата Сообщение от politoto Посмотреть сообщение
Этот подсчёт
Так пафосно написали, я себе голову сломал, что под термином регистрация понимается в данном случае.

Цитата Сообщение от politoto Посмотреть сообщение
Если, например, из GetMessage() вообще не придёт ни одного WM_DDE_ACK, то это никогда не выполнится:
Т.е. из данного блока кода нужно вынести подсчет времени, если так то:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
while(GetMessage(&msg, NULL, 0, 0))
{
    if(msg.message == WM_DDE_ACK)
    {
        ++dwCountOfMessagesDdeAck;
    }
    else if((msg.time - dwTime) > DDE_TIMEOUT)
    {
        if(dwCountOfMessagesDdeAck != DDE_STATES)
            //ERROR MESSAGE
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
Всё остальное обрабатывается в сообщении WM_DDE_ACK
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
case WM_DDE_ACK:
        {
            if(fDoingInitiate)
            {
                if(InSendMessage())
                {
                 uiLow = LOWORD(lParam); 
                 uiHi = HIWORD(lParam);
                 hwndServer = (HWND)wParam;
                 GlobalDeleteAtom((ATOM)uiLow);
                 GlobalDeleteAtom((ATOM)uiHi);
                }
            }
            else if(!InSendMessage())
            {
                if((HWND)wParam == hwndServer)
                {
                UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi);
                FreeDDElParam(WM_DDE_ACK, lParam);
                
                GlobalGetAtomName((ATOM)uiHi, szItem, 20);
                int i;
                for(i = 0; i < DDE_STATES; ++i)
                    if(strcmp(szItem, pop[i].szState) == 0)
                        break;
                if(i < DDE_STATES)
                {
                    DdeAck = *(DDEACK*)&uiLow;
                    
                    if(DdeAck.fAck == TRUE)
                        pop[i].fConfirmed = TRUE; 
                        
                }
                GlobalDeleteAtom((ATOM)uiHi);
                //WORD wStatus = *(DDEACK*)&uiLow;
                }
            }
            return 0;
        }
В любом случае я не понимаю, зачем здесь проверка на то что Отправили сообщение или поставили его в очередь с помощью PostMessage()..
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
20.11.2023, 14:02
Цитата Сообщение от Liss29 Посмотреть сообщение
Т.е. из данного блока кода нужно вынести подсчет времени
А подсчёт интересующих нас ( а не какик попало ) WM_DDE_ACK логично было бы перенести в WndProc(), где уже проверены все условия

Фрагмент обработчика WM_DDE_ACK в WndProc():
C++
28
29
30
31
32
33
34
35
36
37
38
 if(i < DDE_STATES)
      {
          DdeAck = *(DDEACK*)&uiLow;
                    
           if(TRUE != DdeAck.fAck )
              {
                    if(DdeAck.fAck == TRUE) {
                        pop[i].fConfirmed = TRUE; ++dwCountOfMessagesDdeAck;
                      }
              }
       }
но тогда у обработчика должен быть доступ к счётчику dwCountOfMessagesDdeAck
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
20.11.2023, 15:39  [ТС]
Что за условие такое мудрёное оно не противоречит само себе.
C++
1
2
3
4
5
6
7
8
if(TRUE != DdeAck.fAck ) //если поле fAck ложь, зачем это, не проще просто написать if(DdeAck.fAck == TRUE)
{
      if(DdeAck.fAck == TRUE) 
      {
            pop[i].fConfirmed = TRUE; 
            ++dwCountOfMessagesDdeAck;
      }
}
Цитата Сообщение от politoto Посмотреть сообщение
А подсчёт интересующих нас ( а не какик попало ) WM_DDE_ACK логично было бы перенести в WndProc(), где уже проверены все условия
Тогда в цикле обработки сообщений вообще практически ничего не остаётся, действий связанных с обработкой именно сообщений WM_DDE_ACK. Я полагал, что именно этому циклу, циклу обработки сообщений, в данном случае отведена главная роль.

Цитата Сообщение от politoto Посмотреть сообщение
но тогда у обработчика должен быть доступ к счётчику dwCountOfMessagesDdeAck
Объявить его глобально, есть ещё какие-то варианты?

А что с другими сообщениями в которых так же требуется задержка, например, WM_CLOSE? Хотя не совсем понятно зачем там нужна задержка, если время задержки истечёт или сообщение придёт, не важно, результат тот же.
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
20.11.2023, 15:50
Цитата Сообщение от Liss29 Посмотреть сообщение
Что за условие такое мудрёное
Глупое условие.
Должно быть
C++
28
29
30
31
32
33
34
35
36
37
38
if(i < DDE_STATES)
      {
          DdeAck = *(DDEACK*)&uiLow;
                    
           if(TRUE != pop[i].fConfirmed )
              {
                    if(DdeAck.fAck == TRUE) {
                        pop[i].fConfirmed = TRUE; ++dwCountOfMessagesDdeAck;
                      }
              }
       }
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
20.11.2023, 16:08  [ТС]
В приложении сервере тоже самое нужно проделать WM_DDE_ACK через основной цикл сообщений получать?
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
20.11.2023, 19:07
Да, надо как-то избежать блокирования, если клиент попросил в pDdeAdvise->fAckReq отправлять данные с подтверждением. В сервере уже есть таймер, можно сделать его почаще и проверять, не истёк ли срок ожидания WWW_DDE_ACK от клиента в ответ на WM_DDE_DATA.
И убрать MessageBox'ы из ServerProc()
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
21.11.2023, 09:53  [ТС]
Цитата Сообщение от politoto Посмотреть сообщение
В сервере уже есть таймер, можно сделать его почаще
Таймер то тут при чём?

Цитата Сообщение от politoto Посмотреть сообщение
не истёк ли срок ожидания WWW_DDE_ACK от клиента в ответ на WM_DDE_DATA.
Интересно, а как узнать, что сообщение WWW_DDE_ACK, именно ответ, на сообщение WM_DDE_DATA?
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
21.11.2023, 11:12
Цитата Сообщение от Liss29 Посмотреть сообщение
Таймер то тут при чём?
Таймер может помочь, когда долго нет других сообщений.
Цитата Сообщение от Liss29 Посмотреть сообщение
как узнать, что сообщение WM_DDE_ACK, именно ответ, на сообщение WM_DDE_DATA?
В wParam именно тот клиент, с которым сервер беседует, сообщение поставлено в очередь с помощью PostMessage(). А на какое ещё сообщение клиент может ответить серверу PostMessage() WM_DDE_ACK?

https://learn.microsoft.com/ru... wm-dde-ack

Если атом именно тот, для которого мы ждали подтверждения приёма данных, и ACK не отрицательный, то выполняем GlobalFree(), если это необходимо, и считаем, что клиент готов принимать новые данные.

https://learn.microsoft.com/ru... m-dde-data
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,633
21.11.2023, 12:24  [ТС]
Цитата Сообщение от politoto Посмотреть сообщение
Таймер может помочь, когда долго нет других сообщений.
Чем? Тем что будет постоянно пересчитывать значения населения, и, если количество населения изменится, будет отправлять WM_DDE_DATA клиенту, но делать он это будет гораздо чаще, чем на данный момент.

Цитата Сообщение от politoto Посмотреть сообщение
В wParam именно тот клиент, с которым сервер беседует, сообщение поставлено в очередь с помощью PostMessage()
Я в кусе, но вопрос был несколько иной.

Цитата Сообщение от politoto Посмотреть сообщение
А на какое ещё сообщение клиент может ответить серверу PostMessage() WM_DDE_ACK?
Кто его знает) По умолчанию считать, что сообщение WM_DDE_ACK пришло в ответ на WM_DDE_DATA, пусть будет так.

В данном случае я не знаю, как это реализовать, это, видимо, нужно переписать всю функцию ServerProc, думаю, вызовы функции PostDataMessage нужно убрать из сообщения WM_DDE_ADVISE, иначе, как организовать задержку отправки сообщения WM_DDE_DATA. Затем в сообщении WM_DDE_ACK, если проверка атома и флага fAck структуры DDEACK даст положительный результат, вызвать PostDataMessage, но тогда на что клиент должен отвечать, если данные ему не были отправлены из сообщения WM_DDE_ADVISE.... ну и так далее.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
21.11.2023, 12:24

Нужны примеры по Dynamic Data Display
Есть у кого-нибудь какие-нибудь примеры? Хотя бы какую-нибудь линию/фигуру вывести бы:)

Как нарисовать график в Dynamic Data Display
Помогите создать график sin в Dynamic Data Display на имено WPF приложении офф сайте имеются примеры, но нет исходного кода. В Silverlight...

не поддерживается тип контекста в Dynamic Data на VS2012
Добрый день! Кто нибудь пользовался Dynamic Data на VS2012? На 2010 работает без проблем, а в 2012 выдает ошибку &quot;Тип контекста...

Нужен дистрибутив Active Reports Data Dynamic
Нужен дистрибутив Active Reports Data Dynamic если можно, отправьте alm1@rbcmail.ru = спасибо

[WPF] Dynamic Data Display и Множество коллекций
Есть контролл D3 для отображения графиков. Есть ObservableDataSource&lt;Point&gt; tmp; tmp привязан к графику. т.е. при добавлении новых точек...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
80
Ответ Создать тему
Новые блоги и статьи
сукцессия 25. Хронология ошибок
anaschu 12.07.2026
# От 50-тонного гриба до устойчивого леса: хроника ошибок при построении модели вековой сукцессии микоризы ## О чём эта статья В процессе построения ОДУ-модели (система дифференциальных. . .
сукцессия 24. Промежуточное общее описание модели
anaschu 12.07.2026
Хендофф: модель АМ→ЭКМ сукцессии микоризы (ризосфера, 50 лет) Содержание проекта Симуляция вековой (50 лет) экологической сукцессии в почве леса Основные участники: АМ-гриб, ЭКМ-гриб,. . .
сукцессия 23. Более физиологичная физиология, более экологичная экология, более диффурные диффуры.
anaschu 12.07.2026
Что реально нашли и починили за эти 5 часов Правило Линдемана (КПД конверсии сахара в тело, kEff) — раньше 100% полученного углерода шло прямо в биомассу гриба; теперь только kEff=0. 5 (после. . .
сукцессия 22. От артефактов к физиологии: калибровка агентной модели грибной сукцессии для воспроизведения сезонной динамики и pH-плато
anaschu 11.07.2026
Аннотация В данной работе представлена калибровка агентной модели динамики грибных сообществ (fungal-succession), направленная на устранение нефизичных артефактов (коллапс биомассы, мгновенное. . .
Сукцессия 20. Война автоботов. Делаем ставки. Лёд против "пш-пш!".
anaschu 11.07.2026
Битва ИИ в ризосфере: Как мы скрестили жесткие ОДУ, закон Фика и «подземный шантаж» Уважаемые коллеги! Хочу поделиться уникальным опытом ведения междисциплинарной компьютерной разработки. Прямо. . .
Сукцессия 19. Какие выводы я сделал из модели? Часть 2.Внутримикоризный стехиометрический буфер и хроно-дискретные зоны экспансии
anaschu 11.07.2026
Био-Инженерный Ликбез: Архитектура Модели Ризосферы Математический аппарат моделирования
Сукцессия 18. Какие выводы я сделал из войны грибов с деревьями? Часть 1- рассказ и немного про термины
anaschu 11.07.2026
Био-Инженерный Ликбез: Архитектура Модели Ризосферы Математический аппарат моделирования Система ОДУ описывает динамику изменения массы различных компонентов системы во времени. Ключевой. . .
Просветление в 5 секунд
kumehtar 10.07.2026
Андрей Веретенников выдал фразу недавно: "Вам не обязательно кем-то себя считать"
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru