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 bool bForbidden = bInWinExec; 259 // TODO: also check the security level 260 static const char* aBadServers[] = { "cmd" }; 261 for( int i = 0; i < sizeof(aBadServers)/sizeof(*aBadServers); ++i) 262 bForbidden |= (sServer.CompareIgnoreCaseToAscii( aBadServers[i]) == COMPARE_EQUAL); 263 264 // try to start the DDE server if it is not there 265 if( !bForbidden ) 266 { 267 ByteString aCmdLine( sServer, RTL_TEXTENCODING_ASCII_US ); 268 aCmdLine.Append( ".exe " ); 269 aCmdLine.Append( ByteString( sTopic, RTL_TEXTENCODING_ASCII_US ) ); 270 271 if( WinExec( aCmdLine.GetBuffer(), SW_SHOWMINIMIZED ) < 32 ) 272 nError = DDELINK_ERROR_APP; 273 else 274 { 275 sal_uInt16 i; 276 for( i=0; i<5; i++ ) 277 { 278 bInWinExec = sal_True; 279 Application::Reschedule(); 280 bInWinExec = sal_False; 281 282 delete pConnection; 283 pConnection = new DdeConnection( sServer, sTopic ); 284 if( !pConnection->GetError() ) 285 break; 286 } 287 288 if( i == 5 ) 289 { 290 nError = DDELINK_ERROR_APP; 291 } 292 } 293 } 294 else 295 #endif // WNT 296 { 297 nError = DDELINK_ERROR_APP; 298 } 299 } 300 301 if( LINKUPDATE_ALWAYS == nLinkType && !pLink && !pConnection->GetError() ) 302 { 303 // Hot Link einrichten, Daten kommen irgendwann spaeter 304 pLink = new DdeHotLink( *pConnection, sItem ); 305 pLink->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) ); 306 pLink->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) ); 307 pLink->SetFormat( pSvLink->GetContentType() ); 308 pLink->Execute(); 309 } 310 311 if( pConnection->GetError() ) 312 return sal_False; 313 314 AddDataAdvise( pSvLink, 315 SotExchange::GetFormatMimeType( pSvLink->GetContentType()), 316 LINKUPDATE_ONCALL == nLinkType 317 ? ADVISEMODE_ONLYONCE 318 : 0 ); 319 AddConnectAdvise( pSvLink ); 320 SetUpdateTimeout( 0 ); 321 return sal_True; 322 } 323 324 void SvDDEObject::Edit( Window* pParent, sfx2::SvBaseLink* pBaseLink, const Link& rEndEditHdl ) 325 { 326 SvDDELinkEditDialog aDlg( pParent, pBaseLink ); 327 if ( RET_OK == aDlg.Execute() && rEndEditHdl.IsSet() ) 328 { 329 String sCommand = aDlg.GetCmd(); 330 rEndEditHdl.Call( &sCommand ); 331 } 332 } 333 334 sal_Bool SvDDEObject::ImplHasOtherFormat( DdeTransaction& rReq ) 335 { 336 sal_uInt16 nFmt = 0; 337 switch( rReq.GetFormat() ) 338 { 339 case FORMAT_RTF: 340 nFmt = FORMAT_STRING; 341 break; 342 343 case SOT_FORMATSTR_ID_HTML_SIMPLE: 344 case SOT_FORMATSTR_ID_HTML: 345 nFmt = FORMAT_RTF; 346 break; 347 348 case FORMAT_GDIMETAFILE: 349 nFmt = FORMAT_BITMAP; 350 break; 351 352 case SOT_FORMATSTR_ID_SVXB: 353 nFmt = FORMAT_GDIMETAFILE; 354 break; 355 356 // sonst noch irgendwas ?? 357 } 358 if( nFmt ) 359 rReq.SetFormat( nFmt ); // damit nochmal versuchen 360 return 0 != nFmt; 361 } 362 363 sal_Bool SvDDEObject::IsPending() const 364 /* [Beschreibung] 365 366 Die Methode stellt fest, ob aus einem DDE-Object die Daten gelesen 367 werden kann. 368 Zurueckgegeben wird: 369 ERRCODE_NONE wenn sie komplett gelesen wurde 370 ERRCODE_SO_PENDING wenn sie noch nicht komplett gelesen wurde 371 ERRCODE_SO_FALSE sonst 372 */ 373 { 374 return bWaitForData; 375 } 376 377 sal_Bool SvDDEObject::IsDataComplete() const 378 { 379 return bWaitForData; 380 } 381 382 IMPL_LINK( SvDDEObject, ImplGetDDEData, DdeData*, pData ) 383 { 384 sal_uIntPtr nFmt = pData->GetFormat(); 385 switch( nFmt ) 386 { 387 case FORMAT_GDIMETAFILE: 388 break; 389 390 case FORMAT_BITMAP: 391 break; 392 393 default: 394 { 395 const sal_Char* p = (sal_Char*)( pData->operator const void*() ); 396 long nLen = FORMAT_STRING == nFmt ? (p ? strlen( p ) : 0) : (long)*pData; 397 398 Sequence< sal_Int8 > aSeq( (const sal_Int8*)p, nLen ); 399 if( pGetData ) 400 { 401 *pGetData <<= aSeq; // Daten kopieren 402 pGetData = 0; // und den Pointer bei mir zuruecksetzen 403 } 404 else 405 { 406 Any aVal; 407 aVal <<= aSeq; 408 DataChanged( SotExchange::GetFormatMimeType( 409 pData->GetFormat() ), aVal ); 410 bWaitForData = sal_False; 411 } 412 } 413 } 414 415 return 0; 416 } 417 418 IMPL_LINK( SvDDEObject, ImplDoneDDEData, void*, pData ) 419 { 420 sal_Bool bValid = (sal_Bool)(sal_uIntPtr)pData; 421 if( !bValid && ( pRequest || pLink )) 422 { 423 DdeTransaction* pReq = 0; 424 if( !pLink || ( pLink && pLink->IsBusy() )) 425 pReq = pRequest; // dann kann nur der fertig sein 426 else if( pRequest && pRequest->IsBusy() ) 427 pReq = pLink; // dann kann nur der fertig sein 428 429 if( pReq ) 430 { 431 if( ImplHasOtherFormat( *pReq ) ) 432 { 433 pReq->Execute(); 434 } 435 else if( pReq == pRequest ) 436 { 437 // das wars dann 438 bWaitForData = sal_False; 439 } 440 } 441 } 442 else 443 // das warten ist beendet 444 bWaitForData = sal_False; 445 446 return 0; 447 } 448 449 } 450