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_sfx2.hxx" 26 27 #if defined(WNT) 28 #include <tools/svwin.h> 29 #endif 30 31 #include "impldde.hxx" 32 33 #include <vcl/svapp.hxx> 34 #include <vcl/fixed.hxx> 35 #include <vcl/edit.hxx> 36 #include <vcl/button.hxx> 37 #include <vcl/msgbox.hxx> 38 #include <sot/exchange.hxx> 39 #include <rtl/ustring.hxx> 40 41 #include "dde.hrc" 42 #include <sfx2/lnkbase.hxx> 43 #include <sfx2/linkmgr.hxx> 44 #include "sfx2/sfxresid.hxx" 45 46 #include <com/sun/star/uno/Any.hxx> 47 #include <com/sun/star/uno/Sequence.hxx> 48 49 #include <svl/svdde.hxx> 50 #include <sot/formats.hxx> 51 52 #define DDELINK_COLD 0 53 #define DDELINK_HOT 1 54 55 #define DDELINK_ERROR_APP 1 56 #define DDELINK_ERROR_DATA 2 57 #define DDELINK_ERROR_LINK 3 58 59 using namespace ::com::sun::star::uno; 60 61 namespace sfx2 62 { 63 64 class SvDDELinkEditDialog : public ModalDialog 65 { 66 FixedText aFtDdeApp; 67 Edit aEdDdeApp; 68 FixedText aFtDdeTopic; 69 Edit aEdDdeTopic; 70 FixedText aFtDdeItem; 71 Edit aEdDdeItem; 72 FixedLine aGroupDdeChg; 73 OKButton aOKButton1; 74 CancelButton aCancelButton1; 75 76 DECL_STATIC_LINK( SvDDELinkEditDialog, EditHdl_Impl, Edit* ); 77 public: 78 SvDDELinkEditDialog( Window* pParent, SvBaseLink* ); 79 String GetCmd() const; 80 }; 81 82 SvDDELinkEditDialog::SvDDELinkEditDialog( Window* pParent, SvBaseLink* pLink ) 83 : ModalDialog( pParent, SfxResId( MD_DDE_LINKEDIT ) ), 84 aFtDdeApp( this, SfxResId( FT_DDE_APP ) ), 85 aEdDdeApp( this, SfxResId( ED_DDE_APP ) ), 86 aFtDdeTopic( this, SfxResId( FT_DDE_TOPIC ) ), 87 aEdDdeTopic( this, SfxResId( ED_DDE_TOPIC ) ), 88 aFtDdeItem( this, SfxResId( FT_DDE_ITEM ) ), 89 aEdDdeItem( this, SfxResId( ED_DDE_ITEM ) ), 90 aGroupDdeChg( this, SfxResId( GROUP_DDE_CHG ) ), 91 aOKButton1( this, SfxResId( 1 ) ), 92 aCancelButton1( this, SfxResId( 1 ) ) 93 { 94 FreeResource(); 95 96 String sServer, sTopic, sItem; 97 pLink->GetLinkManager()->GetDisplayNames( pLink, &sServer, &sTopic, &sItem ); 98 99 aEdDdeApp.SetText( sServer ); 100 aEdDdeTopic.SetText( sTopic ); 101 aEdDdeItem.SetText( sItem ); 102 103 aEdDdeApp.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl)); 104 aEdDdeTopic.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl)); 105 aEdDdeItem.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl)); 106 107 aOKButton1.Enable( sServer.Len() && sTopic.Len() && sItem.Len() ); 108 } 109 110 String SvDDELinkEditDialog::GetCmd() const 111 { 112 String sCmd( aEdDdeApp.GetText() ), sRet; 113 ::sfx2::MakeLnkName( sRet, &sCmd, aEdDdeTopic.GetText(), aEdDdeItem.GetText() ); 114 return sRet; 115 } 116 117 IMPL_STATIC_LINK( SvDDELinkEditDialog, EditHdl_Impl, Edit *, pEdit ) 118 { 119 (void)pEdit; // unused variable 120 pThis->aOKButton1.Enable( pThis->aEdDdeApp.GetText().Len() && 121 pThis->aEdDdeTopic.GetText().Len() && 122 pThis->aEdDdeItem.GetText().Len() ); 123 return 0; 124 } 125 126 /* */ 127 128 129 SvDDEObject::SvDDEObject() 130 : pConnection( 0 ), pLink( 0 ), pRequest( 0 ), pGetData( 0 ), nError( 0 ) 131 { 132 SetUpdateTimeout( 100 ); 133 bWaitForData = sal_False; 134 } 135 136 SvDDEObject::~SvDDEObject() 137 { 138 delete pLink; 139 delete pRequest; 140 delete pConnection; 141 } 142 143 sal_Bool SvDDEObject::GetData( ::com::sun::star::uno::Any & rData /*out param*/, 144 const String & rMimeType, 145 sal_Bool bSynchron ) 146 { 147 if( !pConnection ) 148 return sal_False; 149 150 if( pConnection->GetError() ) // dann versuchen wir es nochmal 151 { 152 String sServer( pConnection->GetServiceName() ); 153 String sTopic( pConnection->GetTopicName() ); 154 155 delete pConnection; 156 pConnection = new DdeConnection( sServer, sTopic ); 157 if( pConnection->GetError() ) 158 nError = DDELINK_ERROR_APP; 159 } 160 161 if( bWaitForData ) // wir sind rekursiv drin, wieder raus 162 return sal_False; 163 164 // Verriegeln gegen Reentrance 165 bWaitForData = sal_True; 166 167 // falls gedruckt werden soll, warten wir bis die Daten vorhanden sind 168 if( bSynchron ) 169 { 170 DdeRequest aReq( *pConnection, sItem, 5000 ); 171 aReq.SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) ); 172 aReq.SetFormat( SotExchange::GetFormatIdFromMimeType( rMimeType )); 173 174 pGetData = &rData; 175 176 do { 177 aReq.Execute(); 178 } while( aReq.GetError() && ImplHasOtherFormat( aReq ) ); 179 180 if( pConnection->GetError() ) 181 nError = DDELINK_ERROR_DATA; 182 183 bWaitForData = sal_False; 184 } 185 else 186 { 187 // ansonsten wird es asynchron ausgefuehrt 188 // if( !pLink || !pLink->IsBusy() ) 189 { 190 if( pRequest ) 191 delete pRequest; 192 193 pRequest = new DdeRequest( *pConnection, sItem ); 194 pRequest->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) ); 195 pRequest->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) ); 196 pRequest->SetFormat( SotExchange::GetFormatIdFromMimeType( 197 rMimeType ) ); 198 pRequest->Execute(); 199 } 200 201 ::rtl::OUString aEmptyStr; 202 rData <<= aEmptyStr; 203 } 204 return 0 == pConnection->GetError(); 205 } 206 207 208 sal_Bool SvDDEObject::Connect( SvBaseLink * pSvLink ) 209 { 210 #if defined(WNT) 211 static sal_Bool bInWinExec = sal_False; 212 #endif 213 sal_uInt16 nLinkType = pSvLink->GetUpdateMode(); 214 if( pConnection ) // Verbindung steht ja schon 215 { 216 // tja, dann nur noch als Abhaengig eintragen 217 AddDataAdvise( pSvLink, 218 SotExchange::GetFormatMimeType( pSvLink->GetContentType()), 219 LINKUPDATE_ONCALL == nLinkType 220 ? ADVISEMODE_ONLYONCE 221 : 0 ); 222 AddConnectAdvise( pSvLink ); 223 224 return sal_True; 225 } 226 227 if( !pSvLink->GetLinkManager() ) 228 return sal_False; 229 230 String sServer, sTopic; 231 pSvLink->GetLinkManager()->GetDisplayNames( pSvLink, &sServer, &sTopic, &sItem ); 232 233 if( !sServer.Len() || !sTopic.Len() || !sItem.Len() ) 234 return sal_False; 235 236 pConnection = new DdeConnection( sServer, sTopic ); 237 if( pConnection->GetError() ) 238 { 239 // kann man denn das System-Topic ansprechen ? 240 // dann ist der Server oben, kennt nur nicht das Topic! 241 if( sTopic.EqualsIgnoreCaseAscii( "SYSTEM" ) ) 242 { 243 sal_Bool bSysTopic; 244 { 245 DdeConnection aTmp( sServer, String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "SYSTEM" ) ) ); 246 bSysTopic = !aTmp.GetError(); 247 } 248 249 if( bSysTopic ) 250 { 251 nError = DDELINK_ERROR_DATA; 252 return sal_False; 253 } 254 // ansonsten unter Win/WinNT die Applikation direkt starten 255 } 256 257 #if defined(WNT) 258 259 // Server nicht da, starten und nochmal versuchen 260 if( !bInWinExec ) 261 { 262 ByteString aCmdLine( sServer, RTL_TEXTENCODING_ASCII_US ); 263 aCmdLine.Append( ".exe " ); 264 aCmdLine.Append( ByteString( sTopic, RTL_TEXTENCODING_ASCII_US ) ); 265 266 if( WinExec( aCmdLine.GetBuffer(), SW_SHOWMINIMIZED ) < 32 ) 267 nError = DDELINK_ERROR_APP; 268 else 269 { 270 sal_uInt16 i; 271 for( i=0; i<5; i++ ) 272 { 273 bInWinExec = sal_True; 274 Application::Reschedule(); 275 bInWinExec = sal_False; 276 277 delete pConnection; 278 pConnection = new DdeConnection( sServer, sTopic ); 279 if( !pConnection->GetError() ) 280 break; 281 } 282 283 if( i == 5 ) 284 { 285 nError = DDELINK_ERROR_APP; 286 } 287 } 288 } 289 else 290 #endif // WNT 291 { 292 nError = DDELINK_ERROR_APP; 293 } 294 } 295 296 if( LINKUPDATE_ALWAYS == nLinkType && !pLink && !pConnection->GetError() ) 297 { 298 // Hot Link einrichten, Daten kommen irgendwann spaeter 299 pLink = new DdeHotLink( *pConnection, sItem ); 300 pLink->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) ); 301 pLink->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) ); 302 pLink->SetFormat( pSvLink->GetContentType() ); 303 pLink->Execute(); 304 } 305 306 if( pConnection->GetError() ) 307 return sal_False; 308 309 AddDataAdvise( pSvLink, 310 SotExchange::GetFormatMimeType( pSvLink->GetContentType()), 311 LINKUPDATE_ONCALL == nLinkType 312 ? ADVISEMODE_ONLYONCE 313 : 0 ); 314 AddConnectAdvise( pSvLink ); 315 SetUpdateTimeout( 0 ); 316 return sal_True; 317 } 318 319 void SvDDEObject::Edit( Window* pParent, sfx2::SvBaseLink* pBaseLink, const Link& rEndEditHdl ) 320 { 321 SvDDELinkEditDialog aDlg( pParent, pBaseLink ); 322 if ( RET_OK == aDlg.Execute() && rEndEditHdl.IsSet() ) 323 { 324 String sCommand = aDlg.GetCmd(); 325 rEndEditHdl.Call( &sCommand ); 326 } 327 } 328 329 sal_Bool SvDDEObject::ImplHasOtherFormat( DdeTransaction& rReq ) 330 { 331 sal_uInt16 nFmt = 0; 332 switch( rReq.GetFormat() ) 333 { 334 case FORMAT_RTF: 335 nFmt = FORMAT_STRING; 336 break; 337 338 case SOT_FORMATSTR_ID_HTML_SIMPLE: 339 case SOT_FORMATSTR_ID_HTML: 340 nFmt = FORMAT_RTF; 341 break; 342 343 case FORMAT_GDIMETAFILE: 344 nFmt = FORMAT_BITMAP; 345 break; 346 347 case SOT_FORMATSTR_ID_SVXB: 348 nFmt = FORMAT_GDIMETAFILE; 349 break; 350 351 // sonst noch irgendwas ?? 352 } 353 if( nFmt ) 354 rReq.SetFormat( nFmt ); // damit nochmal versuchen 355 return 0 != nFmt; 356 } 357 358 sal_Bool SvDDEObject::IsPending() const 359 /* [Beschreibung] 360 361 Die Methode stellt fest, ob aus einem DDE-Object die Daten gelesen 362 werden kann. 363 Zurueckgegeben wird: 364 ERRCODE_NONE wenn sie komplett gelesen wurde 365 ERRCODE_SO_PENDING wenn sie noch nicht komplett gelesen wurde 366 ERRCODE_SO_FALSE sonst 367 */ 368 { 369 return bWaitForData; 370 } 371 372 sal_Bool SvDDEObject::IsDataComplete() const 373 { 374 return bWaitForData; 375 } 376 377 IMPL_LINK( SvDDEObject, ImplGetDDEData, DdeData*, pData ) 378 { 379 sal_uIntPtr nFmt = pData->GetFormat(); 380 switch( nFmt ) 381 { 382 case FORMAT_GDIMETAFILE: 383 break; 384 385 case FORMAT_BITMAP: 386 break; 387 388 default: 389 { 390 const sal_Char* p = (sal_Char*)( pData->operator const void*() ); 391 long nLen = FORMAT_STRING == nFmt ? (p ? strlen( p ) : 0) : (long)*pData; 392 393 Sequence< sal_Int8 > aSeq( (const sal_Int8*)p, nLen ); 394 if( pGetData ) 395 { 396 *pGetData <<= aSeq; // Daten kopieren 397 pGetData = 0; // und den Pointer bei mir zuruecksetzen 398 } 399 else 400 { 401 Any aVal; 402 aVal <<= aSeq; 403 DataChanged( SotExchange::GetFormatMimeType( 404 pData->GetFormat() ), aVal ); 405 bWaitForData = sal_False; 406 } 407 } 408 } 409 410 return 0; 411 } 412 413 IMPL_LINK( SvDDEObject, ImplDoneDDEData, void*, pData ) 414 { 415 sal_Bool bValid = (sal_Bool)(sal_uIntPtr)pData; 416 if( !bValid && ( pRequest || pLink )) 417 { 418 DdeTransaction* pReq = 0; 419 if( !pLink || ( pLink && pLink->IsBusy() )) 420 pReq = pRequest; // dann kann nur der fertig sein 421 else if( pRequest && pRequest->IsBusy() ) 422 pReq = pLink; // dann kann nur der fertig sein 423 424 if( pReq ) 425 { 426 if( ImplHasOtherFormat( *pReq ) ) 427 { 428 pReq->Execute(); 429 } 430 else if( pReq == pRequest ) 431 { 432 // das wars dann 433 bWaitForData = sal_False; 434 } 435 } 436 } 437 else 438 // das warten ist beendet 439 bWaitForData = sal_False; 440 441 return 0; 442 } 443 444 } 445