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