C++ Wrapper for TFS API - c++

I have 2 projects in VS 2012 trying to build a C++ wrapper for the Team Foundation Server API.
#pragma once
using namespace System;
using namespace System::Reflection;
using namespace System::Collections::ObjectModel;
using namespace Microsoft::TeamFoundation::Client;
using namespace Microsoft::TeamFoundation::Framework::Common;
using namespace Microsoft::TeamFoundation::Framework::Client;
namespace ManagedDll {
public ref class TFSAUth
{
public:
TFSAUth();
~ TFSAUth();
void AuthUser()
{
System::String ^x = gcnew String( "http://myhost:8080/tfs");
System::String ^u = gcnew String( "user");
System::String ^p = gcnew String( "Pass");
System::Net::NetworkCredential ^c = gcnew System::Net::NetworkCredential(u, p);
TeamFoundationServer ^something = gcnew TeamFoundationServer(x, c);
something->Authenticate();
System::String ^col = gcnew String (something->TfsTeamProjectCollection->Name);
Console::WriteLine(col);
}
private:
};
TFSAUth:: TFSAUth()
{
}
TFSAUth::~ TFSAUth()
{
}
}
__declspec(dllexport) void Auth()
{
ManagedDll::TFSAUth work;
work.AuthUser();
}
This is the library project and I have a Test Application using this library.
#include "stdafx.h"
#include "conio.h"
#include <iostream>
#include <windows.h>
#include "ManagedDll.h"
_declspec(dllexport) void Auth();
int _tmain()
{
Auth();
system("pause");
return 0;
}
Was all working for a while, opened this project to see if I can get any further. Today it fails to compile, giving me linker errors.
TestApp.obj : error LNK2019: unresolved external symbol "void __cdecl
Auth(void)" (?Auth##YAXXZ) referenced in function _wmain
I am not sure why as nothing has changed. But more than that, I am wondering whether I am doing the right thing while creating the C++ wrapper for TFS API.
Any help/examples/suggestions is much appreciated as this is my first attempt at a wrapper.

In your native C++ project (Test Application), you have to include the lib file of the managed C++ project (ManagedDll).
The exported DLL function in the manage C++ DLL is treated as the same as that in the native C++ DLLs, you can follow this: Lib Files as Linker Input to make it work.
Also, you should remove
_declspec(dllexport) void Auth();
in the Test Application.

Related

I'm getting unresolved external symbol winrt_make_* when trying to compile C++/WinRT blank app from XamlApplication

I am trying to follow the tutorial here: UWP Xaml Hosting API.
I am at the part of the tutorial where I'm supposed to create a blank app that defines a XamlApplication application. I have defined it in my header (.h) as:
#pragma once
#include "App.xaml.g.h"
namespace winrt::UI_Host::implementation
{
struct App : Microsoft::Toolkit::Win32::UI::XamlHost::XamlApplicationT<App>
{
App();
~App();
};
}
My .cpp file has it defined as:
#include "pch.h"
#include "App.h"
using namespace winrt;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Navigation;
using namespace UI_Host;
using namespace UI_Host::implementation;
winrt::UI_Host::implementation::App::App()
{
Initialize();
}
winrt::UI_Host::implementation::App::~App()
{
Close();
}
If I leave my .IDL file as:
namespace UI_Host{}
It compiles fine, but I can't use the App class in my Win32 Program. So I changed the IDL file to this:
namespace UI_Host
{
[default_interface]
runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
{
App();
}
}
But now it won't compile. The error I get when compiling is this:
>module.g.obj : error LNK2019: unresolved external symbol "void * __cdecl winrt_make_UI_Host_App(void)" (?winrt_make_UI_Host_App##YAPEAXXZ) referenced in function "void * __cdecl winrt_get_activation_factory(class std::basic_string_view<wchar_t,struct std::char_traits<wchar_t> > const &)" (?winrt_get_activation_factory##YAPEAXAEBV?$basic_string_view#_WU?$char_traits#_W#std###std###Z)
Does anyone know why?
C++/WinRT 2.0 introduced a breaking change in order to support Optimized Components. It is used when passing -optimize to cppwinrt.exe. This option is enabled by default for new projects.
The breaking change requires component authors to #include a generated implementation file into the compilation unit that implements that particular type. In your case, you need to #include "App.g.cpp" into App.cpp (make sure to #include it after the header file App.h).
To allow your code to compile with and without the -optimize flag, you can conditionally include App.g.cpp:
#include "App.h"
#if __has_include("App.g.cpp")
# include "App.g.cpp"
#endif
For easy to digest lessons you can read Raymond Chen's blog entry titled Why does my C++/WinRT project get errors of the form "Unresolved external symbol void* __cdecl winrt_make_YourNamespace_YourClass(void)"?.

How to pass object as parameter into function from .h and .cpp

I am relatively new to C++, but have come from Python and C.
I am using an SDK for a lidar sensor. I have 5 main files that are involved; SDK.h, SDK.cpp, setup.h, setup.cpp and main.cpp.
A class is defined within the SDK.
rplidar.h
class RPlidarDriver{
public:
static RPlidarDriver * CreateDriver(_u32 drivertype = DRIVER_TYPE_SERIALPORT);
// more code
}
main.cpp
#include <iostream>
#include "rplidar.h"
#include "setup.h"
using namespace std;
using namespace rp::standalone::rplidar;
int main()
{
//code
RPlidarDriver* lidar = RPlidarDriver::CreateDriver(DRIVER_TYPE_SERIALPORT);
start_reading(lidar, scanMode);
//code
}
setup.cpp
#include "setup.h"
#include "rplidar.h"
using namespace std;
using namespace rp::standalone::rplidar;
void start_reading(RPlidarDriver* driver, const char* scanMode)
{
//start motor
driver->startMotor();
//more code...
}
setup.h
#include "rplidar.h"
using namespace rp::standalone::rplidar;
namespace setup
{
void start_reading(RPlidarDriver* driver, const char* scanMode);
}
However I get this error
main.obj : error LNK2019: unresolved external symbol "void __cdecl setup::start_reading(class rp::standalone::rplidar::RPlidarDriver *,char const *)" (?start_reading#setup##YAXPAVRPlidarDriver#rplidar#standalone#rp##PBD#Z) referenced in function _main
I also get the same error for other functions that I try to use the object as a parameter.
If I put the function in setup.cpp into main.cpp, it compiles easily. I tried to implement & and use the parameter as a reference instead, but not luck.
main.cpp and setup.cpp both need to be compiled and the resulting object files need to be linked together along with the SDK libraries. The error you're getting is telling you you're trying to link the final binary using just main.o and the SDK without setup.o That's why the linker is failing to find the symbol with the implementation of your start_reading function.

Using DLLs wrapping Windows PackageManager in MinGW

In an attempt to incorporate a windows platform feature into an otherwise crossplatform application, I've made a one-function VC++ DLL in visual studio that uses Windows.Management.Deployment.PackageManager to get some details on all installed windows store apps.
The function works fine as a standalone application, and I can successfully build the DLL with MSVC that links properly with my MinGW main application (I can happily return primitive data from the dll, etc) - but any attempt to execute a function from the dll containing code relating to PackageManager crashes my application in runtime with the unhelpful code -529697949.
Here's some minimal code blocks that replicate:
main.cpp in the main application:
#include <QCoreApplication>
#include "mylib/WindowsAppsLib.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
auto hi = (Helpers::sayHi());
qDebug() << (hi);
return a.exec();
}
dll header:
#pragma once
#define WINDOWSAPPSLIB_API __declspec(dllexport)
namespace Helpers
{
extern "C" WINDOWSAPPSLIB_API const char* sayHi();
}
dll source:
#include "stdafx.h"
#include <sddl.h>
#include <collection.h>
#include "WindowsAppsLib.h"
#include <windows.h>
#using <Windows.winmd>
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace std;
const char* Helpers::sayHi()
{
auto packageManager = ref new Windows::Management::Deployment::PackageManager();
auto packages = packageManager->FindPackages();
return "Hi!";
}
Without the two lines relating to packagemanger, the program runs fine and prints "Hi!". When included, the program crashes with code -529697949 as soon as sayHi() is called. The two lines in themselves have their dependencies available and don't cause exceptions.
Any clues on how I might proceed to investigate this? Nothing I've been able to get out of this system is getting me closer to identifying the problem. Is this the sensible way to access Windows.Management.Deployment.PackageManager from within a plain C++ MinGW application to begin with?

link 2019 Error For Simple Class C++

I can't seem to fix this LNK2019 Error that I keep getting on visual studio 2013.
I've been looking on stack exchange for a while, but I think my code is fine.
The error is a result of creating a ParkingMeter variable. I'm not sure how to fix this. Any help would be appreciated.
ParkingMeter.h:
#ifndef PARKINGMETER
#define PARKINGMETER
using namespace std;
class ParkingMeter{
private:
int minPurchased;
public:
ParkingMeter(int);
ParkingMeter();
int getMinutes();
};
#endif
ParkingMeter.cpp:
using namespace std;
#include "ParkingMeter.h"
ParkingMeter::ParkingMeter(int minutes)
{
minPurchased = minutes;
}
ParkingMeter::ParkingMeter(){
minPurchased = 0;
}
int ParkingMeter::getMinutes(){ return minPurchased; }
test.cpp:
#include <iostream>
#include "ParkingMeter.h"
using namespace std;
int main()
{
ParkingMeter meter(2);
}
Full error message:
Error 1 error LNK2019: unresolved external symbol "public: __thiscall ParkingMeter::ParkingMeter(int)" (??0ParkingMeter##QAE#H#Z) referenced in function _main C:\Users\Max\Documents\Visual Studio 2013\Projects\Project3\Project3\test.obj
I don't see any problem with this code.
I have removed below code from your ParkingMeter.h and ParkingMeter.cpp. (keep in test.cpp file)
using namespace std;
Edit: It seems you have not added ParkingMeter.cpp in your project. Please right click on your project - > Add -> existing Item -> and provide cpp file. You are good to go!

How to call managed C++ methods from Un-managed C++

PLEASE SEE UPDATE BELOW
(RESOLVED) Also I have extended this into a second question here Implement a C# DLL COM File In Unmanaged C++ Program
I have researched this to the end of the internet without finding a real, understandable, human example of how to do this.
I have a C# DLL that encrypts and decrypts text.
I don't want to / don't have the intellectual capability to rewrite this in C++ un-managed code. So instead I created a C++/CLR class that interfaces with the C# dll.
NOW I need to know how to call the managed C++ from my unmanaged code.
Here is my managed code and it is verified that it works
// clrTest.cpp : main project file.
#include "cSharpRiJHarn"
#include "stdafx.h"
#include <string>
#include <stdio.h>
using namespace cSharpRiJHarn;
using namespace System;
String^ Encrypt(String ^s)
{
return RijndaelLink::encrypt(s);
}
String^ Decrypt(String ^s)
{
return RijndaelLink::decrpyt(s);
}
int main()
{
//Console::WriteLine(Encrypt("It Works"));
//Console::WriteLine(Decrypt(Encrypt("It Works")));
//Console::ReadLine();
return 0;
}
Now ONCE AGAIN I HAVE researched this.
I have seen allllllll the bad/overly complicated explanations
I know I need to use something called COM or Interop
I don't know how this works and I am just looking for a very simple explanation.
Thanks for the help.
UPDATE
I have turned the C# DLL into a COM File
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace cSharpRiJHarn
{
[Guid("GuiD CODE REMOVED")]
public interface DBCOM_Interface
{
[DispId(1)]
String encrypt(string s);
[DispId(2)]
String decrpyt(string s);
}
[Guid("GuiD CODE REMOVED"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface DBCOM_Events
{
}
[Guid("GuiD CODE REMOVED"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(DBCOM_Events))]
public class RijndaelLink : DBCOM_Interface
{
public String encrypt(String s)
{
return Rijndael.EncryptString(s);
}
public String decrpyt(String s)
{
return Rijndael.DecryptString(s);
}
}
}
Now I am just need to know how to implement this in unmanaged C++...
I have tried both adding just the files to the C++ project and also adding the entire cSharpRiJHarn Project to this solution. Neither work.
#import "cSharpRiJHarn"
#include "stdafx.h"
#include <string>
#include <stdio.h>
#include <iostream>
//using namespace cSharpRiJHarn;
int main(){
cSharpRiJHarn::RijndaelLink::encrypt("It works");
char ch;
std::cin>>ch;
return 0;
}
This is one of the errors I am getting.
Error 6 error C2653: 'cSharpRiJHarn' : is not a class or namespace
name
and
Error 8 IntelliSense: cannot open source file
"C:/.../.../Documents/Visual Studio
2010/Projects/unmannagedCPPExample/unmannagedCPPExample/Debug/cSharpRiJHarn.tlh" c:......\documents\visual
studio
2010\projects\unmannagedcppexample\unmannagedcppexample\unmannagedcppexample.cpp
You could use the cool C++ Marshaling library provided by Microsoft, something like this:
#include "cSharpRiJHarn"
#include "stdafx.h"
#include <string>
#include <stdio.h>
#include "msclr\marshal_cppstd.h" // marshaling library
using namespace cSharpRiJHarn;
using namespace System;
using namespace msclr::interop; // marshaling library
std::wstring Encrypt(std::wstring s)
{
return marshal_as<std::wstring>(RijndaelLink::encrypt(marshal_as<String^>(s)));
}
std::wstring Decrypt(std::wstring s)
{
return marshal_as<std::wstring>(RijndaelLink::decrypt(marshal_as<String^>(s)));
}
First, your methods receive and return a String^ which is a managed object. Unmanaged code does not know this type, and cannot create such object. So, you will need to wrap the function call such that the function marshal the managed type to something that the unmanaged code can understand.
After that, you can add the DllExport attribute to the managed method, as discussed here.