OInterfaceContainerHelper3 needs to be thread-safe
[LibreOffice.git] / svl / source / svdde / ddecli.cxx
bloba4d611e38741d25b2ce928b0eb5a58fa177d7a1c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <string.h>
22 #include <algorithm>
23 #include "ddeimp.hxx"
24 #include <svl/svdde.hxx>
25 #include <osl/thread.h>
26 #include <comphelper/solarmutex.hxx>
28 namespace {
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;
52 struct DdeImp
54 HCONV hConv;
55 long nStatus;
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();
67 assert(pInst);
69 for ( size_t i = 0; i < rAll.size(); ++i)
71 self = rAll[i];
73 if ( self->pImp->hConv == hConv )
74 break;
77 if( self )
79 bool bFound = false;
80 std::vector<DdeTransaction*>::iterator iter;
81 for( iter = self->aTransactions.begin(); iter != self->aTransactions.end(); ++iter )
83 switch( nCode )
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 );
91 bFound = true;
93 break;
95 case XTYP_DISCONNECT:
96 self->pImp->hConv = DdeReconnect( hConv );
97 self->pImp->nStatus = self->pImp->hConv
98 ? DMLERR_NO_ERROR
99 : DdeGetLastError( pInst->hDdeInstCli );
100 iter = self->aTransactions.end();
101 nRet = nullptr;
102 bFound = true;
103 break;
105 case XTYP_ADVDATA:
106 bFound = *(*iter)->pName == hText2;
107 break;
109 if( bFound )
110 break;
113 if( iter != self->aTransactions.end() )
115 switch( nCode )
117 case XTYP_ADVDATA:
118 if( !hData )
120 static_cast<DdeLink*>(*iter)->Notify();
121 nRet = reinterpret_cast<HDDEDATA>(DDE_FACK);
122 break;
124 [[fallthrough]];
126 case XTYP_REQUEST:
127 DdeData d;
128 d.xImp->hData = hData;
129 d.xImp->nFmt = DdeData::GetInternalFormat( nCbType );
130 d.Lock();
131 (*iter)->Data( &d );
132 nRet = reinterpret_cast<HDDEDATA>(DDE_FACK);
133 break;
137 return nRet;
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();
147 if( !pInst )
148 pInst = ImpInitInstData();
149 pInst->nRefCount++;
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);
167 if( !pImp->hConv )
168 pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
171 pInst->aConnections.push_back( this );
174 DdeConnection::~DdeConnection()
176 if ( pImp->hConv )
177 DdeDisconnect( pImp->hConv );
179 delete pService;
180 delete pTopic;
182 DdeInstData* pInst = ImpGetInstData();
183 assert(pInst);
185 std::vector<DdeConnection*>::iterator it(std::find(pInst->aConnections.begin(),
186 pInst->aConnections.end(),
187 this));
188 if (it != pInst->aConnections.end())
189 pInst->aConnections.erase(it);
191 pInst->nInstanceCli--;
192 pInst->nRefCount--;
193 if ( !pInst->nInstanceCli && pInst->hDdeInstCli )
195 if( DdeUninitialize( pInst->hDdeInstCli ) )
197 pInst->hDdeInstCli = 0;
198 if( pInst->nRefCount == 0 )
199 ImpDeinitInstData();
204 bool DdeConnection::IsConnected()
206 CONVINFO c;
207 c.cb = sizeof( c );
208 if ( DdeQueryConvInfo( pImp->hConv, QID_SYNC, &c ) )
209 return true;
210 else
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();
232 assert(pInst);
233 return pInst->aConnections;
236 DdeTransaction::DdeTransaction( DdeConnection& d, const OUString& rItemName,
237 tools::Long n )
238 : rDde( d )
240 DdeInstData* pInst = ImpGetInstData();
241 pName = new DdeString( pInst->hDdeInstCli, rItemName );
242 nTime = n;
243 nId = 0;
244 nType = 0;
245 bBusy = false;
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 );
258 delete pName;
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 )
273 hItem = nullptr;
274 if ( nType != XTYP_EXECUTE && nType != XTYP_POKE )
276 pData = nullptr;
277 nData = 0;
279 if ( nTime )
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 )
290 DdeData d;
291 d.xImp->hData = hData;
292 d.xImp->nFmt = nIntFmt;
293 d.Lock();
294 Data( &d );
296 DdeFreeDataHandle( hData );
299 else
301 if ( nId && rDde.pImp->hConv )
302 DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId);
303 nId = 0;
304 bBusy = true;
305 DWORD result;
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,
309 &result );
310 nId = result;
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();
324 if ( pSolarMutex )
326 pSolarMutex->acquire();
327 aData.Call( p );
328 pSolarMutex = comphelper::SolarMutex::get();
329 if ( pSolarMutex )
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)
344 DdeLink::~DdeLink()
346 nType = sal_uInt16(XTYP_ADVSTOP);
347 nTime = 0;
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 )
362 : DdeLink( d, i, 0 )
364 nType = XTYP_ADVSTART;
367 DdePoke::DdePoke( DdeConnection& d, const OUString& i, const DdeData& rData,
368 tools::Long n )
369 : DdeTransaction( d, i, n )
371 aDdeData = rData;
372 nType = XTYP_POKE;
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: */