LibreOffice Module svl (master) 1
ddecli.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <string.h>
22#include <algorithm>
23#include "ddeimp.hxx"
24#include <svl/svdde.hxx>
25#include <osl/thread.h>
27
28namespace {
29
30DdeInstData * theDdeInstData;
31
32}
33
35{
36 return theDdeInstData;
37}
38
40{
41 theDdeInstData = new DdeInstData;
42 return theDdeInstData;
43}
44
46{
47 delete theDdeInstData;
48 theDdeInstData = nullptr;
49}
50
51
52struct DdeImp
53{
55 UINT nStatus;
56};
57
58HDDEDATA CALLBACK DdeInternal::CliCallback( UINT nCode, UINT nCbType,
59 HCONV hConv, HSZ, HSZ hText2,
60 HDDEDATA hData, ULONG_PTR nInfo1, ULONG_PTR )
61{
62 HDDEDATA nRet = DDE_FNOTPROCESSED;
63 const std::vector<DdeConnection*> &rAll = DdeConnection::GetConnections();
64 DdeConnection* self = nullptr;
65
66 DdeInstData* pInst = ImpGetInstData();
67 assert(pInst);
68
69 for ( size_t i = 0; i < rAll.size(); ++i)
70 {
71 self = rAll[i];
72
73 if ( self->pImp->hConv == hConv )
74 break;
75 }
76
77 if( self )
78 {
79 bool bFound = false;
80 std::vector<DdeTransaction*>::iterator iter;
81 for( iter = self->aTransactions.begin(); iter != self->aTransactions.end(); ++iter )
82 {
83 switch( nCode )
84 {
85 case XTYP_XACT_COMPLETE:
86 if( static_cast<DWORD>((*iter)->nId) == nInfo1 )
87 {
88 nCode = (*iter)->nType & (XCLASS_MASK | XTYP_MASK);
89 (*iter)->bBusy = false;
90 (*iter)->Done( nullptr != hData );
91 bFound = true;
92 }
93 break;
94
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;
104
105 case XTYP_ADVDATA:
106 bFound = *(*iter)->pName == hText2;
107 break;
108 }
109 if( bFound )
110 break;
111 }
112
113 if( iter != self->aTransactions.end() )
114 {
115 switch( nCode )
116 {
117 case XTYP_ADVDATA:
118 if( !hData )
119 {
120 static_cast<DdeLink*>(*iter)->Notify();
121 nRet = reinterpret_cast<HDDEDATA>(DDE_FACK);
122 break;
123 }
124 [[fallthrough]];
125
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;
134 }
135 }
136 }
137 return nRet;
138}
139
140DdeConnection::DdeConnection( const OUString& rService, const OUString& rTopic ):
141 pImp(std::make_unique<DdeImp>())
142{
143 pImp->nStatus = DMLERR_NO_ERROR;
144 pImp->hConv = nullptr;
145
146 DdeInstData* pInst = ImpGetInstData();
147 if( !pInst )
148 pInst = ImpInitInstData();
149 pInst->nRefCount++;
150 pInst->nInstanceCli++;
151 if ( !pInst->hDdeInstCli )
152 {
153 pImp->nStatus = DdeInitializeW( &pInst->hDdeInstCli,
155 APPCLASS_STANDARD | APPCMD_CLIENTONLY |
156 CBF_FAIL_ALLSVRXACTIONS |
157 CBF_SKIP_REGISTRATIONS |
158 CBF_SKIP_UNREGISTRATIONS, 0L );
159 }
160
161 pService = new DdeString( pInst->hDdeInstCli, rService );
162 pTopic = new DdeString( pInst->hDdeInstCli, rTopic );
163
164 if ( pImp->nStatus == DMLERR_NO_ERROR )
165 {
166 pImp->hConv = DdeConnect( pInst->hDdeInstCli,pService->getHSZ(),pTopic->getHSZ(), nullptr);
167 if( !pImp->hConv )
168 pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
169 }
170
171 pInst->aConnections.push_back( this );
172}
173
175{
176 if ( pImp->hConv )
177 DdeDisconnect( pImp->hConv );
178
179 delete pService;
180 delete pTopic;
181
182 DdeInstData* pInst = ImpGetInstData();
183 assert(pInst);
184
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);
190
191 pInst->nInstanceCli--;
192 pInst->nRefCount--;
193 if ( !pInst->nInstanceCli && pInst->hDdeInstCli )
194 {
195 if( DdeUninitialize( pInst->hDdeInstCli ) )
196 {
197 pInst->hDdeInstCli = 0;
198 if( pInst->nRefCount == 0 )
200 }
201 }
202}
203
205{
206 CONVINFO c;
207 c.cb = sizeof( c );
208 if ( DdeQueryConvInfo( pImp->hConv, QID_SYNC, &c ) )
209 return true;
210 else
211 {
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;
216 }
217}
218
220{
221 return pService->toOUString();
222}
223
225{
226 return pTopic->toOUString();
227}
228
229const std::vector<DdeConnection*>& DdeConnection::GetConnections()
230{
231 DdeInstData* pInst = ImpGetInstData();
232 assert(pInst);
233 return pInst->aConnections;
234}
235
236DdeTransaction::DdeTransaction( DdeConnection& d, const OUString& rItemName,
237 tools::Long n )
238 : rDde( d )
239{
240 DdeInstData* pInst = ImpGetInstData();
241 pName = new DdeString( pInst->hDdeInstCli, rItemName );
242 nTime = n;
243 nId = 0;
244 nType = 0;
245 bBusy = false;
246
247 rDde.aTransactions.push_back( this );
248}
249
251{
252 if ( nId && rDde.pImp->hConv )
253 {
254 DdeInstData* pInst = ImpGetInstData();
255 DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId );
256 }
257
258 delete pName;
259 rDde.aTransactions.erase(std::remove(rDde.aTransactions.begin(),
260 rDde.aTransactions.end(),this));
261}
262
264{
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();
271
272 if ( nType == XTYP_EXECUTE )
273 hItem = nullptr;
274 if ( nType != XTYP_EXECUTE && nType != XTYP_POKE )
275 {
276 pData = nullptr;
277 nData = 0;
278 }
279 if ( nTime )
280 {
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 );
285
286 rDde.pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
287 if( hData && nType == XTYP_REQUEST )
288 {
289 {
290 DdeData d;
291 d.xImp->hData = hData;
292 d.xImp->nFmt = nIntFmt;
293 d.Lock();
294 Data( &d );
295 }
296 DdeFreeDataHandle( hData );
297 }
298 }
299 else
300 {
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 );
313 }
314}
315
317{
318 return pName->toOUString();
319}
320
322{
324 if ( pSolarMutex )
325 {
326 pSolarMutex->acquire();
327 aData.Call( p );
328 pSolarMutex = comphelper::SolarMutex::get();
329 if ( pSolarMutex )
330 pSolarMutex->release();
331 }
332}
333
334void DdeTransaction::Done( bool bDataValid )
335{
336 aDone.Call( bDataValid );
337}
338
339DdeLink::DdeLink( DdeConnection& d, const OUString& aItemName, tools::Long n )
340 : DdeTransaction (d, aItemName, n)
341{
342}
343
345{
346 nType = sal_uInt16(XTYP_ADVSTOP);
347 nTime = 0;
348}
349
351{
352 aNotify.Call( nullptr );
353}
354
356 : DdeTransaction( d, i, n )
357{
358 nType = XTYP_REQUEST;
359}
360
361DdeHotLink::DdeHotLink( DdeConnection& d, const OUString& i )
362 : DdeLink( d, i, 0 )
363{
364 nType = XTYP_ADVSTART;
365}
366
367DdePoke::DdePoke( DdeConnection& d, const OUString& i, const DdeData& rData,
368 tools::Long n )
369 : DdeTransaction( d, i, n )
370{
371 aDdeData = rData;
372 nType = XTYP_POKE;
373}
374
375DdeExecute::DdeExecute( DdeConnection& d, const OUString& rData, tools::Long n )
376 : DdeTransaction( d, OUString(), n )
377{
378 aDdeData = DdeData( rData.getStr(), sizeof(sal_Unicode) * (rData.getLength() + 1), SotClipboardFormatId::STRING );
379 nType = XTYP_EXECUTE;
380}
381
383{
384 return pImp->nStatus;
385}
386
387/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const char * pName
double d
bool IsConnected()
Definition: ddecli.cxx:204
tools::Long GetError() const
Definition: ddecli.cxx:382
OUString GetTopicName() const
Definition: ddecli.cxx:224
DdeString * pTopic
Definition: svdde.hxx:174
std::vector< DdeTransaction * > aTransactions
Definition: svdde.hxx:172
DdeString * pService
Definition: svdde.hxx:173
DdeConnection(SAL_UNUSED_PARAMETER const OUString &, SAL_UNUSED_PARAMETER const OUString &)
std::unique_ptr< DdeImp > pImp
Definition: svdde.hxx:175
static const std::vector< DdeConnection * > & GetConnections()
Definition: ddecli.cxx:229
OUString GetServiceName() const
Definition: ddecli.cxx:219
tools::Long getSize() const
Definition: ddedata.cxx:102
static SotClipboardFormatId GetInternalFormat(sal_uLong nFmt)
Definition: ddedata.cxx:144
static sal_uInt32 GetExternalFormat(SotClipboardFormatId nFmt)
Definition: ddedata.cxx:124
void const * getData() const
Definition: ddedata.cxx:97
std::unique_ptr< DdeDataImp > xImp
Definition: svdde.hxx:52
DdeExecute(DdeConnection &, const OUString &, tools::Long=0)
Definition: ddecli.cxx:375
std::vector< DdeConnection * > aConnections
Definition: ddeimp.hxx:89
sal_uInt16 nRefCount
Definition: ddeimp.hxx:88
short nInstanceCli
Definition: ddeimp.hxx:96
DWORD hDdeInstCli
Definition: ddeimp.hxx:95
static HDDEDATA CALLBACK CliCallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, ULONG_PTR, ULONG_PTR)
Definition: ddecli.cxx:58
DdePoke(DdeConnection &, const OUString &, SAL_UNUSED_PARAMETER const DdeData &, tools::Long=0)
Definition: ddecli.cxx:367
DdeRequest(DdeConnection &, const OUString &, tools::Long=0)
Definition: ddecli.cxx:355
HSZ getHSZ()
Definition: ddestrg.cxx:42
const OUString & toOUString() const
Definition: ddeimp.hxx:71
DdeTransaction(DdeConnection &, SAL_UNUSED_PARAMETER const OUString &, SAL_UNUSED_PARAMETER tools::Long=0)
short nType
Definition: svdde.hxx:88
Link< const DdeData *, void > aData
Definition: svdde.hxx:91
OUString GetName() const
Definition: ddecli.cxx:316
Link< bool, void > aDone
Definition: svdde.hxx:92
virtual ~DdeTransaction()
Definition: ddecli.cxx:250
void Execute()
Definition: ddecli.cxx:263
bool bBusy
Definition: svdde.hxx:93
DdeString * pName
Definition: svdde.hxx:87
void Done(bool bDataValid)
Definition: ddecli.cxx:334
sal_IntPtr nId
Definition: svdde.hxx:89
DdeData aDdeData
Definition: svdde.hxx:86
DdeConnection & rDde
Definition: svdde.hxx:85
sal_IntPtr nTime
Definition: svdde.hxx:90
void Data(const DdeData *)
Definition: ddecli.cxx:321
static SolarMutex * get()
sal_uInt32 release(bool bUnlockAll=false)
void acquire(sal_uInt32 nLockCount=1)
void ImpDeinitInstData()
Definition: ddecli.cxx:45
DdeInstData * ImpInitInstData()
Definition: ddecli.cxx:39
DdeInstData * ImpGetInstData()
Definition: ddecli.cxx:34
SotClipboardFormatId
void * p
sal_Int64 n
std::unique_ptr< sal_Int32[]> pData
int i
long Long
#define CALLBACK
sal_Int16 nId
#define HCONV(x)
QPRO_FUNC_TYPE nType
UINT nStatus
Definition: ddecli.cxx:55
HCONV hConv
Definition: ddecli.cxx:54
sal_uInt16 sal_Unicode
Any result