xref: /aoo42x/main/svl/source/svdde/ddesvr.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 "ddeimp.hxx"
33 #include <svl/svdde.hxx>
34 #include <svl/svarray.hxx>
35 #include <tools/debug.hxx>
36 #include <osl/thread.h>
37 
38 //static long         hCurConv  = 0;
39 //static DWORD        hDdeInst  = NULL;
40 //static short        nInstance = 0;
41 //static DdeServices* pServices;
42 
43 enum DdeItemType
44 {
45 	DDEITEM,
46 	DDEGETPUTITEM
47 };
48 
49 struct DdeItemImpData
50 {
51 	sal_uLong nHCnv;
52 	sal_uInt16 nCnt;
53 
54 	DdeItemImpData( sal_uLong nH ) : nHCnv( nH ), nCnt( 1 ) {}
55 };
56 
57 SV_DECL_VARARR( DdeItemImp, DdeItemImpData, 1, 1 )
58 SV_IMPL_VARARR( DdeItemImp, DdeItemImpData )
59 
60 // --- DdeInternat::SvrCallback() ----------------------------------
61 
62 #ifdef WNT
63 HDDEDATA CALLBACK DdeInternal::SvrCallback(
64 			WORD nCode, WORD nCbType, HCONV hConv, HSZ hText1, HSZ hText2,
65 			HDDEDATA hData, DWORD, DWORD )
66 #else
67 #if defined ( MTW ) || ( defined ( GCC ) && defined ( OS2 )) || defined( ICC )
68 HDDEDATA CALLBACK __EXPORT DdeInternal::SvrCallback(
69 			WORD nCode, WORD nCbType, HCONV hConv, HSZ hText1, HSZ hText2,
70 			HDDEDATA hData, DWORD, DWORD )
71 #else
72 HDDEDATA CALLBACK _export DdeInternal::SvrCallback(
73 			WORD nCode, WORD nCbType, HCONV hConv, HSZ hText1, HSZ hText2,
74 			HDDEDATA hData, DWORD, DWORD )
75 #endif
76 #endif
77 {
78 	DdeServices&    rAll = DdeService::GetServices();
79 	DdeService*     pService;
80 	DdeTopic*       pTopic;
81 	DdeItem*        pItem;
82 	DdeData*        pData;
83 	Conversation*   pC;
84 
85 	DdeInstData* pInst = ImpGetInstData();
86 	DBG_ASSERT(pInst,"SVDDE:No instance data");
87 
88 	switch( nCode )
89 	{
90 		case XTYP_WILDCONNECT:
91 		{
92 			int nTopics = 0;
93 
94 #if 1
95 			TCHAR chTopicBuf[250];
96 			if( hText1 )
97 				DdeQueryString( pInst->hDdeInstSvr, hText1, chTopicBuf,
98 								sizeof(chTopicBuf)/sizeof(TCHAR), CP_WINUNICODE );
99 
100 			for( pService = rAll.First();pService;pService = rAll.Next() )
101 			{
102 				if ( !hText2 || ( *pService->pName == hText2 ) )
103 				{
104 					String sTopics( pService->Topics() );
105 					if( sTopics.Len() )
106 					{
107 						if( hText1 )
108 						{
109 							sal_uInt16 n = 0;
110 							while( STRING_NOTFOUND != n )
111 							{
112 								String s( sTopics.GetToken( 0, '\t', n ));
113 								if( s == reinterpret_cast<const sal_Unicode*>(chTopicBuf) )
114 									++nTopics;
115 							}
116 						}
117 						else
118 							nTopics += sTopics.GetTokenCount( '\t' );
119 					}
120 				}
121 			}
122 
123 #else
124 			for( pService = rAll.First();pService;pService = rAll.Next() )
125 			{
126 				if ( !hText2 || ( *pService->pName == hText2 ) )
127 				{
128 					for( pTopic = pService->aTopics.First(); pTopic;
129 						 pTopic = pService->aTopics.Next() )
130 					{
131 						if ( !hText1 || (*pTopic->pName == hText1) )
132 							nTopics++;
133 					}
134 				}
135 			}
136 #endif
137 			if( !nTopics )
138 				return (HDDEDATA)NULL;
139 
140 			HSZPAIR* pPairs = new HSZPAIR [nTopics + 1];
141 			if ( !pPairs )
142 				return (HDDEDATA)NULL;
143 
144 			HSZPAIR* q = pPairs;
145 			for( pService = rAll.First(); pService; pService = rAll.Next() )
146 			{
147 				if ( !hText2 || (*pService->pName == hText2 ) )
148 				{
149 #if 0
150 					for ( pTopic = pService->aTopics.First(); pTopic;
151 						  pTopic = pService->aTopics.Next() )
152 					{
153 						if ( !hText1 || (*pTopic->pName == hText1) )
154 						{
155 							q->hszSvc   = *pService->pName;
156 							q->hszTopic = *pTopic->pName;
157 							q++;
158 						}
159 					}
160 #else
161 					String sTopics( pService->Topics() );
162 					sal_uInt16 n = 0;
163 					while( STRING_NOTFOUND != n )
164 					{
165 						String s( sTopics.GetToken( 0, '\t', n ));
166 						s.EraseAllChars( '\n' ).EraseAllChars( '\r' );
167 						if( !hText1 || s == reinterpret_cast<const sal_Unicode*>(chTopicBuf) )
168 						{
169 							DdeString aDStr( pInst->hDdeInstSvr, s );
170 							pTopic = FindTopic( *pService, (HSZ)aDStr );
171 							if( pTopic )
172 							{
173 								q->hszSvc   = *pService->pName;
174 								q->hszTopic = *pTopic->pName;
175 								q++;
176 							}
177 						}
178 					}
179 
180 #endif
181 				}
182 			}
183 
184 			q->hszSvc   = NULL;
185 			q->hszTopic = NULL;
186 			HDDEDATA h = DdeCreateDataHandle(
187 							pInst->hDdeInstSvr, (LPBYTE) pPairs,
188 							sizeof(HSZPAIR) * (nTopics+1),
189 							0, NULL, nCbType, 0);
190 			delete [] pPairs;
191 			return h;
192 		}
193 
194 		case XTYP_CONNECT:
195 			pService = FindService( hText2 );
196 			if ( pService)
197 				pTopic = FindTopic( *pService, hText1 );
198 			else
199 				pTopic = NULL;
200 			if ( pTopic )
201 				return (HDDEDATA)DDE_FACK;
202 			else
203 				return (HDDEDATA) NULL;
204 
205 		case XTYP_CONNECT_CONFIRM:
206 			pService = FindService( hText2 );
207 			if ( pService )
208 			{
209 				pTopic = FindTopic( *pService, hText1 );
210 				if ( pTopic )
211 				{
212 					pTopic->Connect( (long) hConv );
213 					pC = new Conversation;
214 					pC->hConv = hConv;
215 					pC->pTopic = pTopic;
216 					pService->pConv->Insert( pC );
217 				}
218 			}
219 			return (HDDEDATA)NULL;
220 	}
221 
222 	for ( pService = rAll.First(); pService; pService = rAll.Next() )
223 	{
224 		for( pC = pService->pConv->First(); pC;
225 			 pC = pService->pConv->Next() )
226 		{
227 			if ( pC->hConv == hConv )
228 				goto found;
229 		}
230 	}
231 
232 	return (HDDEDATA) DDE_FNOTPROCESSED;
233 
234 found:
235 	if ( nCode == XTYP_DISCONNECT)
236 	{
237 		pC->pTopic->_Disconnect( (long) hConv );
238 		pService->pConv->Remove( pC );
239 		delete pC;
240 		return (HDDEDATA)NULL;
241 	}
242 
243 	sal_Bool bExec = sal_Bool(nCode == XTYP_EXECUTE);
244 	pTopic = pC->pTopic;
245 	if ( pTopic && !bExec )
246 		pItem = FindItem( *pTopic, hText2 );
247 	else
248 		pItem = NULL;
249 
250 	if ( !bExec && !pService->HasCbFormat( nCbType ) )
251 		pItem = NULL;
252 	if ( !pItem && !bExec )
253 		return (HDDEDATA)DDE_FNOTPROCESSED;
254 	if ( pItem )
255 		pTopic->aItem = pItem->GetName();
256 	else
257 		pTopic->aItem.Erase();
258 
259 	sal_Bool bRes = sal_False;
260 	pInst->hCurConvSvr = (long)hConv;
261 	switch( nCode )
262 	{
263 		case XTYP_REQUEST:
264 		case XTYP_ADVREQ:
265 			{
266 			String aRes;          // darf erst am Ende freigegeben werden!!
267 			if ( pTopic->IsSystemTopic() )
268 			{
269 				if ( pTopic->aItem == reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_TOPICS) )
270 					aRes = pService->Topics();
271 				else if ( pTopic->aItem == reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_SYSITEMS) )
272 					aRes = pService->SysItems();
273 				else if ( pTopic->aItem == reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_STATUS) )
274 					aRes = pService->Status();
275 				else if ( pTopic->aItem == reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_FORMATS) )
276 					aRes = pService->Formats();
277 				else if ( pTopic->aItem ==  reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_HELP) )
278 					aRes = pService->GetHelp();
279 				else
280 					aRes = pService->SysTopicGet( pTopic->aItem );
281 
282 				if ( aRes.Len() )
283 					pData = new DdeData( aRes );
284 				else
285 					pData = NULL;
286 			}
287 			else if( DDEGETPUTITEM == pItem->nType )
288 				pData = ((DdeGetPutItem*)pItem)->Get(
289 							DdeData::GetInternalFormat( nCbType ) );
290 			else
291 				pData = pTopic->Get( DdeData::GetInternalFormat( nCbType ));
292 
293 			if ( pData )
294 				return DdeCreateDataHandle( pInst->hDdeInstSvr,
295 											(LPBYTE)pData->pImp->pData,
296 											pData->pImp->nData,
297 											0, hText2,
298 											DdeData::GetExternalFormat(
299 												pData->pImp->nFmt ),
300 											0 );
301 			}
302 			break;
303 
304 		case XTYP_POKE:
305 			if ( !pTopic->IsSystemTopic() )
306 			{
307 				DdeData d;
308 				d.pImp->hData = hData;
309 				d.pImp->nFmt  = DdeData::GetInternalFormat( nCbType );
310 				d.Lock();
311 				if( DDEGETPUTITEM == pItem->nType )
312 					bRes = ((DdeGetPutItem*)pItem)->Put( &d );
313 				else
314 					bRes = pTopic->Put( &d );
315 			}
316 			pInst->hCurConvSvr = NULL;
317 			if ( bRes )
318 				return (HDDEDATA)DDE_FACK;
319 			else
320 				return (HDDEDATA) DDE_FNOTPROCESSED;
321 
322 		case XTYP_ADVSTART:
323 			{
324 				// wird das Item zum erstenmal ein HotLink ?
325 				if( !pItem->pImpData && pTopic->StartAdviseLoop() )
326 				{
327 					// dann wurde das Item ausgewechselt
328 					pTopic->aItems.Remove( pItem );
329 					DdeItem* pTmp;
330 					for(  pTmp = pTopic->aItems.First(); pTmp;
331 									pTmp = pTopic->aItems.Next() )
332 						if( *pTmp->pName == hText2 )
333 						{
334 							// es wurde tatsaechlich ausgewechselt
335 							delete pItem;
336 							pItem = 0;
337 							break;
338 						}
339 					if( pItem )
340 						// es wurde doch nicht ausgewechselt, also wieder rein
341 						pTopic->aItems.Insert( pItem );
342 					else
343 						pItem = pTmp;
344 				}
345 				pItem->IncMonitor( (long)hConv );
346 				pInst->hCurConvSvr = NULL;
347 			}
348 			return (HDDEDATA)sal_True;
349 
350 		case XTYP_ADVSTOP:
351 			pItem->DecMonitor( (long)hConv );
352 			if( !pItem->pImpData )
353 				pTopic->StopAdviseLoop();
354 			pInst->hCurConvSvr = NULL;
355 			return (HDDEDATA)sal_True;
356 
357 		case XTYP_EXECUTE:
358 			{
359 				DdeData aExec;
360 				aExec.pImp->hData = hData;
361 				aExec.pImp->nFmt  = DdeData::GetInternalFormat( nCbType );
362 				aExec.Lock();
363 				String aName;
364 
365 				aName = (const sal_Unicode *)aExec.pImp->pData;
366 
367 				if( pTopic->IsSystemTopic() )
368 					bRes = pService->SysTopicExecute( &aName );
369 				else
370 					bRes = pTopic->Execute( &aName );
371 			}
372 			pInst->hCurConvSvr = NULL;
373 			if ( bRes )
374 				return (HDDEDATA)DDE_FACK;
375 			else
376 				return (HDDEDATA)DDE_FNOTPROCESSED;
377 	}
378 
379 	return (HDDEDATA)NULL;
380 }
381 
382 // --- DdeInternat::FindService() ----------------------------------
383 
384 DdeService* DdeInternal::FindService( HSZ hService )
385 {
386 	DdeService*  s;
387 	DdeServices& rSvc = DdeService::GetServices();
388 	for ( s = rSvc.First(); s; s = rSvc.Next() )
389 	{
390 		if ( *s->pName == hService )
391 			return s;
392 	}
393 
394 	return NULL;
395 }
396 
397 // --- DdeInternat::FindTopic() ------------------------------------
398 
399 DdeTopic* DdeInternal::FindTopic( DdeService& rService, HSZ hTopic )
400 {
401 	DdeTopic* s;
402 	DdeTopics& rTopics = rService.aTopics;
403 	int bWeiter = sal_False;
404 	DdeInstData* pInst = ImpGetInstData();
405 	DBG_ASSERT(pInst,"SVDDE:No instance data");
406 
407 	do {            // middle check loop
408 		for ( s = rTopics.First(); s; s = rTopics.Next() )
409 		{
410 			if ( *s->pName == hTopic )
411 				return s;
412 		}
413 
414 		bWeiter = !bWeiter;
415 		if( !bWeiter )
416 			break;
417 
418 		// dann befragen wir doch mal unsere Ableitung:
419 		TCHAR chBuf[250];
420 		DdeQueryString(pInst->hDdeInstSvr,hTopic,chBuf,sizeof(chBuf)/sizeof(TCHAR),CP_WINUNICODE );
421 		bWeiter = rService.MakeTopic( reinterpret_cast<const sal_Unicode*>(chBuf) );
422 		// dann muessen wir noch mal suchen
423 	} while( bWeiter );
424 
425 	return 0;
426 }
427 
428 // --- DdeInternal::FindItem() -------------------------------------
429 
430 DdeItem* DdeInternal::FindItem( DdeTopic& rTopic, HSZ hItem )
431 {
432 	DdeItem* s;
433 	DdeItems& rItems = rTopic.aItems;
434 	DdeInstData* pInst = ImpGetInstData();
435 	DBG_ASSERT(pInst,"SVDDE:No instance data");
436 	int bWeiter = sal_False;
437 
438 	do {            // middle check loop
439 
440 		for ( s = rItems.First(); s; s = rItems.Next() )
441 			if ( *s->pName == hItem )
442 				return s;
443 
444 		bWeiter = !bWeiter;
445 		if( !bWeiter )
446 			break;
447 
448 		// dann befragen wir doch mal unsere Ableitung:
449 		TCHAR chBuf[250];
450 		DdeQueryString(pInst->hDdeInstSvr,hItem,chBuf,sizeof(chBuf)/sizeof(TCHAR),CP_WINUNICODE );
451 		bWeiter = rTopic.MakeItem( reinterpret_cast<const sal_Unicode*>(chBuf) );
452 		// dann muessen wir noch mal suchen
453 	} while( bWeiter );
454 
455 	return 0;
456 }
457 
458 // --- DdeService::DdeService() ------------------------------------
459 
460 DdeService::DdeService( const String& rService )
461 {
462 	DdeInstData* pInst = ImpGetInstData();
463 	if( !pInst )
464 		pInst = ImpInitInstData();
465 	pInst->nRefCount++;
466 	pInst->nInstanceSvr++;
467 
468 	if ( !pInst->hDdeInstSvr )
469 	{
470 		nStatus = sal::static_int_cast< short >(
471             DdeInitialize( &pInst->hDdeInstSvr,
472                            (PFNCALLBACK)DdeInternal::SvrCallback,
473                            APPCLASS_STANDARD |
474                            CBF_SKIP_REGISTRATIONS |
475                            CBF_SKIP_UNREGISTRATIONS, 0L ) );
476 		pInst->pServicesSvr = new DdeServices;
477 	}
478 	else
479 		nStatus = DMLERR_NO_ERROR;
480 
481 	pConv = new ConvList;
482 
483 	if ( pInst->pServicesSvr )
484 		pInst->pServicesSvr->Insert( this );
485 
486 	pName = new DdeString( pInst->hDdeInstSvr, rService );
487 	if ( nStatus == DMLERR_NO_ERROR )
488 		if ( !DdeNameService( pInst->hDdeInstSvr, *pName, NULL,
489 								DNS_REGISTER | DNS_FILTEROFF ) )
490 			nStatus = DMLERR_SYS_ERROR;
491 
492 	AddFormat( FORMAT_STRING );
493 	pSysTopic = new DdeTopic( reinterpret_cast<const sal_Unicode*>(SZDDESYS_TOPIC) );
494 	pSysTopic->AddItem( DdeItem( reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_TOPICS) ) );
495 	pSysTopic->AddItem( DdeItem( reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_SYSITEMS) ) );
496 	pSysTopic->AddItem( DdeItem( reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_STATUS) ) );
497 	pSysTopic->AddItem( DdeItem( reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_FORMATS) ) );
498 	pSysTopic->AddItem( DdeItem( reinterpret_cast<const sal_Unicode*>(SZDDESYS_ITEM_HELP) ) );
499 	AddTopic( *pSysTopic );
500 }
501 
502 // --- DdeService::~DdeService() -----------------------------------
503 
504 DdeService::~DdeService()
505 {
506 	DdeInstData* pInst = ImpGetInstData();
507 	DBG_ASSERT(pInst,"SVDDE:No instance data");
508 	if ( pInst->pServicesSvr )
509 		pInst->pServicesSvr->Remove( this );
510 
511 	// MT: Im Auftrage des Herrn (AM) auskommentiert...
512 	// Grund:
513 	// Bei Client/Server werden die Server nicht beendet, wenn mehr
514 	// als einer gestartet.
515 	// Weil keine System-Messagequeue ?!
516 
517 	delete pSysTopic;
518 	delete pName;
519 
520 	pInst->nInstanceSvr--;
521 	pInst->nRefCount--;
522 	if ( !pInst->nInstanceSvr && pInst->hDdeInstSvr )
523 	{
524 		if( DdeUninitialize( pInst->hDdeInstSvr ) )
525 		{
526 			pInst->hDdeInstSvr = NULL;
527 			delete pInst->pServicesSvr;
528 			pInst->pServicesSvr = NULL;
529 			if( pInst->nRefCount == 0)
530 				ImpDeinitInstData();
531 		}
532 	}
533 	delete pConv;
534 }
535 
536 // --- DdeService::GetName() ---------------------------------------
537 
538 const String& DdeService::GetName() const
539 {
540 	return *pName;
541 }
542 
543 // --- DdeService::GetServices() -----------------------------------
544 
545 DdeServices& DdeService::GetServices()
546 {
547 	DdeInstData* pInst = ImpGetInstData();
548 	DBG_ASSERT(pInst,"SVDDE:No instance data");
549 	return *(pInst->pServicesSvr);
550 }
551 
552 // --- DdeService::AddTopic() --------------------------------------
553 
554 void DdeService::AddTopic( const DdeTopic& rTopic )
555 {
556 	RemoveTopic( rTopic );
557 	aTopics.Insert( (DdeTopic*) &rTopic );
558 }
559 
560 // --- DdeService::RemoveTopic() -----------------------------------
561 
562 void DdeService::RemoveTopic( const DdeTopic& rTopic )
563 {
564 	DdeTopic* t;
565 	for ( t = aTopics.First(); t; t = aTopics.Next() )
566 	{
567 		if ( !DdeCmpStringHandles (*t->pName, *rTopic.pName ) )
568 		{
569 			aTopics.Remove( t );
570 			// JP 27.07.95: und alle Conversions loeschen !!!
571 			//              (sonst wird auf geloeschten Topics gearbeitet!!)
572 			for( sal_uLong n = pConv->Count(); n; )
573 			{
574 				Conversation* pC = pConv->GetObject( --n );
575 				if( pC->pTopic == &rTopic )
576 				{
577 					pConv->Remove( pC );
578 					delete pC;
579 				}
580 			}
581 			break;
582 		}
583 	}
584 }
585 
586 // --- DdeService::HasCbFormat() -----------------------------------
587 
588 sal_Bool DdeService::HasCbFormat( sal_uInt16 nFmt )
589 {
590 	return sal_Bool( aFormats.GetPos( nFmt ) != LIST_ENTRY_NOTFOUND );
591 }
592 
593 // --- DdeService::HasFormat() -------------------------------------
594 
595 sal_Bool DdeService::HasFormat( sal_uLong nFmt )
596 {
597 	return HasCbFormat( (sal_uInt16)DdeData::GetExternalFormat( nFmt ));
598 }
599 
600 // --- DdeService::AddFormat() -------------------------------------
601 
602 void DdeService::AddFormat( sal_uLong nFmt )
603 {
604 	nFmt = DdeData::GetExternalFormat( nFmt );
605 	aFormats.Remove( nFmt );
606 	aFormats.Insert( nFmt );
607 }
608 
609 // --- DdeService::RemoveFormat() ----------------------------------
610 
611 void DdeService::RemoveFormat( sal_uLong nFmt )
612 {
613 	aFormats.Remove( DdeData::GetExternalFormat( nFmt ) );
614 }
615 
616 // --- DdeTopic::DdeTopic() ----------------------------------------
617 
618 DdeTopic::DdeTopic( const String& rName )
619 {
620 	DdeInstData* pInst = ImpGetInstData();
621 	DBG_ASSERT(pInst,"SVDDE:No instance data");
622 	pName = new DdeString( pInst->hDdeInstSvr, rName );
623 }
624 
625 // --- DdeTopic::~DdeTopic() ---------------------------------------
626 
627 DdeTopic::~DdeTopic()
628 {
629 	DdeItem* t;
630 	while( ( t = aItems.First() ) != NULL )
631 	{
632 		aItems.Remove( t );
633 		t->pMyTopic = 0;
634 		delete t;
635 	}
636 	delete pName;
637 }
638 
639 // --- DdeTopic::GetName() -----------------------------------------
640 
641 const String& DdeTopic::GetName() const
642 {
643 	return *pName;
644 }
645 
646 // --- DdeTopic::IsSystemTopic() -----------------------------------
647 
648 sal_Bool DdeTopic::IsSystemTopic()
649 {
650 	return sal_Bool (GetName() == reinterpret_cast<const sal_Unicode*>(SZDDESYS_TOPIC));
651 }
652 
653 // --- DdeTopic::AddItem() -----------------------------------------
654 
655 DdeItem* DdeTopic::AddItem( const DdeItem& r )
656 {
657 	DdeItem* s;
658 	if( DDEGETPUTITEM == r.nType )
659 		s = new DdeGetPutItem( r );
660 	else
661 		s = new DdeItem( r );
662 	if ( s )
663 	{
664 		aItems.Insert( s );
665 		s->pMyTopic = this;
666 	}
667 	return s;
668 }
669 
670 // --- DdeTopic::InsertItem() -----------------------------------------
671 
672 void DdeTopic::InsertItem( DdeItem* pNew )
673 {
674 	if( pNew )
675 	{
676 		aItems.Insert( pNew );
677 		pNew->pMyTopic = this;
678 	}
679 }
680 
681 // --- DdeTopic::RemoveItem() --------------------------------------
682 
683 void DdeTopic::RemoveItem( const DdeItem& r )
684 {
685 	DdeItem* s;
686 	for ( s = aItems.First(); s; s = aItems.Next() )
687 	{
688 		if ( !DdeCmpStringHandles (*s->pName, *r.pName ) )
689 			break;
690 	}
691 
692 	if ( s )
693 	{
694 		aItems.Remove( s );
695 		s->pMyTopic = 0;
696 		delete s;
697 	}
698 }
699 
700 // --- DdeTopic::NotifyClient() ------------------------------------
701 
702 void DdeTopic::NotifyClient( const String& rItem )
703 {
704 	DdeItem* pItem;
705 	DdeInstData* pInst = ImpGetInstData();
706 	DBG_ASSERT(pInst,"SVDDE:No instance data");
707 	for ( pItem = aItems.First(); pItem; pItem = aItems.Next() )
708 	{
709 		if ( pItem->GetName() == rItem )
710 		{
711 			if ( pItem->pImpData )
712 				DdePostAdvise( pInst->hDdeInstSvr, *pName, *pItem->pName );
713 		}
714 		break;
715 	}
716 }
717 
718 // --- DdeTopic::Connect() -----------------------------------------
719 
720 void __EXPORT DdeTopic::Connect( long nId )
721 {
722 	aConnectLink.Call( (void*)nId );
723 }
724 
725 // --- DdeTopic::Disconnect() --------------------------------------
726 
727 void __EXPORT DdeTopic::Disconnect( long nId )
728 {
729 	aDisconnectLink.Call( (void*)nId );
730 }
731 
732 // --- DdeTopic::_Disconnect() --------------------------------------
733 
734 void __EXPORT DdeTopic::_Disconnect( long nId )
735 {
736 	for( DdeItem* pItem = aItems.First(); pItem; pItem = aItems.Next() )
737 		pItem->DecMonitor( nId );
738 
739 	Disconnect( nId );
740 }
741 
742 // --- DdeTopic::Get() ---------------------------------------------
743 
744 DdeData* __EXPORT DdeTopic::Get( sal_uLong nFmt )
745 {
746 	if ( aGetLink.IsSet() )
747 		return (DdeData*)aGetLink.Call( (void*)nFmt );
748 	else
749 		return NULL;
750 }
751 
752 // --- DdeTopic::Put() ---------------------------------------------
753 
754 sal_Bool __EXPORT DdeTopic::Put( const DdeData* r )
755 {
756 	if ( aPutLink.IsSet() )
757 		return (sal_Bool)aPutLink.Call( (void*) r );
758 	else
759 		return sal_False;
760 }
761 
762 // --- DdeTopic::Execute() -----------------------------------------
763 
764 sal_Bool __EXPORT DdeTopic::Execute( const String* r )
765 {
766 	if ( aExecLink.IsSet() )
767 		return (sal_Bool)aExecLink.Call( (void*)r );
768 	else
769 		return sal_False;
770 }
771 
772 // --- DdeTopic::GetConvId() ---------------------------------------
773 
774 long DdeTopic::GetConvId()
775 {
776 	DdeInstData* pInst = ImpGetInstData();
777 	DBG_ASSERT(pInst,"SVDDE:No instance data");
778 	return pInst->hCurConvSvr;
779 }
780 
781 // --- DdeTopic::StartAdviseLoop() ---------------------------------
782 
783 sal_Bool DdeTopic::StartAdviseLoop()
784 {
785 	return sal_False;
786 }
787 
788 // --- DdeTopic::StopAdviseLoop() ----------------------------------
789 
790 sal_Bool DdeTopic::StopAdviseLoop()
791 {
792 	return sal_False;
793 }
794 
795 // --- DdeItem::DdeItem() ------------------------------------------
796 
797 DdeItem::DdeItem( const sal_Unicode* p )
798 {
799 	DdeInstData* pInst = ImpGetInstData();
800 	DBG_ASSERT(pInst,"SVDDE:No instance data");
801 	pName = new DdeString( pInst->hDdeInstSvr, p );
802 	nType = DDEITEM;
803 	pMyTopic = 0;
804 	pImpData = 0;
805 }
806 
807 // --- DdeItem::DdeItem() ------------------------------------------
808 
809 DdeItem::DdeItem( const String& r)
810 {
811 	DdeInstData* pInst = ImpGetInstData();
812 	DBG_ASSERT(pInst,"SVDDE:No instance data");
813 	pName = new DdeString( pInst->hDdeInstSvr, r );
814 	nType = DDEITEM;
815 	pMyTopic = 0;
816 	pImpData = 0;
817 }
818 
819 // --- DdeItem::DdeItem() ------------------------------------------
820 
821 DdeItem::DdeItem( const DdeItem& r)
822 {
823 	DdeInstData* pInst = ImpGetInstData();
824 	DBG_ASSERT(pInst,"SVDDE:No instance data");
825 	pName = new DdeString( pInst->hDdeInstSvr, *r.pName );
826 	nType = DDEITEM;
827 	pMyTopic = 0;
828 	pImpData = 0;
829 }
830 
831 // --- DdeItem::~DdeItem() -----------------------------------------
832 
833 DdeItem::~DdeItem()
834 {
835 	if( pMyTopic )
836 		pMyTopic->aItems.Remove( this );
837 	delete pName;
838 	delete pImpData;
839 }
840 
841 // --- DdeItem::GetName() ------------------------------------------
842 
843 const String& DdeItem::GetName() const
844 {
845 	return *pName;
846 }
847 
848 // --- DdeItem::NotifyClient() ------------------------------------------
849 
850 void DdeItem::NotifyClient()
851 {
852 	if( pMyTopic && pImpData )
853 	{
854 		DdeInstData* pInst = ImpGetInstData();
855 		DBG_ASSERT(pInst,"SVDDE:No instance data");
856 		DdePostAdvise( pInst->hDdeInstSvr, *pMyTopic->pName, *pName );
857 	}
858 }
859 
860 // --- DdeItem::IncMonitor() ------------------------------------------
861 
862 void DdeItem::IncMonitor( sal_uLong nHCnv )
863 {
864 	if( !pImpData )
865 	{
866 		pImpData = new DdeItemImp;
867 		if( DDEGETPUTITEM == nType )
868 			((DdeGetPutItem*)this)->AdviseLoop( sal_True );
869 	}
870 	else
871 	{
872 		for( sal_uInt16 n = pImpData->Count(); n; )
873 			if( (*pImpData)[ --n ].nHCnv == nHCnv )
874 			{
875 				++(*pImpData)[ n ].nHCnv;
876 				return ;
877 			}
878 	}
879 
880 	pImpData->Insert( DdeItemImpData( nHCnv ), pImpData->Count() );
881 }
882 
883 // --- DdeItem::DecMonitor() ------------------------------------------
884 
885 void DdeItem::DecMonitor( sal_uLong nHCnv )
886 {
887 	if( pImpData )
888 	{
889 		DdeItemImpData* pData = (DdeItemImpData*)pImpData->GetData();
890 		for( sal_uInt16 n = pImpData->Count(); n; --n, ++pData )
891 			if( pData->nHCnv == nHCnv )
892 			{
893 				if( !pData->nCnt || !--pData->nCnt )
894 				{
895 					if( 1 < pImpData->Count() )
896 						pImpData->Remove( pImpData->Count() - n );
897 					else
898 					{
899 						delete pImpData, pImpData = 0;
900 						if( DDEGETPUTITEM == nType )
901 							((DdeGetPutItem*)this)->AdviseLoop( sal_False );
902 					}
903 				}
904 				return ;
905 			}
906 	}
907 }
908 
909 // --- DdeItem::GetLinks() ------------------------------------------
910 
911 short DdeItem::GetLinks()
912 {
913 	short nCnt = 0;
914 	if( pImpData )
915 		for( sal_uInt16 n = pImpData->Count(); n; )
916 			nCnt = nCnt + (*pImpData)[ --n ].nCnt;
917 	return nCnt;
918 }
919 
920 // --- DdeGetPutItem::DdeGetPutItem() ------------------------------
921 
922 DdeGetPutItem::DdeGetPutItem( const sal_Unicode* p )
923 	: DdeItem( p )
924 {
925 	nType = DDEGETPUTITEM;
926 }
927 
928 // --- DdeGetPutItem::DdeGetPutItem() ------------------------------
929 
930 DdeGetPutItem::DdeGetPutItem( const String& rStr )
931 	: DdeItem( rStr )
932 {
933 	nType = DDEGETPUTITEM;
934 }
935 
936 // --- DdeGetPutItem::DdeGetPutItem() ------------------------------
937 
938 DdeGetPutItem::DdeGetPutItem( const DdeItem& rItem )
939 	: DdeItem( rItem )
940 {
941 	nType = DDEGETPUTITEM;
942 }
943 
944 
945 // --- DdeGetPutData::Get() ----------------------------------------
946 
947 DdeData* DdeGetPutItem::Get( sal_uLong )
948 {
949 	return 0;
950 }
951 
952 // --- DdeGetPutData::Put() ----------------------------------------
953 
954 sal_Bool DdeGetPutItem::Put( const DdeData* )
955 {
956 	return sal_False;
957 }
958 
959 // --- DdeGetPutData::AdviseLoop() ---------------------------------
960 
961 void DdeGetPutItem::AdviseLoop( sal_Bool )
962 {
963 }
964 
965 
966 // --- DdeService::SysItems() --------------------------------------
967 
968 String DdeService::SysItems()
969 {
970 	String s;
971 	DdeTopic* t;
972 	for ( t = aTopics.First(); t; t = aTopics.Next() )
973 	{
974 		if ( t->GetName() == reinterpret_cast<const sal_Unicode*>(SZDDESYS_TOPIC) )
975 		{
976 			short n = 0;
977 			DdeItem* pi;
978 			for ( pi = t->aItems.First(); pi; pi = t->aItems.Next(), n++ )
979 			{
980 				if ( n )
981 					s += '\t';
982 				s += pi->GetName();
983 			}
984 			s += String::CreateFromAscii("\r\n");
985 		}
986 	}
987 
988 	return s;
989 }
990 
991 // --- DdeService::Topics() ----------------------------------------
992 
993 String DdeService::Topics()
994 {
995 	String      s;
996 	DdeTopic*   t;
997 	short       n = 0;
998 
999 	for ( t = aTopics.First(); t; t = aTopics.Next(), n++ )
1000 	{
1001 		if ( n )
1002 			s += '\t';
1003 		s += t->GetName();
1004 	}
1005 	s += String::CreateFromAscii("\r\n");
1006 
1007 	return s;
1008 }
1009 
1010 // --- DdeService::Formats() ---------------------------------------
1011 
1012 String DdeService::Formats()
1013 {
1014 	String      s;
1015 	long        f;
1016 	TCHAR       buf[128];
1017 	LPCTSTR		p;
1018 	short       n = 0;
1019 
1020 	for ( f = aFormats.First(); f; f = aFormats.Next(), n++ )
1021 	{
1022 		if ( n )
1023 			s += '\t';
1024 		p = buf;
1025 
1026 		switch( (sal_uInt16)f )
1027 		{
1028 			case CF_TEXT:
1029 				p = reinterpret_cast<LPCTSTR>(String::CreateFromAscii("TEXT").GetBuffer());
1030 				break;
1031 			case CF_BITMAP:
1032 				p = reinterpret_cast<LPCTSTR>(String::CreateFromAscii("BITMAP").GetBuffer());
1033 				break;
1034 #ifdef OS2
1035 			case CF_DSPTEXT:
1036 				p = String::CreateFromAscii("TEXT").GetBuffer();
1037 				break;
1038 			case CF_DSPBITMAP:
1039 				p = String::CreateFromAscii("BITMAP").GetBuffer();
1040 				break;
1041 			case CF_METAFILE:
1042 				p = String::CreateFromAscii("METAFILE").GetBuffer();
1043 				break;
1044 			case CF_DSPMETAFILE:
1045 				p = String::CreateFromAscii("METAFILE").GetBuffer();
1046 				break;
1047 			case CF_PALETTE:
1048 				p = String::CreateFromAscii("PALETTE").GetBuffer();
1049 				break;
1050 			default:
1051 				p= String::CreateFromAscii("PRIVATE").GetBuffer();
1052 #else
1053 			default:
1054 				GetClipboardFormatName( (UINT)f, buf, sizeof(buf) / sizeof(TCHAR) );
1055 #endif
1056 		}
1057 		s += String( reinterpret_cast<const sal_Unicode*>(p) );
1058 	}
1059 	s += String::CreateFromAscii("\r\n");
1060 
1061 	return s;
1062 }
1063 
1064 // --- DdeService::Status() ----------------------------------------
1065 
1066 String DdeService::Status()
1067 {
1068 	return IsBusy() ? String::CreateFromAscii("Busy\r\n") : String::CreateFromAscii("Ready\r\n");
1069 }
1070 
1071 // --- DdeService::IsBusy() ----------------------------------------
1072 
1073 sal_Bool __EXPORT DdeService::IsBusy()
1074 {
1075 	return sal_False;
1076 }
1077 
1078 // --- DdeService::GetHelp() ----------------------------------------
1079 
1080 String __EXPORT DdeService::GetHelp()
1081 {
1082 	return String();
1083 }
1084 
1085 sal_Bool DdeTopic::MakeItem( const String& )
1086 {
1087 	return sal_False;
1088 }
1089 
1090 sal_Bool DdeService::MakeTopic( const String& )
1091 {
1092 	return sal_False;
1093 }
1094 
1095 String DdeService::SysTopicGet( const String& )
1096 {
1097 	return String();
1098 }
1099 
1100 sal_Bool DdeService::SysTopicExecute( const String* )
1101 {
1102 	return sal_False;
1103 }
1104 
1105