logo
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
yachtfund  
#1 Posted : Thursday, June 8, 2006 1:34:55 PM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

Hi All I have my DLL and I want it to tell a VB app that a strategy alert has been received e.g. Strategy One - Buy alert. My VB is good but my c++ is woefully bad. I wondered if anyone had done this before and if they had a preferred method. Perhaps sending a message through a port that's been monitored with Winsock??? Before I crack on I thought I would ask. Many thanks for your help, YachtFund
wabbit  
#2 Posted : Thursday, June 8, 2006 1:38:52 PM(UTC)
wabbit

Rank: Advanced Member

Groups: Registered, Registered Users, Subscribers, Unverified Users
Joined: 10/28/2004(UTC)
Posts: 3,111
Location: Perth, Western Australia

Was thanked: 16 time(s) in 16 post(s)
Personally, I don't know, BUT I would be interested in the solution should you find one! May I ask that you keep us informed on this one? wabbit :D
yachtfund  
#3 Posted : Thursday, June 8, 2006 2:01:28 PM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

Will do. I began with looking at ths:- http://www.codeproject.c...processcommunication.asp And merged it with my very basic MSX DLL. I thought it was going to work but when I added an expert advisor errors started along the lines of 'access violation error' and I started drowning. Im having a go at creating a VB Winsock app that listens to a port and the DLL sens info through it which is caught by the VB app. Shall let yo know the outcome. YachtFund
wabbit  
#4 Posted : Thursday, June 8, 2006 2:07:16 PM(UTC)
wabbit

Rank: Advanced Member

Groups: Registered, Registered Users, Subscribers, Unverified Users
Joined: 10/28/2004(UTC)
Posts: 3,111
Location: Perth, Western Australia

Was thanked: 16 time(s) in 16 post(s)
YF, I had a whole series of access violation errors when I was trying to write some of my MSX functions. It turned out (I think??) that my <includes> were the cause. Try to use non .h headers where possible?? Particularly for the streams (istream, ostream ,iostream etc) Worth a shot! wabbit :D
yachtfund  
#5 Posted : Thursday, June 8, 2006 2:13:47 PM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

wabbit I currently have all these:- #include "stdafx.h" #include "winuser.h" #include "comutil.h" #include <string.h> #include <float.h> #include <math.h> #include <stdlib.h> #include "MSXStruc.h" Some start with < some ", dont know the difference... YF
wabbit  
#6 Posted : Thursday, June 8, 2006 2:16:57 PM(UTC)
wabbit

Rank: Advanced Member

Groups: Registered, Registered Users, Subscribers, Unverified Users
Joined: 10/28/2004(UTC)
Posts: 3,111
Location: Perth, Western Australia

Was thanked: 16 time(s) in 16 post(s)
Not having used winuser.h and comutil.h I couldnt say for sure if they are the problem? Is there a non .h version? An MFC version?
yachtfund  
#7 Posted : Thursday, June 8, 2006 2:21:14 PM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

I dont know C++ that well so no idea.
wabbit  
#8 Posted : Thursday, June 8, 2006 2:26:31 PM(UTC)
wabbit

Rank: Advanced Member

Groups: Registered, Registered Users, Subscribers, Unverified Users
Joined: 10/28/2004(UTC)
Posts: 3,111
Location: Perth, Western Australia

Was thanked: 16 time(s) in 16 post(s)
neither do I!
Branden Russell  
#9 Posted : Thursday, June 8, 2006 2:45:10 PM(UTC)
Branden Russell

Rank: Advanced Member

Groups: Registered, Registered Users
Joined: 11/28/2005(UTC)
Posts: 276
Location: Salt Lake City, UT

yachtfund wrote:
... Some start with < some ", dont know the difference... YF
<> go around headers that are built in, headers that are found in the main directory. The compiler will already know where those are. "" go around headers that are custom and need to be added into the solution or include a path of where to get to them.
yachtfund  
#10 Posted : Thursday, June 8, 2006 3:37:43 PM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

Ahhh. #include "winuser.h" #include "comutil.h" These two are not in the same directory as my c++ project, should they be when I compile it? There doesnt seem to be any varibale that specifies where they are. Thanks for you help. YF
Branden Russell  
#11 Posted : Thursday, June 8, 2006 3:41:55 PM(UTC)
Branden Russell

Rank: Advanced Member

Groups: Registered, Registered Users
Joined: 11/28/2005(UTC)
Posts: 276
Location: Salt Lake City, UT

I did a search and those are in the compiler's directory. Should probably be <> instead of "". Give that a try.
yachtfund  
#12 Posted : Thursday, June 8, 2006 4:19:44 PM(UTC)
yachtfund

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]
jtrevatt  
#13 Posted : Thursday, June 15, 2006 10:43:01 PM(UTC)
jtrevatt

Rank: Member

Groups: Registered, Registered Users
Joined: 5/25/2006(UTC)
Posts: 13
Location: Brisbane, Australia

Hi YachtFund, I have a similiar goal as you do - sending my trading signals to an external VB app. I considered a number of ways to achieve the communication process including writing to text files, using winsock, using DDE and finally (the one I am happy with) writing to a SQL database table. I decided this simply because it involves the least amount of code. I also considered that I would want to record all my 'filtered' signals in a database anyway for easy access, so it seemed more logical to put it straight in there than through winsock and then into a database. I have a VB.NET app which then accepts calls from the database events (SQL Server 2005) so that I can process the signals using my 'Trading Rules Engine'. To me it makes a lot more sense implementing the business rules for the trades outside of Metastock and the MSX DLL. This approach gives you the most flexibility in being able to change your rules and use your signals any which way you want. Be it to put into an automated trading system (such as my goal) or to email/sms traders. Jeremy
yachtfund  
#14 Posted : Saturday, June 17, 2006 12:46:20 PM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

Hi Jeremy Looking forward to getting this done so I can play more golf!! Did you manage to get the Winsock code working? Cheers YF
jtrevatt  
#15 Posted : Thursday, July 13, 2006 9:48:18 PM(UTC)
jtrevatt

Rank: Member

Groups: Registered, Registered Users
Joined: 5/25/2006(UTC)
Posts: 13
Location: Brisbane, Australia

Hi yachtfund, Sorry for the tardy reply... been busy working on the trading system :).. anyway, I got both the database version (with the database working as a alert storage and message proxy) working, and the Winsock version working. Winsock is soooo easy. Your MSX DLL just needs to act as a TCP client (I did mine in PowerBASIC). open a socket, send a mesage, close the socket. On the other end I set up a TCP Server using VB.NET to receive the messages. From that point you can do what you want with the messages. For me I apply additional trading rules and then write the qualified alerts to the database. The advantage of using the TCP method rather than the DB one is that it achieves the objective of making the MSX DLL quicker. It seems that the faster the MSX DLL is released from its tasks the happier Metastock is. Additionally, qualifiying the alerts by using a post-alert trading rules component means that the DB doesnt get hit unecessarily. In my case I am actually re-posting my qualified alerts to dedicated remote TCP clients (trading associates). With the qualified alerts being written to the database though I have the option of analyzing the performance of the trading systems as well as publishing trade alert history onto a web-server.
yachtfund  
#16 Posted : Monday, July 24, 2006 2:49:23 PM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

Hi jtrevatt I can write to a file, which is easy and thats one way I could do it. Im having problems connecting to my vb winsock server though, good article here http://www.planet-source...?txtCodeId=2241&lngWId=3 although i cant get it working. Do you fancy putting up the basic code that you have to connect to the server? My none working one so far is below, Im getting 'Failed to establish connection with server.' Why oh why oh why oh why, I ask you. 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) { // open log file ofstream myfile; myfile.open ("log.txt", ios::app); // myfile << "Writing this to a file.\\n"; // initialise WSADATA WsaDat; int winsockInitialise = WSAStartup(MAKEWORD(1, 1), &WsaDat); // if the initialisation was succesful if(winsockInitialise == 0){ // create a sockeet SOCKET Socket; Socket = socket(AF_INET, SOCK_STREAM, 0); // if creating the socket was succesful if (Socket != INVALID_SOCKET){ myfile << "Not INVALID_SOCKET.\\n"; SOCKADDR_IN SockAddr; SockAddr.sin_port = 1007; SockAddr.sin_family = AF_INET; SockAddr.sin_addr.S_un.S_un_b.s_b1 = 192; SockAddr.sin_addr.S_un.S_un_b.s_b2 = 168; SockAddr.sin_addr.S_un.S_un_b.s_b3 = 1; SockAddr.sin_addr.S_un.S_un_b.s_b4 = 3; // check socet connection if (connect(Socket, (SOCKADDR *)(&SockAddr), sizeof(SockAddr)) != 0) { // if no connection myfile << "Failed to establish connection with server.\\n"; }else{ // log a connection myfile << "Establish connection with server.\\n"; /* int RetVal = SOCKET_ERROR; char String[] = "Hello"; while (RetVal == SOCKET_ERROR) { RetVal = recv(Socket, String, strlen(String) + 1, 0); if ((RetVal == 0)||(RetVal == 1)||(RetVal == 2)) { myfile << "Connection closed at other end.\\n"; break; } } */ } }else{ // socket not initialised myfile << "INVALID_SOCKET.\\n"; } } BOOL l_bRtrn = MSX_SUCCESS; // 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; // close file myfile.close(); return l_bRtrn; }
jtrevatt  
#17 Posted : Monday, July 24, 2006 9:53:44 PM(UTC)
jtrevatt

Rank: Member

Groups: Registered, Registered Users
Joined: 5/25/2006(UTC)
Posts: 13
Location: Brisbane, Australia

Hi Yachtfund, My client code is quite simple (pasted below). All of the hard stuff is actually built into PowerBASIC already, so sending something involves a basic call to the built-in functions. Therefore I dont think this code will illumunate you much. I assume that since you have a VB Winsock server running you have also tested it out using a VB Winsock Client? At least to prove that you are not missing something really basic. Its frustrating how many times I have looked for hours for complex solutions when the really simple answer was slapping me in the face the whole time! One of the problems I had to overcome was just unblocking the port/app in the firewall software (in my case just the built-in windows firewall. But I know that AVG and Nortons treat blocking in different ways. Also, in my situation I wanted to develop and test locally (on my notebook computer) and then move it into a true production environment that has multiple client machines. Under XP, when you are testing both client and server on the same machine, it is easier to have the server and client listening on different ports. Therefore I set up both the server and client apps to communicate on 2 ports. An upstream (outbound) port and a downstream (inbound) port. So, for example, the client listens on port 997 and sends on port 998, while the server listens on port 998 and sends on port 997. Therefore it is easy to get it working in dev and of course will also work in a multiple machine environment as well. For the same reason its also a good idea to make sure that you are using ports that arent likely to be used by other applications. Seeing as your error message was not exactly specific (typical I know) I am blatting you with possible solutions. I think though that the most important thing would be to try and get a sample piece of code (such as the vb winsock ones) working (client and server) on the same machine. Then you have at least proved that the basics are working on the ports you have chosen. You might have already done all this... in which case Ive been rambling for no good reason :) LOCAL nSocket AS LONG LOCAL sBuffer AS STRING LOCAL sPacket AS STRING LOCAL l_bRtrn AS LONG TCP OPEN PORT 999 AT "127.0.0.1" AS nSocket TIMEOUT 5000 IF ERR THEN 'MSGBOX "Error opening port: " + STR$(ERR) EXIT SUB END IF IF LEN(COMMAND$) THEN TCP PRINT nSocket, COMMAND$; ELSE TCP PRINT nSocket, sMessage; END IF TCP CLOSE nSocket
yachtfund  
#18 Posted : Tuesday, July 25, 2006 9:19:13 AM(UTC)
yachtfund

Rank: Member

Groups: Registered, Registered Users
Joined: 5/22/2006(UTC)
Posts: 27

Ramble away jtrevatt!! I have got the VB server/client working. You might be right about the firewalls. I have tried turning them off but you cant tell with these pesky Windows systems, they never do what you tell them to do. I shall plug away. Have you manged to get your full auto system working yet? Are you going to trust it to its own devices for long amounts of time or are you going to watch it faily closely? Im hoping mine can be left so I can play with my train set. YF
jtrevatt  
#19 Posted : Tuesday, July 25, 2006 9:54:02 AM(UTC)
jtrevatt

Rank: Member

Groups: Registered, Registered Users
Joined: 5/25/2006(UTC)
Posts: 13
Location: Brisbane, Australia

YF, I have been publishing live signals to my associate who lives a couple of hours from me. We have been doing this for a few days. The arent any real issues with TCP although I am introducing a couple of safety measures. A inactivity timeout that will warn us when no data at all has been recieved (I also stream real-time prices through) and a custom ping from the client to the server. So these are basically to tell us that something is wrong with the communication or if Metastock has dumped its guts. My associate then uses the trade signals that come through the client to place the orders. The next stage of development is to automate that entry of the orders onto our platform. I have already done a proof of concept that I am happy with and will start plugging away at the real system over the next week. I am still tweaking the GUI on the client. The full automation requires quite a bit more savvy... not so much in the actual execution, but in the management. For instance I am constructing a market calendar that will stop us from trading around news events, and to close out trades before markets close etc. We will end up baby-sitting it for about 6 months I believe. But its a case of treading gently, learning some things and then taking the next steps. We will figure out what controls we put in place and how quickly we turn different markets on. J
Users browsing this topic
Guest (Hidden)
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.