Rank: Member
Groups: Registered, Registered Users Joined: 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]
|