Office 2007 and a Secret Handshake
Tuesday, December 01, 2009
I have a suspicion there is a whole department in Microsoft Corp. the only purpose of which is to make everyone’s life more difficult. It was created when Windows 95 came out and suddenly the file names were not only longer than 8 characters but could also contain symbols from any funky Unicode language out there. That's when ye olde faithful Norton Commander became pretty much useless, unless I had to repair a file that had the above mentioned funky symbols and could not be opened by some less advanced applications. Oh good old days…
This time the evil geniuses from the Microsoft’s Department of Screw-You-All decided to mess with the file extensions: familiar ‘doc’ for some reason has become ‘docx’ and ‘xls’ – ‘xlsx’. And while the above mentioned file name expansion in Windows 95 at least had some benefits for the users, this one is just an act of pure evil, if you ask me. Is there a single person in the whole world who is not employed by Microsoft and cares for these new extensions? I honestly doubt that. But noooo, they just had to do this… What is wrong with these people?
Oh well, the sad reality is that now even ABAP developers have to deal with this somehow. It looks like even the SAP masterminds did not expect such audacious move by Microsoft (check and mate!), because all the function modules that are somehow involved with the file manipulations (including SO_OBJECT_INSERT, which I used in my previous GOS-related post) have allocated only 3 characters for the variable to hold the file extension.
But there is no need to fear - SAP is here. Well, sort of. I’m not sure if this information is supposed to be given on strictly “need to know” basis or if there is some kind of a secret handshake one must master first, but the solution below doesn’t seem to be documented or disclosed anywhere. We got it from the SAP support team when we sent them a message asking what are we supposed to do with the new 4-character extensions.
As it turns out, the filename with extension may also be passed to the function modules using the table OBJHEAD (I’m talking about FM SO_OBJECT_INSERT here, but a similar table is present, for example, in SO_DOCUMENT_INSERT_API1 and many other SO_... FMs). The only thing is that you can’t just put the filename there, it has to be preceded by “the secret code” (wait for it… wait for it…) '&SO_FILENAME='. Why? I don’t know why, but I guess the SAP developers saw this coming and they created some kind of a back entrance in case something goes wrong (and it did).
Another interesting thing – in the previous post I mentioned that it’s not necessary to calculate the exact object size and it was true for Office 2003 files (at least it worked for me). However, this didn’t work with Office 2007 files and I ended up doing the same thing as everyone else: get the number of lines, read the last line, etc.
Also, since the extension is now not just the last 3 characters of the filename, I used FM CH_SPLIT_FILENAME to split the full filename. Interestingly enough, the extension that we pass in ls_obj_data-file_ext, in fact, does not matter much. You can pass the Word document filename in OBJHEAD table but ‘XLS’ extension and it will still open the attachment in Word. However, in the GOS menu the file will be displayed with an Excel icon, so it’ll just look more neat if we pass the correct extension (it will be truncated to 3 characters, but it’s fine).
Here is the full code from the previous post, enhanced for the Office 2007 extensions (and it should also work fine with the old extensions):
PARAMETERS: p_key TYPE swo_typeid OBLIGATORY,
p_type TYPE swo_objtyp OBLIGATORY,
p_file TYPE string OBLIGATORY,
p_desc TYPE so_obj_des OBLIGATORY.
DATA: ls_fol_id TYPE soodk,
ls_obj_id TYPE soodk,
ls_obj_data TYPE sood1,
ls_folmem_k TYPE sofmk,
ls_note TYPE borident,
ls_object TYPE borident,
lv_ep_note TYPE borident-objkey,
* lv_offset TYPE i,
lv_lines TYPE i,
lv_filename TYPE c LENGTH 100, " file name and ext
lv_extension TYPE c LENGTH 4. " extension only
DATA: it_objhead TYPE STANDARD TABLE OF soli,
it_content LIKE STANDARD TABLE OF soli,
wa_content LIKE soli.
ls_object-objkey = p_key.
ls_object-objtype = p_type.
TRY.
OPEN DATASET p_file FOR INPUT IN BINARY MODE.
WHILE sy-subrc = 0.
READ DATASET p_file INTO wa_content.
APPEND wa_content TO it_content.
ENDWHILE.
CLOSE DATASET p_file.
CATCH cx_sy_file_access_error.
MESSAGE 'Error reading file' TYPE 'E'.
ENDTRY.
CALL FUNCTION 'SO_CONVERT_CONTENTS_BIN'
EXPORTING
it_contents_bin = it_content[]
IMPORTING
et_contents_bin = it_content[].
CALL FUNCTION 'SO_FOLDER_ROOT_ID_GET'
EXPORTING
region = 'B'
IMPORTING
folder_id = ls_fol_id
EXCEPTIONS
OTHERS = 1.
* Get file name and extension
CALL FUNCTION 'CH_SPLIT_FILENAME'
EXPORTING
complete_filename = p_file
IMPORTING
extension = lv_extension
name_with_ext = lv_filename
EXCEPTIONS
invalid_drive = 1
invalid_path = 2
OTHERS = 3.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ls_obj_data-objsns = 'O'.
ls_obj_data-objla = sy-langu.
ls_obj_data-objdes = p_desc.
*lv_offset = STRLEN( p_file ) - 3.
*ls_obj_data-file_ext = p_file+lv_offset(3).
ls_obj_data-file_ext = lv_extension.
*ls_obj_data-objlen = LINES( it_content ) * 255.
CLEAR wa_content.
DESCRIBE TABLE it_content LINES lv_lines.
READ TABLE it_content INTO wa_content INDEX lv_lines.
ls_obj_data-objlen = ( lv_lines - 1 ) * 255 + STRLEN( wa_content ).
* Object header
CLEAR wa_content.
CONCATENATE '&SO_FILENAME=' lv_filename INTO wa_content.
APPEND wa_content TO it_objhead.
CALL FUNCTION 'SO_OBJECT_INSERT'
EXPORTING
folder_id = ls_fol_id
object_type = 'EXT'
object_hd_change = ls_obj_data
IMPORTING
object_id = ls_obj_id
TABLES
objhead = it_objhead
objcont = it_content
EXCEPTIONS
active_user_not_exist = 35
folder_not_exist = 6
object_type_not_exist = 17
owner_not_exist = 22
parameter_error = 23
OTHERS = 1000.
IF sy-subrc = 0 AND ls_object-objkey IS NOT INITIAL.
ls_folmem_k-foltp = ls_fol_id-objtp.
ls_folmem_k-folyr = ls_fol_id-objyr.
ls_folmem_k-folno = ls_fol_id-objno.
ls_folmem_k-doctp = ls_obj_id-objtp.
ls_folmem_k-docyr = ls_obj_id-objyr.
ls_folmem_k-docno = ls_obj_id-objno.
lv_ep_note = ls_folmem_k.
ls_note-objtype = 'MESSAGE'.
ls_note-objkey = lv_ep_note.
CALL FUNCTION 'BINARY_RELATION_CREATE_COMMIT'
EXPORTING
obj_rolea = ls_object
obj_roleb = ls_note
relationtype = 'ATTA'
EXCEPTIONS
OTHERS = 1.
ELSE.
MESSAGE 'Not OK' TYPE 'I'.
RETURN.
ENDIF.
IF sy-subrc = 0.
MESSAGE 'OK' TYPE 'I'.
ELSE.
MESSAGE 'Not OK' TYPE 'I'.
ENDIF.
Not everything is rainbows and butterflies with this solution, unfortunately. So far I have been unable to get it to work absolutely correctly with the Word 2007 files. The files do open, but Word keeps complaining that they’re corrupt and wants to “recover” them. If you click “Yes’ to recover, the file will open just fine, but this is very confusing and annoying to the users. Excel 2007 works fine, but Word just refuses to cooperate. I tried to use GUI_UPLOAD and upload the file from PC, tried different things with the uploaded table, but with no success so far. I know it must be possible to upload Word 2007 files correctly, because it is somehow working in transaction SO01, for example, when adding an attachment to the workflow (don’t forget to implement the note 1364402 beforehand). If anyone finds some solution to this problem, please let us know.
To make up for this – a small bonus feature. While doing some debugging, I discovered another “secret code” – if you add a line to OBJHEAD (or a similar) table with '&SO_FORMAT=BIN' then the file/attachment contents will always be treated as binary. And actually I got to use this one already in another program that calls SO_DOCUMENT_INSERT_API1 and where we had problems with HTML attachments being interpreted as plain text.
Enjoy – no secret handshake required!
posted by Your Friendly ABAPer @ 19:06, Direct link to this post
7 Comments:
- At 3/12/09 10:48, said...
-
Thanks a lot for the posting, this helped me a lot.
After adding the Filename in objhead fixed my file corruption issue while attaching the 4 character document type files.
Thanks again
Mahesh - At 3/12/10 01:35, said...
-
The file name in objhead did not fix my corruption issue. The calculating of the file size fixed my issue
- At 28/2/12 11:28, said...
-
Hi Thomas! I'm actually working on a follow-up post since I myself ran into some issues in a different environment. My new program is reading from a file into xstring, attaching as GOS and also emailing.
I'm using CALL METHOD cl_document_bcs=>xstring_to_solix to convert xstring to SOLIX type table. Then I use SO_FOLDER_ROOT_ID_GET as usual and then SO_DOCUMENT_INSERT_API1 with itab_solix that I got from the method (it's probably the same as FM). The last part is BINARY_RELATION_CREATE_COMMIT.
I'll try to post more info but am just very busy. - At 18/5/14 11:42, itsikshana.com said...
-
Best IT Training Institutes Search Engine Portal in INDIA-www.itsikshana.com
Training Institutes Information,Free Online Tests, Study Materials..More - At 27/2/15 07:54, Unknown said...
-
Hello people!
Here size has calculated wrong!
>>>>>ls_obj_data-objlen = ( lv_lines - 1 ) * 255 + STRLEN( wa_content ).
I got original size of file, and now *.xlsx open correct!
regards, kapion - At 1/7/15 04:42, Anugraha Jain said...
-
Hi,
We have developed a new gen developer friendly BI framework with some extremely unique features. Would like to give you early access & love to hear your opinion. Please do let me know of how to reach out to you. Would be launching product in 3 weeks from now.
Regards,
Anugraha - At 7/2/16 11:00, Unknown said...
-
Hi Friendly Abaper.. thanks for your posts on GOS.
I too came across the corrupt file issue when retrieving from an SAP FI doc that I saved it to.
I was able to fix the issue by correctly calculating the file size as another poster above mentioned.
As an example, your code calculated a file size of 11985 while the real fize size was 11921.
Unfortunately, I can't give you the methods call or FM - the file size was already being passed to me via a web service download.
Now, I do not get the corrupt file error message when I try to open the .docx or .xlsx files.
thanks again.
robert