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 .
20 #include "sal/config.h"
33 #include "basic/sbx.hxx"
34 #include "basic/sbxvar.hxx"
35 #include "runtime.hxx"
36 #include "osl/thread.h"
37 #include "rtl/ref.hxx"
38 #include "rtl/string.hxx"
39 #include "rtl/ustring.hxx"
40 #include "salhelper/simplereferenceobject.hxx"
47 using namespace css::uno
;
51 Missing support for functions returning structs (see TODO in call()).
53 Missing support for additional data types (64 bit integers, Any, ...; would
54 trigger OSL_ASSERT(false) in various switches).
56 It is assumed that the variables passed into SbiDllMgr::Call to represent
57 the arguments and return value have types that exactly match the Declare
58 statement; it would be better if this code had access to the function
59 signature from the Declare statement, so that it could convert the passed
60 variables accordingly.
65 int __stdcall
DllMgr_call32(FARPROC
, void const * stack
, std::size_t size
);
66 double __stdcall
DllMgr_callFp(FARPROC
, void const * stack
, std::size_t size
);
72 char * address(std::vector
< char > & blob
) {
73 return blob
.empty() ? 0 : &blob
[0];
76 SbError
convert(OUString
const & source
, OString
* target
) {
78 source
.convertToString(
79 target
, osl_getThreadTextEncoding(),
80 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
81 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
))
82 ? ERRCODE_NONE
: ERRCODE_BASIC_BAD_ARGUMENT
;
83 //TODO: more specific errcode?
86 SbError
convert(char const * source
, sal_Int32 length
, OUString
* target
) {
88 rtl_convertStringToUString(
89 &target
->pData
, source
, length
, osl_getThreadTextEncoding(),
90 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
91 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
92 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
))
93 ? ERRCODE_NONE
: ERRCODE_BASIC_BAD_ARGUMENT
;
94 //TODO: more specific errcode?
97 struct UnmarshalData
{
98 UnmarshalData(SbxVariable
* theVariable
, void * theBuffer
):
99 variable(theVariable
), buffer(theBuffer
) {}
101 SbxVariable
* variable
;
105 struct StringData
: public UnmarshalData
{
106 StringData(SbxVariable
* theVariable
, void * theBuffer
, bool theSpecial
):
107 UnmarshalData(theVariable
, theBuffer
), special(theSpecial
) {}
112 class MarshalData
: private boost::noncopyable
{
114 std::vector
< char > * newBlob() {
115 blobs_
.push_front(std::vector
< char >());
116 return &blobs_
.front();
119 std::vector
< UnmarshalData
> unmarshal
;
121 std::vector
< StringData
> unmarshalStrings
;
124 std::list
< std::vector
< char > > blobs_
;
127 std::size_t align(std::size_t address
, std::size_t alignment
) {
128 // alignment = 2^k for some k >= 0
129 return (address
+ (alignment
- 1)) & ~(alignment
- 1);
133 std::vector
< char > & blob
, std::size_t alignment
, std::size_t offset
,
136 std::vector
< char >::size_type n
= blob
.size();
137 n
= align(n
- offset
, alignment
) + offset
; //TODO: overflow in align()
138 blob
.resize(n
+ add
); //TODO: overflow
139 return address(blob
) + n
;
142 template< typename T
> void add(
143 std::vector
< char > & blob
, T
const & data
, std::size_t alignment
,
146 *reinterpret_cast< T
* >(align(blob
, alignment
, offset
, sizeof (T
))) = data
;
149 std::size_t alignment(SbxVariable
* variable
) {
150 OSL_ASSERT(variable
!= 0);
151 if ((variable
->GetType() & SbxARRAY
) == 0) {
152 switch (variable
->GetType()) {
164 SbxArray
* props
= PTR_CAST(SbxObject
, variable
->GetObject())->
166 for (sal_uInt16 i
= 0; i
< props
->Count(); ++i
) {
167 n
= std::max(n
, alignment(props
->Get(i
)));
179 SbxDimArray
* arr
= PTR_CAST(SbxDimArray
, variable
->GetObject());
180 int dims
= arr
->GetDims();
181 std::vector
< sal_Int32
> low(dims
);
182 for (int i
= 0; i
< dims
; ++i
) {
184 arr
->GetDim32(i
+ 1, low
[i
], up
);
186 return alignment(arr
->Get32(&low
[0]));
191 bool outer
, SbxVariable
* variable
, bool special
,
192 std::vector
< char > & blob
, std::size_t offset
, MarshalData
& data
);
194 SbError
marshalString(
195 SbxVariable
* variable
, bool special
, MarshalData
& data
, void ** buffer
)
197 OSL_ASSERT(variable
!= 0 && buffer
!= 0);
199 SbError e
= convert(variable
->GetOUString(), &str
);
200 if (e
!= ERRCODE_NONE
) {
203 std::vector
< char > * blob
= data
.newBlob();
205 blob
->begin(), str
.getStr(), str
.getStr() + str
.getLength() + 1);
206 *buffer
= address(*blob
);
207 data
.unmarshalStrings
.push_back(StringData(variable
, *buffer
, special
));
211 SbError
marshalStruct(
212 SbxVariable
* variable
, std::vector
< char > & blob
, std::size_t offset
,
215 OSL_ASSERT(variable
!= 0);
216 SbxArray
* props
= PTR_CAST(SbxObject
, variable
->GetObject())->
218 for (sal_uInt16 i
= 0; i
< props
->Count(); ++i
) {
219 SbError e
= marshal(false, props
->Get(i
), false, blob
, offset
, data
);
220 if (e
!= ERRCODE_NONE
) {
227 SbError
marshalArray(
228 SbxVariable
* variable
, std::vector
< char > & blob
, std::size_t offset
,
231 OSL_ASSERT(variable
!= 0);
232 SbxDimArray
* arr
= PTR_CAST(SbxDimArray
, variable
->GetObject());
233 int dims
= arr
->GetDims();
234 std::vector
< sal_Int32
> low(dims
);
235 std::vector
< sal_Int32
> up(dims
);
236 for (int i
= 0; i
< dims
; ++i
) {
237 arr
->GetDim32(i
+ 1, low
[i
], up
[i
]);
239 for (std::vector
< sal_Int32
> idx
= low
;;) {
241 false, arr
->Get32(&idx
[0]), false, blob
, offset
, data
);
242 if (e
!= ERRCODE_NONE
) {
246 while (idx
[i
] == up
[i
]) {
257 // 8-aligned structs are only 4-aligned on stack, so alignment of members in
258 // such structs must take that into account via "offset"
260 bool outer
, SbxVariable
* variable
, bool special
,
261 std::vector
< char > & blob
, std::size_t offset
, MarshalData
& data
)
263 OSL_ASSERT(variable
!= 0);
265 SbxDataType eVarType
= variable
->GetType();
266 bool bByVal
= (variable
->GetFlags() & SBX_REFERENCE
) == 0;
267 if( !bByVal
&& !SbiRuntime::isVBAEnabled() && eVarType
== SbxSTRING
)
271 if ((eVarType
& SbxARRAY
) == 0) {
274 add(blob
, variable
->GetInteger(), outer
? 4 : 2, offset
);
277 add(blob
, variable
->GetLong(), 4, offset
);
280 add(blob
, variable
->GetSingle(), 4, offset
);
283 add(blob
, variable
->GetDouble(), outer
? 4 : 8, offset
);
288 SbError e
= marshalString(variable
, special
, data
, &p
);
289 if (e
!= ERRCODE_NONE
) {
292 add(blob
, p
, 4, offset
);
297 align(blob
, outer
? 4 : alignment(variable
), offset
, 0);
298 SbError e
= marshalStruct(variable
, blob
, offset
, data
);
299 if (e
!= ERRCODE_NONE
) {
305 add(blob
, variable
->GetBool(), outer
? 4 : 1, offset
);
308 add(blob
, variable
->GetByte(), outer
? 4 : 1, offset
);
315 SbError e
= marshalArray(variable
, blob
, offset
, data
);
316 if (e
!= ERRCODE_NONE
) {
321 if ((eVarType
& SbxARRAY
) == 0) {
329 add(blob
, variable
->data(), 4, offset
);
333 std::vector
< char > * blob2
= data
.newBlob();
335 SbError e
= marshalString(variable
, special
, data
, &p
);
336 if (e
!= ERRCODE_NONE
) {
339 add(*blob2
, p
, 4, 0);
340 add(blob
, address(*blob2
), 4, offset
);
345 std::vector
< char > * blob2
= data
.newBlob();
346 SbError e
= marshalStruct(variable
, *blob2
, 0, data
);
347 if (e
!= ERRCODE_NONE
) {
350 void * p
= address(*blob2
);
352 data
.unmarshal
.push_back(UnmarshalData(variable
, p
));
354 add(blob
, p
, 4, offset
);
362 std::vector
< char > * blob2
= data
.newBlob();
363 SbError e
= marshalArray(variable
, *blob2
, 0, data
);
364 if (e
!= ERRCODE_NONE
) {
367 void * p
= address(*blob2
);
369 data
.unmarshal
.push_back(UnmarshalData(variable
, p
));
371 add(blob
, p
, 4, offset
);
377 template< typename T
> T
read(void const ** pointer
) {
378 T
const * p
= static_cast< T
const * >(*pointer
);
379 *pointer
= static_cast< void const * >(p
+ 1);
383 void const * unmarshal(SbxVariable
* variable
, void const * data
) {
384 OSL_ASSERT(variable
!= 0);
385 if ((variable
->GetType() & SbxARRAY
) == 0) {
386 switch (variable
->GetType()) {
388 variable
->PutInteger(read
< sal_Int16
>(&data
));
391 variable
->PutLong(read
< sal_Int32
>(&data
));
394 variable
->PutSingle(read
< float >(&data
));
397 variable
->PutDouble(read
< double >(&data
));
400 read
< char * >(&data
); // handled by unmarshalString
404 data
= reinterpret_cast< void const * >(
406 reinterpret_cast< sal_uIntPtr
>(data
),
407 alignment(variable
)));
408 SbxArray
* props
= PTR_CAST(SbxObject
, variable
->GetObject())->
410 for (sal_uInt16 i
= 0; i
< props
->Count(); ++i
) {
411 data
= unmarshal(props
->Get(i
), data
);
416 variable
->PutBool(read
< sal_Bool
>(&data
));
419 variable
->PutByte(read
< sal_uInt8
>(&data
));
426 SbxDimArray
* arr
= PTR_CAST(SbxDimArray
, variable
->GetObject());
427 int dims
= arr
->GetDims();
428 std::vector
< sal_Int32
> low(dims
);
429 std::vector
< sal_Int32
> up(dims
);
430 for (int i
= 0; i
< dims
; ++i
) {
431 arr
->GetDim32(i
+ 1, low
[i
], up
[i
]);
433 for (std::vector
< sal_Int32
> idx
= low
;;) {
434 data
= unmarshal(arr
->Get32(&idx
[0]), data
);
436 while (idx
[i
] == up
[i
]) {
450 SbError
unmarshalString(StringData
const & data
, SbxVariable
& result
) {
452 if (data
.buffer
!= 0) {
453 char const * p
= static_cast< char const * >(data
.buffer
);
456 len
= static_cast< sal_Int32
>(result
.GetULong());
457 if (len
< 0) { // i.e., DWORD result >= 2^31
458 return ERRCODE_BASIC_BAD_ARGUMENT
;
459 //TODO: more specific errcode?
462 len
= rtl_str_getLength(p
);
464 SbError e
= convert(p
, len
, &str
);
465 if (e
!= ERRCODE_NONE
) {
469 data
.variable
->PutString(str
);
479 OUString
const & dll
, ProcData
const & proc
, SbxArray
* arguments
,
480 SbxVariable
& result
)
482 std::vector
< char > stack
;
484 // For DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
485 // from kernel32, upon return, filled lpBuffer length is result DWORD, which
486 // requires special handling in unmarshalString; other functions might
487 // require similar treatment, too:
488 bool special
= dll
.equalsIgnoreAsciiCase("KERNEL32.DLL") &&
489 (proc
.name
== OString("GetLogicalDriveStringsA"));
490 for (sal_uInt16 i
= 1; i
< (arguments
== 0 ? 0 : arguments
->Count()); ++i
) {
492 true, arguments
->Get(i
), special
&& i
== 2, stack
, stack
.size(),
494 if (e
!= ERRCODE_NONE
) {
497 align(stack
, 4, 0, 0);
499 switch (result
.GetType()) {
501 DllMgr_call32(proc
.proc
, address(stack
), stack
.size());
505 static_cast< sal_Int16
>(
506 DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
510 static_cast< sal_Int32
>(
511 DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
515 static_cast< float >(
516 DllMgr_callFp(proc
.proc
, address(stack
), stack
.size())));
520 DllMgr_callFp(proc
.proc
, address(stack
), stack
.size()));
524 char const * s1
= reinterpret_cast< char const * >(
525 DllMgr_call32(proc
.proc
, address(stack
), stack
.size()));
527 SbError e
= convert(s1
, rtl_str_getLength(s1
), &s2
);
528 if (e
!= ERRCODE_NONE
) {
531 result
.PutString(s2
);
536 DllMgr_call32(proc
.proc
, address(stack
), stack
.size());
540 static_cast< sal_Bool
>(
541 DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
545 static_cast< sal_uInt8
>(
546 DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
552 for (sal_uInt16 i
= 1; i
< (arguments
== 0 ? 0 : arguments
->Count()); ++i
) {
553 arguments
->Get(i
)->ResetFlag(SBX_REFERENCE
);
554 //TODO: skipped for errors?!?
556 for (std::vector
< UnmarshalData
>::iterator
i(data
.unmarshal
.begin());
557 i
!= data
.unmarshal
.end(); ++i
)
559 unmarshal(i
->variable
, i
->buffer
);
561 for (std::vector
< StringData
>::iterator
i(data
.unmarshalStrings
.begin());
562 i
!= data
.unmarshalStrings
.end(); ++i
)
564 SbError e
= unmarshalString(*i
, result
);
565 if (e
!= ERRCODE_NONE
) {
572 SbError
getProcData(HMODULE handle
, OUString
const & name
, ProcData
* proc
)
574 OSL_ASSERT(proc
!= 0);
575 if (name
.getLength() != 0 && name
[0] == '@') { //TODO: "@" vs. "#"???
576 sal_Int32 n
= name
.copy(1).toInt32(); //TODO: handle bad input
577 if (n
<= 0 || n
> 0xFFFF) {
578 return ERRCODE_BASIC_BAD_ARGUMENT
; //TODO: more specific errcode?
580 FARPROC p
= GetProcAddress(handle
, reinterpret_cast< LPCSTR
>(n
));
582 proc
->name
= OString("#") + OString::valueOf(n
);
588 SbError e
= convert(name
, &name8
);
589 if (e
!= ERRCODE_NONE
) {
592 FARPROC p
= GetProcAddress(handle
, name8
.getStr());
598 sal_Int32 i
= name8
.indexOf('#');
600 name8
= name8
.copy(0, i
);
601 p
= GetProcAddress(handle
, name8
.getStr());
608 OString
real(OString("_") + name8
);
609 p
= GetProcAddress(handle
, real
.getStr());
615 real
= name8
+ OString("A");
616 p
= GetProcAddress(handle
, real
.getStr());
623 return ERRCODE_BASIC_PROC_UNDEFINED
;
626 struct Dll
: public salhelper::SimpleReferenceObject
{
628 typedef std::map
< OUString
, ProcData
> Procs
;
635 SbError
getProc(OUString
const & name
, ProcData
* proc
);
642 if (handle
!= 0 && !FreeLibrary(handle
)) {
643 OSL_TRACE("FreeLibrary(%p) failed with %u", handle
, GetLastError());
647 SbError
Dll::getProc(OUString
const & name
, ProcData
* proc
) {
648 Procs::iterator
i(procs
.find(name
));
649 if (i
!= procs
.end()) {
653 SbError e
= getProcData(handle
, name
, proc
);
654 if (e
== ERRCODE_NONE
) {
655 procs
.insert(Procs::value_type(name
, *proc
));
660 OUString
fullDllName(OUString
const & name
) {
662 if (full
.indexOf('.') == -1) {
670 struct SbiDllMgr::Impl
: private boost::noncopyable
{
672 typedef std::map
< OUString
, rtl::Reference
< Dll
> > Dlls
;
675 Dll
* getDll(OUString
const & name
);
680 Dll
* SbiDllMgr::Impl::getDll(OUString
const & name
) {
681 Dlls::iterator
i(dlls
.find(name
));
682 if (i
== dlls
.end()) {
683 i
= dlls
.insert(Dlls::value_type(name
, new Dll
)).first
;
684 HMODULE h
= LoadLibraryW(reinterpret_cast<LPCWSTR
>(name
.getStr()));
689 i
->second
->handle
= h
;
691 return i
->second
.get();
694 SbError
SbiDllMgr::Call(
695 OUString
const & function
, OUString
const & library
,
696 SbxArray
* arguments
, SbxVariable
& result
, bool cdeclConvention
)
698 if (cdeclConvention
) {
699 return ERRCODE_BASIC_NOT_IMPLEMENTED
;
701 OUString
dllName(fullDllName(library
));
702 Dll
* dll
= impl_
->getDll(dllName
);
704 return ERRCODE_BASIC_BAD_DLL_LOAD
;
707 SbError e
= dll
->getProc(function
, &proc
);
708 if (e
!= ERRCODE_NONE
) {
711 return call(dllName
, proc
, arguments
, result
);
714 void SbiDllMgr::FreeDll(OUString
const & library
) {
715 impl_
->dlls
.erase(library
);
718 SbiDllMgr::SbiDllMgr(): impl_(new Impl
) {}
720 SbiDllMgr::~SbiDllMgr() {}
722 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */