I search many times in Google, SO, and I can't find anything about working with attachment via delphi, so I decide to write this question.
I have a table in .accdb database called Files with those fields:
IDFile PK AutoIncField,
FileName WideStringField,
FilesAttached WideMemoFiled.
How can I save/load files to/from attachment fields using delphi?
Attach files and graphics to the records in your database
The problem here, in delphi the datatype of FilesAttached is TWideMemoField,
when I write ShowMessage(FDTable1FilesAttached.Value); it give just the name of the attachment.
I don't know how to Insert/save files to/from that field using delphi.
It didn't seem that hard to find VBA/C# examples of working with .accdb Attachment fields which should translate fairly easily into Delphi. However, it turned out to be more difficult than I imagined to find something that a) hadn't misunderstood what Attachment fields actually are and b) actually works. Skip to the update section below.
For example, googling
accdb create attachment in vba
gives numerous hits including this one
http://sourcedaddy.com/ms-access/working-with-attachment-fields.html
which you might try as a starting point. It uses MS DAO objects, and includes straightforward code for storing files to Attachment fields and for accessing them. You would need to create a Delphi wrapper unit for the DAO type library, if you don't already have one, using the IDE's Import Type Library
If you would prefer something ADO-based, you might take a look at
https://www.codeproject.com/Questions/843001/Handling-fields-of-Attachment-type-in-MS-Access-us
Update See the function OpenFirstAttachmentAsTempFile in the post by "aspen" (date = 4/11/2012 07:18 am) in this thread
https://access-programmers.co.uk/forums/showthread.php?t=224112&page=2
which shows an apparently successful attempt to extract a file from an attachment field (the thread also contains several other attempts at coding this function).
Note in particular this line
Set rstChild = rstCurrent.Fields(strFieldName).Value ' the .Value for a complex field returns the underlying recordset
which implies that the Value of the attachment field can return a recordset which contains the attached file(s).
Presumably, importing a recent version of the DAO type library into Delphi would allow
a Delphi app to do the same thing, and then one could reverse-engineer the rstChild recordset to see how to populate this field in code. I haven't done that yet, though.
Related
I am using late binding to connect to MS Outlook and to open and extract info from outlook emails using the MailItemobject.
I am trying to save attachments to file. This is fairly straightforward in most instances using the Attachment object and its SaveAsFile method.
However, it does not work where the Attachment Type is olOLE. I believe this only relates to documents embedded in emails created in RTF format (hopefully few and far between nowadays).
Via the Attachment object it is possible to access MAPI properties not exposed by the object model using its PropertyAccessor.
The relevant MAPI property for OLE objects is PR_ATTACH_DATA_OBJ, which can be accessed using the PropertyInspector as in the following example:
Function SaveOLEAttachmentToFile(Attachment:Variant; fn:String): boolean;
var
OPA, PropName : Variant;
begin
Result := false;
OPA := Attachment.PropertyAccessor;
PropName := 'http://schemas.microsoft.com/mapi/proptag/0x3701000D '; //PR_ATTACH_DATA_OBJ
?????? := OPA.GetProperty(PropName);
end;
I am stuck at this point as I can't know work out what Delphi type to save the data to and I am not even sure this is possible having read the MS documentation (Click here). PR_ATTACH_DATA_OBJ returns a PT_OBJECT. I am hoping that this object contains the raw data which (if I could work out how to access it in Delphi) can be simply saved to a file. However, the documentation suggests it may not be that simple and it's possible I may have to work with Extended MAPI. I have spent a few hours researching the latter with no concrete result other than a headache. I appreciate I could use Redemption, but I don't want to use a third party tool for something which is fairly minor in the round.
If anyone can advise as to a data type to hold the PT_OBJECT from which it can be simply saved to file that would be my route one.
Failing that, if I need to dig deeper into MAPI, I would be grateful if anyone could clarify/amplify my research so far. I have the following steps:
Initialize MAPI.
Get an IMAPIPROP interface. I think I should be getting the interface from my Attachment object and the following seems to work (ie compiles and executes without problems): MAPIPROP := IUnknown(Attachment.MAPIObject) as IMAPIPROP. Failing that, I would have to cast the parent MailItem to IMAPIPROP interface and work my way down to the attachment via GetAttachmentTable.
Load the attachment data into an IStream: if Succeeded(MAPIPROP.OpenProperty(PR_ATTACH_DATA_OBJ, IStream, STGM_READ, 0, IUnknown(SourceStream)) then
Extract the data from the IStream and save to file
I have failed to get as far as point 3 as something would seem to be wrong with my initial casting to IMAPIPROP albeit it does not cause any violations. I have tried reading a single property from the MailItem cast to IMAPIPROP using the following code:
if (Succeeded(HrGetOneProp(MAPIPROP, PR_SUBJECT, Prop))) then
And I get an access violation. Likewise if I cast the Attachment object and query an attachment property I also get a violation. I don't think the problem lies with the call to HrGetOneProp, I think it has to be the casting to IMAPIPROP.
Any pointers re the above would be greatly appreciated.
Not quite an answer to my question, but I have thought of an alternative solution. What I am ultimately trying to do is convert a msg email as a pdf. To do that I need to extract the body and then somehow insert the embedded images. With an html email this seemed pretty straightforward ((1) extract all the attachments to a folder, (2) parse the html body for references to SRC IMG and update the location of the image to reference the saved files and (3) save the edited html body to file and open it in Word and save as PDF).
RTF emails cannot be handled in this way. However, for my specific problem there is a much easier way to achieve what I need for all email types using Outtlook and Word.
Use the MailItem.SaveAs function and save the email in either html format or mthml. The former format will save all embedded images to a sub-folder (in png and jpg formats) should you need them for any other reason. once you have your html file, open it with Word and save to PDF.
If Office is not a solution then you need to figure Istorage or use one of the Extended MAPI solutions such as Redemption.
For Delphi users there are also the following commercial offerings that I have come across in my recent travels:
IMIBO
Scalabium
Rapware
I did come across one more solution which I can't find at the moment! Will post an update if I do.
PropertyAccessor (and the Outlook Object Model in general) does not handle PT_OBJECT type properties.
What you need to do is open the PR_ATTACH_DATA_OBJ property as IStorage, and then extract the data from there (it depends on the actual type of the attachment). You can see the data in the streams in OutlookSpy (I am its author) - select the message, click IMessage button on the OutlookSpy rubbon, go to the GetAttachmentTable tab, double click on the attachment to open it, select the PR_ATTACH_DATA_OBJ property, right click, select IMAPIProp::OpenProperty, then IStorage.
If using Redemption (I am also its author) is an option, its version of RDOAttachment.SaveAsFile handles OLE attachment for the most popular formats (Word, Excel, bitmap, Power Point, Adobe PDF, etc.) - create an instance of the RDOSession object (using either CrealeOleObject or RedemptionLoader) and use RDOSession.GetRDOObjectFromOutlookObject method (pass either Attachment or MailItem object) to get back RDOMail or RDOAttachment object respectively.
I work with Wonderware software. One of the objects used to perform communication between Wonderware and the PLC is called Suitelink. In it, I have a table defined that has the name of one of my application fields on the left side and the name of the PLC tag providing its value on the right.
Once this saved and activated (deployed) the PLC tags will feed values in the field attributes to Wonderware.
Does anyone know where is this list saved in the system?
I am working at a web page and want to retrieve this list dynamically so I can have the page updated based on the current live value of the PLC tag being used.
I have looked in the database but could not find it.
C:\ProgramData\Wonderware\DAServer
Then within there you'll have several subfolders for your DA Servers. Open the subfolder to find a *.AAcfg file and your contents are in there in what looks like an XML format. You'll be hunting for all the <DeviceItem> tags
I am looking for a step by step solution on how to download mail attachments using Indy Imap in C++ Builder (I use C++ Builder XE8). I have read some tutorial in Delphi, but really getting Confused.
For example, what should I do after selecting the mailbox?
ImapClient->UIDRetrieve()
or
ImapClient->RetrieveStructure()
or
ImapClient->RetrievePart()
or
ImapClient->RetrieveEnvelop().
Then, what should I do next to identify the MessagePart no, haveing the attachment file?
The Last One, how to save that file to local drive?
Should I translate the following in C++?
TIdAttachmentFile(mbMsgP.MessageParts.Items[liCount]).SaveToFile(fName);
But I cant create a statement like this
TIdAttachmentFile(IdMessage1->MessageParts->items[no])->SaveToFile("filename");
I have read some tutorial in Delphi, but really getting Confused.
Not surprising, since IMAP is a complex and confusing protocol in general. That is why TIdIMAP4 has so many more methods compared to other mailbox protocols like TIdPOP3 and TIdSMTP (and it doesn't even implement everything IMAP is capable of).
For example, what should I do after selecting the mailbox?
ImapClient->UIDRetrieve() or ImapClient->RetrieveStructure() or ImapClient->RetrievePart() od ImapClient->RetrieveEnvelop().
That really depends on what you intend to do with the emails and their attachments.
(UID)Retrieve() downloads an entire email, parsing it into a TIdMessage and marking it as "read" on the server.
(UID)RetrieveStructure() retrieves the parent/child hierarchy of the various MiME parts within an email, creating an entry for each part in a TIdMessage.MessageParts or TIdImapMessageParts collection, providing some basic descriptive information about each part such as content type and part number. The actual content of each part is not retrieved.
(UID)RetrievePart() retrieves the actual content of a specific MIME part of an email. You do not need to download the entire email. But you do have to download the email's structure first so that you know the part number that you want to retrieve.
(UID)RetrieveEnvelope() retrieves some basic top-level headers for an email: date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, and message-id.
Then, what should I do next to identify the MessagePart no, haveing the attachment file?
If you download an entire email, you would have to loop through its MessageParts collection looking for a TIdAttachment object containing the desired filename/contenttype that you are interested in.
If you download just a part of an email, you would have to retrieve the email's structure and loop through the resulting collection looking for an entry containing the desired filename/contenttype that you are interested in, then you can request that specific part's content.
The Last One, how to save that file to local drive?
If you download an entire email, then you would call SaveToFile() on the desired TIdAttachment object:
static_cast<TIdAttachment*>(IdMessage1->MessageParts->Items[no])->SaveToFile("filename");
If you download an email's structure, you can use (UID)RetrievePart() to retrieve the attachment's data into a TStream object, such as a TFileStream.
I cant seem to figure this one out.
Exporting data to Excel works OK but I do not want to use the original table field names but ones of my choice.
Right now, the original field names get exported (with the data,of course). QExport4XLS1 is linked to the data-set. I tried to use qeCustomSource41 (custom source) and changing field names - it worked OK but no data got exported. Only the field names.
Does anyone know how to accomplish this ? I never used these components before, so I am just trying them out. The documentation is horrible.
It seems the only way to do this is through QExport4Dialog1 and not through QExport4XLS1.
I've been asked to prototype a replacement "file transformation process" (that currently is a mess of SQL) using Altova's MapForce. My input is a CSV file with headers. My problem is that I need to capture both the data AND the column name to use in downstream processing.
I need to have MapForce feed a C# method (imported as that takes two parameters: fieldName and value. I can access the value trivially, but after hours pouring over the manual (1000 pages!) I haven't found any examples of how to access the field name as an output.
The reason each output needs the field name and the value has to do with how all our mappings/transformations are currently managed - on a database. The .NET code jumps in at this point and does any necessary database lookups.
For example, if I had the following file:
"Symbol", "Account", "Price", ...
"FOO", "10101", "1.23", ...
"BAR", "10201, "13.56", ...
And a static method string TransformField( string fieldName, string value ),
I'd like to map the CSV file's Symbol data output to the method's value parameter and the Field Name "Symbol" to the method's fieldName parameter.
Some limitations:
I need to keep the "wiring" visible in the MapForce GUI. I'll have non-programmers maintaining the mappings in the future. So doing all this in code is not an option.
MapForce is the tool of choice by the company. Part of the reason our original process is such a mess is because the original programmer rolled his own mapping/transformation tool (out of TSQL no less - ouch).
We can treat all inputs/outputs to the method call as strings. Conversions will happen later.
I would like to avoid using scalar literals as inputs. I already have the column names from the file - I do not want to re-type each one and feed it to my method.
I'm not sure how many users out there have experience with this tool, but after 3 days of tinkering with it, I see much potential. If only I can get past this current sticking point, I think the company will have a solid alternative to their current mess.
Thanks for any/all suggestions.
I solved my issue and, for future reference, want to post a solution. I handled my problem by using MapForce's FlexText. This allowed me to extract the header from the CSV file and "invert" the column names as data inputs to the transformation process. Once I knew the approach to take, I was able to find more information directly from Altova.
I found a couple helpful tutorials while digging through their website:
Altova Online Videos
Web Tutorial
Hope this can help someone else in the future!