tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / basic / source / runtime / dllmgr-x86.cxx
blob7ab84d7f8b569f661360a5b81bd3c462f0ade48e
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 <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>
45 #undef max
47 #include "dllmgr.hxx"
49 using namespace css;
50 using namespace css::uno;
52 /* Open issues:
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.
66 extern "C" {
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);
73 namespace {
75 char * address(std::vector< char > & blob) {
76 return blob.empty() ? 0 : &blob[0];
79 ErrCode convert(OUString const & source, OString * target) {
80 return
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) {
90 return
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;
105 void * buffer;
108 struct StringData: public UnmarshalData {
109 StringData(SbxVariable * theVariable, void * theBuffer, bool theSpecial):
110 UnmarshalData(theVariable, theBuffer), special(theSpecial) {}
112 bool special;
115 class MarshalData {
116 public:
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;
130 private:
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);
139 char * align(
140 std::vector< char > & blob, std::size_t alignment, std::size_t offset,
141 std::size_t add)
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,
151 std::size_t offset)
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()) {
160 case SbxINTEGER:
161 return 2;
162 case SbxLONG:
163 case SbxSINGLE:
164 case SbxSTRING:
165 return 4;
166 case SbxDOUBLE:
167 return 8;
168 case SbxOBJECT:
170 std::size_t n = 1;
171 SbxObject* pobj = dynamic_cast<SbxObject*>(variable->GetObject());
172 assert(pobj);
173 SbxArray* props = pobj->GetProperties();
174 for (sal_uInt32 i = 0; i < props->Count(); ++i)
176 n = std::max(n, alignment(props->Get(i)));
178 return n;
180 case SbxBOOL:
181 case SbxBYTE:
182 return 1;
183 default:
184 assert(false);
185 return 1;
187 } else {
188 SbxDimArray * arr = dynamic_cast<SbxDimArray*>( variable->GetObject() );
189 assert(arr);
190 sal_Int32 dims = arr->GetDims();
191 std::vector< sal_Int32 > low(dims);
192 for (sal_Int32 i = 0; i < dims; ++i) {
193 sal_Int32 up;
194 arr->GetDim(i + 1, low[i], up);
196 return alignment(arr->Get(&low[0]));
200 ErrCode marshal(
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);
208 OString str;
209 ErrCode e = convert(variable->GetOUString(), &str);
210 if (e != ERRCODE_NONE) {
211 return e;
213 std::vector< char > * blob = data.newBlob();
214 blob->insert(
215 blob->begin(), str.getStr(), str.getStr() + str.getLength() + 1);
216 *buffer = address(*blob);
217 data.unmarshalStrings.push_back(StringData(variable, *buffer, special));
218 return ERRCODE_NONE;
221 ErrCode marshalStruct(
222 SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
223 MarshalData & data)
225 assert(variable != 0);
226 SbxObject* pobj = dynamic_cast<SbxObject*>(variable->GetObject());
227 assert(pobj);
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) {
233 return e;
236 return ERRCODE_NONE;
239 ErrCode marshalArray(
240 SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
241 MarshalData & data)
243 assert(variable != 0);
244 SbxDimArray * arr = dynamic_cast<SbxDimArray*>( variable->GetObject() );
245 assert(arr);
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) {
255 return e;
257 sal_Int32 i = dims - 1;
258 while (idx[i] == up[i]) {
259 idx[i] = low[i];
260 if (i == 0) {
261 return ERRCODE_NONE;
263 --i;
265 ++idx[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"
271 ErrCode marshal(
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 )
280 bByVal = true;
282 if (bByVal) {
283 if ((eVarType & SbxARRAY) == 0) {
284 switch (eVarType) {
285 case SbxINTEGER:
286 add(blob, variable->GetInteger(), outer ? 4 : 2, offset);
287 break;
288 case SbxLONG:
289 add(blob, variable->GetLong(), 4, offset);
290 break;
291 case SbxSINGLE:
292 add(blob, variable->GetSingle(), 4, offset);
293 break;
294 case SbxDOUBLE:
295 add(blob, variable->GetDouble(), outer ? 4 : 8, offset);
296 break;
297 case SbxSTRING:
299 void * p;
300 ErrCode e = marshalString(variable, special, data, &p);
301 if (e != ERRCODE_NONE) {
302 return e;
304 add(blob, p, 4, offset);
305 break;
307 case SbxOBJECT:
309 align(blob, outer ? 4 : alignment(variable), offset, 0);
310 ErrCode e = marshalStruct(variable, blob, offset, data);
311 if (e != ERRCODE_NONE) {
312 return e;
314 break;
316 case SbxBOOL:
317 add(blob, variable->GetBool(), outer ? 4 : 1, offset);
318 break;
319 case SbxBYTE:
320 add(blob, variable->GetByte(), outer ? 4 : 1, offset);
321 break;
322 default:
323 assert(false);
324 break;
326 } else {
327 ErrCode e = marshalArray(variable, blob, offset, data);
328 if (e != ERRCODE_NONE) {
329 return e;
332 } else {
333 if ((eVarType & SbxARRAY) == 0) {
334 switch (eVarType) {
335 case SbxINTEGER:
336 case SbxLONG:
337 case SbxSINGLE:
338 case SbxDOUBLE:
339 case SbxBOOL:
340 case SbxBYTE:
341 add(blob, variable->data(), 4, offset);
342 break;
343 case SbxSTRING:
345 void * p;
346 ErrCode e = marshalString(variable, special, data, &p);
347 if (e != ERRCODE_NONE) {
348 return e;
350 std::vector< char > * blob2 = data.newBlob();
351 add(*blob2, p, 4, 0);
352 add(blob, address(*blob2), 4, offset);
353 break;
355 case SbxOBJECT:
357 std::vector< char > * blob2 = data.newBlob();
358 ErrCode e = marshalStruct(variable, *blob2, 0, data);
359 if (e != ERRCODE_NONE) {
360 return e;
362 void * p = address(*blob2);
363 if (outer) {
364 data.unmarshal.push_back(UnmarshalData(variable, p));
366 add(blob, p, 4, offset);
367 break;
369 default:
370 assert(false);
371 break;
373 } else {
374 std::vector< char > * blob2 = data.newBlob();
375 ErrCode e = marshalArray(variable, *blob2, 0, data);
376 if (e != ERRCODE_NONE) {
377 return e;
379 void * p = address(*blob2);
380 if (outer) {
381 data.unmarshal.push_back(UnmarshalData(variable, p));
383 add(blob, p, 4, offset);
386 return ERRCODE_NONE;
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);
392 return *p;
395 void const * unmarshal(SbxVariable * variable, void const * data) {
396 assert(variable != 0);
397 if ((variable->GetType() & SbxARRAY) == 0) {
398 switch (variable->GetType()) {
399 case SbxINTEGER:
400 variable->PutInteger(read< sal_Int16 >(&data));
401 break;
402 case SbxLONG:
403 variable->PutLong(read< sal_Int32 >(&data));
404 break;
405 case SbxSINGLE:
406 variable->PutSingle(read< float >(&data));
407 break;
408 case SbxDOUBLE:
409 variable->PutDouble(read< double >(&data));
410 break;
411 case SbxSTRING:
412 read< char * >(&data); // handled by unmarshalString
413 break;
414 case SbxOBJECT:
416 data = reinterpret_cast< void const * >(
417 align(
418 reinterpret_cast< sal_uIntPtr >(data),
419 alignment(variable)));
420 SbxObject* pobj = dynamic_cast<SbxObject*>(variable->GetObject());
421 assert(pobj);
422 SbxArray* props = pobj->GetProperties();
423 for (sal_uInt32 i = 0; i < props->Count(); ++i)
425 data = unmarshal(props->Get(i), data);
427 break;
429 case SbxBOOL:
430 variable->PutBool(read< sal_Bool >(&data));
431 break;
432 case SbxBYTE:
433 variable->PutByte(read< sal_uInt8 >(&data));
434 break;
435 default:
436 assert(false);
437 break;
439 } else {
440 SbxDimArray * arr = dynamic_cast<SbxDimArray*>( variable->GetObject() );
441 assert(arr);
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]) {
452 idx[i] = low[i];
453 if (i == 0) {
454 goto done;
456 --i;
458 ++idx[i];
460 done:;
462 return data;
465 ErrCode unmarshalString(StringData const & data, SbxVariable & result) {
466 OUString str;
467 if (data.buffer != 0) {
468 char const * p = static_cast< char const * >(data.buffer);
469 sal_Int32 len;
470 if (data.special) {
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?
476 } else {
477 len = rtl_str_getLength(p);
479 ErrCode e = convert(p, len, &str);
480 if (e != ERRCODE_NONE) {
481 return e;
484 data.variable->PutString(str);
485 return ERRCODE_NONE;
488 struct ProcData {
489 OString name;
490 FARPROC proc;
493 ErrCode call(
494 OUString const & dll, ProcData const & proc, SbxArray * arguments,
495 SbxVariable & result)
497 std::vector< char > stack;
498 MarshalData data;
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(),
508 data);
509 if (e != ERRCODE_NONE) {
510 return e;
512 align(stack, 4, 0, 0);
514 switch (result.GetType()) {
515 case SbxEMPTY:
516 DllMgr_call32(proc.proc, address(stack), stack.size());
517 break;
518 case SbxINTEGER:
519 result.PutInteger(
520 static_cast< sal_Int16 >(
521 DllMgr_call32(proc.proc, address(stack), stack.size())));
522 break;
523 case SbxLONG:
524 result.PutLong(
525 static_cast< sal_Int32 >(
526 DllMgr_call32(proc.proc, address(stack), stack.size())));
527 break;
528 case SbxSINGLE:
529 result.PutSingle(
530 static_cast< float >(
531 DllMgr_callFp(proc.proc, address(stack), stack.size())));
532 break;
533 case SbxDOUBLE:
534 result.PutDouble(
535 DllMgr_callFp(proc.proc, address(stack), stack.size()));
536 break;
537 case SbxSTRING:
539 char const * s1 = reinterpret_cast< char const * >(
540 DllMgr_call32(proc.proc, address(stack), stack.size()));
541 OUString s2;
542 ErrCode e = convert(s1, rtl_str_getLength(s1), &s2);
543 if (e != ERRCODE_NONE) {
544 return e;
546 result.PutString(s2);
547 break;
549 case SbxOBJECT:
550 //TODO
551 DllMgr_call32(proc.proc, address(stack), stack.size());
552 break;
553 case SbxBOOL:
554 result.PutBool(
555 bool(DllMgr_call32(proc.proc, address(stack), stack.size())));
556 break;
557 case SbxBYTE:
558 result.PutByte(
559 static_cast< sal_uInt8 >(
560 DllMgr_call32(proc.proc, address(stack), stack.size())));
561 break;
562 default:
563 assert(false);
564 break;
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) {
579 return e;
582 return ERRCODE_NONE;
585 ErrCode getProcData(HMODULE handle, OUString const & name, ProcData * proc)
587 assert(proc != 0);
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));
594 if (p != 0) {
595 proc->name = OString("#") + OString::number(n);
596 proc->proc = p;
597 return ERRCODE_NONE;
599 } else {
600 OString name8;
601 ErrCode e = convert(name, &name8);
602 if (e != ERRCODE_NONE) {
603 return e;
605 FARPROC p = GetProcAddress(handle, name8.getStr());
606 if (p != 0) {
607 proc->name = name8;
608 proc->proc = p;
609 return ERRCODE_NONE;
611 sal_Int32 i = name8.indexOf('#');
612 if (i != -1) {
613 name8 = name8.copy(0, i);
614 p = GetProcAddress(handle, name8.getStr());
615 if (p != 0) {
616 proc->name = name8;
617 proc->proc = p;
618 return ERRCODE_NONE;
621 OString real(OString("_") + name8);
622 p = GetProcAddress(handle, real.getStr());
623 if (p != 0) {
624 proc->name = real;
625 proc->proc = p;
626 return ERRCODE_NONE;
628 real = name8 + OString("A");
629 p = GetProcAddress(handle, real.getStr());
630 if (p != 0) {
631 proc->name = real;
632 proc->proc = p;
633 return ERRCODE_NONE;
636 return ERRCODE_BASIC_PROC_UNDEFINED;
639 struct Dll: public salhelper::SimpleReferenceObject {
640 private:
641 typedef std::map< OUString, ProcData > Procs;
643 virtual ~Dll();
645 public:
646 Dll(): handle(0) {}
648 ErrCode getProc(OUString const & name, ProcData * proc);
650 HMODULE handle;
651 Procs procs;
654 Dll::~Dll() {
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()) {
663 *proc = i->second;
664 return ERRCODE_NONE;
666 ErrCode e = getProcData(handle, name, proc);
667 if (e == ERRCODE_NONE) {
668 procs.emplace(name, *proc);
670 return e;
673 OUString fullDllName(OUString const & name) {
674 OUString full(name);
675 if (full.indexOf('.') == -1) {
676 full += ".DLL";
678 return full;
683 struct SbiDllMgr::Impl {
684 private:
685 typedef std::map< OUString, rtl::Reference< Dll > > Dlls;
687 public:
688 Impl() = default;
689 Impl(const Impl&) = delete;
690 const Impl& operator=(const Impl&) = delete;
692 Dll * getDll(OUString const & name);
694 Dlls dlls;
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()));
702 if (h == 0) {
703 dlls.erase(i);
704 return 0;
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);
720 if (dll == 0) {
721 return ERRCODE_BASIC_BAD_DLL_LOAD;
723 ProcData proc;
724 ErrCode e = dll->getProc(OUString(function), &proc);
725 if (e != ERRCODE_NONE) {
726 return e;
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: */