1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #include <svl/svdde.hxx>
25 #include <osl/thread.h>
26 #include <comphelper/solarmutex.hxx>
30 DdeInstData
* theDdeInstData
;
34 DdeInstData
* ImpGetInstData()
36 return theDdeInstData
;
39 DdeInstData
* ImpInitInstData()
41 theDdeInstData
= new DdeInstData
;
42 return theDdeInstData
;
45 void ImpDeinitInstData()
47 delete theDdeInstData
;
48 theDdeInstData
= nullptr;
58 HDDEDATA CALLBACK
DdeInternal::CliCallback( UINT nCode
, UINT nCbType
,
59 HCONV hConv
, HSZ
, HSZ hText2
,
60 HDDEDATA hData
, ULONG_PTR nInfo1
, ULONG_PTR
)
62 HDDEDATA nRet
= DDE_FNOTPROCESSED
;
63 const std::vector
<DdeConnection
*> &rAll
= DdeConnection::GetConnections();
64 DdeConnection
* self
= nullptr;
66 DdeInstData
* pInst
= ImpGetInstData();
69 for ( size_t i
= 0; i
< rAll
.size(); ++i
)
73 if ( self
->pImp
->hConv
== hConv
)
80 std::vector
<DdeTransaction
*>::iterator iter
;
81 for( iter
= self
->aTransactions
.begin(); iter
!= self
->aTransactions
.end(); ++iter
)
85 case XTYP_XACT_COMPLETE
:
86 if( static_cast<DWORD
>((*iter
)->nId
) == nInfo1
)
88 nCode
= (*iter
)->nType
& (XCLASS_MASK
| XTYP_MASK
);
89 (*iter
)->bBusy
= false;
90 (*iter
)->Done( nullptr != hData
);
96 self
->pImp
->hConv
= DdeReconnect( hConv
);
97 self
->pImp
->nStatus
= self
->pImp
->hConv
99 : DdeGetLastError( pInst
->hDdeInstCli
);
100 iter
= self
->aTransactions
.end();
106 bFound
= *(*iter
)->pName
== hText2
;
113 if( iter
!= self
->aTransactions
.end() )
120 static_cast<DdeLink
*>(*iter
)->Notify();
121 nRet
= reinterpret_cast<HDDEDATA
>(DDE_FACK
);
128 d
.xImp
->hData
= hData
;
129 d
.xImp
->nFmt
= DdeData::GetInternalFormat( nCbType
);
132 nRet
= reinterpret_cast<HDDEDATA
>(DDE_FACK
);
140 DdeConnection::DdeConnection( const OUString
& rService
, const OUString
& rTopic
):
141 pImp(std::make_unique
<DdeImp
>())
143 pImp
->nStatus
= DMLERR_NO_ERROR
;
144 pImp
->hConv
= nullptr;
146 DdeInstData
* pInst
= ImpGetInstData();
148 pInst
= ImpInitInstData();
150 pInst
->nInstanceCli
++;
151 if ( !pInst
->hDdeInstCli
)
153 pImp
->nStatus
= DdeInitializeW( &pInst
->hDdeInstCli
,
154 DdeInternal::CliCallback
,
155 APPCLASS_STANDARD
| APPCMD_CLIENTONLY
|
156 CBF_FAIL_ALLSVRXACTIONS
|
157 CBF_SKIP_REGISTRATIONS
|
158 CBF_SKIP_UNREGISTRATIONS
, 0L );
161 pService
= new DdeString( pInst
->hDdeInstCli
, rService
);
162 pTopic
= new DdeString( pInst
->hDdeInstCli
, rTopic
);
164 if ( pImp
->nStatus
== DMLERR_NO_ERROR
)
166 pImp
->hConv
= DdeConnect( pInst
->hDdeInstCli
,pService
->getHSZ(),pTopic
->getHSZ(), nullptr);
168 pImp
->nStatus
= DdeGetLastError( pInst
->hDdeInstCli
);
171 pInst
->aConnections
.push_back( this );
174 DdeConnection::~DdeConnection()
177 DdeDisconnect( pImp
->hConv
);
182 DdeInstData
* pInst
= ImpGetInstData();
185 std::vector
<DdeConnection
*>::iterator
it(std::find(pInst
->aConnections
.begin(),
186 pInst
->aConnections
.end(),
188 if (it
!= pInst
->aConnections
.end())
189 pInst
->aConnections
.erase(it
);
191 pInst
->nInstanceCli
--;
193 if ( !pInst
->nInstanceCli
&& pInst
->hDdeInstCli
)
195 if( DdeUninitialize( pInst
->hDdeInstCli
) )
197 pInst
->hDdeInstCli
= 0;
198 if( pInst
->nRefCount
== 0 )
204 bool DdeConnection::IsConnected()
208 if ( DdeQueryConvInfo( pImp
->hConv
, QID_SYNC
, &c
) )
212 DdeInstData
* pInst
= ImpGetInstData();
213 pImp
->hConv
= DdeReconnect( pImp
->hConv
);
214 pImp
->nStatus
= pImp
->hConv
? DMLERR_NO_ERROR
: DdeGetLastError( pInst
->hDdeInstCli
);
215 return pImp
->nStatus
== DMLERR_NO_ERROR
;
219 OUString
DdeConnection::GetServiceName() const
221 return pService
->toOUString();
224 OUString
DdeConnection::GetTopicName() const
226 return pTopic
->toOUString();
229 const std::vector
<DdeConnection
*>& DdeConnection::GetConnections()
231 DdeInstData
* pInst
= ImpGetInstData();
233 return pInst
->aConnections
;
236 DdeTransaction::DdeTransaction( DdeConnection
& d
, const OUString
& rItemName
,
240 DdeInstData
* pInst
= ImpGetInstData();
241 pName
= new DdeString( pInst
->hDdeInstCli
, rItemName
);
247 rDde
.aTransactions
.push_back( this );
250 DdeTransaction::~DdeTransaction()
252 if ( nId
&& rDde
.pImp
->hConv
)
254 DdeInstData
* pInst
= ImpGetInstData();
255 DdeAbandonTransaction( pInst
->hDdeInstCli
, rDde
.pImp
->hConv
, nId
);
259 rDde
.aTransactions
.erase(std::remove(rDde
.aTransactions
.begin(),
260 rDde
.aTransactions
.end(),this));
263 void DdeTransaction::Execute()
265 HSZ hItem
= pName
->getHSZ();
266 void const * pData
= aDdeData
.getData();
267 DWORD nData
= static_cast<DWORD
>(aDdeData
.getSize());
268 SotClipboardFormatId nIntFmt
= aDdeData
.xImp
->nFmt
;
269 UINT nExtFmt
= DdeData::GetExternalFormat( nIntFmt
);
270 DdeInstData
* pInst
= ImpGetInstData();
272 if ( nType
== XTYP_EXECUTE
)
274 if ( nType
!= XTYP_EXECUTE
&& nType
!= XTYP_POKE
)
281 HDDEDATA hData
= DdeClientTransaction( static_cast<LPBYTE
>(const_cast<void *>(pData
)),
282 nData
, rDde
.pImp
->hConv
,
283 hItem
, nExtFmt
, static_cast<UINT
>(nType
),
284 static_cast<DWORD
>(nTime
), nullptr );
286 rDde
.pImp
->nStatus
= DdeGetLastError( pInst
->hDdeInstCli
);
287 if( hData
&& nType
== XTYP_REQUEST
)
291 d
.xImp
->hData
= hData
;
292 d
.xImp
->nFmt
= nIntFmt
;
296 DdeFreeDataHandle( hData
);
301 if ( nId
&& rDde
.pImp
->hConv
)
302 DdeAbandonTransaction( pInst
->hDdeInstCli
, rDde
.pImp
->hConv
, nId
);
306 HDDEDATA hRet
= DdeClientTransaction( static_cast<LPBYTE
>(const_cast<void *>(pData
)), nData
,
307 rDde
.pImp
->hConv
, hItem
, nExtFmt
,
308 static_cast<UINT
>(nType
), TIMEOUT_ASYNC
,
311 rDde
.pImp
->nStatus
= hRet
? DMLERR_NO_ERROR
312 : DdeGetLastError( pInst
->hDdeInstCli
);
316 OUString
DdeTransaction::GetName() const
318 return pName
->toOUString();
321 void DdeTransaction::Data( const DdeData
* p
)
323 comphelper::SolarMutex
*pSolarMutex
= comphelper::SolarMutex::get();
326 pSolarMutex
->acquire();
328 pSolarMutex
= comphelper::SolarMutex::get();
330 pSolarMutex
->release();
334 void DdeTransaction::Done( bool bDataValid
)
336 aDone
.Call( bDataValid
);
339 DdeLink::DdeLink( DdeConnection
& d
, const OUString
& aItemName
, tools::Long n
)
340 : DdeTransaction (d
, aItemName
, n
)
346 nType
= sal_uInt16(XTYP_ADVSTOP
);
350 void DdeLink::Notify()
352 aNotify
.Call( nullptr );
355 DdeRequest::DdeRequest( DdeConnection
& d
, const OUString
& i
, tools::Long n
)
356 : DdeTransaction( d
, i
, n
)
358 nType
= XTYP_REQUEST
;
361 DdeHotLink::DdeHotLink( DdeConnection
& d
, const OUString
& i
)
364 nType
= XTYP_ADVSTART
;
367 DdePoke::DdePoke( DdeConnection
& d
, const OUString
& i
, const DdeData
& rData
,
369 : DdeTransaction( d
, i
, n
)
375 DdeExecute::DdeExecute( DdeConnection
& d
, const OUString
& rData
, tools::Long n
)
376 : DdeTransaction( d
, OUString(), n
)
378 aDdeData
= DdeData( rData
.getStr(), sizeof(sal_Unicode
) * (rData
.getLength() + 1), SotClipboardFormatId::STRING
);
379 nType
= XTYP_EXECUTE
;
382 tools::Long
DdeConnection::GetError() const
384 return pImp
->nStatus
;
387 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */