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>
32 #include <basic/sbx.hxx>
33 #include <basic/sbxvar.hxx>
34 #include <comphelper/string.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 <sal/log.hxx>
41 #include <salhelper/simplereferenceobject.hxx>
42 #include <o3tl/char16_t2wchar_t.hxx>
43 #include <o3tl/string_view.hxx>
50 using namespace css::uno
;
54 Missing support for functions returning structs (see TODO in call()).
56 Missing support for additional data types (64 bit integers, Any, ...; would
57 trigger assert(false) in various switches).
59 It is assumed that the variables passed into SbiDllMgr::Call to represent
60 the arguments and return value have types that exactly match the Declare
61 statement; it would be better if this code had access to the function
62 signature from the Declare statement, so that it could convert the passed
63 variables accordingly.
68 int __stdcall
DllMgr_call32(FARPROC
, void const * stack
, std::size_t size
);
69 double __stdcall
DllMgr_callFp(FARPROC
, void const * stack
, std::size_t size
);
75 char * address(std::vector
< char > & blob
) {
76 return blob
.empty() ? 0 : &blob
[0];
79 ErrCode
convert(OUString
const & source
, OString
* target
) {
81 source
.convertToString(
82 target
, osl_getThreadTextEncoding(),
83 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
84 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
))
85 ? ERRCODE_NONE
: ERRCODE_BASIC_BAD_ARGUMENT
;
86 //TODO: more specific errcode?
89 ErrCode
convert(char const * source
, sal_Int32 length
, OUString
* target
) {
91 rtl_convertStringToUString(
92 &target
->pData
, source
, length
, osl_getThreadTextEncoding(),
93 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
94 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
95 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
))
96 ? ERRCODE_NONE
: ERRCODE_BASIC_BAD_ARGUMENT
;
97 //TODO: more specific errcode?
100 struct UnmarshalData
{
101 UnmarshalData(SbxVariable
* theVariable
, void * theBuffer
):
102 variable(theVariable
), buffer(theBuffer
) {}
104 SbxVariable
* variable
;
108 struct StringData
: public UnmarshalData
{
109 StringData(SbxVariable
* theVariable
, void * theBuffer
, bool theSpecial
):
110 UnmarshalData(theVariable
, theBuffer
), special(theSpecial
) {}
117 MarshalData() = default;
118 MarshalData(const MarshalData
&) = delete;
119 const MarshalData
& operator=(const MarshalData
&) = delete;
121 std::vector
< char > * newBlob() {
122 blobs_
.push_back(std::vector
< char >());
123 return &blobs_
.back();
126 std::vector
< UnmarshalData
> unmarshal
;
128 std::vector
< StringData
> unmarshalStrings
;
131 std::vector
< std::vector
< char > > blobs_
;
134 std::size_t align(std::size_t address
, std::size_t alignment
) {
135 // alignment = 2^k for some k >= 0
136 return (address
+ (alignment
- 1)) & ~(alignment
- 1);
140 std::vector
< char > & blob
, std::size_t alignment
, std::size_t offset
,
143 std::vector
< char >::size_type n
= blob
.size();
144 n
= align(n
- offset
, alignment
) + offset
; //TODO: overflow in align()
145 blob
.resize(n
+ add
); //TODO: overflow
146 return address(blob
) + n
;
149 template< typename T
> void add(
150 std::vector
< char > & blob
, T
const & data
, std::size_t alignment
,
153 *reinterpret_cast< T
* >(align(blob
, alignment
, offset
, sizeof (T
))) = data
;
156 std::size_t alignment(SbxVariable
* variable
) {
157 assert(variable
!= 0);
158 if ((variable
->GetType() & SbxARRAY
) == 0) {
159 switch (variable
->GetType()) {
171 SbxObject
* pobj
= dynamic_cast<SbxObject
*>(variable
->GetObject());
173 SbxArray
* props
= pobj
->GetProperties();
174 for (sal_uInt32 i
= 0; i
< props
->Count(); ++i
)
176 n
= std::max(n
, alignment(props
->Get(i
)));
188 SbxDimArray
* arr
= dynamic_cast<SbxDimArray
*>( variable
->GetObject() );
190 sal_Int32 dims
= arr
->GetDims();
191 std::vector
< sal_Int32
> low(dims
);
192 for (sal_Int32 i
= 0; i
< dims
; ++i
) {
194 arr
->GetDim(i
+ 1, low
[i
], up
);
196 return alignment(arr
->Get(&low
[0]));
201 bool outer
, SbxVariable
* variable
, bool special
,
202 std::vector
< char > & blob
, std::size_t offset
, MarshalData
& data
);
204 ErrCode
marshalString(
205 SbxVariable
* variable
, bool special
, MarshalData
& data
, void ** buffer
)
207 assert(variable
!= 0 && buffer
!= 0);
209 ErrCode e
= convert(variable
->GetOUString(), &str
);
210 if (e
!= ERRCODE_NONE
) {
213 std::vector
< char > * blob
= data
.newBlob();
215 blob
->begin(), str
.getStr(), str
.getStr() + str
.getLength() + 1);
216 *buffer
= address(*blob
);
217 data
.unmarshalStrings
.push_back(StringData(variable
, *buffer
, special
));
221 ErrCode
marshalStruct(
222 SbxVariable
* variable
, std::vector
< char > & blob
, std::size_t offset
,
225 assert(variable
!= 0);
226 SbxObject
* pobj
= dynamic_cast<SbxObject
*>(variable
->GetObject());
228 SbxArray
* props
= pobj
->GetProperties();
229 for (sal_uInt32 i
= 0; i
< props
->Count(); ++i
)
231 ErrCode e
= marshal(false, props
->Get(i
), false, blob
, offset
, data
);
232 if (e
!= ERRCODE_NONE
) {
239 ErrCode
marshalArray(
240 SbxVariable
* variable
, std::vector
< char > & blob
, std::size_t offset
,
243 assert(variable
!= 0);
244 SbxDimArray
* arr
= dynamic_cast<SbxDimArray
*>( variable
->GetObject() );
246 sal_Int32 dims
= arr
->GetDims();
247 std::vector
< sal_Int32
> low(dims
);
248 std::vector
< sal_Int32
> up(dims
);
249 for (sal_Int32 i
= 0; i
< dims
; ++i
) {
250 arr
->GetDim(i
+ 1, low
[i
], up
[i
]);
252 for (std::vector
< sal_Int32
> idx
= low
;;) {
253 ErrCode e
= marshal(false, arr
->Get(&idx
[0]), false, blob
, offset
, data
);
254 if (e
!= ERRCODE_NONE
) {
257 sal_Int32 i
= dims
- 1;
258 while (idx
[i
] == up
[i
]) {
269 // 8-aligned structs are only 4-aligned on stack, so alignment of members in
270 // such structs must take that into account via "offset"
272 bool outer
, SbxVariable
* variable
, bool special
,
273 std::vector
< char > & blob
, std::size_t offset
, MarshalData
& data
)
275 assert(variable
!= 0);
277 SbxDataType eVarType
= variable
->GetType();
278 bool bByVal
= !(variable
->GetFlags() & SbxFlagBits::Reference
);
279 if( !bByVal
&& !SbiRuntime::isVBAEnabled() && eVarType
== SbxSTRING
)
283 if ((eVarType
& SbxARRAY
) == 0) {
286 add(blob
, variable
->GetInteger(), outer
? 4 : 2, offset
);
289 add(blob
, variable
->GetLong(), 4, offset
);
292 add(blob
, variable
->GetSingle(), 4, offset
);
295 add(blob
, variable
->GetDouble(), outer
? 4 : 8, offset
);
300 ErrCode e
= marshalString(variable
, special
, data
, &p
);
301 if (e
!= ERRCODE_NONE
) {
304 add(blob
, p
, 4, offset
);
309 align(blob
, outer
? 4 : alignment(variable
), offset
, 0);
310 ErrCode e
= marshalStruct(variable
, blob
, offset
, data
);
311 if (e
!= ERRCODE_NONE
) {
317 add(blob
, variable
->GetBool(), outer
? 4 : 1, offset
);
320 add(blob
, variable
->GetByte(), outer
? 4 : 1, offset
);
327 ErrCode e
= marshalArray(variable
, blob
, offset
, data
);
328 if (e
!= ERRCODE_NONE
) {
333 if ((eVarType
& SbxARRAY
) == 0) {
341 add(blob
, variable
->data(), 4, offset
);
346 ErrCode e
= marshalString(variable
, special
, data
, &p
);
347 if (e
!= ERRCODE_NONE
) {
350 std::vector
< char > * blob2
= data
.newBlob();
351 add(*blob2
, p
, 4, 0);
352 add(blob
, address(*blob2
), 4, offset
);
357 std::vector
< char > * blob2
= data
.newBlob();
358 ErrCode e
= marshalStruct(variable
, *blob2
, 0, data
);
359 if (e
!= ERRCODE_NONE
) {
362 void * p
= address(*blob2
);
364 data
.unmarshal
.push_back(UnmarshalData(variable
, p
));
366 add(blob
, p
, 4, offset
);
374 std::vector
< char > * blob2
= data
.newBlob();
375 ErrCode e
= marshalArray(variable
, *blob2
, 0, data
);
376 if (e
!= ERRCODE_NONE
) {
379 void * p
= address(*blob2
);
381 data
.unmarshal
.push_back(UnmarshalData(variable
, p
));
383 add(blob
, p
, 4, offset
);
389 template< typename T
> T
read(void const ** pointer
) {
390 T
const * p
= static_cast< T
const * >(*pointer
);
391 *pointer
= static_cast< void const * >(p
+ 1);
395 void const * unmarshal(SbxVariable
* variable
, void const * data
) {
396 assert(variable
!= 0);
397 if ((variable
->GetType() & SbxARRAY
) == 0) {
398 switch (variable
->GetType()) {
400 variable
->PutInteger(read
< sal_Int16
>(&data
));
403 variable
->PutLong(read
< sal_Int32
>(&data
));
406 variable
->PutSingle(read
< float >(&data
));
409 variable
->PutDouble(read
< double >(&data
));
412 read
< char * >(&data
); // handled by unmarshalString
416 data
= reinterpret_cast< void const * >(
418 reinterpret_cast< sal_uIntPtr
>(data
),
419 alignment(variable
)));
420 SbxObject
* pobj
= dynamic_cast<SbxObject
*>(variable
->GetObject());
422 SbxArray
* props
= pobj
->GetProperties();
423 for (sal_uInt32 i
= 0; i
< props
->Count(); ++i
)
425 data
= unmarshal(props
->Get(i
), data
);
430 variable
->PutBool(read
< sal_Bool
>(&data
));
433 variable
->PutByte(read
< sal_uInt8
>(&data
));
440 SbxDimArray
* arr
= dynamic_cast<SbxDimArray
*>( variable
->GetObject() );
442 sal_Int32 dims
= arr
->GetDims();
443 std::vector
< sal_Int32
> low(dims
);
444 std::vector
< sal_Int32
> up(dims
);
445 for (sal_Int32 i
= 0; i
< dims
; ++i
) {
446 arr
->GetDim(i
+ 1, low
[i
], up
[i
]);
448 for (std::vector
< sal_Int32
> idx
= low
;;) {
449 data
= unmarshal(arr
->Get(&idx
[0]), data
);
450 sal_Int32 i
= dims
- 1;
451 while (idx
[i
] == up
[i
]) {
465 ErrCode
unmarshalString(StringData
const & data
, SbxVariable
& result
) {
467 if (data
.buffer
!= 0) {
468 char const * p
= static_cast< char const * >(data
.buffer
);
471 len
= static_cast< sal_Int32
>(result
.GetULong());
472 if (len
< 0) { // i.e., DWORD result >= 2^31
473 return ERRCODE_BASIC_BAD_ARGUMENT
;
474 //TODO: more specific errcode?
477 len
= rtl_str_getLength(p
);
479 ErrCode e
= convert(p
, len
, &str
);
480 if (e
!= ERRCODE_NONE
) {
484 data
.variable
->PutString(str
);
494 OUString
const & dll
, ProcData
const & proc
, SbxArray
* arguments
,
495 SbxVariable
& result
)
497 std::vector
< char > stack
;
499 // For DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
500 // from kernel32, upon return, filled lpBuffer length is result DWORD, which
501 // requires special handling in unmarshalString; other functions might
502 // require similar treatment, too:
503 bool special
= dll
.equalsIgnoreAsciiCase("KERNEL32.DLL") &&
504 (proc
.name
== OString("GetLogicalDriveStringsA"));
505 for (sal_uInt32 i
= 1; i
< (arguments
== 0 ? 0 : arguments
->Count()); ++i
)
507 ErrCode e
= marshal(true, arguments
->Get(i
), special
&& i
== 2, stack
, stack
.size(),
509 if (e
!= ERRCODE_NONE
) {
512 align(stack
, 4, 0, 0);
514 switch (result
.GetType()) {
516 DllMgr_call32(proc
.proc
, address(stack
), stack
.size());
520 static_cast< sal_Int16
>(
521 DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
525 static_cast< sal_Int32
>(
526 DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
530 static_cast< float >(
531 DllMgr_callFp(proc
.proc
, address(stack
), stack
.size())));
535 DllMgr_callFp(proc
.proc
, address(stack
), stack
.size()));
539 char const * s1
= reinterpret_cast< char const * >(
540 DllMgr_call32(proc
.proc
, address(stack
), stack
.size()));
542 ErrCode e
= convert(s1
, rtl_str_getLength(s1
), &s2
);
543 if (e
!= ERRCODE_NONE
) {
546 result
.PutString(s2
);
551 DllMgr_call32(proc
.proc
, address(stack
), stack
.size());
555 bool(DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
559 static_cast< sal_uInt8
>(
560 DllMgr_call32(proc
.proc
, address(stack
), stack
.size())));
566 for (sal_uInt32 i
= 1; i
< (arguments
== 0 ? 0 : arguments
->Count()); ++i
)
568 arguments
->Get(i
)->ResetFlag(SbxFlagBits::Reference
);
569 //TODO: skipped for errors?!?
571 for (auto& rUnmarshalData
: data
.unmarshal
)
573 unmarshal(rUnmarshalData
.variable
, rUnmarshalData
.buffer
);
575 for (const auto& rStringData
: data
.unmarshalStrings
)
577 ErrCode e
= unmarshalString(rStringData
, result
);
578 if (e
!= ERRCODE_NONE
) {
585 ErrCode
getProcData(HMODULE handle
, OUString
const & name
, ProcData
* proc
)
588 if ( !name
.isEmpty() && name
[0] == '@' ) { //TODO: "@" vs. "#"???
589 sal_Int32 n
= o3tl::toInt32(name
.subView(1)); //TODO: handle bad input
590 if (n
<= 0 || n
> 0xFFFF) {
591 return ERRCODE_BASIC_BAD_ARGUMENT
; //TODO: more specific errcode?
593 FARPROC p
= GetProcAddress(handle
, reinterpret_cast< LPCSTR
>(n
));
595 proc
->name
= OString("#") + OString::number(n
);
601 ErrCode e
= convert(name
, &name8
);
602 if (e
!= ERRCODE_NONE
) {
605 FARPROC p
= GetProcAddress(handle
, name8
.getStr());
611 sal_Int32 i
= name8
.indexOf('#');
613 name8
= name8
.copy(0, i
);
614 p
= GetProcAddress(handle
, name8
.getStr());
621 OString
real(OString("_") + name8
);
622 p
= GetProcAddress(handle
, real
.getStr());
628 real
= name8
+ OString("A");
629 p
= GetProcAddress(handle
, real
.getStr());
636 return ERRCODE_BASIC_PROC_UNDEFINED
;
639 struct Dll
: public salhelper::SimpleReferenceObject
{
641 typedef std::map
< OUString
, ProcData
> Procs
;
648 ErrCode
getProc(OUString
const & name
, ProcData
* proc
);
655 if (handle
!= 0 && !FreeLibrary(handle
)) {
656 SAL_WARN("basic", "FreeLibrary(" << handle
<< ") failed with " << GetLastError());
660 ErrCode
Dll::getProc(OUString
const & name
, ProcData
* proc
) {
661 Procs::iterator
i(procs
.find(name
));
662 if (i
!= procs
.end()) {
666 ErrCode e
= getProcData(handle
, name
, proc
);
667 if (e
== ERRCODE_NONE
) {
668 procs
.emplace(name
, *proc
);
673 OUString
fullDllName(OUString
const & name
) {
675 if (full
.indexOf('.') == -1) {
683 struct SbiDllMgr::Impl
{
685 typedef std::map
< OUString
, rtl::Reference
< Dll
> > Dlls
;
689 Impl(const Impl
&) = delete;
690 const Impl
& operator=(const Impl
&) = delete;
692 Dll
* getDll(OUString
const & name
);
697 Dll
* SbiDllMgr::Impl::getDll(OUString
const & name
) {
698 Dlls::iterator
i(dlls
.find(name
));
699 if (i
== dlls
.end()) {
700 i
= dlls
.emplace(name
, new Dll
).first
;
701 HMODULE h
= LoadLibraryW(o3tl::toW(name
.getStr()));
706 i
->second
->handle
= h
;
708 return i
->second
.get();
711 ErrCode
SbiDllMgr::Call(
712 std::u16string_view function
, std::u16string_view library
,
713 SbxArray
* arguments
, SbxVariable
& result
, bool cdeclConvention
)
715 if (cdeclConvention
) {
716 return ERRCODE_BASIC_NOT_IMPLEMENTED
;
718 OUString
dllName(fullDllName(OUString(library
)));
719 Dll
* dll
= impl_
->getDll(dllName
);
721 return ERRCODE_BASIC_BAD_DLL_LOAD
;
724 ErrCode e
= dll
->getProc(OUString(function
), &proc
);
725 if (e
!= ERRCODE_NONE
) {
728 return call(dllName
, proc
, arguments
, result
);
731 void SbiDllMgr::FreeDll(OUString
const & library
) {
732 impl_
->dlls
.erase(library
);
735 SbiDllMgr::SbiDllMgr(): impl_(new Impl
) {}
737 SbiDllMgr::~SbiDllMgr() {}
739 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */