Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Class constructor after dllimport

Status
Not open for further replies.

iipee

Programmer
Mar 23, 2006
6
FI
I am trying to upgrage an old VB3 & RDM4.5 application with fairly big database into VS.net and RMD7.1. As RDM 7.1 has been created with unmanaged C, I have instead of VB made a test program as a VC++ forms application.

Now I can transfer the RDM functions with for instance:
[DllImport("rdm7.dll", EntryPoint = "d_opentask",
CharSet = Ansi)]
extern "C" int d_opentask(void *);

and even the unmanaged structures with:
[StructLayout( LayoutKind::Sequential )]
public __gc class mVETS
{
public:
int mvetno;
String* mvetnimi;
String* mprof;
String* merik;
}

VC++ creates a __gc class FORM1 with an event button1_click. As Windows demands that the designers of the Form are as the first member of the class FORM1, I have created a separate namespace WinSys32 for the above marshalling. Everything works fine with the test routine in button1_click till I try to read some real data from the old (but converted)data base. After that I receive a NullReferenceError and I have no luck either after trying to place a constructor for the data in many different places.

I am sure I can't write or place the constructor correctly and I wonder if someone could help me. I have tried the following contsructor:

mVETS::mVETS( int eno, String *ell, String *amm, String
*spe )
{
mvetno = eno;
mvetnimi = ell;
mprof = amm;
merik = spe;
}

If I put the constructor in the class WinSys32::mVETS and declare the class in Form1 button1_click with

SysWin32::mVETS *pvet = new SysWin32::mVETS;

I get an error message telling that there is no default constructor available.

Thankful for help!
Ilkka Pitkänen


 
Since you gave it a constructor that takes some parameters, I don't think the compiler automatically creates a default constructor for you. If you really intended to create a new default mVETS object, add a default constructor:
Code:
mVETS::mVETS()
{
    // Give mvetno, mvetnimi, mprof & merik some default values here.
};
 
Hi!
Thank you very much for your message. I allready once tried a default constructor, but I thougth it was not correct or in a wrong place. Now after I added it to the class, compiler and linker accept it, but executing the code, I get again the awkward:
'System.NullReferenceException',
which I thought was a result of bad constructor definition and which I also received earlier without a constructor.

Did I do correctly what you suggested, could you still look at the shortened code of the test program:

#pragma once
#include "stdafx.h"
#using <mscorlib.dll>
using namespace System;
using namespace System::Runtime::InteropServices;

#using <system.windows.forms.dll>
#include "rdm.h"
- - - - -
namespace SysWin32
{
- - - - - -
[DllImport("rdm7.dll", EntryPoint = "d_recread", CharSet = Ansi)]
extern "C" int d_recread(void*, DB_TASK*, int);
- - - - -
[StructLayout( LayoutKind::Sequential )]
public __gc class mVETS
{
public:
int mvetno;
String* mvetnimi;
String* mprof;
String* merik;

mVETS::mVETS( int eno, String *ell, String *amm, String *spe )
{
mvetno = eno;
mvetnimi = ell;
mprof = amm;
merik = spe;
}

// here I added your suggested default constructor

mVETS::mVETS()
{
// Give mvetno, mvetnimi, mprof & merik some default values here.
mvetno = 1;
mvetnimi = "XXXXX YYYYYYYYYYY ";
mprof = "ZZZZZZZZZZZ ";
mvetnimi = " ";
} // end dft cnstrt
}; //end class
} // end namespace SysWin32

namespace MC9
{
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::Text;

public __gc class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
}

protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}
private: System::Windows::Forms::Button * button2;
private:
System::ComponentModel::Container * components;
void InitializeComponent(void)
{
this->MC9 = new System::Windows::Forms::Label();
- - - - -
(VC++ designer code)
- - - - -

private: System::Void button1_Click(System::Object * sender, System::EventArgs * e)
{
int stat;
- - - - -
DB_TASK *Currtask;
SysWin32::mVETS *pvet = new SysWin32::mVETS;
- - - - - -
if stat = (SysWin32::d_recread(&pvet, Currtask, CURR_DB))
// This row now gives the NullReferenceException
{
- - - - -

DB_TASK and CURR_DB have in rdm.h definitions:
typedef void DB_TASK;
#define CURR_DB -1


I tried to include everything essential.
 
Code:
String* mvetnimi;
String* mprof;
String* merik;
Since these are pointers, you shouldn't assign literal values to them. You should allocate memory to them
Code:
mvetnimi = new String;
...
and then assign the text into that new String.
I guess you can do this:
Code:
*mvetnimi = "some text";

I've never used Managed C++, so I don't know if you have to explicitely delete your pointers when you're done or just set them to NULL?

Is there a reason why those Strings have to be pointers? If they were just String then you could assign values to them much easier without having to worry about new & delete.
 
Thank you again for your reply!

The reason why I used pointers String* in the class came from some example and it was the only way to make the compiler accept those strings. Using the method you suggested:
mvetnimi = new String;
gives in compiling the error:
C2501: 'SysWin32::mVETS::mvetnimi' : missing storage-
class or type specifiers

I tried in many ways to define the storage class or type but I could not do it so that the compiler would accept it.

Also, I tried in button1_click() the definition
SysWin32::mVETS *pvet = new SysWin32::mVETS();
compiler and linker accept, but the test program executes with the same NullReferenceException result with additional explanation:
'Object reference not set to an instance of an object'.

I also tried to change the class to an unmanaged class with __nogc definition, again with the same results.

About managed classes like __gc class mVETS the books tell that:
"Managed types are garbage collected (i.e. memory no
longer in use is freed) and managed by the CLR part of
the .NET Framework that executes MC++ programs"

I also found out that in the class MC9 I can define
String elk;
end then after *pvet definition in the click routine
elk = pvet->mvetno;
and the compiler accepts even this and the same with other members in the class, but the function d_recread leads to the same NullReferenceException.

So, something is still wrong what I don't seem to be able to solve.
Thank you for your patience!


 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top