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