A few years ago, I was able to convert a native PB emailer to FF, but it didn't handle attachments. I hit many snags as I tried to upgrade the code, so I decided to look for samples of code that already handled attachments.
I scoured the PB forum, this forum, and the Jose Roca forum for information. I found many examples and fragments, and tried (unsuccessfully) to get them to compile.
So then I figured: let me go straight to the routines that I know are in Jose's headers: CAfxSmtpMail.inc
That file looks like CLASS stuff that I've never used, so I'm a bit hesitant. I do see that the end of the file contains a native PBMAIN, so I'm converting that over to fit into my FF code.
I'm most curious about these lines:
cMail.AuthType = "AUTH LOGIN"
cMail.AuthUsername = "myusername@something.com"
cMail.AuthPassword = "mypassword"
In the simple code I used to use, I never had to enter any authorization info. Do I REALLY have to put my password into a string? REALLY? It would be visible if I examined the EXE in a hex editor, so that can't be right!
And I have no clue what AuthType is, or what values it would take. Where can I read about that?
I appreciate any and all help offered!!
Thanks,
-John
John,
I think the "AUTH CRAM-MD5" is more secure than the other two.
The AuthPassword can come from any "string source". In FF, for instance: cMail.AuthPassword = FF_Control_GetText(HWND_LogInFrm_PassWTb)
David
Thanks, David,
Please forgive my ignorance -- what other two?
I've been trying to get any intelligent info from MSDN and have nothing.
But I don't understand why my old code sends email, but this new class thing fails to connect! Since that's an early test in the SendMail method, I'm inclined to think that one of the new properties or attributes is set wrong, that wasn't being set in the old code... but I can't tell which.
Can you point me to any documentation that I could read/study?
Thanks,
-John
Sorry John,
I've been away for over a day.
Quotewhat other two?
There are three AuthType's documented in Jose's "Windows API Wrappers Reference".
AUTH LOGIN
AUTH PLAIN
AUTH CRAM-MD5
Here is a site that had some detailed information on the three: http://www.samlogic.net/articles/smtp-commands-reference-auth.htm (http://www.samlogic.net/articles/smtp-commands-reference-auth.htm)
QuoteI've been trying to get any intelligent info from MSDN and have nothing.
It has to do with SMTP. SMTP is a internet mail protocol, you can implement it in any language and access it with any language. But MS didn't create it, so they wouldn't document it.
QuoteCan you point me to any documentation that I could read/study?
The following example code is from Jose's help file mentioned above:
' ===========================================================================================
' Usage example.
' ===========================================================================================
#COMPILE EXE
#INCLUDE "CAfxSmtpMail.inc"
FUNCTION PBMAIN () AS LONG
' NOTES:
' The 'SendTo', 'CC', 'BCC' fields can be a one address or a
' semicolon(;) or comma(,) deliminated list of multiple addresses.
' SMTP only allows 100 recipients max at a time (per rfc821), therefore
' for large mailings you should break it into multiple emails.
' Multiple attachments can be sent by simply separating the file
' names with a semicolon or comma.
' You can use 'Plain' text emails or 'HTML' emails, or 'Both'.
' When sending "Both", the email client application will use whichever
' one it can render based on the user's settings.
' Default values for the following that are already set by the
' class (constructor). Change them here if you want a different value.
' e.g.
' cMail.ServerTimeOut = 60000 ' milliseconds ' default is 60000
' cMail.LocalHost = "MySuperComputer" ' default is localhost
' cMail.CharSet = "us-ascii" ' default is iso-8859-1
' cMail.MessageStyle = "both" ' default is Plain
LOCAL cMail AS AfxSmtpMail
cMail = CLASS "CAfxSmtpMail"
cMail.SMTPServer = "mysmtpxxxx.com"
cMail.SendFrom = "support@planetsquires.com"
cMail.SendTo = "support@planetsquires.com"
cMail.CC = "support@planetsquires.com"
cMail.BCC = "planetsquires@gmail.com"
cMail.ReplyTo = "support@planetsquires.com"
cMail.Subject = "test subject"
cMail.EnableAuth = %TRUE
cMail.AuthType = "AUTH LOGIN"
cMail.AuthUsername = "myusername@something.com"
cMail.AuthPassword = "mypassword"
cMail.MessageStyle = "both"
cMail.Attachments = "" ' eg. "myfilename.zip"
' // HTML text email
cMail.HTMLMessage = "<html>" & $CRLF & _
"<body>" & $CRLF & _
"<center><b>This Is a test!</b></center>" & $CRLF & _
"</body>" & $CRLF & _
"</html>" & $CRLF
' // Send the actual email and deal with any error/message response.
IF ISFALSE cMail.SendMail THEN
MSGBOX "Error sending email: " & cMail.Response
ELSE
MSGBOX "Email(s) sent okay."
END IF
END FUNCTION
' ===========================================================================================
I had assumed that you had already seen this and is where you got your example code from. It appears to be a complete example but I have not tested it. I would start there. You might also check Jose's site. He is really good about posting examples of most things his wrappers cover. Sometimes it is challenging to find them though. You can post questions there also (you need to have a login and that means sending a request to Jose himself).
Another avenue would be to ask Paul (Squires of course). Jose's mail class is heavily based off the work of Paul (posted on PB's website). Paul's code brought good comments from other forum members who tried it.
BTW, I tried Paul's code from PB.com and Jose's both. They didn't work for me either. I thought, since I use GMail, that it would be as simple as setting the SMTPPort property because GMail uses a non-standard port. It was a step in the right direction because it changed the error message from "Error sending email: Cannot connect to E-mail server: SMTP.gmail.com" to "Error sending email:". Normally, for GMail, you also have to tell your email client to use SSL, but I couldn't find any settings for that. I didn't attempt to trouble shoot it any further.
David
Grab some source code I posted on the PB forums in April 2010. It's doesn't do secure sockets and it was one of my early attempts so be nice to me.
http://www.powerbasic.com/support/pbforums/showthread.php?t=43403
(http://www.powerbasic.com/support/pbforums/showthread.php?t=43403)
Rick
As stated in the header of CAfxSmtpMail.inc:
Quote
' Based on code posted by Paul Squires at:
' http://www.powerbasic.com/support/pbforums/showthread.php?t=41961&highlight=tcp
' with minimal changes by Jose Roca (also changed the logic of the return value of the
' SendMail method)
I only did some small changes to avoid possible conflicts with my headers.
Jose, I saw your acknowledgment in the header. I should have quoted it like you did. It was not my intention to imply that it was not properly acknowledged. If it did come across that way, please accept my profuse apology.
Rick, I wish I could say it is definitely SSL that is causing my problem with GMail. But I am far from being able to claim that with certainty. I'm just stating that it's the only thing I could see right off that might be a problem. As I stated, when setting up MS Outlook (or other email clients), I have to make sure SSL is checked or it just wont work. I will give yours a try. Thanks for the link.
John, I appeared to have contradicted myself in my last post about trying the code referenced. I hadn't when I wrote that, but I had some things to do, and didn't finish the post until the next day. I had tested the class before I finished the post as documented in the "BTW" at the bottom.
All, again I stopped here and tried some other things. I tried a yahoo email account of mine. Just as GMail, it uses SSL and outgoing port 465. It failed the same as GMail. I then tried my wife's email through our local ISP. It doesn't require SSL and uses the default port of 25. It works. I know others at PB's forums had luck with setting the port with the SMTPPort method, so I am still thinking that it is the SSL requirement that is the problem. Also, BTW, the attachment came through fine!
David
This works with gmail:
#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "windows.inc"
#INCLUDE ONCE "cdosys.inc"
#INCLUDE ONCE "ado.inc"
#INCLUDE ONCE "ole2utils.inc"
FUNCTION PBMAIN () AS LONG
DIM iMsg AS CDO_IMessage
DIM iConf AS CDO_IConfiguration
DIM Flds AS ADOFields
iMsg = NEWCOM "CDO.Message"
iConf = NEWCOM "CDO.Configuration"
TRY
Flds = iConf.Fields
DIM schema AS STRING
schema = "http://schemas.microsoft.com/cdo/configuration/"
Flds.Item(schema & "sendusing").Value = 2
Flds.Item(schema & "smtpserver").Value = "smtp.gmail.com"
Flds.Item(schema & "smtpserverport").Value = 465
Flds.Item(schema & "smtpauthenticate").Value = 1
Flds.Item(schema & "sendusername").Value = "mymail@gmail.com"
Flds.Item(schema & "sendpassword").Value = "mypassword"
Flds.Item(schema & "smtpusessl").Value = 1
Flds.Update
iMsg.To = "your first email address"
iMsg.From = "your 2nd email address"
iMsg.Subject = "Test send with gmail account"
iMsg.HTMLBody = "Test send with gmail account"
iMsg.Sender = "your name"
iMsg.Organization = "Jose Roca"
iMsg.ReplyTo = "your 2nd email address"
iMsg.Configuration = iConf
iMsg.Send
? "Message sent successfully"
CATCH
? OleGetErrorInfo(OBJRESULT)
END TRY
END FUNCTION
Thanks for the help, guys!
Richard,
Your code was among many SMTP threads I looked at over the past week, and I downloaded the ZIP, but haven't started to experiment with it yet. I promise I will, and I promise I will be nice, too! Thanks!
David,
Thanks for letting me know that SMTP is not MS, so I'll search farther across the net for more info...
Yes, I did use the example code at the end of Jose's CAfxSmtpMail.inc. But I hadn't examined the file enough to recognize the MD5 type you mentioned. So between messages, I went back and examined CAfxSmtpMail.inc more closely, found the 3 types, and have been experimenting with them (and lots of other settings...)
Jose,
I saw Paul's code too, but I stopped trying to get into it when I saw your note that your code is based on his. My first presumption was that your code covered his completely. Now, I wonder if that's an incorrect assumption on my part. Because I'm only programming occasionally, I find it really hard to decipher the threads on all the different forums where there are "code mazes" and ambiguities. I apologize, I'm one that has to start with a complete example; it's really hard for me to keep up with the professionals who can grab snippets and fragments and produce a grand masterpiece!
If you could just let me know if there is more to Paul's code than your code covers that I should be trying to incorporate, I'll go back and re-examine it. I am more than willing to read and experiment and learn, so I'm appreciative if you can just tell me where I should be looking.
I see a newer post with GMAIL settings. I will experiment with them, too.
ALL:
I think I may also be experiencing a firewall problem at home:
- I had no success all weekend trying to send emails from my laptop using code based on CAfxSmtpMail.inc.
- This morning at work, code that I had compiled at home over the weekend DID succeed in getting a message out! I had made no changes and had not re-compiled...
SO, I will continue experimenting and reporting back. I thank you all for your ideas and suggestions!
-John
P.S. I have 3 email accounts, and I generally test each EXE against:
- Comcast.net
- gmail.com
- businesss.com
Now, I'm thinking there are very different settings for each that I have to re-organize.
Does it matter that the LAN at work is running Outlook? (I have never been able to send a message through that account.)
Quote from: Jose Roca on April 29, 2014, 02:50:20 PM
This works with gmail:
#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "windows.inc"
#INCLUDE ONCE "cdosys.inc"
#INCLUDE ONCE "ado.inc"
#INCLUDE ONCE "ole2utils.inc"
FUNCTION PBMAIN () AS LONG
DIM iMsg AS CDO_IMessage
DIM iConf AS CDO_IConfiguration
DIM Flds AS ADOFields
iMsg = NEWCOM "CDO.Message"
iConf = NEWCOM "CDO.Configuration"
TRY
Flds = iConf.Fields
DIM schema AS STRING
schema = "http://schemas.microsoft.com/cdo/configuration/"
Flds.Item(schema & "sendusing").Value = 2
Flds.Item(schema & "smtpserver").Value = "smtp.gmail.com"
Flds.Item(schema & "smtpserverport").Value = 465
Flds.Item(schema & "smtpauthenticate").Value = 1
Flds.Item(schema & "sendusername").Value = "mymail@gmail.com"
Flds.Item(schema & "sendpassword").Value = "mypassword"
Flds.Item(schema & "smtpusessl").Value = 1
Flds.Update
iMsg.To = "your first email address"
iMsg.From = "your 2nd email address"
iMsg.Subject = "Test send with gmail account"
iMsg.HTMLBody = "Test send with gmail account"
iMsg.Sender = "your name"
iMsg.Organization = "Jose Roca"
iMsg.ReplyTo = "your 2nd email address"
iMsg.Configuration = iConf
iMsg.Send
? "Message sent successfully"
CATCH
? OleGetErrorInfo(OBJRESULT)
END TRY
END FUNCTION
Jose,
Am I understanding correctly that CAfxSmtpMail.inc does not handle GMAIL accounts? That in order to handle GMAIL, I must use those additional include files, and this ADO/schema?
Not that it would be difficult to incorporate, but just wondering because it's not mentioned anywhere else that this is the proper/only approach...
Thanks,
-John
David,
Quotea site that had some detailed information on the three: http://www.samlogic.net/articles/smtp-commands-reference-auth.htm
This is great! Thank you for this link!!!
OK, I'm off and reading for awhile!
-John
>Am I understanding correctly that CAfxSmtpMail.inc does not handle GMAIL accounts?
> That in order to handle GMAIL, I must use those additional include files, and this ADO/schema?
That class from Paul uses obsolete PowerBASIC's TCP statements. I never use them. I just incorporated his class into my headers because so many people wants to use no matter what except COM (Component Object Model), specially if it uses PB built-in statements.
The requirements have changed, but PB's TCP statements don't. M$ added a configuration schema for security reasons.
The following example, sends an email with an attachment using an smtp server.
' ########################################################################################
' CDO - Sending a text email with an attached file.
' ########################################################################################
' SED_PBWIN - Use the PBWin compiler
#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "CDOSYS.INC"
#INCLUDE ONCE "OLE2UTILS.INC"
' ========================================================================================
' Main
' ========================================================================================
FUNCTION PBMAIN () AS LONG
LOCAL pMessage AS CDO_IMessage ' // CDOSYS - IMessage interface
LOCAL iConf AS CDO_IConfiguration
LOCAL Flds AS ADOFields
' // Create an instance of the CDO Message interface
pMessage = NEWCOM("CDO.Message")
IF ISNOTHING(pMessage) THEN EXIT FUNCTION
iConf = NEWCOM "CDO.Configuration"
IF ISNOTHING(iConf) THEN EXIT FUNCTION
TRY
' // Configuration
Flds = iConf.Fields
LOCAL schema AS STRING
schema = "http://schemas.microsoft.com/cdo/configuration/"
Flds.Item(schema & "sendusing").Value = %CdoSendUsingPort
Flds.Item(schema & "smtpserver").Value = "<your smtp server name>" ' --> change me
Flds.Item(schema & "smtpserverport").Value = 25
Flds.Item(schema & "smtpauthenticate").Value = 1
Flds.Item(schema & "sendusername").Value = <"your email address"> ' --> change me
Flds.Item(schema & "sendpassword").Value = "<your password>" ' --> change me
Flds.Item(schema & "smtpusessl").Value = 1
Flds.Update
' // Recipient name --> change as needed
pMessage.To = "<recipient address>" ' --> change me
' // Sender name --> change as needed
pMessage.From = "<your email address>" ' --> change me
' // Subject --> change as needed
pMessage.Subject = "This is a sample subject"
' // Text body --> change as needed
pMessage.TextBody = "This is a sample message text"
' // Add the attachment (use absolute paths).
' // Note By repeating the call you can attach more than one file.
pMessage.AddAttachment "<absolute path of the attachement>" ' --> change me
' // Set the configuration
pMessage.Configuration = iConf
' // Send the message
pMessage.Send
MSGBOX "Message sent"
CATCH
' // Display the error message
OleShowErrorInfo OBJRESULT
FINALLY
' // Release the Message object
pMessage = NOTHING
END TRY
END FUNCTION
' ========================================================================================
Warning: The web is full of obsolete CDO scripts that don't use the configuration schema and won't work with Windows 7.
MSDN information about "http://schemas.microsoft.com/cdo/configuration/"
Link: http://msdn.microsoft.com/en-us/library/ms526318%28v=exchg.10%29.aspx
PS: Don't take the above example literally. It all depends of your configuration. Fields like "smtpauthenticate" must be filled if your server requires authentication; otherwise, don't.
An added value of using CDO is that if there is an error, my function OleShowErrorInfo OBJRESULT will display an, hopefully, meaningful message.
Quote
Jose,
Am I understanding correctly that CAfxSmtpMail.inc does not handle GMAIL accounts? That in order to handle GMAIL, I must use those additional include files, and this ADO/schema?
Not that it would be difficult to incorporate, but just wondering because it's not mentioned anywhere else that this is the proper/only approach...
I don't know if there are other ways (probably, yes), but this is the one that works for me.
Thanks, Jose!
After a bit of tweaking, I was able to send a message with attachment from a POP3 account at the office!!! Hooray!!!
I'll see what happens tonight at home...
Next, I'm going to try sending via GMAIL account and then from an Exchange account...
I'll be back!
Thanks again,
-John
OK, I'm making progress. Once I have something solid, I'll clean it up and post it.
But in the meantime, I have an observation. The posted code shows:
Flds.Item(schema & "sendpassword").Value = "mypassword"
Instead, I'm suggesting that as a minimum, the password be coded like this:
pw = Chr$(112,97,115,115,119,111,114,100) ' password
? pw 'comment this out after development tests...
Flds.Item(schema & "sendpassword").Value = pw
...because the PB compiler will embed "mypassword" as a literal, and you can see it "plain as day" in the .EXE when you view it in a hex editor/file viewer.
Instead, the PB compiler interprets the CHR$() command sometime "on the fly", so it's never embedded in the .EXE. Yet you can still verify it easily, as the msgbox command shows.
I know there are better ways to do this, but this method works fine during development & initial checking...
-John
John,
You could also read an encrypted password from a file and decrypt it. But your way would be just fine. I now see that you are just talking about using the password embedded in the program for development only. I didn't realize that when you asked about it before. I am comfortable just using the literal for testing as others don't have access to it my test programs and my password is changed often enough.
Thanks for the feedback, David, I just wanted developers to recognize a possible weakness in the published code that they could address easily...
UPDATE:
From home, I was able to determine settings that allowed me to successfully send an email with attachment from my comcast and my gmail accounts.
Unfortunately, I was not able to determine the proper settings to send through my MS Exchange work account. What's strange is that I can do it through Thunderbird, but not through my own program. And I tried every combination of settings I could.
Well, I can see I have a lot more reading to do over the weekend...
-John
For sending emails using Exchange, see:
http://msdn.microsoft.com/en-us/library/aa494235%28v=exchg.80%29.aspx
Quote from: Jose Roca on May 01, 2014, 11:43:36 AM
For sending emails using Exchange, see:
http://msdn.microsoft.com/en-us/library/aa494235%28v=exchg.80%29.aspx
Where do you FIND these things?!?
You are truly amazing!!
I'm reading and testing it now!
Thanks!!!!!
-John
OK, now here's where my ignorance really shines brightly!
I'm converting the example VBS code, and there's a statement up front that I cannot resolve:
Dim Conn As ADODB.Connection
Here's how I try to figure it out:
- search all the JR header files for "ADODB.Connection"
- read and examine all matches and the surrounding lines/sections of text and code.
- try to find "ADODB.Connection" at MSDN.
Before JR headers, I could usually dope it out. But the JR headers are in a different kind of notation, and I don't know how to read it.
I guess that sums up my biggest problem in recent years - that since the move to COM, PB files are written in a new language, and I don't know where to learn all the details.
I can read the files and figure out some of the things, but the deeper significance of a lot of the notation, I just cannot follow, let alone comprehend!
Attributes, properties, methods are pretty self-explanatory. It's the way that various groups of them relate to others that isn't easy to grasp.
If I wanted to get proficient in understanding a whole file (not just fragments here and there), where could I go to get simple explanations? I need to understand how the whole INC is structured, what it contains, all the sections, and how they relate to each other...
Did I just hijack my own thread? Maybe I should start another just for this topic...
[ADDED: OK, I just did: http://www.planetsquires.com/protect/forum/index.php?topic=3542.new#new]
Let's keep this thread focused on CDO email code...
-John
OK, following the example Jose gave me in the other thread, I tried the same pattern of conversion for two other objects:
' Dim Msg As CDO.Message
Local Msg As CDOMessage
' Dim Config As CDO.Configuration
Local Config As CDOConfiguration
' Create message and configuration objects.
' Set Msg = CreateObject("CDO.Message")
Msg = NewCom "CDO.Message"
' Set Config = CreateObject("CDO.Configuration")
Config = NewCom "CDO.Configuration"
Of course, I first searched the headers for "CDO.Message" to see where it was defined, and found it in CDOSys.inc.
So I examined it and related files, and concluded that the file I needed to #INCLUDE is "CDOSYS.inc"
But now PBWIN is complaining that it can't find a TYPE definition for "CDOMessage".
Here's where I get confused as to how to resolve this: I cannot find a TYPE definition for "CDOMessage" in any of the header files.
I do see in "cdoexstr.inc" that there's a section of values in a section entitled "CdoContentTypeValues", but I've never seen strings that start with two dollar-signs ($$), and I don't know what that signifies.
In that list are entries such as
$$cdoMessageExternalBody = "message/external-body"$$
...but there are similar items sprinkled throughout the file. It's not clear to me why they're all spread out like that.
I have no doubt that there is documentation for such things, so I search MSDN for it and find:
Quotehttp://msdn.microsoft.com/en-us/library/ms527255(v=EXCHG.10).aspx
I can't understand this page, so I go up a level and start examining what's there. I notice that there's an entry for "CDOConfiguration", so I am tempted to go there. But I also notice that there's NO entry for CDOMessage...
So I go up another level, and now I can see the broad scope, and I'm lost...
That's when I come to the forum and ask for help, and my question comes out like this:
"Why is PBWIN complaining about this, when I've included the only file that looks like it deals with this object?"
Local Msg As CDOMessageOK, enough of my sob story... Can anyone see an avenue that I haven't explored? or a method for tracking down these kinds of things?
I appreciate being directed to something I can read and learn from!
Thanks,
-John
VB is using Automation and my example low-level COM. Verfy different animals. In my headers, the interface is called CDO_IMessage.
You can't translate examples from other languages literally. You can read them to get an idea of what you have to do and then adapt it to the syntax of your tool.
Yes, I do know that translation is complicated and takes effort; I actually enjoy doing the work.
I just need to know how to distinguish one thing from another!
Thanks for the guidance, I'll keep at it.
-John
Jose took care of most of this in your other thread, but in regards to this:
$$cdoMessageExternalBody = "message/external-body"$$It's a PB string constant statement. First "$$" means its a unicode constant, named cdoMessageExternalBody. The string being assigning to the Equate is "message/external-body" and the second "$$" says this is a unicode string. For more info, type "string equates" into the index tab of the PB help file.
QuoteBut now PBWIN is complaining that it can't find a TYPE definition for "CDOMessage".
It used to be that the only variable type besides built-in types (integer, string, dword, etc.) were UDT's. PB's message should probably say "undefinded type or interface" now. If you search the CDO includes for interface definitions you will find CDO_IMessage and CDO_IConfiguration. (added: looks like he beat me to it)
Sounds like... rather, reads like you are getting frustrated. Been there. You are just in an unfamiliar area. COM, PB classes (the differences between them), unicode, etc. It gets better, and you will start to pick it up soon. I'm only a little ahead of you in these area's myself.
David
It happens that the name of an interface is irrelevant. You could rename it as John_Montenigro_Message and it will work just changing DIM pIMessage AS CDO_IMessage to DIM pIMessage AS John_Montenigro_Message. What counts is the unique GUID that identifies it, i.e. GUID$("{CD000020-8B95-11D1-82DB-00C04FB1625D}") in the case of that CDO interface. By convention, low-level COM interfaces are prefixed with an "I" of interface, but isn't mandatory, just convenient. So, in CDO, there is an Automation object called Message and a low-level interface called IMessage. But it happens that in other components there are also objects and interfaces with that common name, so to avoid conflicts, I have added "CDO_" as a prefix.
To complicate matters, nobody looks at the C++ examples, as they should, because they use a weird syntax, but at the VB examples, that use the Automation Message object instead of the IMessage interface.
Jose,
First off, I am sure you know what regular expressions are and how to use them. The information below is meant to help other people find information quickly if they don't already have a system of their own.
QuoteIt happens that the name of an interface is irrelevant.
But you have kept it close enough to relevant. I use baregrep to search your include files regularly (no pun intended). It's a free utility that searches files using regular expressions. I can usually find what I'm looking for with a couple educated guesses in a minute or two. Even if I don't know the Interface name, I can still search for all Interfaces and inspect them manually.
From the ReadMe.txt that came with my current version of your headers:
QuoteThis version has been updated using the SDK for Windows 7.1.
In less than ten seconds baregrep, using this expression "^\s*interface" (^ = Newline, \s* = zero or more whitespace), finds 7,831 interfaces in 517 of 1,184 include files searched. That is using a "*.inc" wildcard on the file names. Your file naming convention is really handy. If I change from wildcards to regular expression for file filtering in baregrep, and use the expression "cdo" (find "cdo" anywhere in a filename similar to "*cdo*" using wildcards), then the list is reduced to 39 interfaces in 2 files of 4 searched.
7,831 interfaces!!! That is why all of us will always need to search the include files. Could you imagine how long it would take one person (Jose) to document all those? It's not really possible.
David
Quote... low-level COM interfaces are prefixed with an "I" of interface, but isn't mandatory, just convenient. So, in CDO, there is an Automation object called Message and a low-level interface called IMessage. But it happens that in other components there are also objects and interfaces with that common name, so to avoid conflicts, I have added "CDO_" as a prefix.
To complicate matters, nobody looks at the C++ examples, as they should, because they use a weird syntax, but at the VB examples, that use the Automation Message object instead of the IMessage interface.
I know that PowerBASIC isn't used by a large enough population on the planet to demand this, but I would've loved a "PowerBASIC COM Programming" book. Just sayin'.
David, thanks for your encouragement - much appreciated! Also, your explanation of the $$... I didn't realize that one was a compiler directive and the other a type indicator! I thought I was looking at a set of begin/end delimiters! Doh!
Jose, Thanks for that explanation!!!! THAT is the kind of information that really helps!!! And yes, I apologize, I have not learned to read the C++ examples, and I do reflexively go to the VB examples that look more familiar. I am more than happy to work with any such explanations and guidance you are able to provide! Thanks!
David (again), you have echoed my process, too, of using a search tool to narrow down the locations that *might* be relevant. The problem is to figure out which are and which aren't! I also examine the "tree" or "chain" of "#INCLUDE"s...
Jim, I agree - it would be great to have a comprehensive explanation of "COM with a PB flavor"... Maybe I should start keeping notes on what I'm learning, although I'm not doing it fast enough to benefit anyone else, I'm sure.
OK, so here's another question that would "open more doors" of understanding:
Jose, you say the example is VB Automation, and I will search over the weekend to read and understand that more.
But for now, my next question would relate to this code line (from that MS example you provided a link to):
' Set the sendusing field to 'cdoSendUsingExchange'.
Config("http://schemas.microsoft.com/cdo/configuration/sendusing") = 3
I'm not asking you to translate it for me, but to tell me where I might learn how to read and understand this, so that I can be able to translate it for myself.
Thanks for all the help! This is indeed a most supportive community!
-John
I just went back to the MS examples that Jose pointed me to at this link:
http://msdn.microsoft.com/en-us/library/aa494235(v=exchg.80).aspx (http://msdn.microsoft.com/en-us/library/aa494235(v=exchg.80).aspx)
and I took time to look at the C++ code...
What I mainly noticed is this: that I have NO IDEA how to understand what's going on in the C++ code...
But interestingly, when I went back to the VB code, I realized that I THOUGHT I had some idea of what was going on, because the syntax looks familiar.
But in reality, I also have NO IDEA just from looking at it, what is REALLY going on in that code!
So I have been deluding myself in thinking that I could translate the VB code fairly directly... It would appear that I have to read a LOT more about VB Automation in order to be able to do such a translation.
BUT!!! I would not have known that I need to learn "VB Automation", if Jose had not identified it.
Little by little...I'll get there...eventually!
-John
> ' Set the sendusing field to 'cdoSendUsingExchange'.
> Config("http://schemas.microsoft.com/cdo/configuration/sendusing") = 3
If you look at the examples that I have posted, for example:
Flds = iConf.Fields
DIM schema AS STRING
schema = "http://schemas.microsoft.com/cdo/configuration/"
Flds.Item(schema & "sendusing").Value = 2
Flds.Item(schema & "smtpserver").Value = "smtp.gmail.com"
Flds.Item(schema & "smtpserverport").Value = 465
Flds.Item(schema & "smtpauthenticate").Value = 1
Flds.Item(schema & "sendusername").Value = "mymail@gmail.com"
Flds.Item(schema & "sendpassword").Value = "mypassword"
Flds.Item(schema & "smtpusessl").Value = 1
Flds.Update
you can deduct that you have to use:
Flds.Item("http://schemas.microsoft.com/cdo/configuration/sendusing").Value = 3
And this exemplifies one of the main problems of trying to translate VB code. VB uses all kinds of tricks and shortcuts, such as the Item and Value properties being defaults that you can omit and the compiler adds it for you. If you don't know that, how are you going to guess that to translate it you have to add the missing Item and Value properties?
No wonder millions of VB programmers have been using COM during many years and most haven't learnerd anything in the process.
The use of the compound syntax also hides clarity. The steps are the following:
DIM pConfig AS CDO_IConfiguration
pConfig = NEWCOM "CDO.Configuration"
DIM pFields AS ADOFields
pFields = pConfig.Fields
DIM pField AS AdoField
pField = pFields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing")
pField.Value = 3
This code creates a CDO Configuration object:
DIM pConfig AS CDO_IConfiguration
pConfig = NEWCOM "CDO.Configuration"
This one gets a reference to the ADO fields collection of the CDO Configuration object:
DIM pFields AS ADOFields
pFields = pConfig.Fields
This one gets a reference to the wanted field in the fields collection:
DIM pField AS AdoField
pField = pFields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing")
An this one sets the wanted value to that field:
pField.Value = 3
Doing it step by step, it is clear what it does.
Using:
Config("http://schemas.microsoft.com/cdo/configuration/sendusing") = 3
it is as clear as mud.
Compound syntax and defaut values save typing at the cost of clarity.
The C++ example is also difficult to understand if you're a beginner in COM programming, but at least it shows the needed steps:
// Get the sendusing field.
FieldsPtr Flds = Config->GetFields();
FieldPtr Fld1 = Flds->GetItem("http://schemas.microsoft.com/cdo/configuration/sendusing");
// Set the sendusing field to cdoSendUsingExchange.
Fld1->Value = "3";
FieldsPtr Flds = Config->GetFields();
is equivalent to
DIM pFields AS ADOFields
pFields = pConfig.Fields
in the code that I have posted
FieldPtr Fld1 = Flds->GetItem("http://schemas.microsoft.com/cdo/configuration/sendusing");
is equivalent to
DIM pField AS AdoField
pField = pFields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing")
and
// Set the sendusing field to cdoSendUsingExchange.
Fld1->Value = "3";
is equivalent to
pField.Value = 3
Time for a shameless plug. If you want to avoid all of the "fun" with CDO and want a simple, API oriented solution, try SocketTools. There's a thread (http://www.powerbasic.com/support/pbforums/showthread.php?t=50905) I had posted over on the PowerBASIC forums that answers a similar question a while back. It handles all of the SSL/TLS stuff, message composition, etc. and three's no dependency on CDO, COM and so on. Here's an updated version of the example code:
#COMPILE EXE
#DIM ALL
#INCLUDE "CSTOOLS8.INC"
FUNCTION PBMAIN () AS LONG
Dim mailServer As SMTPSERVER
Dim mailMessage As SMTPMESSAGE
Dim strHostName As String
Dim strUserName As String
Dim strPassword As String
Dim strSender As String
Dim strRecipient As String
Dim strSubject As String
Dim strMessage As String
Dim strAttachment As String
Dim nResult As Long
SmtpInitialize($CSTOOLS8_LICENSE_KEY)
strHostName = "smtp.gmail.com"
strUserName = "username@gmail.com"
strPassword = "secret"
' Configure the server options and user credentials for GMail
mailServer.lpszHostName = StrPtr(strHostName)
mailServer.nHostPort = %SMTP_PORT_SUBMIT
mailServer.lpszUserName = StrPtr(strUserName)
mailServer.lpszPassword = StrPtr(strPassword)
mailServer.dwOptions = %SMTP_OPTION_SECURE
strSender = "User Name <username@gmail.com>"
strRecipient = "Robert Smith <rsmith@company.com>"
strSubject = "This is a test message from PowerBasic"
strMessage = "This is a test, this is only a test"
strAttachment = "C:\Users\UserName\Documents\SomeFile.zip"
' Compose the email message with a file attachment
mailMessage.lpszFrom = StrPtr(strSender)
mailMessage.lpszTo = StrPtr(strRecipient)
mailMessage.lpszSubject = StrPtr(strSubject)
mailMessage.lpszText = StrPtr(strMessage)
mailMessage.lpszAttach = StrPtr(strAttachment)
' Submit the message to GMail for delivery
nResult = SmtpSubmitMessage(mailServer, mailMessage, 0, 0)
If nResult = %SMTP_ERROR Then
? "Unable to send message to " + strRecipient
Else
? "Message was sent to " + strRecipient
End If
END FUNCTION