xref: /aoo41x/main/svl/source/svdde/ddecli.cxx (revision cdf0e10c)
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