bump product version to 5.0.4.1
[LibreOffice.git] / svl / source / svdde / ddecli.cxx
blob860f7c65579b0adaa158adc1251df36af1bb996c
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 #define UNICODE
22 #include <string.h>
23 #include <algorithm>
24 #include "ddeimp.hxx"
25 #include <svl/svdde.hxx>
27 #include <osl/thread.h>
28 #include <tools/debug.hxx>
29 #include <tools/solarmutex.hxx>
30 #include <osl/mutex.hxx>
32 DdeInstData* ImpInitInstData()
34 DdeInstData* pData = new DdeInstData;
36 DdeInstData** ppInst = (DdeInstData**)GetAppData( SHL_SVDDE );
37 *ppInst = pData;
38 return pData;
41 void ImpDeinitInstData()
43 DdeInstData** ppInst = (DdeInstData**)GetAppData( SHL_SVDDE );
44 delete (*ppInst);
45 *ppInst = 0;
49 struct DdeImp
51 HCONV hConv;
52 long nStatus;
55 HDDEDATA CALLBACK DdeInternal::CliCallback( WORD nCode, WORD nCbType,
56 HCONV hConv, HSZ, HSZ hText2,
57 HDDEDATA hData, DWORD nInfo1, DWORD )
59 HDDEDATA nRet = DDE_FNOTPROCESSED;
60 const std::vector<DdeConnection*> &rAll = DdeConnection::GetConnections();
61 DdeConnection* self = 0;
63 DdeInstData* pInst = ImpGetInstData();
64 DBG_ASSERT(pInst,"SVDDE:No instance data");
66 for ( size_t i = 0; i < rAll.size(); ++i)
68 self = rAll[i];
70 if ( self->pImp->hConv == hConv )
71 break;
74 if( self )
76 bool bFound = false;
77 std::vector<DdeTransaction*>::iterator iter;
78 for( iter = self->aTransactions.begin(); iter != self->aTransactions.end(); ++iter )
80 switch( nCode )
82 case XTYP_XACT_COMPLETE:
83 if( (DWORD)(*iter)->nId == nInfo1 )
85 nCode = (*iter)->nType & (XCLASS_MASK | XTYP_MASK);
86 (*iter)->bBusy = false;
87 (*iter)->Done( 0 != hData );
88 bFound = true;
90 break;
92 case XTYP_DISCONNECT:
93 self->pImp->hConv = DdeReconnect( hConv );
94 self->pImp->nStatus = self->pImp->hConv
95 ? DMLERR_NO_ERROR
96 : DdeGetLastError( pInst->hDdeInstCli );
97 iter = self->aTransactions.end();
98 nRet = 0;
99 bFound = true;
100 break;
102 case XTYP_ADVDATA:
103 bFound = *(*iter)->pName == hText2;
104 break;
106 if( bFound )
107 break;
110 if( iter != self->aTransactions.end() )
112 switch( nCode )
114 case XTYP_ADVDATA:
115 if( !hData )
117 static_cast<DdeLink*>(*iter)->Notify();
118 nRet = (HDDEDATA)DDE_FACK;
119 break;
121 // no break
123 case XTYP_REQUEST:
124 if( !hData && XTYP_REQUEST == nCode )
129 DdeData d;
130 d.pImp->hData = hData;
131 d.pImp->nFmt = DdeData::GetInternalFormat( nCbType );
132 d.Lock();
133 (*iter)->Data( &d );
134 nRet = (HDDEDATA)DDE_FACK;
135 break;
139 return nRet;
142 DdeConnection::DdeConnection( const OUString& rService, const OUString& rTopic )
144 pImp = new DdeImp;
145 pImp->nStatus = DMLERR_NO_ERROR;
146 pImp->hConv = NULL;
148 DdeInstData* pInst = ImpGetInstData();
149 if( !pInst )
150 pInst = ImpInitInstData();
151 pInst->nRefCount++;
152 pInst->nInstanceCli++;
153 if ( !pInst->hDdeInstCli )
155 pImp->nStatus = DdeInitialize( &pInst->hDdeInstCli,
156 (PFNCALLBACK)DdeInternal::CliCallback,
157 APPCLASS_STANDARD | APPCMD_CLIENTONLY |
158 CBF_FAIL_ALLSVRXACTIONS |
159 CBF_SKIP_REGISTRATIONS |
160 CBF_SKIP_UNREGISTRATIONS, 0L );
163 pService = new DdeString( pInst->hDdeInstCli, rService );
164 pTopic = new DdeString( pInst->hDdeInstCli, rTopic );
166 if ( pImp->nStatus == DMLERR_NO_ERROR )
168 pImp->hConv = DdeConnect( pInst->hDdeInstCli,*pService,*pTopic, NULL);
169 if( !pImp->hConv )
170 pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
173 pInst->aConnections.push_back( this );
176 DdeConnection::~DdeConnection()
178 if ( pImp->hConv )
179 DdeDisconnect( pImp->hConv );
181 delete pService;
182 delete pTopic;
184 DdeInstData* pInst = ImpGetInstData();
185 DBG_ASSERT(pInst,"SVDDE:No instance data");
187 std::vector<DdeConnection*>::iterator it(std::find(pInst->aConnections.begin(),
188 pInst->aConnections.end(),
189 this));
190 if (it != pInst->aConnections.end())
191 pInst->aConnections.erase(it);
193 pInst->nInstanceCli--;
194 pInst->nRefCount--;
195 if ( !pInst->nInstanceCli && pInst->hDdeInstCli )
197 if( DdeUninitialize( pInst->hDdeInstCli ) )
199 pInst->hDdeInstCli = 0;
200 if( pInst->nRefCount == 0 )
201 ImpDeinitInstData();
204 delete pImp;
207 bool DdeConnection::IsConnected()
209 CONVINFO c;
210 c.cb = sizeof( c );
211 if ( DdeQueryConvInfo( pImp->hConv, QID_SYNC, &c ) )
212 return true;
213 else
215 DdeInstData* pInst = ImpGetInstData();
216 pImp->hConv = DdeReconnect( pImp->hConv );
217 pImp->nStatus = pImp->hConv ? DMLERR_NO_ERROR : DdeGetLastError( pInst->hDdeInstCli );
218 return pImp->nStatus == DMLERR_NO_ERROR;
222 const OUString DdeConnection::GetServiceName()
224 return pService->toOUString();
227 const OUString DdeConnection::GetTopicName()
229 return pTopic->toOUString();
232 sal_IntPtr DdeConnection::GetConvId()
234 return (sal_IntPtr)pImp->hConv;
237 const std::vector<DdeConnection*>& DdeConnection::GetConnections()
239 DdeInstData* pInst = ImpGetInstData();
240 DBG_ASSERT(pInst,"SVDDE:No instance data");
241 return pInst->aConnections;
244 DdeTransaction::DdeTransaction( DdeConnection& d, const OUString& rItemName,
245 long n )
246 : rDde( d )
248 DdeInstData* pInst = ImpGetInstData();
249 pName = new DdeString( pInst->hDdeInstCli, rItemName );
250 nTime = n;
251 nId = 0;
252 nType = 0;
253 bBusy = false;
255 rDde.aTransactions.push_back( this );
258 DdeTransaction::~DdeTransaction()
260 if ( nId && rDde.pImp->hConv )
262 DdeInstData* pInst = ImpGetInstData();
263 DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId );
266 delete pName;
267 rDde.aTransactions.erase(std::remove(rDde.aTransactions.begin(),
268 rDde.aTransactions.end(),this));
271 void DdeTransaction::Execute()
273 HSZ hItem = *pName;
274 void* pData = (void*)(const void *)aDdeData;
275 DWORD nData = (DWORD)(long)aDdeData;
276 SotClipboardFormatId nIntFmt = aDdeData.pImp->nFmt;
277 UINT nExtFmt = DdeData::GetExternalFormat( nIntFmt );
278 DdeInstData* pInst = ImpGetInstData();
280 if ( nType == XTYP_EXECUTE )
281 hItem = NULL;
282 if ( nType != XTYP_EXECUTE && nType != XTYP_POKE )
284 pData = NULL;
285 nData = 0L;
287 if ( nTime )
289 HDDEDATA hData = DdeClientTransaction( (unsigned char*)pData,
290 nData, rDde.pImp->hConv,
291 hItem, nExtFmt, (UINT)nType,
292 (DWORD)nTime, (DWORD FAR*)NULL );
294 rDde.pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
295 if( hData && nType == XTYP_REQUEST )
298 DdeData d;
299 d.pImp->hData = hData;
300 d.pImp->nFmt = nIntFmt;
301 d.Lock();
302 Data( &d );
304 DdeFreeDataHandle( hData );
307 else
309 if ( nId && rDde.pImp->hConv )
310 DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId);
311 nId = 0;
312 bBusy = true;
313 HDDEDATA hRet = DdeClientTransaction( (unsigned char*)pData, nData,
314 rDde.pImp->hConv, hItem, nExtFmt,
315 (UINT)nType, TIMEOUT_ASYNC,
316 (DWORD FAR *) ((long*) &nId) );
317 rDde.pImp->nStatus = hRet ? DMLERR_NO_ERROR
318 : DdeGetLastError( pInst->hDdeInstCli );
322 const OUString DdeTransaction::GetName() const
324 return pName->toOUString();
327 void DdeTransaction::Data( const DdeData* p )
329 if ( ::tools::SolarMutex::Acquire() )
331 aData.Call( (void*)p );
332 ::tools::SolarMutex::Release();
336 void DdeTransaction::Done( bool bDataValid )
338 const sal_uIntPtr nDataValid(bDataValid);
339 aDone.Call( reinterpret_cast<void*>(nDataValid) );
342 DdeLink::DdeLink( DdeConnection& d, const OUString& aItemName, long n )
343 : DdeTransaction (d, aItemName, n)
347 DdeLink::~DdeLink()
349 nType = (sal_uInt16)XTYP_ADVSTOP;
350 nTime = 0;
353 void DdeLink::Notify()
355 aNotify.Call( NULL );
358 DdeRequest::DdeRequest( DdeConnection& d, const OUString& i, long n )
359 : DdeTransaction( d, i, n )
361 nType = XTYP_REQUEST;
364 DdeWarmLink::DdeWarmLink( DdeConnection& d, const OUString& i, long n )
365 : DdeLink( d, i, n )
367 nType = XTYP_ADVSTART | XTYPF_NODATA;
370 DdeHotLink::DdeHotLink( DdeConnection& d, const OUString& i, long n )
371 : DdeLink( d, i, n )
373 nType = XTYP_ADVSTART;
376 DdePoke::DdePoke( DdeConnection& d, const OUString& i, const char* p,
377 long l, SotClipboardFormatId f, long n )
378 : DdeTransaction( d, i, n )
380 aDdeData = DdeData( p, l, f );
381 nType = XTYP_POKE;
384 DdePoke::DdePoke( DdeConnection& d, const OUString& i, const OUString& rData,
385 long n )
386 : DdeTransaction( d, i, n )
388 aDdeData = DdeData( (void*) rData.getStr(), sizeof(sal_Unicode) * (rData.getLength()), SotClipboardFormatId::STRING );
389 nType = XTYP_POKE;
392 DdePoke::DdePoke( DdeConnection& d, const OUString& i, const DdeData& rData,
393 long n )
394 : DdeTransaction( d, i, n )
396 aDdeData = rData;
397 nType = XTYP_POKE;
400 DdeExecute::DdeExecute( DdeConnection& d, const OUString& rData, long n )
401 : DdeTransaction( d, OUString(), n )
403 aDdeData = DdeData( (void*)rData.getStr(), sizeof(sal_Unicode) * (rData.getLength() + 1), SotClipboardFormatId::STRING );
404 nType = XTYP_EXECUTE;
407 long DdeConnection::GetError()
409 return pImp->nStatus;
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */