fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / basic / source / runtime / dllmgr-x86.cxx
blob2bfd0377d1c3aef5820ec9b28f9b8761e89dd18d
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(WNT)
23 #include <windows.h>
24 #undef GetObject
25 #endif
27 #include <algorithm>
28 #include <cstddef>
29 #include <list>
30 #include <map>
31 #include <vector>
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"
42 #undef max
44 #include "dllmgr.hxx"
46 using namespace css;
47 using namespace css::uno;
49 /* Open issues:
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.
63 extern "C" {
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);
70 namespace {
72 char * address(std::vector< char > & blob) {
73 return blob.empty() ? 0 : &blob[0];
76 SbError convert(OUString const & source, OString * target) {
77 return
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) {
87 return
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;
102 void * buffer;
105 struct StringData: public UnmarshalData {
106 StringData(SbxVariable * theVariable, void * theBuffer, bool theSpecial):
107 UnmarshalData(theVariable, theBuffer), special(theSpecial) {}
109 bool special;
112 class MarshalData: private boost::noncopyable {
113 public:
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;
123 private:
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);
132 char * align(
133 std::vector< char > & blob, std::size_t alignment, std::size_t offset,
134 std::size_t add)
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,
144 std::size_t offset)
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()) {
153 case SbxINTEGER:
154 return 2;
155 case SbxLONG:
156 case SbxSINGLE:
157 case SbxSTRING:
158 return 4;
159 case SbxDOUBLE:
160 return 8;
161 case SbxOBJECT:
163 std::size_t n = 1;
164 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())->
165 GetProperties();
166 for (sal_uInt16 i = 0; i < props->Count(); ++i) {
167 n = std::max(n, alignment(props->Get(i)));
169 return n;
171 case SbxBOOL:
172 case SbxBYTE:
173 return 1;
174 default:
175 OSL_ASSERT(false);
176 return 1;
178 } else {
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) {
183 sal_Int32 up;
184 arr->GetDim32(i + 1, low[i], up);
186 return alignment(arr->Get32(&low[0]));
190 SbError marshal(
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);
198 OString str;
199 SbError e = convert(variable->GetOUString(), &str);
200 if (e != ERRCODE_NONE) {
201 return e;
203 std::vector< char > * blob = data.newBlob();
204 blob->insert(
205 blob->begin(), str.getStr(), str.getStr() + str.getLength() + 1);
206 *buffer = address(*blob);
207 data.unmarshalStrings.push_back(StringData(variable, *buffer, special));
208 return ERRCODE_NONE;
211 SbError marshalStruct(
212 SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
213 MarshalData & data)
215 OSL_ASSERT(variable != 0);
216 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())->
217 GetProperties();
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) {
221 return e;
224 return ERRCODE_NONE;
227 SbError marshalArray(
228 SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
229 MarshalData & data)
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;;) {
240 SbError e = marshal(
241 false, arr->Get32(&idx[0]), false, blob, offset, data);
242 if (e != ERRCODE_NONE) {
243 return e;
245 int i = dims - 1;
246 while (idx[i] == up[i]) {
247 idx[i] = low[i];
248 if (i == 0) {
249 return ERRCODE_NONE;
251 --i;
253 ++idx[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"
259 SbError marshal(
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 )
268 bByVal = true;
270 if (bByVal) {
271 if ((eVarType & SbxARRAY) == 0) {
272 switch (eVarType) {
273 case SbxINTEGER:
274 add(blob, variable->GetInteger(), outer ? 4 : 2, offset);
275 break;
276 case SbxLONG:
277 add(blob, variable->GetLong(), 4, offset);
278 break;
279 case SbxSINGLE:
280 add(blob, variable->GetSingle(), 4, offset);
281 break;
282 case SbxDOUBLE:
283 add(blob, variable->GetDouble(), outer ? 4 : 8, offset);
284 break;
285 case SbxSTRING:
287 void * p;
288 SbError e = marshalString(variable, special, data, &p);
289 if (e != ERRCODE_NONE) {
290 return e;
292 add(blob, p, 4, offset);
293 break;
295 case SbxOBJECT:
297 align(blob, outer ? 4 : alignment(variable), offset, 0);
298 SbError e = marshalStruct(variable, blob, offset, data);
299 if (e != ERRCODE_NONE) {
300 return e;
302 break;
304 case SbxBOOL:
305 add(blob, variable->GetBool(), outer ? 4 : 1, offset);
306 break;
307 case SbxBYTE:
308 add(blob, variable->GetByte(), outer ? 4 : 1, offset);
309 break;
310 default:
311 OSL_ASSERT(false);
312 break;
314 } else {
315 SbError e = marshalArray(variable, blob, offset, data);
316 if (e != ERRCODE_NONE) {
317 return e;
320 } else {
321 if ((eVarType & SbxARRAY) == 0) {
322 switch (eVarType) {
323 case SbxINTEGER:
324 case SbxLONG:
325 case SbxSINGLE:
326 case SbxDOUBLE:
327 case SbxBOOL:
328 case SbxBYTE:
329 add(blob, variable->data(), 4, offset);
330 break;
331 case SbxSTRING:
333 std::vector< char > * blob2 = data.newBlob();
334 void * p;
335 SbError e = marshalString(variable, special, data, &p);
336 if (e != ERRCODE_NONE) {
337 return e;
339 add(*blob2, p, 4, 0);
340 add(blob, address(*blob2), 4, offset);
341 break;
343 case SbxOBJECT:
345 std::vector< char > * blob2 = data.newBlob();
346 SbError e = marshalStruct(variable, *blob2, 0, data);
347 if (e != ERRCODE_NONE) {
348 return e;
350 void * p = address(*blob2);
351 if (outer) {
352 data.unmarshal.push_back(UnmarshalData(variable, p));
354 add(blob, p, 4, offset);
355 break;
357 default:
358 OSL_ASSERT(false);
359 break;
361 } else {
362 std::vector< char > * blob2 = data.newBlob();
363 SbError e = marshalArray(variable, *blob2, 0, data);
364 if (e != ERRCODE_NONE) {
365 return e;
367 void * p = address(*blob2);
368 if (outer) {
369 data.unmarshal.push_back(UnmarshalData(variable, p));
371 add(blob, p, 4, offset);
374 return ERRCODE_NONE;
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);
380 return *p;
383 void const * unmarshal(SbxVariable * variable, void const * data) {
384 OSL_ASSERT(variable != 0);
385 if ((variable->GetType() & SbxARRAY) == 0) {
386 switch (variable->GetType()) {
387 case SbxINTEGER:
388 variable->PutInteger(read< sal_Int16 >(&data));
389 break;
390 case SbxLONG:
391 variable->PutLong(read< sal_Int32 >(&data));
392 break;
393 case SbxSINGLE:
394 variable->PutSingle(read< float >(&data));
395 break;
396 case SbxDOUBLE:
397 variable->PutDouble(read< double >(&data));
398 break;
399 case SbxSTRING:
400 read< char * >(&data); // handled by unmarshalString
401 break;
402 case SbxOBJECT:
404 data = reinterpret_cast< void const * >(
405 align(
406 reinterpret_cast< sal_uIntPtr >(data),
407 alignment(variable)));
408 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())->
409 GetProperties();
410 for (sal_uInt16 i = 0; i < props->Count(); ++i) {
411 data = unmarshal(props->Get(i), data);
413 break;
415 case SbxBOOL:
416 variable->PutBool(read< sal_Bool >(&data));
417 break;
418 case SbxBYTE:
419 variable->PutByte(read< sal_uInt8 >(&data));
420 break;
421 default:
422 OSL_ASSERT(false);
423 break;
425 } else {
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);
435 int i = dims - 1;
436 while (idx[i] == up[i]) {
437 idx[i] = low[i];
438 if (i == 0) {
439 goto done;
441 --i;
443 ++idx[i];
445 done:;
447 return data;
450 SbError unmarshalString(StringData const & data, SbxVariable & result) {
451 OUString str;
452 if (data.buffer != 0) {
453 char const * p = static_cast< char const * >(data.buffer);
454 sal_Int32 len;
455 if (data.special) {
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?
461 } else {
462 len = rtl_str_getLength(p);
464 SbError e = convert(p, len, &str);
465 if (e != ERRCODE_NONE) {
466 return e;
469 data.variable->PutString(str);
470 return ERRCODE_NONE;
473 struct ProcData {
474 OString name;
475 FARPROC proc;
478 SbError call(
479 OUString const & dll, ProcData const & proc, SbxArray * arguments,
480 SbxVariable & result)
482 std::vector< char > stack;
483 MarshalData data;
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) {
491 SbError e = marshal(
492 true, arguments->Get(i), special && i == 2, stack, stack.size(),
493 data);
494 if (e != ERRCODE_NONE) {
495 return e;
497 align(stack, 4, 0, 0);
499 switch (result.GetType()) {
500 case SbxEMPTY:
501 DllMgr_call32(proc.proc, address(stack), stack.size());
502 break;
503 case SbxINTEGER:
504 result.PutInteger(
505 static_cast< sal_Int16 >(
506 DllMgr_call32(proc.proc, address(stack), stack.size())));
507 break;
508 case SbxLONG:
509 result.PutLong(
510 static_cast< sal_Int32 >(
511 DllMgr_call32(proc.proc, address(stack), stack.size())));
512 break;
513 case SbxSINGLE:
514 result.PutSingle(
515 static_cast< float >(
516 DllMgr_callFp(proc.proc, address(stack), stack.size())));
517 break;
518 case SbxDOUBLE:
519 result.PutDouble(
520 DllMgr_callFp(proc.proc, address(stack), stack.size()));
521 break;
522 case SbxSTRING:
524 char const * s1 = reinterpret_cast< char const * >(
525 DllMgr_call32(proc.proc, address(stack), stack.size()));
526 OUString s2;
527 SbError e = convert(s1, rtl_str_getLength(s1), &s2);
528 if (e != ERRCODE_NONE) {
529 return e;
531 result.PutString(s2);
532 break;
534 case SbxOBJECT:
535 //TODO
536 DllMgr_call32(proc.proc, address(stack), stack.size());
537 break;
538 case SbxBOOL:
539 result.PutBool(
540 static_cast< sal_Bool >(
541 DllMgr_call32(proc.proc, address(stack), stack.size())));
542 break;
543 case SbxBYTE:
544 result.PutByte(
545 static_cast< sal_uInt8 >(
546 DllMgr_call32(proc.proc, address(stack), stack.size())));
547 break;
548 default:
549 OSL_ASSERT(false);
550 break;
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) {
566 return e;
569 return 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));
581 if (p != 0) {
582 proc->name = OString("#") + OString::valueOf(n);
583 proc->proc = p;
584 return ERRCODE_NONE;
586 } else {
587 OString name8;
588 SbError e = convert(name, &name8);
589 if (e != ERRCODE_NONE) {
590 return e;
592 FARPROC p = GetProcAddress(handle, name8.getStr());
593 if (p != 0) {
594 proc->name = name8;
595 proc->proc = p;
596 return ERRCODE_NONE;
598 sal_Int32 i = name8.indexOf('#');
599 if (i != -1) {
600 name8 = name8.copy(0, i);
601 p = GetProcAddress(handle, name8.getStr());
602 if (p != 0) {
603 proc->name = name8;
604 proc->proc = p;
605 return ERRCODE_NONE;
608 OString real(OString("_") + name8);
609 p = GetProcAddress(handle, real.getStr());
610 if (p != 0) {
611 proc->name = real;
612 proc->proc = p;
613 return ERRCODE_NONE;
615 real = name8 + OString("A");
616 p = GetProcAddress(handle, real.getStr());
617 if (p != 0) {
618 proc->name = real;
619 proc->proc = p;
620 return ERRCODE_NONE;
623 return ERRCODE_BASIC_PROC_UNDEFINED;
626 struct Dll: public salhelper::SimpleReferenceObject {
627 private:
628 typedef std::map< OUString, ProcData > Procs;
630 virtual ~Dll();
632 public:
633 Dll(): handle(0) {}
635 SbError getProc(OUString const & name, ProcData * proc);
637 HMODULE handle;
638 Procs procs;
641 Dll::~Dll() {
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()) {
650 *proc = i->second;
651 return ERRCODE_NONE;
653 SbError e = getProcData(handle, name, proc);
654 if (e == ERRCODE_NONE) {
655 procs.insert(Procs::value_type(name, *proc));
657 return e;
660 OUString fullDllName(OUString const & name) {
661 OUString full(name);
662 if (full.indexOf('.') == -1) {
663 full += ".DLL";
665 return full;
670 struct SbiDllMgr::Impl: private boost::noncopyable {
671 private:
672 typedef std::map< OUString, rtl::Reference< Dll > > Dlls;
674 public:
675 Dll * getDll(OUString const & name);
677 Dlls dlls;
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()));
685 if (h == 0) {
686 dlls.erase(i);
687 return 0;
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);
703 if (dll == 0) {
704 return ERRCODE_BASIC_BAD_DLL_LOAD;
706 ProcData proc;
707 SbError e = dll->getProc(function, &proc);
708 if (e != ERRCODE_NONE) {
709 return e;
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: */