I am trying to follow this tutorial to build a C++/CLI wrapper for my .NET assembly and I am having issues.
I managed to get it to compile by retyping some of the text but now I have this problem when building:
Severity Code Description Project File Line Suppression State
Error LNK1146 no argument specified with option '/EXPORT' MSAToolsLibraryWrapper D:\My Programs\2017\MSAToolsLibraryWrapper\MSAToolsLibraryWrapper\LINK 1
Update
If I remove /EXPORT
from my Properties -> Linker -> Command Line -> Additional Options then it compiles. But, in the tutorial it said:
Step3. Configure the C++/CLI class library to export symbols. The symbols can be imported and called by native C++ applications.
Ah, I get it, the instructions that followed were the steps to take. I did not need to modify the build.
Update 2
OK, so take for example this method in my C# library:
What is the right syntax for exposing that in my wrapper class?
Update 3:
I got a bit further:
HRESULT CSimpleMSAToolsLibraryWrapper::GetPersonnelNames(bool bSort)
{
// Get the pinned CSSimpleObject object from its memory address.
GCHandle h = GCHandle::FromIntPtr(IntPtr(m_impl));
MSAToolsLibraryClass^ obj = safe_cast<MSAToolsLibraryClass^>(h.Target);
HRESULT hr = S_FALSE; // Fallback
try
{
// Redirect the call to the corresponding method of the wrapped
// MSAToolsLibraryClass object.
array<System::String^>^ listNames = obj->GetPersonnelNames(bSort);
hr = S_OK;
}
catch (Exception ^ e)
{
hr = Marshal::GetHRForException(e);
// Do we do anything else here?
}
if (SUCCEEDED(hr))
{
// What exactly do we do with "listNames"?
// Ideally I want to return the array rather than HRESULT.
// Convert System::String to PCWSTR.
//marshal_context ^ context = gcnew marshal_context();
//PCWSTR pszStr = context->marshal_as<const wchar_t*>(str);
//hr = StringCchCopy(pszBuffer, dwSize, pszStr == NULL ? L"" : pszStr);
//delete context; // This will also free the memory pointed by pszStr
}
return hr;
}
But as you can see, I have a couple of questions there still.
Update 4
I ended up doing this:
std::vector<std::string> CSimpleMSAToolsLibraryWrapper::GetPersonnelNames(bool bSort)
{
// Get the pinned CSSimpleObject object from its memory address.
GCHandle h = GCHandle::FromIntPtr(IntPtr(m_impl));
MSAToolsLibraryClass^ obj = safe_cast<MSAToolsLibraryClass^>(h.Target);
std::vector<std::string> vectorListNames;
HRESULT hr;
try
{
// Redirect the call to the corresponding method of the wrapped
// MSAToolsLibraryClass object.
array<String^>^ listNames = obj->GetPersonnelNames(bSort);
vectorListNames = ConvertToUnManaged(listNames);
}
catch (Exception ^ e)
{
hr = Marshal::GetHRForException(e);
// Do we do anything else here?
}
return vectorListNames;
}
std::vector<std::string> CSimpleMSAToolsLibraryWrapper::ConvertToUnManaged(array<String^>^ ar)
{
std::vector<std::string> vector(ar->Length);
for (int i = 0; i < ar->Length; ++i) {
auto s = ar[i];
vector[i] = msclr::interop::marshal_as<std::string>(s);
}
return vector;
}
But now I have another problem:
Severity Code Description Project File Line Suppression State
Error C3395 'CSimpleMSAToolsLibraryWrapper::ConvertToUnManaged': __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention
MSAToolsLibraryWrapper d:\my programs\2017\msatoolslibrarywrapper\msatoolslibrarywrapper\MSAToolsLibraryWrapper.h 26
I got around that by moving the method out of the class.
Another related issue I can't get my head around is the tutorials they said to add a reference to your DLL, which I did. But I have one DLL for x86 and one DLL for x64 and I don't know how to reference each DLL based on the build being made. Separate question?
Update 5
Is it supposed to be:
#ifdef MSATOOLSLIBRARYWRAPPER_EXPORTS
#define SYMBOL_DECLSPEC __declspec(dllexport)
#else
#define SYMBOL_DECLSPEC __declspec(dllimport)
#endif
using namespace System;
// This native C++ class wraps the C# class CSSimpleObject defined in the
// .NET class library CSClassLibrary.
class SYMBOL_DECLSPEC CSimpleMSAToolsLibraryWrapper
Or just:
public ref class CSimpleMSAToolsLibraryWrapper