unresolved external symbol due to name mangling - c++

I am facing linker error for a XERCES function while upgrading it from 2.6 to 2.8
unresolved external symbol (?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QBG0#Z)
I checked the xerces-c_2.8.lib and found that name lib is bit different that the one in my .obj file It is as shown
?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QB_W0#Z
So I understand that linker wont find the match and throw error.
But I am unable to understand why my .obj file contains different signature.
code is including correct header files and lib from still incorrect name.
Any help would be appreciated.

You can use the undname.exe utility to recover the original C++ declaration.
?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QBG0#Z converts to:
virtual class xercesc_2_8::InputSource *
__thiscall xercesc_2_8::HandlerBase::resolveEntity(
unsigned short const * const,
unsigned short const * const)
?resolveEntity#HandlerBase#xercesc_2_8##UAEPAVInputSource#2#QB_W0#Z converts to:
virtual class xercesc_2_8::InputSource *
__thiscall xercesc_2_8::HandlerBase::resolveEntity(
wchar_t const * const,
wchar_t const * const)
Note the differences in the argument types, unsigned short vs wchar_t. For some reason, your compiler is not recognizing the wchar_t type. That could be because you have a very old compiler. Or it can be an option set wrong, on msvc it is C/C++, Language, "Treat wchar_t as Built-in type". Or you've got a macro that hacks the string type to unsigned short.

C++ allows function overloading so the parameters to a function are recorded in the name mangling. you might be trying to call the function with different parameter types than what the DLL expects.
Make sure that your header file matches the version of your DLL.

Related

I'm getting tautological compiler errors. How am I supposed to fix "argument of type "X" is incompatible with parameter of type "X"?

The specific details in my case: I'm using MSVC with AMD's vulkan memory allocator, which is a stb-style single header file. (So you include it in your project like:
#define VMA_IMPLEMENTATION
#include "vk_mem_alloc.h"
within a single compilation unit to compile it, and just
#include "vk_mem_alloc.h"
in any file that needs to use it.)
Anyways:
Some examples of specific errors I'm getting are:
argument of type "VmaDeviceMemoryBlock *" is incompatible with parameter of type "VmaDeviceMemoryBlock *"
and
a value of type "VmaSuballocationType" cannot be assigned to an entity of type "VmaSuballocationType"
and
declaration is incompatible with "void VmaBlockMetadata::PrintDetailedMap_Allocation(VmaJsonWriter &json, VkDeviceSize offset, VmaAllocation hAllocation) const"
when the definition is
void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json,
VkDeviceSize offset,
VmaAllocation hAllocation) const
These errors, as well as many others that aren't obviously broken, absolutely litter the file. Even stranger, I can build the program and it compiles and runs without issue. Its populating of my error window with this noise is totally undermining the error window's usefulness. I'm also now getting other strange errors throughout my code, and I'm unsure how to proceed.
I got this exact same set of errors using visual studio 2019. The error in my case was using uniform initialization with an implicit cast.
I needed to change
uint32_t uniformOffset{ pad_uniform_buffer_size(sizeof(GPUSceneData)) * frameIndex };
to
uint32_t uniformOffset{ static_cast<uint32_t>(pad_uniform_buffer_size(sizeof(GPUSceneData)) * frameIndex) };
because pad_uniform_buffer_size returns size_t and I was trying to implicity cast it to uint32_t with uniform initialization.
I have no idea why the error manifested itself in that vma file, but this was the solution in my case.

LNK2001 unresolved external symbol with CPP_XLOPER

I'm migrating a XLL from 32-Bit to 64-Bit with VS2015 and C++.
I started changing the datatypes. So I switched 'int' to '_int64'.
CPP_XLOPER Create_XLOperHeader_form_Str(const wchar_t*aBegin,_int64 strlen,bool aTranspose){
static CPP_XLOPER xlDefault(L" ");
_int64 l = strlen;
and it throws me the error:
Error
LNK2001 unresolved external symbol
"class CPP_XLOPER __cdecl Create_XLOperTable_from_Str(wchar_t const *,__int64,bool,bool)"
(?Create_XLOperTable_from_Str##YA?AVCPP_XLOPER##PEB_W_J_N2#Z)
I guess I have to modify 'class CPP_XLOPER', isn't it?
Any hint much appreciated,
thx in advance;
surplus
The method linker is complaining about has last two parameters of type bool - ...,int64,bool,bool), while the one you have modified has only one last parameter of type bool. Either you have deleted another existing method, or you have also removed one bool from the implementation (and only you know if this was or was not intentional). But yeah, in general you should fix the function declaration to match the definition.

Obtain Mangled Symbol Name based on C++ Signature

Does someone know how to obtain the mangled symbol name based on a given C++ function signature?
e.g.:
__stdcall unsigned char MyClass::MyFunc(const int param1, int param2);
would become:
?MyFunc#MyClass##QGE#?BHH#Z
when using the Microsoft Visual C++ Compiler.
I was thinking about some WINAPI-function, but I did not find any...
EDIT: Ok - I know, this is not a very clearly formulated question. What I want to achieve is the following:
GetMangledName("__stdcall unsigned char MyClass::MyFunc(const int param1, int param2);");
// Returns "?MyFunc#MyClass##QGE#?BHH#Z"
I believe the name mangling is compiler dependent and not part of the c++ specification. So as far as I can see the only reliable way is to invoke the actual compiler that you are using and get back a mapping of how the source names map to the mangled names.

Why does MobileSubstrate use such a long function name when hooking C++ functions?

From the example of hooking C++ methods with MobileSubstrate I found this:
void (*X_ZN20WebFrameLoaderClient23dispatchWillSendRequestEPN7WebCore14DocumentLoaderEmRNS0_15ResourceRequestERKNS0_16ResourceResponseE) (void* something, void* loader, unsigned long identifier, void* request, const void** response);
Why do we need this x_zn20...23....7...14 etc. between the names? What does this mean? I don't think that this is the real name.
C++ mangles names of symbols emitted to the binary, to distinguish void foo(int) and void foo(double). Also, on many platforms, it needs to encode X::Y somehow to make it an alphanumeric string. This adds the extra characters and is platform dependent.
The notation you see is called name mangling.
It's a way of encoding method signatures (in the binary) so that they are unique across the binary, even if two methods have the same name and they belong to classes of the same name, but differ only by the scope (namespace) or parameters
It looks like some platform specific hack to bind to a symbol in a compiled object.
You should look for the header file which contains that function name and call it properly.
This is bad because as compiler evolve and the code base changes specifics of the symbol name will change.

Calling a Visual Basic DLL in C++

I have acquired a DLL that was created in Visual Basic from a third party vendor(Sensor DLL.dll). This DLL contains functions for talking to a sensor, and I need to call these functions from a Visual C++ program I am writing. The vendor will not provide a header file, and I do not know Visual Basic. If I had a header file this would be a 15 minute project... instead I am still struggling with it a week later. Please Help!
I am told one function (Get_Data) in the DLL is of the form:
Public Function Get_Data(ByVal Handle As String) As String
I have tried several methods for calling this Get_Data function with no success:
Method 1) the DllImport attribute
#using <mscorlib.dll>
using namespace System::Runtime::InteropServices;
namespace Sensor
{
[DllImport("Sensor DLL.dll", EntryPoint = "Get_Data", CharSet = System::Runtime::InteropServices::CharSet::Unicode)]
BSTR Get_Data(BSTR Handle);
}
//then I call the function
Sensor::Get_Data(Handle);
This method seems to be the closest I have gotten to a sloution. It compiles, but gives the following error when it runs:
An unhandled exception of type 'System.EntryPointNotFoundException' occurred
Additional information: Unable to find an entry point named 'Get_Data' in DLL 'Sensor DLL.dll'.
I have tried various datatype combinations/permutations besides BSTR including BSTR*, wchar_t, int, etc. It is possible that I missed one, but each datatype returns the same error.
Method 2) dllimport storage-class attribute
__declspec(dllimport) BSTR Get_Data(BSTR Handle);
//then I call the function
Get_Data(Handle);
This method is confusing to me because I don't specify the DLL I want to import from. I have copied the DLL to the project folder and I have added it to the project manually, so hopefully that means it can be found. When I compile the linker returns the following errors:
error LNK2028: unresolved token (0A00034F) "wchar_t * __cdecl Get_Data(wchar_t *)" (?Get_Data##$$FYAPA_WPA_W#Z) referenced in function "int __cdecl main(void)" (?main##$$HYAHXZ)
error LNK2019: unresolved external symbol "wchar_t * __cdecl Get_Data(wchar_t *)" (?Get_Data##$$FYAPA_WPA_W#Z) referenced in function "int __cdecl main(void)" (?main##$$HYAHXZ)
I suspected maybe this meant I should be using wchar_t or wchar_t* instead of BSTR, but changing to either datatype results in the same error.
Method 3) GetProcAddress
typedef BSTR (*Get_Data_Ptr)(BSTR Handle);
HINSTANCE LoadMe;
LoadMe = LoadLibraryA("Sensor DLL.dll");
if (!LoadMe)
std::cout << "\nDLL failed to load!\n";
Get_Data_Ptr LibMainGet_Data;
LibMainGet_Data = (Get_Data_Ptr)GetProcAddress(LoadMe,"Get_Data");
//then I call the function
LibMainGet_Data(Handle);
This will compile, but gives the following error when run:
An unhandled exception of type 'System.AccessViolationException' occurred
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
When I mouse over the various parts of this code in debug mode it seems that, like the first method, it was also unable to find the 'Get_Data' entry point in the DLL.
Has anyone called functions from a VB DLL using C++ when you haven't made the DLL yourself and you don't have .idl files, etc? Does anyone have a working example like this you could share?
Thanks!
A VB6 DLL is normally a COM server. You do in fact have the equivalent of a .h file, it has a type library embedded in it. Start this off with Project + Properties, Common Properties, Framework and References. Add New Reference button, Browse tab, select the DLL.
Next, View + Object Browser. You should see the generated Interop library in the list. Open the node to see what is there. You write normal managed code, like gcnew, to create the COM object and call the interface methods. You do need some minimum documentation on the available methods to have a guess at how they should be called.
I believe the missing piece is the calling convention. C++ has its own function calling convention different than VB6 (I assume VB6 since you haven't stated VB.NET explicitly). VB6 uses STDCALL convention whereas C++, depending on the vendor, uses a different calling convention termed __cdecl, which is why you see the __cdecl in the compiler error line for method #2. It assumes your external function is using that calling convention by default. Calling convention is a set of rules describing how functions call one another; specifically about how registers are used, what order parameters are delivered in, how by-value / by-reference is determined, etc.
I would suggest sticking with method #3 since method #1 is for Managed C++ which is not standard C++, and method #2 is unfamiliar to me and looks a bit ambiguous. What you want to try is declaring the function pointer typedef to use STDCALL.
typedef BSTR (__stdcall *Get_Data_Ptr)(BSTR Handle);
In the OLE/COM viewer, in order to view the COM type library in a dll/exe/... you have to open it by using "File->View TypeLib" instead of "File->Bind to File"
It sounds like the DLL isn't actually exporting a function named Get_Data. Open up a command prompt and use dumpbin to get the list of exports of the DLL, e.g.:
dumpbin /exports "Sensor DLL.dll"
(dumpbin.exe is located in VC\bin within your Visual Studio install folder, which istypically something like C:\Program Files\Microsoft Visual Studio 10.0).
Then, replace Get_Data with the actual entry point and see if you have any better luck.
A Visual basic program normally needs a runtime to execute.
If you have a COM object (implemented in VB) use the COM API to communicate with it from C++. You will have to register the COM first. Here is a thread that explains hot to do that: http://forums.devx.com/archive/index.php/t-87059.html
If you use a .NET language, use the method of Hans Passant with a reference that will create an interop dll for you. This is far much easier.
Method 1: Do not do that, if you have a COM object that you want to use from a .NET environment, reference it.
Method 2: You get errors because you lack the the .lib file to properly link to the DLL (statically dynamically linking)
Method 3: Would be a pure dynamic solution but you have to know the exact names of the methods in the DLL. These may vary according to the parameters and calling convention used. This is very similar (actually identical, I would say) to the issue you face with your Method 1 solution. The name of the method is for yure not "Get_Data" but something else. With a tool like the dependency viewer you can have a look at the exported names.
Even Method 3 with the right names is likely to fail because if it is a COM object you will need some environment called Appartment to use the COM objects. You "enter" this appartment by calling CoInitialize. This creates some magical stuff in the TLS (Thread Local Storage) to perform the COM magic. I hope this explains why your tries will be pointless if the DLL you have is happening to be a COM component, what is quite likely according to the ATL like naming we can see.
EDIT:
I forgot to say that you can also easily see what is inside the dll if it is a COM with the OLE/COM Viewer (normally if you have a compiler you will have such a tool around).