xref: /trunk/main/svl/source/svdde/ddecli.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 
31 #define UNICODE
32 #include <string.h> // memset
33 #include "ddeimp.hxx"
34 #include <svl/svdde.hxx>
35 
36 #include <osl/thread.h>
37 #include <tools/debug.hxx>
38 #include <tools/solarmutex.hxx>
39 #include <vos/mutex.hxx>
40 
41 // static DWORD        hDdeInst  = NULL;
42 // static short        nInstance = 0;
43 
44 // DdeConnections*     DdeConnection::pConnections = NULL;
45 
46 DdeInstData* ImpInitInstData()
47 {
48     DdeInstData* pData = new DdeInstData;
49     memset( pData,0,sizeof(DdeInstData) );
50     DdeInstData** ppInst = (DdeInstData**)GetAppData( SHL_SVDDE );
51     *ppInst = pData;
52     return pData;
53 }
54 
55 void ImpDeinitInstData()
56 {
57     DdeInstData** ppInst = (DdeInstData**)GetAppData( SHL_SVDDE );
58     delete (*ppInst);
59     *ppInst = 0;
60 }
61 
62 
63 struct DdeImp
64 {
65     HCONV   hConv;
66     long    nStatus;
67 };
68 
69 // --- DdeInternat::CliCallback() ----------------------------------
70 
71 HDDEDATA CALLBACK DdeInternal::CliCallback(
72             WORD nCode, WORD nCbType, HCONV hConv, HSZ, HSZ hText2,
73             HDDEDATA hData, DWORD nInfo1, DWORD )
74 {
75     HDDEDATA nRet = DDE_FNOTPROCESSED;
76     DdeConnections&     rAll = (DdeConnections&)DdeConnection::GetConnections();
77     DdeConnection*      self = 0;
78 
79     DdeInstData* pInst = ImpGetInstData();
80     DBG_ASSERT(pInst,"SVDDE:No instance data");
81 
82     for ( self = rAll.First(); self; self = rAll.Next() )
83         if ( self->pImp->hConv == hConv )
84             break;
85 
86     if( self )
87     {
88         DdeTransaction* t;
89         sal_Bool bFound = sal_False;
90         for( t = self->aTransactions.First(); t; t = self->aTransactions.Next() )
91         {
92             switch( nCode )
93             {
94                 case XTYP_XACT_COMPLETE:
95                     if( (DWORD)t->nId == nInfo1 )
96                     {
97                         nCode = t->nType & (XCLASS_MASK | XTYP_MASK);
98                         t->bBusy = sal_False;
99                         t->Done( 0 != hData );
100                         bFound = sal_True;
101                     }
102                     break;
103 
104                 case XTYP_DISCONNECT:
105                     self->pImp->hConv = DdeReconnect( hConv );
106                     self->pImp->nStatus = self->pImp->hConv
107                                     ? DMLERR_NO_ERROR
108                                     : DdeGetLastError( pInst->hDdeInstCli );
109                     t = 0;
110                     nRet = 0;
111                     bFound = sal_True;
112                     break;
113 
114                 case XTYP_ADVDATA:
115                     bFound = sal_Bool( *t->pName == hText2 );
116                     break;
117             }
118             if( bFound )
119                 break;
120         }
121 
122         if( t )
123         {
124             switch( nCode )
125             {
126             case XTYP_ADVDATA:
127                 if( !hData )
128                 {
129                     ((DdeLink*) t)->Notify();
130                     nRet = (HDDEDATA)DDE_FACK;
131                     break;
132                 }
133                 // kein break;
134 
135             case XTYP_REQUEST:
136                 if( !hData && XTYP_REQUEST == nCode )
137                 {
138 
139                 }
140 
141                 DdeData d;
142                 d.pImp->hData = hData;
143                 d.pImp->nFmt  = DdeData::GetInternalFormat( nCbType );
144                 d.Lock();
145                 t->Data( &d );
146                 nRet = (HDDEDATA)DDE_FACK;
147                 break;
148             }
149         }
150     }
151     return nRet;
152 }
153 
154 // --- DdeConnection::DdeConnection() ------------------------------
155 
156 DdeConnection::DdeConnection( const String& rService, const String& rTopic )
157 {
158     pImp = new DdeImp;
159     pImp->nStatus  = DMLERR_NO_ERROR;
160     pImp->hConv    = NULL;
161 
162     DdeInstData* pInst = ImpGetInstData();
163     if( !pInst )
164         pInst = ImpInitInstData();
165     pInst->nRefCount++;
166     pInst->nInstanceCli++;
167     if ( !pInst->hDdeInstCli )
168     {
169         pImp->nStatus = DdeInitialize( &pInst->hDdeInstCli,
170                                        (PFNCALLBACK)DdeInternal::CliCallback,
171                                        APPCLASS_STANDARD | APPCMD_CLIENTONLY |
172                                        CBF_FAIL_ALLSVRXACTIONS |
173                                        CBF_SKIP_REGISTRATIONS  |
174                                        CBF_SKIP_UNREGISTRATIONS, 0L );
175         pInst->pConnections = new DdeConnections;
176     }
177 
178     pService = new DdeString( pInst->hDdeInstCli, rService );
179     pTopic   = new DdeString( pInst->hDdeInstCli, rTopic );
180 
181     if ( pImp->nStatus == DMLERR_NO_ERROR )
182     {
183         pImp->hConv = DdeConnect( pInst->hDdeInstCli,*pService,*pTopic, NULL);
184         if( !pImp->hConv )
185             pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
186     }
187 
188     if ( pInst->pConnections )
189         pInst->pConnections->Insert( this );
190 }
191 
192 // --- DdeConnection::~DdeConnection() -----------------------------
193 
194 DdeConnection::~DdeConnection()
195 {
196     if ( pImp->hConv )
197         DdeDisconnect( pImp->hConv );
198 
199     delete pService;
200     delete pTopic;
201 
202     DdeInstData* pInst = ImpGetInstData();
203     DBG_ASSERT(pInst,"SVDDE:No instance data");
204     if ( pInst->pConnections )
205         pInst->pConnections->Remove( this );
206 
207     pInst->nInstanceCli--;
208     pInst->nRefCount--;
209     if ( !pInst->nInstanceCli && pInst->hDdeInstCli )
210     {
211         if( DdeUninitialize( pInst->hDdeInstCli ) )
212         {
213             pInst->hDdeInstCli = NULL;
214             delete pInst->pConnections;
215             pInst->pConnections = NULL;
216             if( pInst->nRefCount == 0 )
217                 ImpDeinitInstData();
218         }
219     }
220     delete pImp;
221 }
222 
223 // --- DdeConnection::IsConnected() --------------------------------
224 
225 sal_Bool DdeConnection::IsConnected()
226 {
227     CONVINFO c;
228 #ifdef OS2
229     c.nSize = sizeof( c );
230 #else
231     c.cb = sizeof( c );
232 #endif
233     if ( DdeQueryConvInfo( pImp->hConv, QID_SYNC, &c ) )
234         return sal_True;
235     else
236     {
237         DdeInstData* pInst = ImpGetInstData();
238         pImp->hConv = DdeReconnect( pImp->hConv );
239         pImp->nStatus = pImp->hConv ? DMLERR_NO_ERROR : DdeGetLastError( pInst->hDdeInstCli );
240         return sal_Bool( pImp->nStatus == DMLERR_NO_ERROR );
241     }
242 }
243 
244 // --- DdeConnection::GetServiceName() -----------------------------
245 
246 const String& DdeConnection::GetServiceName()
247 {
248     return (const String&)*pService;
249 }
250 
251 // --- DdeConnection::GetTopicName() -------------------------------
252 
253 const String& DdeConnection::GetTopicName()
254 {
255     return (const String&)*pTopic;
256 }
257 
258 // --- DdeConnection::GetConvId() ----------------------------------
259 
260 long DdeConnection::GetConvId()
261 {
262     return (long)pImp->hConv;
263 }
264 
265 const DdeConnections& DdeConnection::GetConnections()
266 {
267     DdeInstData* pInst = ImpGetInstData();
268     DBG_ASSERT(pInst,"SVDDE:No instance data");
269     return *(pInst->pConnections);
270 }
271 
272 // --- DdeTransaction::DdeTransaction() ----------------------------
273 
274 DdeTransaction::DdeTransaction( DdeConnection& d, const String& rItemName,
275                                 long n ) :
276                     rDde( d )
277 {
278     DdeInstData* pInst = ImpGetInstData();
279     pName = new DdeString( pInst->hDdeInstCli, rItemName );
280     nTime = n;
281     nId   = 0;
282     nType = 0;
283     bBusy = sal_False;
284 
285     rDde.aTransactions.Insert( this );
286 }
287 
288 // --- DdeTransaction::~DdeTransaction() ---------------------------
289 
290 DdeTransaction::~DdeTransaction()
291 {
292     if ( nId && rDde.pImp->hConv )
293     {
294         DdeInstData* pInst = ImpGetInstData();
295         DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId );
296     }
297 
298     delete pName;
299     rDde.aTransactions.Remove( this );
300 }
301 
302 // --- DdeTransaction::Execute() -----------------------------------
303 
304 void DdeTransaction::Execute()
305 {
306     HSZ     hItem = *pName;
307     void*   pData = (void*)(const void *)aDdeData;
308     DWORD   nData = (DWORD)(long)aDdeData;
309     sal_uLong   nIntFmt = aDdeData.pImp->nFmt;
310     UINT    nExtFmt  = DdeData::GetExternalFormat( nIntFmt );
311     DdeInstData* pInst = ImpGetInstData();
312 
313     if ( nType == XTYP_EXECUTE )
314         hItem = NULL;
315     if ( nType != XTYP_EXECUTE && nType != XTYP_POKE )
316     {
317         pData = NULL;
318         nData = 0L;
319     }
320     if ( nTime )
321     {
322         HDDEDATA hData = DdeClientTransaction( (unsigned char*)pData,
323                                                nData, rDde.pImp->hConv,
324                                                hItem, nExtFmt, (UINT)nType,
325                                                (DWORD)nTime, (DWORD FAR*)NULL );
326 
327         rDde.pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
328         if( hData && nType == XTYP_REQUEST )
329         {
330             {
331                 DdeData d;
332                 d.pImp->hData = hData;
333                 d.pImp->nFmt = nIntFmt;
334                 d.Lock();
335                 Data( &d );
336             }
337             DdeFreeDataHandle( hData );
338         }
339     }
340     else
341     {
342         if ( nId && rDde.pImp->hConv )
343             DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId);
344         nId = 0;
345         bBusy = sal_True;
346         HDDEDATA hRet = DdeClientTransaction( (unsigned char*)pData, nData,
347                                             rDde.pImp->hConv, hItem, nExtFmt,
348                                             (UINT)nType, TIMEOUT_ASYNC,
349                                             (DWORD FAR *) ((long*) &nId) );
350         rDde.pImp->nStatus = hRet ? DMLERR_NO_ERROR
351                                   : DdeGetLastError( pInst->hDdeInstCli );
352     }
353 }
354 
355 // --- DdeTransaction::GetName() -----------------------------------
356 
357 const String& DdeTransaction::GetName() const
358 {
359     return *pName;
360 }
361 
362 // --- DdeTransaction::Data() --------------------------------------
363 
364 
365 void __EXPORT DdeTransaction::Data( const DdeData* p )
366 {
367     if ( ::tools::SolarMutex::Acquire() )
368     {
369         aData.Call( (void*)p );
370         ::tools::SolarMutex::Release();
371     }
372 }
373 
374 // --- DdeTransaction::Done() --------------------------------------
375 
376 void __EXPORT DdeTransaction::Done( sal_Bool bDataValid )
377 {
378     aDone.Call( (void*)bDataValid );
379 }
380 
381 // --- DdeLink::DdeLink() ------------------------------------------
382 
383 DdeLink::DdeLink( DdeConnection& d, const String& aItemName, long n ) :
384             DdeTransaction (d, aItemName, n)
385 {
386 }
387 
388 // --- DdeLink::~DdeLink() -----------------------------------------
389 
390 DdeLink::~DdeLink()
391 {
392     nType = (sal_uInt16)XTYP_ADVSTOP;
393     nTime = 0;
394 }
395 
396 // --- DdeLink::Notify() -----------------------------------------
397 
398 void __EXPORT DdeLink::Notify()
399 {
400     aNotify.Call( NULL );
401 }
402 
403 // --- DdeRequest::DdeRequest() ------------------------------------
404 
405 DdeRequest::DdeRequest( DdeConnection& d, const String& i, long n ) :
406                 DdeTransaction( d, i, n )
407 {
408     nType = XTYP_REQUEST;
409 }
410 
411 // --- DdeWarmLink::DdeWarmLink() ----------------------------------
412 
413 DdeWarmLink::DdeWarmLink( DdeConnection& d, const String& i, long n ) :
414                 DdeLink( d, i, n )
415 {
416     nType = XTYP_ADVSTART | XTYPF_NODATA;
417 }
418 
419 // --- DdeHotLink::DdeHotLink() ------------------------------------
420 
421 DdeHotLink::DdeHotLink( DdeConnection& d, const String& i, long n ) :
422                 DdeLink( d, i, n )
423 {
424     nType = XTYP_ADVSTART;
425 }
426 
427 // --- DdePoke::DdePoke() ------------------------------------------
428 
429 DdePoke::DdePoke( DdeConnection& d, const String& i, const char* p,
430                   long l, sal_uLong f, long n ) :
431             DdeTransaction( d, i, n )
432 {
433     aDdeData = DdeData( p, l, f );
434     nType = XTYP_POKE;
435 }
436 
437 // --- DdePoke::DdePoke() ------------------------------------------
438 
439 DdePoke::DdePoke( DdeConnection& d, const String& i, const String& rData,
440                   long n ) :
441             DdeTransaction( d, i, n )
442 {
443 //  ByteString aByteStr( rData, osl_getThreadTextEncoding() );
444     aDdeData = DdeData( (void*) rData.GetBuffer(), sizeof(sal_Unicode) * (rData.Len()), CF_TEXT );
445     nType = XTYP_POKE;
446 }
447 
448 // --- DdePoke::DdePoke() ------------------------------------------
449 
450 DdePoke::DdePoke( DdeConnection& d, const String& i, const DdeData& rData,
451                   long n ) :
452             DdeTransaction( d, i, n )
453 {
454     aDdeData = rData;
455     nType = XTYP_POKE;
456 }
457 
458 // --- DdeExecute::DdeExecute() ------------------------------------
459 
460 DdeExecute::DdeExecute( DdeConnection& d, const String& rData, long n ) :
461                 DdeTransaction( d, String(), n )
462 {
463 //  ByteString aByteStr( rData, osl_getThreadTextEncoding() );
464     aDdeData = DdeData( (void*)rData.GetBuffer(), sizeof(sal_Unicode) * (rData.Len() + 1), CF_TEXT );
465     nType = XTYP_EXECUTE;
466 }
467 
468 // --- DdeConnection::GetError() -----------------------------------
469 
470 long DdeConnection::GetError()
471 {
472     return pImp->nStatus;
473 }
474