VS C++ Issue with InvokeRequired / delegate void - c++-cli

I am new to C++ and Im using VS2010.
Could someone check the code below and help to solve it? Everytime the function UpdateDataGrid(unsigned char CANPacket[15])
is called the following message is shown in a new window and the application closes.
An unhandled exception of type 'System.ArgumentException' occurred in System.Windows.Forms.dll
Additional information: Object of type 'System.Byte' cannot be converted to type 'System.Byte*'.
I have to use unsinged char data type and not String^ in this project.
Is there any way to correct my code?
//Piece of my code
namespace VCCDC {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Threading;
public ref class Form1 : public System::Windows::Forms::Form
{
delegate void UpdateDataGridCallback(unsigned char CanPacket[15]);
private: void UpdateDataGrid(unsigned char CANPacket[15]) {
if (this->dataGridView1->InvokeRequired) {
UpdateDataGridCallback^ d = gcnew UpdateDataGridCallback(this,&VCCDC::Form1::UpdateDataGrid);
this->Invoke(d,gcnew unsigned char(CANPacket[15]));
}
else {
//Update dataGridView1 with new data
}
}
}
}]

Change the line
this->Invoke(d,gcnew unsigned char(CANPacket[15]));
to
this->Invoke(d,CANPacket));
You already have an unsigned char pointer, pass it through. With gcnew you intent to create another one, which is unnecessary.
Also error caused by this gcnew line. You have to construct the Byte* with a Byte parameter. Yours is Byte* too.

Related

Trying to use C# DLL with ComVisible attribute set from unmanaged C++

TL;DR: I'm trying to use a C# library in C++. Why am I getting an undeclared identifier error when trying to use an identifier from my .tlh file? There must be tons of examples out there, but I haven't been able to find any that include both the C# and C++ code, and that work. Links to such examples would be greatly appreciated.
I have the following classes defined in C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using CrystalDecisions.CrystalReports.Engine;
namespace CapsCrystalReportLib
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("B4E5F784-12E6-4311-9BB9-D5B3252F20A3")]
public interface ICapsCrystalReport
{
[DispId(1)]
void DisplayReport(string fileName);
[DispId(2)]
void PrintReport(string fileName);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("89402DE5-BA26-4AC0-AB40-00ADD2876FF4")]
[ProgId("CAPSCrystalReport.Report")]
[ComDefaultInterface(typeof(ICapsCrystalReport))]
public class CapsCrystalReport : ICapsCrystalReport
{
public void DisplayReport(string fileName)
{
MessageBox.Show("Displaying report " + fileName);
}
public void PrintReport(string fileName)
{
MessageBox.Show("Printing report " + fileName);
}
}
}
I have the following C++ program attempting to use this class:
#include "stdafx.h"
#import "W:\\CAPS Builds\\trunk\\CapsCrystalReportLib\\bin\\Debug\\CapsCrystalReportLib.tlb" no_namespace
int _tmain(int argc, _TCHAR* argv[])
{
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
CapsCrystalReport CRPtr(__uuidof(CapsCrystalReport));
long lResult = 0;
// Call the Add method.
CRPtr->DisplayReport("SomeReport.rpt");
// Uninitialize COM.
CoUninitialize();
return 0;
}
I am getting an undeclared identifier error. The compiler doesn't know what a CapsCrystalReport is. What am I doing wrong?
P.S. I took another look at the sample I copied this from. One of the comments asks the same question, and it was never answered.
You were very close, but CRPtr is a COM interface reference (=pointer) so it must be declared like this:
ICapsCrystalReportPtr CRPtr(__uuidof(CapsCrystalReport));
The IxxxPtr class was generated for you by #import in a .tlh file. What you can do when you have issues with #import, is just open the generated .tlh file and look at it.
Note you don't have to declare a default interface in C#, you can just declare the class like this:
[ComVisible(true)]
[Guid("89402DE5-BA26-4AC0-AB40-00ADD2876FF4")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("CAPSCrystalReport.Report")]
public class CapsCrystalReport
{
... same ...
}
And in C++, you would have to adapt your imports like this:
#import "C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\mscorlib.tlb" auto_rename
#import "W:\\CAPS Builds\\trunk\\CapsCrystalReportLib\\bin\\Debug\\CapsCrystalReportLib.tlb" no_namespace
and you would use it like that (the interface was implicitely created by .NET and wrapped by the #import):
_CapsCrystalReportPtr CRPtr(__uuidof(CapsCrystalReport));
PS: I would recommend you to keep the namespace, avoid no_namespace because it can cause problems with collisions especially in C++.

Static Object of a class in another class in aggregation relationship C++

I have two classes first class contains the object of another class as static but C++ doesnot allow me to do this and gives me some error.
source.cpp
#include"control.h"
int main()
{
Controller cnt;
cnt.tempcont();
return 0;
}
control.h
#include"recorder.h"
class Controller
{
public:
static recorder rec;
void tempcont();
};
recorder Controller::rec;
control.cpp
#include"control.h"
void Controller::tempcont()
{
rec.temprec();
}
recorder.h
#include<iostream>
using namespace std;
class recorder
{
public:
int a;
void temprec();
};
recorder.cpp
#include"recorder.h"
void recorder::temprec()
{
cout << "temp rec called";
}
I am getting the following errors and i have no idea why these errors are comming..
Error LNK1169 one or more multiply defined symbols found
Error LNK2005 "public: static class recorder Controller::rec" (?rec#Controller##2Vrecorder##A) already defined in control.obj
You define the variable Controller::rec in the header file. That means the variable will be defined in every translation unit where that header file have been included. It should only be defined in one single translation unit.
This is very easy to do: Just move the definition to a single source file.

EntryPointNotFoundException occurred while calling C++ function from C#

I wish to call C++ function (here Score()) which is present in Score_Update1.dll.
Both C# & C++ files get compiled successfully. I have also put above dll into the Debug/bin of C# project. But when I run C# code it gives EntryPointNotFoundException.
What could be the reason behind this Exception?
I tried dependency walker for Score_Update1.dll. But it doesn't show any Entry Point
I wish to use PInvoke technique for calling C++ function from C#
// Score_Update1.h
#pragma once
#include <iostream>
using namespace std;
using namespace System;
extern "C"{
#define MYAPI __declspec(dllexport)
namespace Score_Update1 {
public class MYAPI UpdateScore
{
// TODO: Add your methods for this class here.
public:
void Score();
};
}
}
// This is the main Score_Updat1.dll DLL file.
#include "stdafx.h"
#include "Score_Update1.h"
using namespace Score_Update1;
void UpdateScore::Score()
{
cout<<"Score has been updated";
}
C# code is as follows:
using Score_Update1;
using System.Runtime.InteropServices;
namespace GameTesting
{
class Game
{
[DllImport("Score_Update1.dll")]
internal extern static void Score();
static void Main(string[] args)
{
try
{
Game.Score();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
The reason for EntryPointNotFoundException is that the DLL does not contain an entry point named Score. If you look at the exported names using dumpbin or some similar tool you will see mangled names.
However, using the mangled name isn't going to help you here. You've exported a class and the function you want to call is a member function. You cannot directly instantiate a C++ class from pinvoke. And you cannot call member functions. If you wish to use pinvoke you would need to flatten the class to a C style interface. Another route would be to compile the C++ code to a mixed mode C++/CLI assembly and consume that.

Runtime exception when calling C++/CLI derived class

Edited by the OP 5 August 2014:
Much simplified code:
public ref class CXmlWriter : public System::Xml::XmlTextWriter
{
public:
CXmlWriter(System::String ^sFilename) : XmlTextWriter(sFilename, System::Text::Encoding::Unicode)
{
}
~CXmlWriter()
{
}
};
Call a function containing code that instantiates CXmlWriter (you don't have to execute that instantiation code) and you get the exception.
Comment out the destructor and you don't get the exception. Making the destructor virtual doesn't fix it.
End of edit
I am using Version 4 of the .NET framework.
I have C++/CLI classes CXmlWriter derived from System::Xml::XmlTextWriter and CMinMaxXmlWriter derived from CXmlWriter.
Implementation is pretty simple for both classes and everything compiles without error. However, when I try to instantiate CMinMaxXmlWriter at runtime I get a TypeLoadException with the error message:
Declaration referenced in a method implementation cannot be a final method
with a mention of CXmlWriter
This used to work without any problem in Version 2 of the framework.
Here's the header for CXmlWriter:
public ref class CXmlWriter : public System::Xml::XmlTextWriter
{
public:
CXmlWriter(System::String ^sFilename);
~CXmlWriter();
!CXmlWriter() {}
virtual bool Open();
virtual void Close() override;
virtual bool WriteValueAndAttribute(System::String ^sElementName, System::String ^sElementValue, System::String ^sAttrName, System::String ^sAttrValue);
virtual bool WriteValueAndAttribute(System::String ^sElementName, double dElementValue, System::String ^sAttrName, System::String ^sAttrValue);
protected:
bool m_bIsOpen;
};
CMinMaxXmlWriter is defined in a very similar way.
Please can someone explain why the exception occurs and what I should do to avoid it.

Unable to find an entry point

I import two WinApi functions and use them in my class
using namespace System::Runtime::InteropServices;
[DllImport("user32",ExactSpelling = true)]
extern bool CloseWindow(int hwnd);
[DllImport("user32",ExactSpelling = true)]
extern int FindWindow(String^ classname,String^ windowname);
public ref class WinApiInvoke
{
public:
bool CloseWindowCall(String^ title)
{
int pointer = FindWindow(nullptr,title);
return CloseWindow(pointer);
}
};
Then I create object in main program and call CloseWindowCall method
Console::WriteLine("Window's title");
String ^s = Console::ReadLine();
WinApiInvoke^ obj = gcnew WinApiInvoke();
if (obj->CloseWindowCall(s))
Console::WriteLine("Window successfully closed!");
else Console::WriteLine("Some error occured!");
When I write in console for example Chess Titans to close I've got an error
Unable to find an entry point named 'FindWindow' in DLL 'user32'
What entry point?
You are using the ExactSpelling property inappropriately. There is no FindWindow function in user32.dll, just like the exception message says. There is FindWindowA and FindWindowW. The first one handles legacy 8-bit character strings, the second uses Unicode strings. Any Windows api function that accepts strings has two versions, you don't see this in C or C++ code because the UNICODE macro selects between the two.
Avoid ExactSpelling on winapi functions, the pinvoke marshaller knows how to deal with this. You have some other mistakes, the proper declaration is:
[DllImport("user32.dll", CharSet = CharSet::Auto, SetLastError = true)]
static IntPtr FindWindow(String^ classname, String^ windowname);