__declspec(dllexport) to return char but errors in VB6

J

Jason W

I have a C# class that I wan't to be able to use in VB6 and VBA
applications. To do this I was trying to use a mixed managed VC++ dll and
export a function. Doing this I get an error "The memory could not be
"read"".

Can any one explain what I am doing wrong?

This is my Code.


..CPP

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#using <mscorlib.dll>
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Collections;
using namespace WdCadTmInfo;
#define WDINFO_LINKAGE __declspec(dllexport)
#include "PlotAccounting-C.h"

__gc class ManagedObjects{
public:
};

BOOL APIENTRY
DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{

return TRUE;
}

extern "C"{
WDINFO_LINKAGE char* getWdInfo(char* Param){

wdCadTeamInfo* tmpInfo = new wdCadTeamInfo();

IntPtr ptr = Marshal::StringToHGlobalAnsi(tmpInfo->GetWdCadTmInfo(Param));
char __nogc* pStr = static_cast<char*>(ptr.ToPointer());

Marshal::FreeHGlobal(ptr);

return pStr;

}
}

..H

#ifndef WDINFO_LINKAGE
#define WDINFO_LINKAGE __declspec(dllimport)
#endif
extern "C"{
WDINFO_LINKAGE char* getWdInfo(char* Param);
}
 
M

Mattias Sjögren

Can any one explain what I am doing wrong?

The pointer you're returning is invalid since you just freed the
memory it points to.



Mattias
 
J

Jason W

Thank you for your reply!

I was switching code around and placed the FreeHGlobal in the wrong place
for my post.

changing it to this

WDINFO_LINKAGE char* getWdInfo(char* Param){

IntPtr ptr = Marshal::StringToHGlobalAnsi(S"Testing return");
char __nogc* pStr = static_cast<char*>(ptr.ToPointer());

return pStr;

Marshal::FreeHGlobal(ptr);
}

doesn't give me the error but doesn't return anything back.

Thanks in advance.

Jason
Wood
 
M

Mattias Sjögren

WDINFO_LINKAGE char* getWdInfo(char* Param){
IntPtr ptr = Marshal::StringToHGlobalAnsi(S"Testing return");
char __nogc* pStr = static_cast<char*>(ptr.ToPointer());

return pStr;

Marshal::FreeHGlobal(ptr);
}

doesn't give me the error but doesn't return anything back.


Now the FreeHGlobal call is dead code that will never execute instead,
the compiler should warn you about that.

You either have to switch to a model where the caller passes in a
buffer to be filled, specify that the caller must free the memory with
LocalFree, or provide another function that frees the memory later.
You can't both return the pointer and free the memory it points to in
the same function.

As to why you don't get anything on the VB side, I would have to see
the callng code to tell.



Mattias
 
J

Jason W

I didn't think I was doing it correct. I've been reading and found what I
believe to be the correct way to do this but VB6 still errors.

I can get it to work in C# but that isn't the language I'm looking for.
Am I making since about what I'm asking for?

<C# Code>
[DllImport(@"PlotAccounting-C.dll")]
static extern long getWdInfo(
string param,
System.Text.StringBuilder returnParm
);

[STAThread]
static void Main(string[] args)
{
System.Text.StringBuilder returnIt = new
System.Text.StringBuilder(500,500);
Console.WriteLine(getWdInfo("Testing", returnIt).ToString());
Console.WriteLine(returnIt.ToString());
}



<VB6 Code>
Public Declare Function getWdInfo Lib "PlotAccounting-C.dll" (ByVal param As
String, paramOut As String) As Long
Dim testing As String
testing = "Not Set"
MsgBox getWdInfo("PlotAccounting", testing)

<PlotAccount-c.cpp>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#using <mscorlib.dll>
#define WDINFO_LINKAGE __declspec(dllexport)
#include "PlotAccounting-C.h"
#include "shlwapi.h"

__gc class ManagedObjects{
public:
};

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

extern "C"{
WDINFO_LINKAGE void getWdInfo(char* Param, LPTSTR returnParm){
char __nogc* pStr =
static_cast<char*>(System::Runtime::InteropServices::Marshal::StringToHGloba
lAnsi(S"Return Value").ToPointer());
StrCpy(returnParm,pStr);

System::Runtime::InteropServices::Marshal::FreeCoTaskMem(System::IntPtr((voi
d*)pStr));
return;

}
}


<PlotAccounting-c.h>
#ifndef WDINFO_LINKAGE
#define WDINFO_LINKAGE __declspec(dllimport)
#endif

extern "C"{
WDINFO_LINKAGE void getWdInfo(char* Param, LPTSTR returnKey);
}
 
J

Jason W

I've found what I'm doing wrong. After reading a little feather in to StrCpy
I foud that I'm causing a buffer overrun by coping more than the origial
has. I need to test for the lenght before I copy the data.

Thanks for all your help Mattias!

Jason
Wood




Jason W said:
I didn't think I was doing it correct. I've been reading and found what I
believe to be the correct way to do this but VB6 still errors.

I can get it to work in C# but that isn't the language I'm looking for.
Am I making since about what I'm asking for?

<C# Code>
[DllImport(@"PlotAccounting-C.dll")]
static extern long getWdInfo(
string param,
System.Text.StringBuilder returnParm
);

[STAThread]
static void Main(string[] args)
{
System.Text.StringBuilder returnIt = new
System.Text.StringBuilder(500,500);
Console.WriteLine(getWdInfo("Testing", returnIt).ToString());
Console.WriteLine(returnIt.ToString());
}



<VB6 Code>
Public Declare Function getWdInfo Lib "PlotAccounting-C.dll" (ByVal param As
String, paramOut As String) As Long
Dim testing As String
testing = "Not Set"
MsgBox getWdInfo("PlotAccounting", testing)

<PlotAccount-c.cpp>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#using <mscorlib.dll>
#define WDINFO_LINKAGE __declspec(dllexport)
#include "PlotAccounting-C.h"
#include "shlwapi.h"

__gc class ManagedObjects{
public:
};

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

extern "C"{
WDINFO_LINKAGE void getWdInfo(char* Param, LPTSTR returnParm){
char __nogc* pStr =
static_cast said:
lAnsi(S"Return Value").ToPointer());
StrCpy(returnParm,pStr);

System::Runtime::InteropServices::Marshal::FreeCoTaskMem(System::IntPtr((voi
d*)pStr));
return;

}
}


<PlotAccounting-c.h>
#ifndef WDINFO_LINKAGE
#define WDINFO_LINKAGE __declspec(dllimport)
#endif

extern "C"{
WDINFO_LINKAGE void getWdInfo(char* Param, LPTSTR returnKey);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top