| 
Rank: Member
 Groups: Registered, Registered UsersJoined: 5/22/2006(UTC)
 Posts: 27
 
 | 
            
	      
                Im still getting the access violation problem. Im going to try using Winsock to pass my info but just incase anyone wants to have a look at the code and see if there is anything glaringly obvious:-
[code:1:a14efdd9ea]
//Inter Process Communication Example, Visual C++ 6.0 Test DLL
//Programming by Axonn Echysttas. E-Mail: axonnus at yahoo dot com
//Comment Language: English.
//
//Main DLL source file.
//Created on 2005-07-10. Last updated on 2005-11-04.
//For the creation of this code, I would like to express my thanks to:
//Nicholas Skapura from flipcode.com, moeur from vbforums.com, Randor from www.codeproject.com 
//and all the people-that-help-people on the CodeProject Message Boards or other Forums,
//especially to those which personally helped me by answering my questions.
#include "stdafx.h"
#include <winuser.h> //API functions.
#include <comutil.h> //For the _variant_t data type.
#include <string.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
// TODO: Make sure this include is in your search path or added explicitly to the project.
#include "MSXStruc.h" // required definitions
// we don't want C++ name-mangling
#ifdef __cplusplus
extern "C" {
#endif
#pragma bss_seg("DLLShare") //Sharing uninitialized data across instances of the DLL.
HWND hwndExternalApplication; //Handle to the VB Test Application.
//Addresses of public procedures declared in the module of the VB Test
//Application and which can be called by the VC++ DLL from the EXE of the
long extNumberProc; //VB Test Application. These will be called throughout the 
long extStringProc; //DLL. The addresses are received from the VB Application as long
long extStructureProc; //parameters upon the call of the Activate procedure.
long extArrayProc;
#pragma bss_seg()
//A structure used to transmit various information to the VB Test Application.
struct DLLStatusStruct
{
		long lFirst;
		long lSecond;
		long lThird;
		long lFourth;
		long lFifth;
		long lSixth;
};
//A structure with more diverse members.
struct AdvancedStruct
{
		long lFirst;
		long lSecond;
		_variant_t sThird; //The _variant_t type is a COM type used to send strings back to VB.
		BSTR sFourth; //But BSTR can also be used.
};
HANDLE hDLL; //Instance handle of this DLL.
//The entry point for the DLL.
BOOL APIENTRY DllMain (HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	hDLL = hModule;
	BOOL l_bRtrn = TRUE;
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH: //When a process connects to the DLL, displaying a debug message.
			SendMessage(hwndExternalApplication, WM_SETTEXT, NULL, (LPARAM) "Process attached to VC++ TEST DLL. (Sent via WM_SETTEXT)");
			break;
	case DLL_THREAD_ATTACH:
			break;
	case DLL_THREAD_DETACH:
			break;
	case DLL_PROCESS_DETACH: //When a process disconnects from the DLL, displaying a debug message.
			SendMessage(hwndExternalApplication, WM_SETTEXT, NULL, (LPARAM) "Process dettached from VC++ TEST DLL. (Sent via WM_SETTEXT)");
			break;
	}
 return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//FUNCTIONS USED INTERNALLY BY THE DLL
///////////////////////////////////////////////////////////////////////////////
//Converts a Char to a BSTR. Needed when working with strings with Visual Basic.
BSTR ConvertCharToBSTR(char* CharValue)
{
	int i; //Iteration counter.
	int iLength = strlen(CharValue); //Finding out the length of the Char.
	unsigned short* bstrResult = new unsigned short[iLength + 1]; //Creating a BSTR with the required length.
	//Going through the Char characters.
	for (i = 0; i < iLength; i++)
	{
		char iCharacter = CharValue[i]; //Taking the next char.
		bstrResult[i] = iCharacter; //Adding it to the string.
		bstrResult[i + 1] = '\\0'; //Adding the null-termination.
	}
	return bstrResult; //Returning the result.
}
///////////////////////////////////////////////////////////////////////////////
//FUNCTIONS THAT CALL OTHER FUNCTIONS FROM THE VISUAL BASIC TEST APPLICATION
//(VISUAL C++ -> VISUAL BASIC)
///////////////////////////////////////////////////////////////////////////////
//Using the extNumberProc variable, which is a pointer to the VB function for Numbers, calling
//that function and passing to it the value received as parameter.
void CallVBFunctionForNumber (long lSomeValueToSend)
{
	typedef long (__stdcall *OutsideFunction)(long AValue); //Defining the prototype of the function.
	OutsideFunction FunctionCall; //Creating an instance that will be used to call the function.
	FunctionCall = (OutsideFunction)extNumberProc; //Assigning the address to be used for the call.
	long da = FunctionCall(lSomeValueToSend); //Calling the function with the parameter.
	da++;
}
//Using the extStringProc variable, which is a pointer to the VB function for Strings,
//calling that function and passing to it the value received as parameter.
void CallVBFunctionForString (char *cSomeStringToSend)
{
	typedef void (__stdcall *OutsideFunction)(BSTR AValue); //Same as above, creating a function
	OutsideFunction FunctionCall; //prototype, instantiating it, and linking it to the real VB
	FunctionCall = (OutsideFunction)extStringProc; //function by doing this cast.
	BSTR bstrTemp = ConvertCharToBSTR(cSomeStringToSend); //VB Strings need a BSTR parameter.
	//Now that we have a BSTR, using SysAllocString on it and calling the VB function.
	FunctionCall(SysAllocString(bstrTemp));
}
//Using the extStructureProc variable, which is a pointer to the VB function for
//Structures, calling that function and passing to it a structure created locally.
void CallVBFunctionForStructure ()
{
	typedef void (__stdcall *OutsideFunction)(AdvancedStruct *AValue); //Same as above, creating a function
	OutsideFunction FunctionCall; //prototype, instantiating it, and linking it to the real VB
	FunctionCall = (OutsideFunction)extStructureProc; //function by doing this cast.
	AdvancedStruct *cmForCall = new AdvancedStruct; //Creating a new structure.
	cmForCall->lFirst = 10; //Setting its members.
	cmForCall->lSecond = 33;
	cmForCall->sThird = (_variant_t)"Some string value hardcoded in VC++.";
	FunctionCall(cmForCall); //Calling the VB function.
	delete cmForCall; //Freeing the memory.
}
//Using the extArrayProc variable, which is a pointer to the VB function for Arrays, calling
//that function and passing to it a locally created array of numbers and then strings.
void CallVBFunctionForArray ()
{
	typedef void (__stdcall *OutsideFunction)(VARIANT *AValue); //Same as above, creating a function
	OutsideFunction FunctionCall; //prototype, instantiating it, and linking it to the real VB
	FunctionCall = (OutsideFunction)extArrayProc; //function by doing this cast.
	VARIANT pVariant; //A variant typed pointer.
	SAFEARRAY *sarrVC; //The safe array.
	SAFEARRAYBOUND sabBound; //For the array properties (elements and bounds).
	sabBound.cElements = 10; sabBound.lLbound = 0; //Setting number of elements and bounds.
	VariantInit (&pVariant); //Initializing.
	//NUMERIC ARRAY.
	pVariant.vt = VT_ARRAY | VT_I4; //Setting the type of the variant.
	sarrVC = SafeArrayCreate(VT_I4, 1, &sabBound); //Creating the safe array.
	for (long lCounter = 0; lCounter < 10; lCounter++) //Inserting data in the array.
	{ long lToSend = lCounter * lCounter; SafeArrayPutElement(sarrVC, &lCounter, &lToSend); }
 pVariant.parray = sarrVC; //Setting the data of the Variant.
	FunctionCall(&pVariant); //Calling the VB function.
	SafeArrayDestroy(sarrVC); //Freeing memory.
	//STRING ARRAY.
	BSTR sarrToSend[5]; //A BSTR string array (VB uses BSTR. It might be possible to use another type).
	sabBound.cElements = 5; //This array will only have 5 elements.
 sarrToSend[0] = SysAllocString(ConvertCharToBSTR("1st value")); //Populating the BSTR array.
	sarrToSend[1] = SysAllocString(ConvertCharToBSTR("The 2 value"));
	sarrToSend[2] = SysAllocString(ConvertCharToBSTR("III value"));
	sarrToSend[3] = SysAllocString(ConvertCharToBSTR("Value number 4"));
	sarrToSend[4] = SysAllocString(ConvertCharToBSTR("Fifth and last value"));
	pVariant.vt = VT_ARRAY | VT_BSTR; //Setting the type of the variant.
	sarrVC = SafeArrayCreate(VT_BSTR, 1, &sabBound); //Creating the safe array.
	for (lCounter = 0; lCounter < 5; lCounter++) //Inserting data in the array.
	{ SafeArrayPutElement(sarrVC, &lCounter, sarrToSend[lCounter]); }
 pVariant.parray = sarrVC; //Setting the data of the Variant.
	FunctionCall(&pVariant); //Calling the VB function.
	SafeArrayDestroy(sarrVC); //Freeing memory.
	for (lCounter = 0; lCounter < 5; lCounter++) //Also freeing memory used by the BSTR string array.
		SysFreeString(sarrToSend[lCounter]);
}
//////////////////////////////////////////////////////////////////////////////
//FUNCTIONS CALLED FROM THE VISUAL BASIC TEST APPLICATION
//(VISUAL BASIC -> VISUAL C++)
//////////////////////////////////////////////////////////////////////////////
//Intializes the DLL.
void WINAPI Activate (long lVBNumberDemoFunction, long lVBStringDemoFunction, long lVBStructureDemoFunction, long VBArrayDemoFunction)
{
	hwndExternalApplication = FindWindow(NULL, "Test VB Application"); //Getting the handle for the Visual Basic Test Application.
	//Saving the data received from the VB Test Application in the global variables of the DLL.
	extNumberProc = lVBNumberDemoFunction; //These long parameters will hold the addresses of
	extStringProc = lVBStringDemoFunction; //public functions from the VB Test Application and will
	extStructureProc = lVBStructureDemoFunction; //be used to call these functions throughout the DLL.
	extArrayProc = VBArrayDemoFunction;
	//Sending a message to the VB Application. The VB Application is subclassed and trained
	//to handle these messages. See there for details, in the Functionality.bas module.
	SendMessage(hwndExternalApplication, WM_SETTEXT, NULL, (LPARAM) "Addresses of VB functions saved. Ready for demonstration. (Sent via WM_SETTEXT)");
	SendMessage(hwndExternalApplication, WM_USER + 241, NULL, (LPARAM) "Addresses of VB functions saved. Ready for demonstration. (Sent via WM_USER + 241)");
}
//The VB Application will call this function to trigger the DLL to begin a particular demonstration.
void WINAPI Demonstrate (int WhatToDemonstrate)
{
	switch (WhatToDemonstrate) //Depending on what demonstration has been commanded.
	{
		case 1: //Demo 1 = Demonstrate calling a string function from VB.
		{
			CallVBFunctionForString("Greetings from VC++!"); //Calling a VB function that accepts a string as parameter.
			break;
		}
		case 2: //Demo 2 = Demonstrate calling a number function from VB.
		{
			CallVBFunctionForNumber(22); //Calling a VB function that accepts a (long) number as parameter.
			break;
		}
		case 3: //Demo 3 = Demonstrate calling a structure function from VB.
		{
			CallVBFunctionForStructure(); //Calling the VB function for structures.
			break;
		}
		case 4: //Demo 4 = Demonstrate sending data via WM_COPYDATA.
		{
			COPYDATASTRUCT cdsData; //The structure used to send data.
			//SENDING A STRING VIA WM_COPYDATA.
			char cTemp[50]; //A temporary character.
			BSTR sString; //String to send to VB.
			strcpy(cTemp, "This is the string passed via WM_COPYDATA.\\0"); //The string to send.
			sString = SysAllocString(ConvertCharToBSTR(cTemp)); //Creating VB compatible string.
			cdsData.dwData = 1000; //Setting an arbitrary value which will tell VB we're sending a string.
			cdsData.cbData = strlen(cTemp)*2; //Wide characters = lenght times two.
			cdsData.lpData = sString; //Setting the string to be sent.
			//Sending the data.
			SendMessage(hwndExternalApplication, WM_COPYDATA, (WPARAM)hwndExternalApplication, (LPARAM)&cdsData);
			SysFreeString(sString); //Freeing memory used by SysAlloc.
			//SENDING AN ARRAY OF LONGS VIA WM_COPYDATA.
			long larrNumbers[5] = {4, 6, 0, 1, 8}; //The array to be sent.
			cdsData.dwData = 1001; //Indicating VB we're sending a long array.
			cdsData.cbData = 5 * sizeof(long); //Lenght of the array times the size of the long data type.
			cdsData.lpData = larrNumbers; //Setting the data to be sent.
			//Sending the data.
			SendMessage(hwndExternalApplication, WM_COPYDATA, (WPARAM)hwndExternalApplication, (LPARAM)&cdsData);
			//MY METHOD OF SENDING AN ARRAY OF STRINGS TO VB (there are several others possible
			//but I consider this one has a higher educational value).
			int iStrings = 5; //Number of strings to be sent.
			char cArrayTemp[5][50]; //The array of strings.
			BSTR sSendString; //String to send in a step.
			strcpy(cArrayTemp[0], "The first string.");
			strcpy(cArrayTemp[1], "Second string.");
			strcpy(cArrayTemp[2], "T H I R D.");
			strcpy(cArrayTemp[3], "Fourth");
			strcpy(cArrayTemp[4], ""); //When encountering this element VB will know the array ended.
			//Signalling the end of the array could also be done by sending some WM_USER + SOMETHING 
			//message to the VB application or sending a special string token.
			for (int iCounter = 0; iCounter < 5; iCounter ++) //Sending the array in steps.
			{ //Allocating space for this particular element of the array.
				sSendString = SysAllocString(ConvertCharToBSTR(cArrayTemp[iCounter]));
				cdsData.dwData = 1002 + iCounter; //Telling VB that we're sending a string array.
				//Also adding the iCounter to the value to tell VB which element this is.
				cdsData.cbData = strlen(cArrayTemp[iCounter])*2; //Wide characters = lenght times two.
				cdsData.lpData = sSendString; //Setting the string to be sent.
				//Sending the data.
				SendMessage(hwndExternalApplication, WM_COPYDATA, (WPARAM)hwndExternalApplication, (LPARAM)&cdsData);
				SysFreeString(sSendString); //Freeing memory used by SysAlloc.
			}
			break;
		}
		case 5: //Demo 5 = Demonstrate calling a VB function with an array parameter.
		{
			CallVBFunctionForArray();
			break;
		}
	}
}
//The VB Application will call this function passing it a LONG parameter. This function will
//notify that it successfully received the value, by calling another function, from the VB
//and passing it a string value. See the StringDemoFunction's comments, in the VB Application.
void WINAPI VCNumber (long ValueFromVB)
{
	char cValue[12]; //Used to convert the value received from VB.
	char cText[30] = "The number is: "; //The final result.
	_ltoa(ValueFromVB, cValue, 10); //Converting the value from VB to a text.
	strcat(cText, cValue); //Adding the text after the "The number is: " text.
	CallVBFunctionForString(cText); //Sending the text obtained above back to the VB Application.
}
//This function will return a structure back to the VB Application. The VB Application calls
//this function and specifies a Number argument and a Text argument.
AdvancedStruct WINAPI VCStructure (long Number, BSTR Text)
{
	AdvancedStruct cmResponse; //Used to fill out the members of the structure.
	char cTemp[2000]; //Used for concatenation.
	strcpy(cTemp, (LPCSTR)Text); //First, adding in cTemp the value from VB.
	strcat(cTemp, " Concatenated with this string from VC++."); //Now adding some more text to it.
	cmResponse.lFirst = Number; //Sending back the number.
	cmResponse.lSecond = Number + 200; //The number plus a value.
	cmResponse.sThird = _variant_t(cTemp); //And finally, the concatenated text from above, as _variant_t.
	//_variant_t must be used for a good transmission of strings from VC++ to VB (COM).
	cmResponse.sFourth = SysAllocString((LPCWSTR)"This is a BSTR String in VC++."); //Sending via BSTR casted to LPCWSTR.
	return cmResponse;
}
//Returns data about the DLL. Uses *Response, a parameter received through reference to send back data to Visual Basic.
void WINAPI GetDLLData (DLLStatusStruct *Response)
{
	Response->lFirst = extNumberProc; //Sending back to the Visual Basic application the addresses of its own functions.
	Response->lSecond = extStringProc; //These addresses were set above, in the Activate procedure. When calling this
	Response->lThird = extStructureProc; //function from Visual Basic, the DLLStatusStruct variable received as parameter
	Response->lFourth = extArrayProc; //will be filled with data and Visual Basic will read and display that data.
	Response->lFifth = 123; //As the fifth value, returning a hardcoded value.
	Response->lSixth = GetTickCount(); //As the sixth value, returning the result of the GetTickCount function.
}
//Receives from VB a numeric array and returns the element designated by the Index.
long WINAPI VCNumericArray (LPSAFEARRAY FAR *ArrayData, int Index)
{
	long *sarrTemp; //Array used to put the argument in.
	
	sarrTemp = (long*)(*ArrayData)->pvData; //Taking the array into our local one.
	Index--; //Decreasing Index with 1 since in VB arrays begin with 1, not 0.
	sarrTemp[1] += 100; //Modifying the second element of the array. 
	return(sarrTemp[Index]); //Returning the requested value.
}
//Receives from VB a string array and returns the element designated by the Index.
BSTR WINAPI VCStringArray (LPSAFEARRAY FAR *ArrayData, int Index)
{
	BSTR *sarrTemp; //Array used to put the argument in.
	sarrTemp = (BSTR*)(*ArrayData)->pvData; //Taking the array into our local one.
	Index--; //Decreasing Index with 1 since in VB arrays begin with 1, not 0.
	return(SysAllocString(sarrTemp[Index])); //Returning the requested value.
}
BOOL __stdcall MSXInfo (MSXDLLDef *a_psDLLDef)
{
	// TODO: replace with your copyright information...
	strncpy (a_psDLLDef->szCopyright, "Copyright (c) ",
			sizeof(a_psDLLDef->szCopyright)-1);
	// TODO: set the number of functions you are exporting
	// (don't forget to add them to your .def file)
	a_psDLLDef->iNFuncs = 1; // change this if you have more than 1 function to export.
	a_psDLLDef->iVersion = MSX_VERSION;
	return MSX_SUCCESS;
}
BOOL __stdcall MSXNthFunction (int a_iNthFunc, MSXFuncDef *a_psFuncDef)
{
	int l_bRtrn = MSX_SUCCESS; // no error
	switch (a_iNthFunc)
	{
	// TODO: define a case entry (starting at 0) for each of your functions
	// This "EmptyFunc" entry should be modified with the name and description
	// of your function.
	case 0:
		strcpy (a_psFuncDef->szFunctionName, "NewAlert");
		strcpy (a_psFuncDef->szFunctionDescription, "Metastock has a new strategy alert.");
		a_psFuncDef->iNArguments = 1;
		break;
	default:
		l_bRtrn = MSX_ERROR; // This will help MSXTest find errors in your code
		break;
	}
	return l_bRtrn;
}
BOOL __stdcall MSXNthArg (int a_iNthFunc, int a_iNthArg,
 MSXFuncArgDef *a_psFuncArgDef)
{
	BOOL l_bRtrn = MSX_SUCCESS;
	a_psFuncArgDef->iNCustomStrings = 0; // init just to be nice
	// If your functions have arguments, uncomment this switch statement
	// and add the appropriate case statements.
	
	switch (a_iNthFunc)	{
	case 0: // NewAlert
		switch (a_iNthArg) {
		case 0: // NewAlert:Arg0
			a_psFuncArgDef->iArgType = MSXString; // String
			strcpy (a_psFuncArgDef->szArgName, "AlertType");
		break;
		default:
			l_bRtrn = MSX_ERROR; // This will help MSXTest find errors in your code
		break;
	}
	break;
	default:
		l_bRtrn = MSX_ERROR; // This will help MSXTest find errors in your code
		break;
	}
	
	return l_bRtrn;
}
#define MSXMax(a,b) (((a) > (b)) ? (a) : (b))
#define MSXMin(a,b) (((a) < (b)) ? (a) : (b))
double ForceFloatRange (double a_lfDbl)
{
	if (a_lfDbl > 0.0)
	{
		a_lfDbl = MSXMin (a_lfDbl, double(FLT_MAX)); // make sure pos number <= FLT_MAX
		a_lfDbl = MSXMax (a_lfDbl, double(FLT_MIN)); // make sure pos number >= FLT_MIN
	}
	else
	{
		if (a_lfDbl < 0.0)
		{
			a_lfDbl = MSXMax (a_lfDbl, double(-FLT_MAX)); // make sure neg number >= -FLT_MAX
			a_lfDbl = MSXMin (a_lfDbl, double(-FLT_MIN)); // make sure neg number <= -FLT_MIN
		}
	}
	return a_lfDbl;
}
BOOL __stdcall NewAlert (const MSXDataRec *a_psDataRec,
 const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
 const MSXNumericArgsArray *a_psNumericArgs,
 const MSXStringArgsArray *a_psStringArgs,
 const MSXCustomArgsArray *a_psCustomArgs,
 MSXResultRec *a_psResultRec)
{
	BOOL l_bRtrn = MSX_SUCCESS;
	
	CallVBFunctionForString("Adams Here");
	// in case you don't flesh this out before running it, we'll invalidate
	// the return array to prevent potential problems.
	a_psResultRec->psResultArray->iFirstValid = 0;
	a_psResultRec->psResultArray->iLastValid = -1;
	return l_bRtrn;
}
#ifdef __cplusplus
}
#endif
[/code:1:a14efdd9ea] |