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 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 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 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 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 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 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 242 const String& DdeConnection::GetServiceName() 243 { 244 return (const String&)*pService; 245 } 246 247 // --- DdeConnection::GetTopicName() ------------------------------- 248 249 const String& DdeConnection::GetTopicName() 250 { 251 return (const String&)*pTopic; 252 } 253 254 // --- DdeConnection::GetConvId() ---------------------------------- 255 256 long DdeConnection::GetConvId() 257 { 258 return (long)pImp->hConv; 259 } 260 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 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 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 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 353 const String& DdeTransaction::GetName() const 354 { 355 return *pName; 356 } 357 358 // --- DdeTransaction::Data() -------------------------------------- 359 360 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 372 void __EXPORT DdeTransaction::Done( sal_Bool bDataValid ) 373 { 374 aDone.Call( (void*)bDataValid ); 375 } 376 377 // --- DdeLink::DdeLink() ------------------------------------------ 378 379 DdeLink::DdeLink( DdeConnection& d, const String& aItemName, long n ) : 380 DdeTransaction (d, aItemName, n) 381 { 382 } 383 384 // --- DdeLink::~DdeLink() ----------------------------------------- 385 386 DdeLink::~DdeLink() 387 { 388 nType = (sal_uInt16)XTYP_ADVSTOP; 389 nTime = 0; 390 } 391 392 // --- DdeLink::Notify() ----------------------------------------- 393 394 void __EXPORT DdeLink::Notify() 395 { 396 aNotify.Call( NULL ); 397 } 398 399 // --- DdeRequest::DdeRequest() ------------------------------------ 400 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 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 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 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 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 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 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 466 long DdeConnection::GetError() 467 { 468 return pImp->nStatus; 469 } 470