Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / runtime / dllmgr-x86.cxx
blob74b470da2e0485722400174547c9dfa8ed16e7e0
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 .
20 #include <sal/config.h>
22 #if defined(_WIN32)
23 #include <prewin.h>
24 #include <postwin.h>
25 #endif
27 #include <algorithm>
28 #include <cstddef>
29 #include <map>
30 #include <vector>
32 #include <basic/sbx.hxx>
33 #include <basic/sbxvar.hxx>
34 #include "runtime.hxx"
35 #include <osl/thread.h>
36 #include <rtl/ref.hxx>
37 #include <rtl/string.hxx>
38 #include <rtl/ustring.hxx>
39 #include <sal/log.hxx>
40 #include <salhelper/simplereferenceobject.hxx>
41 #include <o3tl/char16_t2wchar_t.hxx>
43 #undef max
45 #include "dllmgr.hxx"
47 using namespace css;
48 using namespace css::uno;
50 /* Open issues:
52 Missing support for functions returning structs (see TODO in call()).
54 Missing support for additional data types (64 bit integers, Any, ...; would
55 trigger OSL_ASSERT(false) in various switches).
57 It is assumed that the variables passed into SbiDllMgr::Call to represent
58 the arguments and return value have types that exactly match the Declare
59 statement; it would be better if this code had access to the function
60 signature from the Declare statement, so that it could convert the passed
61 variables accordingly.
64 extern "C" {
66 int __stdcall DllMgr_call32(FARPROC, void const * stack, std::size_t size);
67 double __stdcall DllMgr_callFp(FARPROC, void const * stack, std::size_t size);
71 namespace {
73 char * address(std::vector< char > & blob) {
74 return blob.empty() ? 0 : &blob[0];
77 ErrCode convert(OUString const & source, OString * target) {
78 return
79 source.convertToString(
80 target, osl_getThreadTextEncoding(),
81 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
82 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
83 ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT;
84 //TODO: more specific errcode?
87 ErrCode convert(char const * source, sal_Int32 length, OUString * target) {
88 return
89 rtl_convertStringToUString(
90 &target->pData, source, length, osl_getThreadTextEncoding(),
91 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
92 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
93 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))
94 ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT;
95 //TODO: more specific errcode?
98 struct UnmarshalData {
99 UnmarshalData(SbxVariable * theVariable, void * theBuffer):
100 variable(theVariable), buffer(theBuffer) {}
102 SbxVariable * variable;
103 void * buffer;
106 struct StringData: public UnmarshalData {
107 StringData(SbxVariable * theVariable, void * theBuffer, bool theSpecial):
108 UnmarshalData(theVariable, theBuffer), special(theSpecial) {}
110 bool special;
113 class MarshalData {
114 public:
115 MarshalData() = default;
116 MarshalData(const MarshalData&) = delete;
117 const MarshalData& operator=(const MarshalData&) = delete;
119 std::vector< char > * newBlob() {
120 blobs_.push_back(std::vector< char >());
121 return &blobs_.back();
124 std::vector< UnmarshalData > unmarshal;
126 std::vector< StringData > unmarshalStrings;
128 private:
129 std::vector< std::vector< char > > blobs_;
132 std::size_t align(std::size_t address, std::size_t alignment) {
133 // alignment = 2^k for some k >= 0
134 return (address + (alignment - 1)) & ~(alignment - 1);
137 char * align(
138 std::vector< char > & blob, std::size_t alignment, std::size_t offset,
139 std::size_t add)
141 std::vector< char >::size_type n = blob.size();
142 n = align(n - offset, alignment) + offset; //TODO: overflow in align()
143 blob.resize(n + add); //TODO: overflow
144 return address(blob) + n;
147 template< typename T > void add(
148 std::vector< char > & blob, T const & data, std::size_t alignment,
149 std::size_t offset)
151 *reinterpret_cast< T * >(align(blob, alignment, offset, sizeof (T))) = data;
154 std::size_t alignment(SbxVariable * variable) {
155 OSL_ASSERT(variable != 0);
156 if ((variable->GetType() & SbxARRAY) == 0) {
157 switch (variable->GetType()) {
158 case SbxINTEGER:
159 return 2;
160 case SbxLONG:
161 case SbxSINGLE:
162 case SbxSTRING:
163 return 4;
164 case SbxDOUBLE:
165 return 8;
166 case SbxOBJECT:
168 std::size_t n = 1;
169 SbxObject* pobj = dynamic_cast<SbxObject*>(variable->GetObject());
170 assert(pobj);
171 SbxArray* props = pobj->GetProperties();
172 for (sal_uInt16 i = 0; i < props->Count(); ++i) {
173 n = std::max(n, alignment(props->Get(i)));
175 return n;
177 case SbxBOOL:
178 case SbxBYTE:
179 return 1;
180 default:
181 OSL_ASSERT(false);
182 return 1;
184 } else {
185 SbxDimArray * arr = dynamic_cast<SbxDimArray*>( variable->GetObject() );
186 assert(arr);
187 int dims = arr->GetDims();
188 std::vector< sal_Int32 > low(dims);
189 for (int i = 0; i < dims; ++i) {
190 sal_Int32 up;
191 arr->GetDim32(i + 1, low[i], up);
193 return alignment(arr->Get32(&low[0]));
197 ErrCode marshal(
198 bool outer, SbxVariable * variable, bool special,
199 std::vector< char > & blob, std::size_t offset, MarshalData & data);
201 ErrCode marshalString(
202 SbxVariable * variable, bool special, MarshalData & data, void ** buffer)
204 OSL_ASSERT(variable != 0 && buffer != 0);
205 OString str;
206 ErrCode e = convert(variable->GetOUString(), &str);
207 if (e != ERRCODE_NONE) {
208 return e;
210 std::vector< char > * blob = data.newBlob();
211 blob->insert(
212 blob->begin(), str.getStr(), str.getStr() + str.getLength() + 1);
213 *buffer = address(*blob);
214 data.unmarshalStrings.push_back(StringData(variable, *buffer, special));
215 return ERRCODE_NONE;
218 ErrCode marshalStruct(
219 SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
220 MarshalData & data)
222 OSL_ASSERT(variable != 0);
223 SbxObject* pobj = dynamic_cast<SbxObject*>(variable->GetObject());
224 assert(pobj);
225 SbxArray* props = pobj->GetProperties();
226 for (sal_uInt16 i = 0; i < props->Count(); ++i) {
227 ErrCode e = marshal(false, props->Get(i), false, blob, offset, data);
228 if (e != ERRCODE_NONE) {
229 return e;
232 return ERRCODE_NONE;
235 ErrCode marshalArray(
236 SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
237 MarshalData & data)
239 OSL_ASSERT(variable != 0);
240 SbxDimArray * arr = dynamic_cast<SbxDimArray*>( variable->GetObject() );
241 assert(arr);
242 int dims = arr->GetDims();
243 std::vector< sal_Int32 > low(dims);
244 std::vector< sal_Int32 > up(dims);
245 for (int i = 0; i < dims; ++i) {
246 arr->GetDim32(i + 1, low[i], up[i]);
248 for (std::vector< sal_Int32 > idx = low;;) {
249 ErrCode e = marshal(
250 false, arr->Get32(&idx[0]), false, blob, offset, data);
251 if (e != ERRCODE_NONE) {
252 return e;
254 int i = dims - 1;
255 while (idx[i] == up[i]) {
256 idx[i] = low[i];
257 if (i == 0) {
258 return ERRCODE_NONE;
260 --i;
262 ++idx[i];
266 // 8-aligned structs are only 4-aligned on stack, so alignment of members in
267 // such structs must take that into account via "offset"
268 ErrCode marshal(
269 bool outer, SbxVariable * variable, bool special,
270 std::vector< char > & blob, std::size_t offset, MarshalData & data)
272 OSL_ASSERT(variable != 0);
274 SbxDataType eVarType = variable->GetType();
275 bool bByVal = !(variable->GetFlags() & SbxFlagBits::Reference);
276 if( !bByVal && !SbiRuntime::isVBAEnabled() && eVarType == SbxSTRING )
277 bByVal = true;
279 if (bByVal) {
280 if ((eVarType & SbxARRAY) == 0) {
281 switch (eVarType) {
282 case SbxINTEGER:
283 add(blob, variable->GetInteger(), outer ? 4 : 2, offset);
284 break;
285 case SbxLONG:
286 add(blob, variable->GetLong(), 4, offset);
287 break;
288 case SbxSINGLE:
289 add(blob, variable->GetSingle(), 4, offset);
290 break;
291 case SbxDOUBLE:
292 add(blob, variable->GetDouble(), outer ? 4 : 8, offset);
293 break;
294 case SbxSTRING:
296 void * p;
297 ErrCode e = marshalString(variable, special, data, &p);
298 if (e != ERRCODE_NONE) {
299 return e;
301 add(blob, p, 4, offset);
302 break;
304 case SbxOBJECT:
306 align(blob, outer ? 4 : alignment(variable), offset, 0);
307 ErrCode e = marshalStruct(variable, blob, offset, data);
308 if (e != ERRCODE_NONE) {
309 return e;
311 break;
313 case SbxBOOL:
314 add(blob, variable->GetBool(), outer ? 4 : 1, offset);
315 break;
316 case SbxBYTE:
317 add(blob, variable->GetByte(), outer ? 4 : 1, offset);
318 break;
319 default:
320 OSL_ASSERT(false);
321 break;
323 } else {
324 ErrCode e = marshalArray(variable, blob, offset, data);
325 if (e != ERRCODE_NONE) {
326 return e;
329 } else {
330 if ((eVarType & SbxARRAY) == 0) {
331 switch (eVarType) {
332 case SbxINTEGER:
333 case SbxLONG:
334 case SbxSINGLE:
335 case SbxDOUBLE:
336 case SbxBOOL:
337 case SbxBYTE:
338 add(blob, variable->data(), 4, offset);
339 break;
340 case SbxSTRING:
342 void * p;
343 ErrCode e = marshalString(variable, special, data, &p);
344 if (e != ERRCODE_NONE) {
345 return e;
347 std::vector< char > * blob2 = data.newBlob();
348 add(*blob2, p, 4, 0);
349 add(blob, address(*blob2), 4, offset);
350 break;
352 case SbxOBJECT:
354 std::vector< char > * blob2 = data.newBlob();
355 ErrCode e = marshalStruct(variable, *blob2, 0, data);
356 if (e != ERRCODE_NONE) {
357 return e;
359 void * p = address(*blob2);
360 if (outer) {
361 data.unmarshal.push_back(UnmarshalData(variable, p));
363 add(blob, p, 4, offset);
364 break;
366 default:
367 OSL_ASSERT(false);
368 break;
370 } else {
371 std::vector< char > * blob2 = data.newBlob();
372 ErrCode e = marshalArray(variable, *blob2, 0, data);
373 if (e != ERRCODE_NONE) {
374 return e;
376 void * p = address(*blob2);
377 if (outer) {
378 data.unmarshal.push_back(UnmarshalData(variable, p));
380 add(blob, p, 4, offset);
383 return ERRCODE_NONE;
386 template< typename T > T read(void const ** pointer) {
387 T const * p = static_cast< T const * >(*pointer);
388 *pointer = static_cast< void const * >(p + 1);
389 return *p;
392 void const * unmarshal(SbxVariable * variable, void const * data) {
393 OSL_ASSERT(variable != 0);
394 if ((variable->GetType() & SbxARRAY) == 0) {
395 switch (variable->GetType()) {
396 case SbxINTEGER:
397 variable->PutInteger(read< sal_Int16 >(&data));
398 break;
399 case SbxLONG:
400 variable->PutLong(read< sal_Int32 >(&data));
401 break;
402 case SbxSINGLE:
403 variable->PutSingle(read< float >(&data));
404 break;
405 case SbxDOUBLE:
406 variable->PutDouble(read< double >(&data));
407 break;
408 case SbxSTRING:
409 read< char * >(&data); // handled by unmarshalString
410 break;
411 case SbxOBJECT:
413 data = reinterpret_cast< void const * >(
414 align(
415 reinterpret_cast< sal_uIntPtr >(data),
416 alignment(variable)));
417 SbxObject* pobj = dynamic_cast<SbxObject*>(variable->GetObject());
418 assert(pobj);
419 SbxArray* props = pobj->GetProperties();
420 for (sal_uInt16 i = 0; i < props->Count(); ++i) {
421 data = unmarshal(props->Get(i), data);
423 break;
425 case SbxBOOL:
426 variable->PutBool(read< sal_Bool >(&data));
427 break;
428 case SbxBYTE:
429 variable->PutByte(read< sal_uInt8 >(&data));
430 break;
431 default:
432 OSL_ASSERT(false);
433 break;
435 } else {
436 SbxDimArray * arr = dynamic_cast<SbxDimArray*>( variable->GetObject() );
437 assert(arr);
438 int dims = arr->GetDims();
439 std::vector< sal_Int32 > low(dims);
440 std::vector< sal_Int32 > up(dims);
441 for (int i = 0; i < dims; ++i) {
442 arr->GetDim32(i + 1, low[i], up[i]);
444 for (std::vector< sal_Int32 > idx = low;;) {
445 data = unmarshal(arr->Get32(&idx[0]), data);
446 int i = dims - 1;
447 while (idx[i] == up[i]) {
448 idx[i] = low[i];
449 if (i == 0) {
450 goto done;
452 --i;
454 ++idx[i];
456 done:;
458 return data;
461 ErrCode unmarshalString(StringData const & data, SbxVariable & result) {
462 OUString str;
463 if (data.buffer != 0) {
464 char const * p = static_cast< char const * >(data.buffer);
465 sal_Int32 len;
466 if (data.special) {
467 len = static_cast< sal_Int32 >(result.GetULong());
468 if (len < 0) { // i.e., DWORD result >= 2^31
469 return ERRCODE_BASIC_BAD_ARGUMENT;
470 //TODO: more specific errcode?
472 } else {
473 len = rtl_str_getLength(p);
475 ErrCode e = convert(p, len, &str);
476 if (e != ERRCODE_NONE) {
477 return e;
480 data.variable->PutString(str);
481 return ERRCODE_NONE;
484 struct ProcData {
485 OString name;
486 FARPROC proc;
489 ErrCode call(
490 OUString const & dll, ProcData const & proc, SbxArray * arguments,
491 SbxVariable & result)
493 std::vector< char > stack;
494 MarshalData data;
495 // For DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
496 // from kernel32, upon return, filled lpBuffer length is result DWORD, which
497 // requires special handling in unmarshalString; other functions might
498 // require similar treatment, too:
499 bool special = dll.equalsIgnoreAsciiCase("KERNEL32.DLL") &&
500 (proc.name == OString("GetLogicalDriveStringsA"));
501 for (sal_uInt16 i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) {
502 ErrCode e = marshal(
503 true, arguments->Get(i), special && i == 2, stack, stack.size(),
504 data);
505 if (e != ERRCODE_NONE) {
506 return e;
508 align(stack, 4, 0, 0);
510 switch (result.GetType()) {
511 case SbxEMPTY:
512 DllMgr_call32(proc.proc, address(stack), stack.size());
513 break;
514 case SbxINTEGER:
515 result.PutInteger(
516 static_cast< sal_Int16 >(
517 DllMgr_call32(proc.proc, address(stack), stack.size())));
518 break;
519 case SbxLONG:
520 result.PutLong(
521 static_cast< sal_Int32 >(
522 DllMgr_call32(proc.proc, address(stack), stack.size())));
523 break;
524 case SbxSINGLE:
525 result.PutSingle(
526 static_cast< float >(
527 DllMgr_callFp(proc.proc, address(stack), stack.size())));
528 break;
529 case SbxDOUBLE:
530 result.PutDouble(
531 DllMgr_callFp(proc.proc, address(stack), stack.size()));
532 break;
533 case SbxSTRING:
535 char const * s1 = reinterpret_cast< char const * >(
536 DllMgr_call32(proc.proc, address(stack), stack.size()));
537 OUString s2;
538 ErrCode e = convert(s1, rtl_str_getLength(s1), &s2);
539 if (e != ERRCODE_NONE) {
540 return e;
542 result.PutString(s2);
543 break;
545 case SbxOBJECT:
546 //TODO
547 DllMgr_call32(proc.proc, address(stack), stack.size());
548 break;
549 case SbxBOOL:
550 result.PutBool(
551 bool(DllMgr_call32(proc.proc, address(stack), stack.size())));
552 break;
553 case SbxBYTE:
554 result.PutByte(
555 static_cast< sal_uInt8 >(
556 DllMgr_call32(proc.proc, address(stack), stack.size())));
557 break;
558 default:
559 OSL_ASSERT(false);
560 break;
562 for (sal_uInt16 i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) {
563 arguments->Get(i)->ResetFlag(SbxFlagBits::Reference);
564 //TODO: skipped for errors?!?
566 for (auto& rUnmarshalData : data.unmarshal)
568 unmarshal(rUnmarshalData.variable, rUnmarshalData.buffer);
570 for (const auto& rStringData : data.unmarshalStrings)
572 ErrCode e = unmarshalString(rStringData, result);
573 if (e != ERRCODE_NONE) {
574 return e;
577 return ERRCODE_NONE;
580 ErrCode getProcData(HMODULE handle, OUString const & name, ProcData * proc)
582 OSL_ASSERT(proc != 0);
583 if ( !name.isEmpty() && name[0] == '@' ) { //TODO: "@" vs. "#"???
584 sal_Int32 n = name.copy(1).toInt32(); //TODO: handle bad input
585 if (n <= 0 || n > 0xFFFF) {
586 return ERRCODE_BASIC_BAD_ARGUMENT; //TODO: more specific errcode?
588 FARPROC p = GetProcAddress(handle, reinterpret_cast< LPCSTR >(n));
589 if (p != 0) {
590 proc->name = OString("#") + OString::number(n);
591 proc->proc = p;
592 return ERRCODE_NONE;
594 } else {
595 OString name8;
596 ErrCode e = convert(name, &name8);
597 if (e != ERRCODE_NONE) {
598 return e;
600 FARPROC p = GetProcAddress(handle, name8.getStr());
601 if (p != 0) {
602 proc->name = name8;
603 proc->proc = p;
604 return ERRCODE_NONE;
606 sal_Int32 i = name8.indexOf('#');
607 if (i != -1) {
608 name8 = name8.copy(0, i);
609 p = GetProcAddress(handle, name8.getStr());
610 if (p != 0) {
611 proc->name = name8;
612 proc->proc = p;
613 return ERRCODE_NONE;
616 OString real(OString("_") + name8);
617 p = GetProcAddress(handle, real.getStr());
618 if (p != 0) {
619 proc->name = real;
620 proc->proc = p;
621 return ERRCODE_NONE;
623 real = name8 + OString("A");
624 p = GetProcAddress(handle, real.getStr());
625 if (p != 0) {
626 proc->name = real;
627 proc->proc = p;
628 return ERRCODE_NONE;
631 return ERRCODE_BASIC_PROC_UNDEFINED;
634 struct Dll: public salhelper::SimpleReferenceObject {
635 private:
636 typedef std::map< OUString, ProcData > Procs;
638 virtual ~Dll();
640 public:
641 Dll(): handle(0) {}
643 ErrCode getProc(OUString const & name, ProcData * proc);
645 HMODULE handle;
646 Procs procs;
649 Dll::~Dll() {
650 if (handle != 0 && !FreeLibrary(handle)) {
651 SAL_WARN("basic", "FreeLibrary(" << handle << ") failed with " << GetLastError());
655 ErrCode Dll::getProc(OUString const & name, ProcData * proc) {
656 Procs::iterator i(procs.find(name));
657 if (i != procs.end()) {
658 *proc = i->second;
659 return ERRCODE_NONE;
661 ErrCode e = getProcData(handle, name, proc);
662 if (e == ERRCODE_NONE) {
663 procs.emplace(name, *proc);
665 return e;
668 OUString fullDllName(OUString const & name) {
669 OUString full(name);
670 if (full.indexOf('.') == -1) {
671 full += ".DLL";
673 return full;
678 struct SbiDllMgr::Impl {
679 private:
680 typedef std::map< OUString, rtl::Reference< Dll > > Dlls;
682 public:
683 Impl() = default;
684 Impl(const Impl&) = delete;
685 const Impl& operator=(const Impl&) = delete;
687 Dll * getDll(OUString const & name);
689 Dlls dlls;
692 Dll * SbiDllMgr::Impl::getDll(OUString const & name) {
693 Dlls::iterator i(dlls.find(name));
694 if (i == dlls.end()) {
695 i = dlls.emplace(name, new Dll).first;
696 HMODULE h = LoadLibraryW(o3tl::toW(name.getStr()));
697 if (h == 0) {
698 dlls.erase(i);
699 return 0;
701 i->second->handle = h;
703 return i->second.get();
706 ErrCode SbiDllMgr::Call(
707 OUString const & function, OUString const & library,
708 SbxArray * arguments, SbxVariable & result, bool cdeclConvention)
710 if (cdeclConvention) {
711 return ERRCODE_BASIC_NOT_IMPLEMENTED;
713 OUString dllName(fullDllName(library));
714 Dll * dll = impl_->getDll(dllName);
715 if (dll == 0) {
716 return ERRCODE_BASIC_BAD_DLL_LOAD;
718 ProcData proc;
719 ErrCode e = dll->getProc(function, &proc);
720 if (e != ERRCODE_NONE) {
721 return e;
723 return call(dllName, proc, arguments, result);
726 void SbiDllMgr::FreeDll(OUString const & library) {
727 impl_->dlls.erase(library);
730 SbiDllMgr::SbiDllMgr(): impl_(new Impl) {}
732 SbiDllMgr::~SbiDllMgr() {}
734 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */