1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "precompiled_basic.hxx" 29 #include "sal/config.h" 30 31 #include <algorithm> 32 #include <cstddef> 33 #include <list> 34 #include <map> 35 #include <vector> 36 37 #include "basic/sbx.hxx" 38 #include "basic/sbxvar.hxx" 39 #include "runtime.hxx" 40 #include "osl/thread.h" 41 #include "rtl/ref.hxx" 42 #include "rtl/string.hxx" 43 #include "rtl/ustring.hxx" 44 #include "salhelper/simplereferenceobject.hxx" 45 #include "tools/svwin.h" 46 47 #undef max 48 49 #include "dllmgr.hxx" 50 51 /* Open issues: 52 53 Only 32-bit Windows for now. 54 55 Missing support for functions returning structs (see TODO in call()). 56 57 Missing support for additional data types (64 bit integers, Any, ...; would 58 trigger OSL_ASSERT(false) in various switches). 59 60 It is assumed that the variables passed into SbiDllMgr::Call to represent 61 the arguments and return value have types that exactly match the Declare 62 statement; it would be better if this code had access to the function 63 signature from the Declare statement, so that it could convert the passed 64 variables accordingly. 65 */ 66 67 #if defined WNT // only 32-bit Windows, actually 68 69 extern "C" { 70 71 int __stdcall DllMgr_call32(FARPROC, void const * stack, std::size_t size); 72 double __stdcall DllMgr_callFp(FARPROC, void const * stack, std::size_t size); 73 74 } 75 76 namespace { 77 78 char * address(std::vector< char > & blob) { 79 return blob.empty() ? 0 : &blob[0]; 80 } 81 82 SbError convert(rtl::OUString const & source, rtl::OString * target) { 83 return 84 source.convertToString( 85 target, osl_getThreadTextEncoding(), 86 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | 87 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)) 88 ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT; 89 //TODO: more specific errcode? 90 } 91 92 SbError convert(char const * source, sal_Int32 length, rtl::OUString * target) { 93 return 94 rtl_convertStringToUString( 95 &target->pData, source, length, osl_getThreadTextEncoding(), 96 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | 97 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | 98 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) 99 ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT; 100 //TODO: more specific errcode? 101 } 102 103 struct UnmarshalData { 104 UnmarshalData(SbxVariable * theVariable, void * theBuffer): 105 variable(theVariable), buffer(theBuffer) {} 106 107 SbxVariable * variable; 108 void * buffer; 109 }; 110 111 struct StringData: public UnmarshalData { 112 StringData(SbxVariable * theVariable, void * theBuffer, bool theSpecial): 113 UnmarshalData(theVariable, theBuffer), special(theSpecial) {} 114 115 bool special; 116 }; 117 118 class MarshalData: private boost::noncopyable { 119 public: 120 std::vector< char > * newBlob() { 121 blobs_.push_front(std::vector< char >()); 122 return &blobs_.front(); 123 } 124 125 std::vector< UnmarshalData > unmarshal; 126 127 std::vector< StringData > unmarshalStrings; 128 129 private: 130 std::list< std::vector< char > > blobs_; 131 }; 132 133 std::size_t align(std::size_t address, std::size_t alignment) { 134 // alignment = 2^k for some k >= 0 135 return (address + (alignment - 1)) & ~(alignment - 1); 136 } 137 138 char * align( 139 std::vector< char > & blob, std::size_t alignment, std::size_t offset, 140 std::size_t add) 141 { 142 std::vector< char >::size_type n = blob.size(); 143 n = align(n - offset, alignment) + offset; //TODO: overflow in align() 144 blob.resize(n + add); //TODO: overflow 145 return address(blob) + n; 146 } 147 148 template< typename T > void add( 149 std::vector< char > & blob, T const & data, std::size_t alignment, 150 std::size_t offset) 151 { 152 *reinterpret_cast< T * >(align(blob, alignment, offset, sizeof (T))) = data; 153 } 154 155 std::size_t alignment(SbxVariable * variable) { 156 OSL_ASSERT(variable != 0); 157 if ((variable->GetType() & SbxARRAY) == 0) { 158 switch (variable->GetType()) { 159 case SbxINTEGER: 160 return 2; 161 case SbxLONG: 162 case SbxSINGLE: 163 case SbxSTRING: 164 return 4; 165 case SbxDOUBLE: 166 return 8; 167 case SbxOBJECT: 168 { 169 std::size_t n = 1; 170 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())-> 171 GetProperties(); 172 for (sal_uInt16 i = 0; i < props->Count(); ++i) { 173 n = std::max(n, alignment(props->Get(i))); 174 } 175 return n; 176 } 177 case SbxBOOL: 178 case SbxBYTE: 179 return 1; 180 default: 181 OSL_ASSERT(false); 182 return 1; 183 } 184 } else { 185 SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject()); 186 int dims = arr->GetDims(); 187 std::vector< sal_Int32 > low(dims); 188 for (int i = 0; i < dims; ++i) { 189 sal_Int32 up; 190 arr->GetDim32(i + 1, low[i], up); 191 } 192 return alignment(arr->Get32(&low[0])); 193 } 194 } 195 196 SbError marshal( 197 bool outer, SbxVariable * variable, bool special, 198 std::vector< char > & blob, std::size_t offset, MarshalData & data); 199 200 SbError marshalString( 201 SbxVariable * variable, bool special, MarshalData & data, void ** buffer) 202 { 203 OSL_ASSERT(variable != 0 && buffer != 0); 204 rtl::OString str; 205 SbError e = convert(variable->GetString(), &str); 206 if (e != ERRCODE_NONE) { 207 return e; 208 } 209 std::vector< char > * blob = data.newBlob(); 210 blob->insert( 211 blob->begin(), str.getStr(), str.getStr() + str.getLength() + 1); 212 *buffer = address(*blob); 213 data.unmarshalStrings.push_back(StringData(variable, *buffer, special)); 214 return ERRCODE_NONE; 215 } 216 217 SbError marshalStruct( 218 SbxVariable * variable, std::vector< char > & blob, std::size_t offset, 219 MarshalData & data) 220 { 221 OSL_ASSERT(variable != 0); 222 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())-> 223 GetProperties(); 224 for (sal_uInt16 i = 0; i < props->Count(); ++i) { 225 SbError e = marshal(false, props->Get(i), false, blob, offset, data); 226 if (e != ERRCODE_NONE) { 227 return e; 228 } 229 } 230 return ERRCODE_NONE; 231 } 232 233 SbError marshalArray( 234 SbxVariable * variable, std::vector< char > & blob, std::size_t offset, 235 MarshalData & data) 236 { 237 OSL_ASSERT(variable != 0); 238 SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject()); 239 int dims = arr->GetDims(); 240 std::vector< sal_Int32 > low(dims); 241 std::vector< sal_Int32 > up(dims); 242 for (int i = 0; i < dims; ++i) { 243 arr->GetDim32(i + 1, low[i], up[i]); 244 } 245 for (std::vector< sal_Int32 > idx = low;;) { 246 SbError e = marshal( 247 false, arr->Get32(&idx[0]), false, blob, offset, data); 248 if (e != ERRCODE_NONE) { 249 return e; 250 } 251 int i = dims - 1; 252 while (idx[i] == up[i]) { 253 idx[i] = low[i]; 254 if (i == 0) { 255 return ERRCODE_NONE; 256 } 257 --i; 258 } 259 ++idx[i]; 260 } 261 } 262 263 // 8-aligned structs are only 4-aligned on stack, so alignment of members in 264 // such structs must take that into account via "offset" 265 SbError marshal( 266 bool outer, SbxVariable * variable, bool special, 267 std::vector< char > & blob, std::size_t offset, MarshalData & data) 268 { 269 OSL_ASSERT(variable != 0); 270 271 SbxDataType eVarType = variable->GetType(); 272 bool bByVal = (variable->GetFlags() & SBX_REFERENCE) == 0; 273 if( !bByVal && !SbiRuntime::isVBAEnabled() && eVarType == SbxSTRING ) 274 bByVal = true; 275 276 if (bByVal) { 277 if ((eVarType & SbxARRAY) == 0) { 278 switch (eVarType) { 279 case SbxINTEGER: 280 add(blob, variable->GetInteger(), outer ? 4 : 2, offset); 281 break; 282 case SbxLONG: 283 add(blob, variable->GetLong(), 4, offset); 284 break; 285 case SbxSINGLE: 286 add(blob, variable->GetSingle(), 4, offset); 287 break; 288 case SbxDOUBLE: 289 add(blob, variable->GetDouble(), outer ? 4 : 8, offset); 290 break; 291 case SbxSTRING: 292 { 293 void * p; 294 SbError e = marshalString(variable, special, data, &p); 295 if (e != ERRCODE_NONE) { 296 return e; 297 } 298 add(blob, p, 4, offset); 299 break; 300 } 301 case SbxOBJECT: 302 { 303 align(blob, outer ? 4 : alignment(variable), offset, 0); 304 SbError e = marshalStruct(variable, blob, offset, data); 305 if (e != ERRCODE_NONE) { 306 return e; 307 } 308 break; 309 } 310 case SbxBOOL: 311 add(blob, variable->GetBool(), outer ? 4 : 1, offset); 312 break; 313 case SbxBYTE: 314 add(blob, variable->GetByte(), outer ? 4 : 1, offset); 315 break; 316 default: 317 OSL_ASSERT(false); 318 break; 319 } 320 } else { 321 SbError e = marshalArray(variable, blob, offset, data); 322 if (e != ERRCODE_NONE) { 323 return e; 324 } 325 } 326 } else { 327 if ((eVarType & SbxARRAY) == 0) { 328 switch (eVarType) { 329 case SbxINTEGER: 330 case SbxLONG: 331 case SbxSINGLE: 332 case SbxDOUBLE: 333 case SbxBOOL: 334 case SbxBYTE: 335 add(blob, variable->data(), 4, offset); 336 break; 337 case SbxSTRING: 338 { 339 std::vector< char > * blob2 = data.newBlob(); 340 void * p; 341 SbError e = marshalString(variable, special, data, &p); 342 if (e != ERRCODE_NONE) { 343 return e; 344 } 345 add(*blob2, p, 4, 0); 346 add(blob, address(*blob2), 4, offset); 347 break; 348 } 349 case SbxOBJECT: 350 { 351 std::vector< char > * blob2 = data.newBlob(); 352 SbError e = marshalStruct(variable, *blob2, 0, data); 353 if (e != ERRCODE_NONE) { 354 return e; 355 } 356 void * p = address(*blob2); 357 if (outer) { 358 data.unmarshal.push_back(UnmarshalData(variable, p)); 359 } 360 add(blob, p, 4, offset); 361 break; 362 } 363 default: 364 OSL_ASSERT(false); 365 break; 366 } 367 } else { 368 std::vector< char > * blob2 = data.newBlob(); 369 SbError e = marshalArray(variable, *blob2, 0, data); 370 if (e != ERRCODE_NONE) { 371 return e; 372 } 373 void * p = address(*blob2); 374 if (outer) { 375 data.unmarshal.push_back(UnmarshalData(variable, p)); 376 } 377 add(blob, p, 4, offset); 378 } 379 } 380 return ERRCODE_NONE; 381 } 382 383 template< typename T > T read(void const ** pointer) { 384 T const * p = static_cast< T const * >(*pointer); 385 *pointer = static_cast< void const * >(p + 1); 386 return *p; 387 } 388 389 void const * unmarshal(SbxVariable * variable, void const * data) { 390 OSL_ASSERT(variable != 0); 391 if ((variable->GetType() & SbxARRAY) == 0) { 392 switch (variable->GetType()) { 393 case SbxINTEGER: 394 variable->PutInteger(read< sal_Int16 >(&data)); 395 break; 396 case SbxLONG: 397 variable->PutLong(read< sal_Int32 >(&data)); 398 break; 399 case SbxSINGLE: 400 variable->PutSingle(read< float >(&data)); 401 break; 402 case SbxDOUBLE: 403 variable->PutDouble(read< double >(&data)); 404 break; 405 case SbxSTRING: 406 read< char * >(&data); // handled by unmarshalString 407 break; 408 case SbxOBJECT: 409 { 410 data = reinterpret_cast< void const * >( 411 align( 412 reinterpret_cast< sal_uIntPtr >(data), 413 alignment(variable))); 414 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())-> 415 GetProperties(); 416 for (sal_uInt16 i = 0; i < props->Count(); ++i) { 417 data = unmarshal(props->Get(i), data); 418 } 419 break; 420 } 421 case SbxBOOL: 422 variable->PutBool(read< sal_Bool >(&data)); 423 break; 424 case SbxBYTE: 425 variable->PutByte(read< sal_uInt8 >(&data)); 426 break; 427 default: 428 OSL_ASSERT(false); 429 break; 430 } 431 } else { 432 SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject()); 433 int dims = arr->GetDims(); 434 std::vector< sal_Int32 > low(dims); 435 std::vector< sal_Int32 > up(dims); 436 for (int i = 0; i < dims; ++i) { 437 arr->GetDim32(i + 1, low[i], up[i]); 438 } 439 for (std::vector< sal_Int32 > idx = low;;) { 440 data = unmarshal(arr->Get32(&idx[0]), data); 441 int i = dims - 1; 442 while (idx[i] == up[i]) { 443 idx[i] = low[i]; 444 if (i == 0) { 445 goto done; 446 } 447 --i; 448 } 449 ++idx[i]; 450 } 451 done:; 452 } 453 return data; 454 } 455 456 SbError unmarshalString(StringData const & data, SbxVariable & result) { 457 rtl::OUString str; 458 if (data.buffer != 0) { 459 char const * p = static_cast< char const * >(data.buffer); 460 sal_Int32 len; 461 if (data.special) { 462 len = static_cast< sal_Int32 >(result.GetULong()); 463 if (len < 0) { // i.e., DWORD result >= 2^31 464 return ERRCODE_BASIC_BAD_ARGUMENT; 465 //TODO: more specific errcode? 466 } 467 } else { 468 len = rtl_str_getLength(p); 469 } 470 SbError e = convert(p, len, &str); 471 if (e != ERRCODE_NONE) { 472 return e; 473 } 474 } 475 data.variable->PutString(String(str)); 476 return ERRCODE_NONE; 477 } 478 479 struct ProcData { 480 rtl::OString name; 481 FARPROC proc; 482 }; 483 484 SbError call( 485 rtl::OUString const & dll, ProcData const & proc, SbxArray * arguments, 486 SbxVariable & result) 487 { 488 std::vector< char > stack; 489 MarshalData data; 490 // For DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer) 491 // from kernel32, upon return, filled lpBuffer length is result DWORD, which 492 // requires special handling in unmarshalString; other functions might 493 // require similar treatment, too: 494 bool special = 495 dll.equalsIgnoreAsciiCaseAsciiL( 496 RTL_CONSTASCII_STRINGPARAM("KERNEL32.DLL")) && 497 (proc.name == 498 rtl::OString(RTL_CONSTASCII_STRINGPARAM("GetLogicalDriveStringsA"))); 499 for (sal_uInt16 i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) { 500 SbError e = marshal( 501 true, arguments->Get(i), special && i == 2, stack, stack.size(), 502 data); 503 if (e != ERRCODE_NONE) { 504 return e; 505 } 506 align(stack, 4, 0, 0); 507 } 508 switch (result.GetType()) { 509 case SbxEMPTY: 510 DllMgr_call32(proc.proc, address(stack), stack.size()); 511 break; 512 case SbxINTEGER: 513 result.PutInteger( 514 static_cast< sal_Int16 >( 515 DllMgr_call32(proc.proc, address(stack), stack.size()))); 516 break; 517 case SbxLONG: 518 result.PutLong( 519 static_cast< sal_Int32 >( 520 DllMgr_call32(proc.proc, address(stack), stack.size()))); 521 break; 522 case SbxSINGLE: 523 result.PutSingle( 524 static_cast< float >( 525 DllMgr_callFp(proc.proc, address(stack), stack.size()))); 526 break; 527 case SbxDOUBLE: 528 result.PutDouble( 529 DllMgr_callFp(proc.proc, address(stack), stack.size())); 530 break; 531 case SbxSTRING: 532 { 533 char const * s1 = reinterpret_cast< char const * >( 534 DllMgr_call32(proc.proc, address(stack), stack.size())); 535 rtl::OUString s2; 536 SbError e = convert(s1, rtl_str_getLength(s1), &s2); 537 if (e != ERRCODE_NONE) { 538 return e; 539 } 540 result.PutString(String(s2)); 541 break; 542 } 543 case SbxOBJECT: 544 //TODO 545 DllMgr_call32(proc.proc, address(stack), stack.size()); 546 break; 547 case SbxBOOL: 548 result.PutBool( 549 static_cast< sal_Bool >( 550 DllMgr_call32(proc.proc, address(stack), stack.size()))); 551 break; 552 case SbxBYTE: 553 result.PutByte( 554 static_cast< sal_uInt8 >( 555 DllMgr_call32(proc.proc, address(stack), stack.size()))); 556 break; 557 default: 558 OSL_ASSERT(false); 559 break; 560 } 561 for (sal_uInt16 i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) { 562 arguments->Get(i)->ResetFlag(SBX_REFERENCE); 563 //TODO: skipped for errors?!? 564 } 565 for (std::vector< UnmarshalData >::iterator i(data.unmarshal.begin()); 566 i != data.unmarshal.end(); ++i) 567 { 568 unmarshal(i->variable, i->buffer); 569 } 570 for (std::vector< StringData >::iterator i(data.unmarshalStrings.begin()); 571 i != data.unmarshalStrings.end(); ++i) 572 { 573 SbError e = unmarshalString(*i, result); 574 if (e != ERRCODE_NONE) { 575 return e; 576 } 577 } 578 return ERRCODE_NONE; 579 } 580 581 SbError getProcData(HMODULE handle, rtl::OUString const & name, ProcData * proc) 582 { 583 OSL_ASSERT(proc != 0); 584 if (name.getLength() != 0 && name[0] == '@') { //TODO: "@" vs. "#"??? 585 sal_Int32 n = name.copy(1).toInt32(); //TODO: handle bad input 586 if (n <= 0 || n > 0xFFFF) { 587 return ERRCODE_BASIC_BAD_ARGUMENT; //TODO: more specific errcode? 588 } 589 FARPROC p = GetProcAddress(handle, reinterpret_cast< LPCSTR >(n)); 590 if (p != 0) { 591 proc->name = rtl::OString(RTL_CONSTASCII_STRINGPARAM("#")) + 592 rtl::OString::valueOf(n); 593 proc->proc = p; 594 return ERRCODE_NONE; 595 } 596 } else { 597 rtl::OString name8; 598 SbError e = convert(name, &name8); 599 if (e != ERRCODE_NONE) { 600 return e; 601 } 602 FARPROC p = GetProcAddress(handle, name8.getStr()); 603 if (p != 0) { 604 proc->name = name8; 605 proc->proc = p; 606 return ERRCODE_NONE; 607 } 608 sal_Int32 i = name8.indexOf('#'); 609 if (i != -1) { 610 name8 = name8.copy(0, i); 611 p = GetProcAddress(handle, name8.getStr()); 612 if (p != 0) { 613 proc->name = name8; 614 proc->proc = p; 615 return ERRCODE_NONE; 616 } 617 } 618 rtl::OString real( 619 rtl::OString(RTL_CONSTASCII_STRINGPARAM("_")) + name8); 620 p = GetProcAddress(handle, real.getStr()); 621 if (p != 0) { 622 proc->name = real; 623 proc->proc = p; 624 return ERRCODE_NONE; 625 } 626 real = name8 + rtl::OString(RTL_CONSTASCII_STRINGPARAM("A")); 627 p = GetProcAddress(handle, real.getStr()); 628 if (p != 0) { 629 proc->name = real; 630 proc->proc = p; 631 return ERRCODE_NONE; 632 } 633 } 634 return ERRCODE_BASIC_PROC_UNDEFINED; 635 } 636 637 struct Dll: public salhelper::SimpleReferenceObject { 638 private: 639 typedef std::map< rtl::OUString, ProcData > Procs; 640 641 virtual ~Dll(); 642 643 public: 644 Dll(): handle(0) {} 645 646 SbError getProc(rtl::OUString const & name, ProcData * proc); 647 648 HMODULE handle; 649 Procs procs; 650 }; 651 652 Dll::~Dll() { 653 if (handle != 0 && !FreeLibrary(handle)) { 654 OSL_TRACE("FreeLibrary(%p) failed with %u", handle, GetLastError()); 655 } 656 } 657 658 SbError Dll::getProc(rtl::OUString const & name, ProcData * proc) { 659 Procs::iterator i(procs.find(name)); 660 if (i != procs.end()) { 661 *proc = i->second; 662 return ERRCODE_NONE; 663 } 664 SbError e = getProcData(handle, name, proc); 665 if (e == ERRCODE_NONE) { 666 procs.insert(Procs::value_type(name, *proc)); 667 } 668 return e; 669 } 670 671 rtl::OUString fullDllName(rtl::OUString const & name) { 672 rtl::OUString full(name); 673 if (full.indexOf('.') == -1) { 674 full += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".DLL")); 675 } 676 return full; 677 } 678 679 } 680 681 struct SbiDllMgr::Impl: private boost::noncopyable { 682 private: 683 typedef std::map< rtl::OUString, rtl::Reference< Dll > > Dlls; 684 685 public: 686 Dll * getDll(rtl::OUString const & name); 687 688 Dlls dlls; 689 }; 690 691 Dll * SbiDllMgr::Impl::getDll(rtl::OUString const & name) { 692 Dlls::iterator i(dlls.find(name)); 693 if (i == dlls.end()) { 694 i = dlls.insert(Dlls::value_type(name, new Dll)).first; 695 HMODULE h = LoadLibraryW(reinterpret_cast<LPCWSTR>(name.getStr())); 696 if (h == 0) { 697 dlls.erase(i); 698 return 0; 699 } 700 i->second->handle = h; 701 } 702 return i->second.get(); 703 } 704 705 SbError SbiDllMgr::Call( 706 rtl::OUString const & function, rtl::OUString const & library, 707 SbxArray * arguments, SbxVariable & result, bool cdeclConvention) 708 { 709 if (cdeclConvention) { 710 return ERRCODE_BASIC_NOT_IMPLEMENTED; 711 } 712 rtl::OUString dllName(fullDllName(library)); 713 Dll * dll = impl_->getDll(dllName); 714 if (dll == 0) { 715 return ERRCODE_BASIC_BAD_DLL_LOAD; 716 } 717 ProcData proc; 718 SbError e = dll->getProc(function, &proc); 719 if (e != ERRCODE_NONE) { 720 return e; 721 } 722 return call(dllName, proc, arguments, result); 723 } 724 725 void SbiDllMgr::FreeDll(rtl::OUString const & library) { 726 impl_->dlls.erase(library); 727 } 728 729 #else 730 731 struct SbiDllMgr::Impl {}; 732 733 SbError SbiDllMgr::Call( 734 rtl::OUString const &, rtl::OUString const &, SbxArray *, SbxVariable &, 735 bool) 736 { 737 return ERRCODE_BASIC_NOT_IMPLEMENTED; 738 } 739 740 void SbiDllMgr::FreeDll(rtl::OUString const &) {} 741 742 #endif 743 744 SbiDllMgr::SbiDllMgr(): impl_(new Impl) {} 745 746 SbiDllMgr::~SbiDllMgr() {} 747