AutoHotkey Community

It is currently May 27th, 2012, 10:55 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: December 7th, 2006, 1:56 pm 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
seems that DDE support should be easy. Something desperately searching to do with AHK (not via perl workaround, etc...)... and seems like... on surface.... with little help can develop a simple AHK function for DDE (at least client side) communication. Should allow tapping into windows word, etc. *and* hundreds of older programs using the DDE server protocols which desperately need some AHK intervention in the post win'95 world.



here's what I have so far:


Windows Messages include:

WM_DDE_INITIATE = 0x3E0
WM_DDE_REQUEST = 0x3E6
WM_DDE_POKE = 0x3E7
WM_DDE_EXECUTE = 0x3E8



so..


something like:


Postmessage,0x3E0,Server,Subject,,ahk_id 0xFFFF

VarSetCapacity(test,500)
SendMessage,0x3E6 ,something,&test,,ahk_id winID


or something....

should want to work... no ?

http://msdn2.microsoft.com/en-us/library/ms648998.aspx

tells us:




PostMessage(
(HWND) hWnd,
WM_DDE_REQUEST,
(WPARAM) wParam,
(LPARAM) lParam
);

Parameters

wParam
Handle to the client window sending the message.
lParam
The low-order word specifies a standard or registered clipboard format.
The high-order word contains an atom that identifies the data item requested from the server.

Return Value

No return value.
Remarks

Posting

The client application allocates the atom by calling the GlobalAddAtom function.

Receiving

If the receiving (server) application can satisfy the request, it responds with a WM_DDE_DATA message containing the requested data. Otherwise, it responds with a negative WM_DDE_ACK message.

When responding with either a WM_DDE_DATA or WM_DDE_ACK message, the server application can either reuse the atom or it can delete the atom and create a new one.

#### #####


but golly...


1) how to determine the "Handle to the client window sending the message." that should be easy to find our script's (assuming we have NO GUI) handle... but somehow (embarassingly) i'm not finding it.......


2) What are these... and how in the heck do I get them ?
The low-order word specifies a standard or registered clipboard format.
The high-order word contains an atom that identifies the data item requested from the server.


is an atom = to sending a &Var ???


http://msdn2.microsoft.com/en-us/library/ms648779.aspx

gives us a list of clipboard formats::

CF_BITMAP

CF_DIB

CF_DIF

CF_ENHMETAFILE

CF_METAFILEPICT

CF_OEMTEXT

CF_PALETTE

CF_PENDATA

CF_RIFF

CF_SYLK

CF_TEXT

CF_TIFF

CF_WAVE

CF_UNICODETEXT


do we iD them as a text ?? numeric ?? ideas ?

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject: here...
PostPosted: December 14th, 2006, 12:04 am 
A Dynamic Data Exchange (DDE) conversation begins when a client program
posts a WM_DDE_INITIATE message. When a server program acknowledges
this message, a "cold link" is established.
In a "cold link", a client requests data from the server by posting a
WM_DDE_REQUEST message. If the server can supply this data item, it
responds by posting a WM_DDE_DATA message to the client.
If the client were to post a WM_DDE_ADVISE message instead of the
WM_DDE_REQUEST message, the server will reply with its WM_DDE_DATA
message as above and will CONTINUE to reply with WM_DDE_DATA messages
whenever the data requested has been altered. This is called a "hot
link".
A "warm link" can be established if the client passes a flag with the
WM_DDE_ADVISE message indicating that this is the desired relationship.
Under a warm link, if data is changed a message is posted by the server
indicating as much, but it is up to the client at that point to request
the data by posting a follow up WM_DDE_REQUEST message.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 14th, 2006, 8:55 am 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Nice thread.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 14th, 2006, 10:00 am 
As I remember MacroScheduler (shareware) has provided that option, which was quite usefull when it came to communicate with a worksheet in MSExcel 8).
I'd really appreciate if that could be accomplished with AHK too.

btw. MSched has also offered to use embedded VBScript which might be of interest for someone out there ...


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 18th, 2006, 12:46 am 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
so....

it seems so simple.... for AHK to do this....


just need to know...




1) the Handle to the client window sending the message.

hmmm.... that's the handle to the running AHK script... right ?

WHERE IS THIS ???

(probably a stupid question.....)




2) standard or registered clipboard format... hmmm... need to figure out how & where... but ok,....


3) The high-order word contains an atom that identifies the data item requested from the server....


gosh.... *Someone* must surely know what an atom is... and how it id's the requested data.... (probably another stupid q...)


and...

gosh...

with just some simple knowledge... (which somehow is eluding me...)....

ahk and DDE are.... like... in bed together....

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 18th, 2006, 11:42 am 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
I studied DDE ages ago... and forgot most of it. It isn't so much used since Win95...
Joy2DWorld wrote:
1) the Handle to the client window sending the message.
Gui +LastFound
guiID := WinExist()

Quote:
2) standard or registered clipboard format... hmmm... need to figure out how & where... but ok,....
SetClipboardData might help you here.

Quote:
3) The high-order word contains an atom that identifies the data item requested from the server....

gosh.... *Someone* must surely know what an atom is... and how it id's the requested data.... (probably another stupid q...)
That's a Windows "object" that must be created (and handled) using the related Windows API... Can't say much more, you have to find some DDE tutorial, I suppose.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2006, 11:13 pm 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
PhiLho wrote:
IGui +LastFound
guiID := WinExist()



gives the id to the running thread, even without a Gui ?


ie.

is it the same as this:

Code:
; To find the process ID of an AHK script (supposed to be an alternative to "WinGet PID"):
SetTitleMatchMode, 2
DetectHiddenWindows, on
SendMessage, 0x44, 0x405, 0, , tester1.ahk

WinGet, OV , ID,  ahk_pid %ErrorLevel%
MsgBox %OV% is the windowHandle id.

return


or can winget give the handle directly ?? (ie. is the code just circular ?)

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 20th, 2006, 11:55 am 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
Ah, when you wrote "client window", I supposed you had a GUI.
No, so indeed, I suppose the code you gave is the way to go, it is probably the handle of the AutoHotkey window hiding behind the notification area icon.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 20th, 2006, 3:19 pm 
Quote:
Can't say much more, you have to find some DDE tutorial, I suppose

[a previous DDE thread with several links]

Search showed 20 hits on 'DDE' within the AHK forum.


Report this post
Top
  
Reply with quote  
PostPosted: December 21st, 2006, 10:08 am 
What is going on here? Is this connecting to a Windows based server platform to exchange data, or is it something else? :) Looks interesting and would like to hear fresh insights into this :) :)

[Moderator's note: Removed extra-long useless quote... Seems to be a trend today...]


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 26th, 2006, 7:57 pm 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
1. WHY DDE ??

http://www.angelfire.com/biz/rhaminisys ... Epreferred

Quote:
Connecting to a particular instance of an application
Some applications such as Excel do register themselves in the ROT and support multiple instances. However, there is no way to connect to a particular instance of Excel with COM. For example, the GetObject() method in Visual Basic returns a random instance, even when a file name is specified.
With DDE you can manipulate any worksheet without regard to the instance hosting it, because Excel offers a separate topic name for each worksheet. For more information on controlling Excel go to Controlling Excel with DDE.

With some care it is possible to connect to particular instances with DDE, even when the topics supported by each instance are the same. The client must start when at most one of the instances of the server is running. The client must capture the instance handle of each instance as it registers with DDEML, and connect using it. Connections made using a string for the service name, e.g. IExplore, will connect to a random instance.



2. HOW ??? maybe via DLL ??


http://msdn2.microsoft.com/en-us/library/ms648715.aspx

...

http://msdn2.microsoft.com/en-us/library/ms648768.aspx

Quote:
Initialization
Before calling any other DDEML function, an application must call the DdeInitialize function. DdeInitialize obtains an instance identifier for the application, registers the application's DDE callback function with the DDE, and specifies the transaction filter flags for the callback function.

Each instance of an application or a DLL must pass its instance identifier as the idInst parameter to any other DDEML function that requires it. The purpose of multiple DDEML instances is to support DLLs that must use the DDEML at the same time an application is using it. An application must not use more than one instance of the DDEML.

Transaction filters optimize system performance by preventing the DDEML from passing unwanted transactions to the application's DDE callback function. An application sets the transaction filters in the DdeInitialize ufCmd parameter. An application must specify a transaction filter flag for each type of transaction that it does not process in its callback function. An application can change its transaction filters with a subsequent call to DdeInitialize. For more information about transactions, see Transaction Management.

The following example shows how to initialize an application to use the DDEML.

Copy Code
DWORD idInst = 0;
HINSTANCE hinst;

DdeInitialize(&idInst, // receives instance identifier
(PFNCALLBACK) DdeCallback, // pointer to callback function
CBF_FAIL_EXECUTES | // filter XTYPE_EXECUTE
CBF_SKIP_ALLNOTIFICATIONS, // filter notifications
0);
An application must call the DdeUninitialize function when it is no longer going to use the DDEML. This function terminates any conversations currently open for the application and frees the DDEML resources the system allocated for the application




OK... so... with all the DLL gurus here...


help in finding the AHK way to DDE... .... ...

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 27th, 2006, 8:24 am 
Offline

Joined: July 6th, 2004, 10:07 am
Posts: 171
Location: Manchester, England.
@Joy2DWorld,

Quote:
2) What are these... and how in the heck do I get them ?
The low-order word specifies a standard or registered clipboard format.
The high-order word contains an atom that identifies the data item requested from the server


Well the answer lies in the question. a DOUBLE WORD, 32 bits


Code:
dword = 0xA023DD44
lWord := dword & 0xffff
hWord := dWord >> 16

msgbox % "hiWord = "d2h(hWord) "`n" "loWord = " d2h(lWord)

d2h(_dec)
{
setformat,integer,h
_dec+=0
setformat,integer,d
return _dec
}


Regards

Dave.

_________________
Simple ideas lie within reach, only of complex minds


Report this post
Top
 Profile  
Reply with quote  
 Post subject: (Visual) C++ and DDE
PostPosted: December 27th, 2006, 11:04 pm 
Quote:
Introduction to DDE

Foreword

Definition of Dynamic data exchange: Dynamic data exchange (DDE) is a form of interprocess communication that uses shared memory to exchange data between applications. Applications can use DDE for one-time data transfers and for ongoing exchanges and updating of data.

In this report, the use of DDE functions will be made clear and a detailed description will be given too. You need to use a lot of functions to let two or more applications work together, as one function needs another one.

This report also describe all the functions in detail. The syntax, return values and the arguments will be explained with a little description with each argument.



1. Introduction to DDE



DDE is an interprocess communication method that allows two or more applications running simultaneously to exchange data and commands. This means that two or more applications can work together to create a new application One way to enable DDE is by use of the function DDEAdvise ( )

1.1 DDEAdvise ( )
DDEAdvise( ) is used to create a notify link or an automatic link to an item name in a server application. When a notify link is created with DDEAdvise( ), the server application notifies that the item name has been modified. If an automatic link is created, the server application notifies that the item name has been modified and passes the new data to Visual C++. You can also use DDEAdvise( ) to turn off notification from the server. Before you can create a link, you must establish a channel to the server application with DDEInitiate( ).

1.2 DDEInitiate( )
DDEInitiate( ) establishes a DDE channel between Visual C+++ and a DDE server application. Once a channel is established, Visual C++ can request data from the server by referring to the channel in subsequent DDE functions. Visual C++ acts as the client, requesting data from the server application through the channel. If the channel is successfully established, DDEInitiate( ) returns the channel number. Channel numbers are non-negative, and the number of channels you can establish is limited only by your system resources. DDEInitiate( ) returns –1 if the channel cannot be established. If the server application isn't open, Visual C++ asks if you would like to open it. If you choose Yes, Visual C++ attempts to open the application. (You can use DDELastError( ) to determine why a channel cannot be established.) To avoid being asked whether you want to open the application, set the DDESetOption( ) SAFETY option. You can also use RUN with the /N option to start the application. A channel can be closed with DDETerminate( ).

1.3 DDETerminate( )
If the channel is successfully closed, DDETerminate( ) returns true (.T.). If the channel cannot be closed, DDETerminate( ) returns false (.F.). Be sure to close channels as soon as they are no longer needed to conserve system resources. All channels are automatically closed if you exit Visual C++ by choosing Exit from the File menu

1.4 DDERequest ( )
Another way to enable DDE is by using DDERequest. Before you can request data using DDERequest( ), you must establish a channel to the server application with DDEInitiate( ). If the request for data is successful, DDERequest( ) returns the data as a character string. If the request fails, DDERequest( ) returns an empty string and DDELastError( ) returns a nonzero value. If you include the asynchronous user-defined function cUDFName, DDERequest( ) returns a transaction number if successful, or –1 if an error occurs.

1.5 DDEExecute ( )
A third method to enable DDE is DDEExecute. The command sent with DDEExecute( ) must be understood by the application. Before you can execute the command, you must establish a channel to the server application with DDEInitiate( ). For example, Microsoft Excel has an extensive set of macro commands, including DDE commands that let you request data from Visual C++ from within Microsoft Excel. If you establish a channel to Excel, you can then use DDEExecute( ) to send macro commands to Excel from within Visual C++ If the receiving application successfully executes the command, DDEExecute( ) returns true (.T.). If the receiving application cannot successfully execute the command or if the channel number you include is not valid, DDEExecute( ) returns false (.F.). If the optional asynchronous user-defined function cUDFName is included, a transaction number is returned. If an error occurs, DDEExecute( ) returns –1.

1.6 DDELastError ( )
You can use DDELastError( ) to help determine the cause of an error when a DDE function doesn't execute successfully. DDELastError( ) returns 0 if the last DDE function executed successfully. It returns a nonzero value if the last DDE function was unsuccessful. The following table lists the error numbers and their descriptions (figure number 1).

Error number
Description

1
Service busy

2
Topic busy

3
Channel busy

4
No such service

5
No such topic

6
Bad channel

7
Insufficient memory

8
Acknowledge timeout

9
Request timeout

10
No DDEInitiate( )

11
Client attempted server transaction

12
Execute timeout

13
Bad parameter

14
Low memory

15
Memory error

16
Connect failure

17
Request failure

18
Poke timeout

19
Could not display message

20
Multiple synchronous transactions

21
Server died

22
Internal DDE error

23
Advise timeout

24
Invalid transaction identifier

25
Unknown


Figure 1: Error numbers

2. Explanation of the DDE functions
This paragraph will explain the different functions by giving an example of the use of the functions. For each function will the syntax, return value and the arguments be given.

2.1 DDEAdvise ( ) details Syntax

DDEAdvise(nChannelNumber, cItemName, cUDFName, nLinkType)

Return values

Logical

Arguments

nChannelNumber

Specifies the channel number.

cItemName

Specifies the item name. For example, Microsoft Excel uses row and column notation to refer to cells in a worksheet. The item name R1C1 designates the cell in the first row and first column of the worksheet.

cUDFName

Specifies the user-defined function that is executed when a notify link or an automatic link is established and the item cItemName is modified. When the user-defined function is executed, it is passed the following six parameters in the order given below:

2.2 DDEInitiate ( ) details Syntax

DDEInitiate(cServiceName, cTopicName)

Return values

Numeric

Arguments

cServiceName

Specifies the service name of the server application which, in most cases, is the name of the executable file without its extension. If you are establishing a channel to Microsoft Excel, cServiceName is Excel.

cTopicName

Specifies the topic name. The topic is application-specific and must be understood by the application. For example, one topic supplied by most DDE servers is the System topic. See the application documentation for the service and topic names supported by the application.

2.3 DDETerminate details Syntax

DDETerminate(nChannelNumber | cServiceName)

Return values

Logical

Arguments

nChannelNumber

Specifies the channel number to close.

cServiceName

Specifies the service name to close.

2.4 DDERequest ( ) details Syntax

DDERequest(nChannelNumber, cItemName [, cDataFormat [, cUDFName]])

Return values

Character

Arguments

nChannelNumber

Specifies the channel number of the server application.

cItemName

Specifies the item name. The item name is application-specific and must be understood by the application. For example, Microsoft Excel uses row and column notation to refer to cells in a worksheet. The item name R1C1 designates the cell in the first row and first column of the worksheet.

cDataFormat

Specifies a format for the data requested. The default format is CF_TEXT. In this format, fields are delimited with tabs and records are delimited with a carriage return and a line feed.

cUDFNameAllows an asynchronous data transfer. If you omit cUDFName, Visual C++ waits for the data from the server for the period specified with DDESetOption( ). If you specify the name of a user-defined function with cUDFName, Visual C++ continues program execution immediately after the request is made. When the data is available from the server application, the user-defined function specified with cUDFName is executed. The user-defined function is passed six parameters in this order: (see figure number 2)



Parameter
Contents

Channel Number
The channel number of the server application.

Action
XACTCOMPLETE (successful transaction). XACTFAIL (failed transaction).

Item
The item name; for example, R1C1 for a Microsoft Excel worksheet cell.

Data
The new data (REQUEST) or data passed (POKE or EXECUTED).

Format
The data format; for example, CF_TEXT.

Transaction Number
The transaction number returned by DDERequest( ).


Figure 2: cUDFName parameters

If the transaction fails, you can use DDELastError( ) to determine why it failed. When you include cUDFName, DDERequest( ) returns a transaction number equal to or greater than 0 if successful, or –1 if an error occurs.

2.5 DDEExecute ( ) details Syntax

DDEExecute(nChannelNumber, cCommand [, cUDFName])

Return values

Logical

Arguments

nChannelNumber

Specifies the channel number.

cCommand

Specifies the command you want to send to the other application. The format of the command is determined by the application you are sending it to. Consult the application's documentation for the correct syntax.

cUDFNameAllows asynchronous command execution requests. If you omit cUDFName, a client application waits for the period specified with DDESetOption( ). If you specify a user-defined function with cUDFName, client program execution continues immediately after the command execution request is made. When the server application finishes executing the command, the user-defined function you specify with cUDFName is executed. The user-defined function is passed six parameters in the order shown in the above table (see figure number 2).

2.6 DDELastError ( ) details Syntax

DDELastError( )

Return values

Numeric

Afterword
As you could read in this report, the use of DDE has several advantages and disadvantages. One of the main advantages is that the use of DDE results in applications using DDE for one-time data transfers and for ongoing exchanges and updating of data.

When an application is not responding, the function DDELastError will give an error number, of which a description can be found in the following table: (see figure number 1). One minor problem is that not al error descriptions are clear. For example: error number 13 / bad parameter. Usually no further description is given so you have to find out for yourself what to change.

[from here]


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 27th, 2006, 11:53 pm 
Quote:
Quote:
Dynamic Data Exchange (DDE) and NetDDE FAQ

Why it is not replaced by COM, how it works, network DDE, links to other sources of information

On this page you will find

Overviews and detailed articles about DDE and how it used
Download links for DDE tools, components and samples
Where to find DDE information on MSDN
Newsletter signup, tell you friends about this site
Related pages
Support for our DDServer and DDClient ActiveX controls
DDE in Visual Basic, Web Browsers, the Windows Shell, Excel and other applications

Questions and topics
DDE, COM and interprocess communication
What is DDE and why is it totally different from COM?
When is DDE more suitable?
When is COM more suitable?
COM and DDE data transfer speeds compared
Will Microsoft continue to support DDE?
Other forms of interprocess communication
Programming DDE
DDE mechanism overview
Network DDE (NetDDE)
Using the DDEML Application Programming Interface
A memory leak using DDEML
Why do I get the DDEML Reentrancy error?
Why does DDE sometimes change the case of the Service, Topic and Item names?
Service, Topic and Item names: number and length limits
Why does my Execute command data get corrupted?
Using DDEML in an MFC project
DDE performance
The missing data and unreliability problems

How can I improve the performance of my DDE client?

Applications hanging because of DDE

Causes of slow DDE communication

DDE use by particular applications
DDE and COM in Visual Basic
DDE and Visual Basic.NET
How the Windows Shell uses DDE
Cannot find the file.... (or one of its components)...
Web browser DDE
Controlling Excel with DDE
Why does Excel crash when I link a cell to a DDE server?
Obtaining data from Reuter's IDNDDE
DDE in different Windows versions
What are the 16/32-bit and Windows version issues?
Why does my program run differently on Windows 9x and NT?
Windows NT NetDDE security and other issues
Windows 2000 issues
DDE in NT Services
Working with Unicode
General
"The following System files have been replaced..." error message
How to get further information
Newsletter and referral form

Before you leave ---

Click this link to investigate our software. Most of it is free!


Report this post
Top
  
Reply with quote  
PostPosted: December 28th, 2006, 12:04 am 
Quote:
Dynamic Data Studio
A DDE monitoring, alias channel, record and playback system

Dynamic Data Studio is a general purpose Dynamic Data Exchange (DDE) tool which has features useful to both computer users and program developers. It comes with a universal DDE client program which you use to make a server send out its data. With these programs you can -

Connect otherwise incompatible DDE servers and clients.
Rename a DDE source by creating an Alias.
Record data from any DDE server.
Playback the recorded data, altering the speed if required, or playing back data at fixed intervals.
Create a file driven DDE server using your own data file.
Monitor DDE activity.
Find DDE servers and the topics they support, if they respond to "Wildconnect"
Dynamic Data Studio has four components, each with its own output and control window.

Alias Channels

DDSTUDIO acts as an intermediary, allowing otherwise incompatible programs to communicate. Service and topic names can be changed, allowing DDE sources with fixed names to supply data under any service and topic name desired. The server timeout characteristics are under user control so can be adjusted to suit the client program.

Data Recorder

DDSTUDIO writes data to a file so that it can be played back later, or analysed by other software. Timing information is kept, so it is possible to re-create exactly the data supplied by any DDE server. The recording can be in plain text, readable and editable by the user, even if it is binary data. The file format is described in the help file.

DDE data becomes available for recording when a server sends it in response to a request. You can use an existing client program to request the data, or the DDCLIENT.EXE program which comes with DDSTUDIO. Alternatively, you can write a Visual Basic program to act as a DDE client, using our DDClient ActiveX control.

Data Playback

DDSTUDIO is a DDE server playing back data from a file. The file may be one written by DDSTUDIO, or it may be one constructed by the user. DDSTUDIO can be made to mimic the data supply of almost any DDE server.

Monitoring DDE activity

DDSTUDIO monitors the DDE events specified by the user. This is a debugging feature primarily for program developers. It gives more readable and accurate information than the DDESPY program provided by Microsoft.

[Download] - [More..]


Report this post
Top
  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: HotkeyStick and 15 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group