46f894c63397ded825af1c78a8e008fcd2073dba
[simantics/platform.git] / bundles / org.simantics.excel / native / Interface.cpp
1
2 //#include "stdafx.h"
3
4 //#ifndef _UNICODE
5 //#define _UNICODE
6 //#endif
7
8 #include <sstream>
9 #include <map>
10 //#include <cmath>
11 //#include <TCHAR.H>
12
13 using namespace std;
14
15 #import "c:/program files (x86)/common files/microsoft shared/office12/mso.dll" \
16         rename( "RGB", "MSORGB" )
17
18 using namespace Office;
19
20 #import "c:/program files (x86)/common files/microsoft shared/vba/vba6/vbe6ext.olb" \
21
22 using namespace VBIDE;
23
24 #import "c:/program files (x86)/microsoft office/office12/excel.exe" \
25         rename( "DialogBox", "ExcelDialogBox" ) \
26         rename( "RGB", "ExcelRGB" ) \
27         rename( "CopyFile", "ExcelCopyFile" ) \
28         rename( "ReplaceText", "ExcelReplaceText" )
29
30 #include "jni2.h"
31
32 //#define SIMANTICS_DEBUG(...) \
33 //{ FILE *fp = fopen("d:/excel.log", "ab"); fprintf(fp, __VA_ARGS__); fflush(fp); fclose(fp);  }
34
35 #define SIMANTICS_DEBUG(...)
36
37 using namespace std;
38 using namespace Excel;
39
40 map<int, Excel::_WorksheetPtr> handles;
41 static int handleCounter = 1;
42
43 void replace(std::string &s, const std::string &s1, const std::string &s2) {
44
45         int index = 0;
46
47         index = s.find(s1, index);
48         while(index != std::string::npos) {
49                 s.replace(index, s1.length(), s2.c_str(), s2.length());
50                 index = s.find(s1, index + 1);
51         }
52
53 }
54
55 boolean getString(JNIEnv *env, jstring str, char *target) {
56
57     jboolean iscopy;
58     const char *chars = env->GetStringUTFChars(str, &iscopy);
59         if(!chars) return false;
60
61         strcpy(target, chars);
62
63     env->ReleaseStringUTFChars(str, chars);
64
65         return true;
66
67 }
68
69 string getString(JNIEnv *env, jstring str) {
70
71     jboolean iscopy;
72     const char *chars = env->GetStringUTFChars(str, &iscopy);
73         if(!chars) return 0;
74         string result = chars;
75     env->ReleaseStringUTFChars(str, chars);
76         return result;
77
78 }
79
80 Excel::_ApplicationPtr getApplication(bool create) {
81         
82         Excel::_ApplicationPtr application;
83
84         CLSID clsid;
85         HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);
86         if(FAILED(hr)) {
87                 return 0;
88         }
89
90         if (!SUCCEEDED(application.GetActiveObject(clsid)))
91         {
92                 if(create) {
93                         hr = application.CreateInstance(clsid);
94                         if(FAILED(hr)) {
95                                 return 0;
96                         }
97                 } else {
98                         return 0;
99                 }
100         }
101
102         application->EnableEvents = VARIANT_FALSE;
103
104         return application;
105
106 }
107
108 JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_init(JNIEnv *env, jobject) {
109
110         SIMANTICS_DEBUG("Excel init\r\n");
111
112         HRESULT hr = ::OleInitialize(NULL);
113         if(FAILED(hr)) {
114                 return hr;
115         }
116
117         /*
118         Excel::_ApplicationPtr application = getApplication(true);
119         if(!application) return -1;
120         bstr_t version = application->GetVersion(0);
121         ostringstream os;
122         os << version << endl;
123         SIMANTICS_DEBUG("Init successful with version %s\r\n",  os.str().c_str());
124
125         application->put_Interactive( 0, VARIANT_FALSE );
126         application->put_Visible( 0, VARIANT_FALSE );
127         */
128
129         return 0;
130
131 }
132
133 Excel::_WorkbookPtr getWorkbook(const Excel::_ApplicationPtr &application, const string &fileName) {
134
135         SIMANTICS_DEBUG("getWorkbook(%s)\r\n", fileName.c_str());
136
137         for(int i=0;i<application->Workbooks->Count;i++) {
138                 _bstr_t fullName;
139                 Excel::_WorkbookPtr workbook = application->Workbooks->GetItem( _variant_t(i+1) );
140                 workbook->get_FullName(0, &fullName.GetBSTR());
141                 std::string fullNameStr = fullName;
142                 SIMANTICS_DEBUG("'%s'\r\n", fullNameStr.c_str());
143                 if(fullNameStr == fileName) return workbook;
144         }
145
146         return 0;
147
148 }
149
150 Excel::_WorksheetPtr getWorksheet(const Excel::_WorkbookPtr workbook, const string &sheetName) {
151
152         SIMANTICS_DEBUG("getWorksheet(%s)\r\n", sheetName.c_str());
153
154         for(int i=0;i<workbook->Sheets->Count;i++) {
155                 Excel::_WorksheetPtr sheet = workbook->Sheets->GetItem(_variant_t(i+1));
156                 std:string name = sheet->Name;
157                 SIMANTICS_DEBUG("'%s'\r\n", name.c_str());
158                 if(name == sheetName) return sheet;
159         }
160
161         return 0;
162
163 }
164
165 char message[1024];
166
167 JNIEXPORT jstring JNICALL Java_org_simantics_excel_Excel_open(JNIEnv *env, jobject, jstring fileName, jstring sheetName_) {
168
169         string name = getString(env, fileName);
170         string sheetName = getString(env, sheetName_);
171
172         _variant_t varOption( (long) DISP_E_PARAMNOTFOUND, VT_ERROR );
173
174         Excel::_ApplicationPtr application = getApplication(true);
175         if(!application) return env->NewStringUTF("Excel application could not be started.");
176
177         Excel::_WorkbookPtr workbook = getWorkbook(application, name);
178         if(!workbook) {
179
180                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Opening.\r\n", name.c_str());
181
182                 FILE *fp = fopen(name.c_str(), "r");
183                 if(fp) {
184
185                 SIMANTICS_DEBUG("getWorkbook(%s) book was found. Opening file.\r\n", name.c_str());
186
187                         fclose(fp);
188                         workbook = application->Workbooks->OpenXML(_bstr_t(name.c_str()), 
189                                 varOption, varOption);
190                         if(!workbook) return env->NewStringUTF("File could not be opened.");
191
192                 } else {
193
194                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creating file.\r\n", name.c_str());
195
196                         workbook = application->Workbooks->Add(varOption);
197
198                         if(!workbook) return env->NewStringUTF("New workbook could not be created.");
199
200                         try {
201
202                                 Excel::_WorksheetPtr sheet = workbook->Sheets->Add();
203                                 sheet->Name = _bstr_t(sheetName.c_str());
204
205                                 /*
206                                 // Does not work for some unknown reason
207                                 for(int i=0;i<workbook->Sheets->Count;i++) {
208                                         Excel::_WorksheetPtr sheet = workbook->Sheets->GetItem(_variant_t(i+1));
209                                         if(name != sheetName)
210                                                 sheet->PutVisible(0, Excel::XlSheetVisibility::xlSheetVeryHidden);
211                                 }
212                                 */
213
214                                 workbook->SaveAs(_bstr_t(name.c_str()), varOption, varOption, varOption, varOption,
215                                         varOption, Excel::xlExclusive, varOption, varOption, varOption, varOption, 0);
216
217                         } catch (_com_error& e) {
218                                 _bstr_t bstr = _bstr_t(e.ErrorMessage());
219                                 string s(bstr);
220                                 _bstr_t bstr2 = _bstr_t(e.Description());
221                                 string s2(bstr2);
222                                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 1 '%s' '%s'\r\n", name.c_str(), s.c_str(), s2.c_str());
223                                 strcpy(message, s2.c_str());
224                                 return env->NewStringUTF(message);
225                         } catch (exception& e) {
226                                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 2 '%s'\r\n", name.c_str(), e.what());
227                                 return env->NewStringUTF(e.what());
228                         } catch (...) {
229                                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 3 \r\n", name.c_str());
230                                 return env->NewStringUTF("Undefined error");
231                         }
232                 
233
234                 }
235
236         }
237
238         application->put_Interactive( 0, VARIANT_TRUE );
239         application->put_Visible( 0, VARIANT_TRUE );
240
241         workbook->Activate();
242
243         SIMANTICS_DEBUG("getWorkbook(%s) searches for sheet '%s'\r\n", name.c_str(), sheetName.c_str());
244
245         try {
246                 Excel::_WorksheetPtr sheet = getWorksheet(workbook, sheetName);
247                 if(!sheet) {
248                         SIMANTICS_DEBUG("creating sheet %s for '%s'\r\n", sheetName.c_str(), name.c_str());
249                         sheet = workbook->Sheets->Add();
250                         sheet->Name = _bstr_t(sheetName.c_str());
251                 }
252             int handle = handleCounter++;
253         SIMANTICS_DEBUG("opened handle %d for '%s'\r\n", handle, name.c_str());
254         handles[handle] = sheet;
255                 ostringstream os;
256                 os << handle;
257                 return env->NewStringUTF(os.str().c_str());
258
259         } catch (_com_error& e) {
260                 _bstr_t bstr = _bstr_t(e.ErrorMessage());
261                 string s(bstr);
262                 _bstr_t bstr2 = _bstr_t(e.Description());
263                 string s2(bstr2);
264                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 1 '%s' '%s'\r\n", name.c_str(), s.c_str(), s2.c_str());
265                 return env->NewStringUTF(s2.c_str());
266         } catch (exception& e) {
267                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 2 '%s'\r\n", name.c_str(), e.what());
268                 return env->NewStringUTF(e.what());
269         } catch (...) {
270                 SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error\r\n", name.c_str());
271                 return env->NewStringUTF("Unhandled exception.");
272         }
273
274
275         //Excel::_WorksheetPtr sheet = workbook->ActiveSheet;
276         //if(!sheet) return -4;
277
278
279 }
280
281 string cellName(int row, int column) {
282
283         string result;
284
285         SIMANTICS_DEBUG("cellName(%d, %d) -> ", row, column);
286
287         do {
288                 char rem = column % 26;
289                 char c = 'A' + rem;
290                 result += c;
291                 column -= rem;
292                 column /= 26;
293         } while(column);
294
295         ostringstream os;
296         os << (row + 1);
297         result += os.str();
298
299         SIMANTICS_DEBUG("%s\r\n", result.c_str());
300
301         return result;
302
303 }
304
305 /*
306 Excel::_WorkbookPtr getWorkbook(int handle) {
307         map<int, Excel::_WorkbookPtr>::iterator it = handles.find(handle);
308         if(it != handles.end()) return (*it).second;
309         else return 0;
310 }
311 */
312
313 Excel::_WorksheetPtr getWorksheet(int handle) {
314         map<int, Excel::_WorksheetPtr>::iterator it = handles.find(handle);
315         if(it != handles.end()) return (*it).second;
316         else return 0;
317 }
318
319 JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setDouble(JNIEnv *env, jobject, jint handle, jint row, jint column, jdouble value) {
320
321         SIMANTICS_DEBUG("setDouble(%d, %d, %f)\r\n", row, column, value);
322
323         Excel::_WorksheetPtr sheet = getWorksheet(handle);
324         if(!sheet) return -1;
325         Excel::RangePtr range = sheet->Cells;
326         if(!range) return -2;
327         range->Item[row+1][column+1] = value;
328
329         return 0;
330
331 }
332
333 JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setString(JNIEnv *env, jobject, jint handle, jint row, jint column, jstring value) {
334
335         string val = getString(env, value);
336
337         SIMANTICS_DEBUG("setString(%d, %d, %s)\r\n", row, column, val.c_str());
338
339         Excel::_WorksheetPtr sheet = getWorksheet(handle);
340         if(!sheet) return -1;
341         Excel::RangePtr range = sheet->Cells;
342         if(!range) return -2;
343
344         const char *text = val.c_str();
345
346         range->Item[row+1][column+1] = text;
347         //range->Name[row+1][column+1] = text;
348
349         return 0;
350
351 }
352
353 JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setName(JNIEnv *env, jobject, jint handle, jint row, jint column, jstring value) {
354
355         string val = getString(env, value);
356
357         SIMANTICS_DEBUG("setName(%d, %d, %s)\r\n", row, column, val.c_str());
358
359         Excel::_WorksheetPtr sheet = getWorksheet(handle);
360         if(!sheet) return -1;
361         //sheet->c
362         Excel::RangePtr range = sheet->GetRange(_variant_t(cellName(row, column).c_str()));
363         if(!range) return -2;
364         range->Name = _variant_t(val.c_str());
365
366
367         //range->Item[row+1][column+1] = text;
368         //range->Name[row+1][column+1] = text;
369
370         return 0;
371
372 }
373
374 JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setVisible(JNIEnv *env, jobject, jint handle, jboolean value) {
375
376         SIMANTICS_DEBUG("setVisible(%d)\r\n", value);
377
378         Excel::_WorksheetPtr sheet = getWorksheet(handle);
379         if(!sheet) return -1;
380         Excel::_ApplicationPtr application = sheet->Application;
381         if(!application) return -2;
382
383         if(value) {
384                 application->put_Interactive( 0, VARIANT_TRUE );
385                 application->put_Visible( 0, VARIANT_TRUE );
386         } else {
387                 application->put_Interactive( 0, VARIANT_FALSE );
388                 application->put_Visible( 0, VARIANT_FALSE );
389         }
390
391         return 0;
392
393 }
394
395 JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_close(JNIEnv *env, jobject, jint handle) {
396
397         SIMANTICS_DEBUG("closing handle %d\r\n", handle);
398
399         Excel::_WorksheetPtr sheet = getWorksheet(handle);
400         if(!sheet) return -1;
401         Excel::_ApplicationPtr application = sheet->Application;
402         if(!application) return -2;
403
404         Excel::_WorkbookPtr workbook = (Excel::_WorkbookPtr)sheet->Parent;
405         if(!workbook) return -3;
406
407 //      SIMANTICS_DEBUG("About to save\r\n");
408         HRESULT hr = workbook->Save();
409 //      workbook->put_Saved(0, VARIANT_TRUE);
410         if(FAILED(hr)) {
411                 SIMANTICS_DEBUG("Save failed with %d\r\n", hr);
412                 return hr;
413         }
414 //      SIMANTICS_DEBUG("About to AcceptAllChanges\r\n");
415 //      HRESULT hr = workbook->AcceptAllChanges();
416 //      if(FAILED(hr)) {
417
418         //SIMANTICS_DEBUG("Close failed with %d\r\n", hr);
419         //      return hr;
420         //}
421
422         // Release this reference for Close
423         handles.erase(handle);
424
425         map<int, Excel::_WorksheetPtr>::iterator it = handles.begin();
426         for(;it != handles.end();++it) {
427                 Excel::_WorksheetPtr sheet2 = (*it).second;
428                 Excel::_WorkbookPtr book = (Excel::_WorkbookPtr)sheet2->Parent;
429                 // The book remains open
430                 if(book->Name == workbook->Name) return 0;
431         }
432
433         //SIMANTICS_DEBUG("About to PutUserControl\r\n");
434         //workbook->PutUserControl(VARIANT_FALSE);
435         SIMANTICS_DEBUG("About to Close\r\n");
436         hr = workbook->Close(VARIANT_FALSE);
437         if(FAILED(hr)) {
438                 SIMANTICS_DEBUG("Close failed with %d\r\n", hr);
439                 return hr;
440         }
441
442         long remaining = 0;
443
444         application->Workbooks->get_Count(&remaining);
445         if(!remaining) {
446                 application->put_Interactive( 0, VARIANT_FALSE );
447                 application->put_Visible( 0, VARIANT_FALSE );
448                 hr = application->Quit();
449                 if(FAILED(hr)) {
450                         SIMANTICS_DEBUG("Close failed with %d\r\n", hr);
451                         return hr;
452                 }
453         }
454
455 //      SIMANTICS_DEBUG("About to hide");
456
457 //      application->put_Interactive( 0, VARIANT_FALSE );
458 //      application->put_Visible( 0, VARIANT_FALSE );
459
460 //      if(handles.empty())
461 //              application->Quit();
462
463         return 0;
464
465 }
466
467 /**
468 JNIEXPORT jdouble JNICALL Java_org_simantics_excel_Excel_getDouble(JNIEnv *env, jobject, jint handle, jint row, jint column) {
469
470         SIMANTICS_DEBUG("getDouble(%d, %d)\r\n", row, column);
471
472         Excel::_WorksheetPtr sheet = getWorksheet(handle);
473         if(!sheet) return 0.0; // TODO: NAN
474         Excel::RangePtr range = sheet->Cells;
475         if(!range) return 0.0; // TODO: NAN
476
477         variant_t val = range->Item[row+1][column+1];
478         if (val.vt != VT_NULL) {
479                 try {
480                         double d = val;
481                         SIMANTICS_DEBUG("%f\r\n",d);
482                         return d;
483                 } catch (...) {
484                         return 0.0; // TODO: NAN
485                 }
486         }
487         return 0.0; // TODO: NAN
488
489 }
490
491 JNIEXPORT jstring JNICALL Java_org_simantics_excel_Excel_getString(JNIEnv *env, jobject, jint handle, jint row, jint column) {
492
493         //string val = getString(env, value);
494
495         SIMANTICS_DEBUG("getString(%d, %d)\r\n", row, column);
496
497         Excel::_WorksheetPtr sheet = getWorksheet(handle);
498         if(!sheet) return NULL;
499         Excel::RangePtr range = sheet->Cells;
500         if(!range) return NULL;
501
502         variant_t val = range->Item[row+1][column+1];
503         if (val.vt != VT_NULL) {  // val.vt seems to be always VT_DISPATCH.
504                 try {
505                         //this call will crash the application, if the cell is empty!
506                         _bstr_t bstrt = val;
507                         TCHAR text[1024];
508                         // TODO: this uses wide character (16-bit) while NewStringUTF expext regular character (8-bit), hence Java gets only the fisrt charater of the whole string.
509                         _stprintf(text, _T("%s"), (LPCTSTR)bstrt);
510                         //const char *text = bstrt;
511                         SIMANTICS_DEBUG("%s\r\n",text);
512         
513                         // this code returns "??" for all cells.
514                         //BSTR bstr = val.bstrVal;
515                         //const char *text = _com_util::ConvertBSTRToString(bstr);
516
517                         jstring ret = env->NewStringUTF((const char*)text);
518                         delete[] text;
519                         return ret;
520                 } catch (...) {
521                         return NULL; 
522                 }
523         } 
524         SIMANTICS_DEBUG("%d\r\n",val.vt);
525         return NULL; 
526
527 }
528 */