#include #include #include #include #include #include using namespace std; // mso.dll #import "libid:{2df8d04c-5bfa-101b-bde5-00aa0044de52}" auto_rename // vb6ext.olb #import "libid:{0002e157-0000-0000-c000-000000000046}" auto_rename // excel.exe #import "libid:{00020813-0000-0000-c000-000000000046}" auto_rename using namespace Excel; #include "jni2.h" //#define SIMANTICS_DEBUG(...) \ //{ FILE *fp = fopen("d:/excel.log", "ab"); fprintf(fp, __VA_ARGS__); fflush(fp); fclose(fp); } #define SIMANTICS_DEBUG(...) //using namespace std; //using namespace Office; map handles; static int handleCounter = 1; void replace(std::string &s, const std::string &s1, const std::string &s2) { int index = 0; index = s.find(s1, index); while(index != std::string::npos) { s.replace(index, s1.length(), s2.c_str(), s2.length()); index = s.find(s1, index + 1); } } boolean getString(JNIEnv *env, jstring str, char *target) { jboolean iscopy; const char *chars = env->GetStringUTFChars(str, &iscopy); if(!chars) return false; strcpy(target, chars); env->ReleaseStringUTFChars(str, chars); return true; } string getString(JNIEnv *env, jstring str) { jboolean iscopy; const char *chars = env->GetStringUTFChars(str, &iscopy); if(!chars) return 0; string result = chars; env->ReleaseStringUTFChars(str, chars); return result; } Excel::_ApplicationPtr getApplication(bool create) { Excel::_ApplicationPtr application; CLSID clsid; HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid); if(FAILED(hr)) { return 0; } if (!SUCCEEDED(application.GetActiveObject(clsid))) { if(create) { hr = application.CreateInstance(clsid); if(FAILED(hr)) { return 0; } } else { return 0; } } application->EnableEvents = VARIANT_FALSE; return application; } JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_init(JNIEnv *env, jobject) { SIMANTICS_DEBUG("Excel init\r\n"); HRESULT hr = ::OleInitialize(NULL); if(FAILED(hr)) { return hr; } /* Excel::_ApplicationPtr application = getApplication(true); if(!application) return -1; bstr_t version = application->GetVersion(0); ostringstream os; os << version << endl; SIMANTICS_DEBUG("Init successful with version %s\r\n", os.str().c_str()); application->put_Interactive( 0, VARIANT_FALSE ); application->put_Visible( 0, VARIANT_FALSE ); */ return 0; } Excel::_WorkbookPtr getWorkbook(const Excel::_ApplicationPtr &application, const string &fileName) { SIMANTICS_DEBUG("getWorkbook(%s)\r\n", fileName.c_str()); for(int i=0;iWorkbooks->Count;i++) { _bstr_t fullName; Excel::_WorkbookPtr workbook = application->Workbooks->GetItem( _variant_t(i+1) ); workbook->get_FullName(0, &fullName.GetBSTR()); std::string fullNameStr = fullName; SIMANTICS_DEBUG("'%s'\r\n", fullNameStr.c_str()); if(fullNameStr == fileName) return workbook; } return 0; } Excel::_WorksheetPtr getWorksheet(const Excel::_WorkbookPtr workbook, const string &sheetName) { SIMANTICS_DEBUG("getWorksheet(%s)\r\n", sheetName.c_str()); for(int i=0;iSheets->Count;i++) { Excel::_WorksheetPtr sheet = workbook->Sheets->GetItem(_variant_t(i+1)); std:string name = sheet->Name; SIMANTICS_DEBUG("'%s'\r\n", name.c_str()); if(name == sheetName) return sheet; } return 0; } char message[1024]; JNIEXPORT jstring JNICALL Java_org_simantics_excel_Excel_open(JNIEnv *env, jobject, jstring fileName, jstring sheetName_) { string name = getString(env, fileName); string sheetName = getString(env, sheetName_); _variant_t varOption( (long) DISP_E_PARAMNOTFOUND, VT_ERROR ); Excel::_ApplicationPtr application = getApplication(true); if(!application) return env->NewStringUTF("Excel application could not be started."); Excel::_WorkbookPtr workbook = getWorkbook(application, name); if(!workbook) { SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Opening.\r\n", name.c_str()); FILE *fp = fopen(name.c_str(), "r"); if(fp) { SIMANTICS_DEBUG("getWorkbook(%s) book was found. Opening file.\r\n", name.c_str()); fclose(fp); workbook = application->Workbooks->OpenXML(_bstr_t(name.c_str()), varOption, varOption); if(!workbook) return env->NewStringUTF("File could not be opened."); } else { SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creating file.\r\n", name.c_str()); workbook = application->Workbooks->Add(varOption); if(!workbook) return env->NewStringUTF("New workbook could not be created."); try { Excel::_WorksheetPtr sheet = workbook->Sheets->Add(); sheet->Name = _bstr_t(sheetName.c_str()); /* // Does not work for some unknown reason for(int i=0;iSheets->Count;i++) { Excel::_WorksheetPtr sheet = workbook->Sheets->GetItem(_variant_t(i+1)); if(name != sheetName) sheet->PutVisible(0, Excel::XlSheetVisibility::xlSheetVeryHidden); } */ workbook->SaveAs(_bstr_t(name.c_str()), varOption, varOption, varOption, varOption, varOption, Excel::xlExclusive, varOption, varOption, varOption, varOption, 0); } catch (_com_error& e) { _bstr_t bstr = _bstr_t(e.ErrorMessage()); string s(bstr); _bstr_t bstr2 = _bstr_t(e.Description()); string s2(bstr2); SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 1 '%s' '%s'\r\n", name.c_str(), s.c_str(), s2.c_str()); strcpy(message, s2.c_str()); return env->NewStringUTF(message); } catch (exception& e) { SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 2 '%s'\r\n", name.c_str(), e.what()); return env->NewStringUTF(e.what()); } catch (...) { SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 3 \r\n", name.c_str()); return env->NewStringUTF("Undefined error"); } } } application->put_Interactive( 0, VARIANT_TRUE ); application->put_Visible( 0, VARIANT_TRUE ); workbook->Activate(); SIMANTICS_DEBUG("getWorkbook(%s) searches for sheet '%s'\r\n", name.c_str(), sheetName.c_str()); try { Excel::_WorksheetPtr sheet = getWorksheet(workbook, sheetName); if(!sheet) { SIMANTICS_DEBUG("creating sheet %s for '%s'\r\n", sheetName.c_str(), name.c_str()); sheet = workbook->Sheets->Add(); sheet->Name = _bstr_t(sheetName.c_str()); } int handle = handleCounter++; SIMANTICS_DEBUG("opened handle %d for '%s'\r\n", handle, name.c_str()); handles[handle] = sheet; ostringstream os; os << handle; return env->NewStringUTF(os.str().c_str()); } catch (_com_error& e) { _bstr_t bstr = _bstr_t(e.ErrorMessage()); string s(bstr); _bstr_t bstr2 = _bstr_t(e.Description()); string s2(bstr2); SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 1 '%s' '%s'\r\n", name.c_str(), s.c_str(), s2.c_str()); return env->NewStringUTF(s2.c_str()); } catch (exception& e) { SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error 2 '%s'\r\n", name.c_str(), e.what()); return env->NewStringUTF(e.what()); } catch (...) { SIMANTICS_DEBUG("getWorkbook(%s) book was not found. Creation error\r\n", name.c_str()); return env->NewStringUTF("Unhandled exception."); } //Excel::_WorksheetPtr sheet = workbook->ActiveSheet; //if(!sheet) return -4; } string cellName(int row, int column) { string result; SIMANTICS_DEBUG("cellName(%d, %d) -> ", row, column); do { char rem = column % 26; char c = 'A' + rem; result += c; column -= rem; column /= 26; } while(column); ostringstream os; os << (row + 1); result += os.str(); SIMANTICS_DEBUG("%s\r\n", result.c_str()); return result; } /* Excel::_WorkbookPtr getWorkbook(int handle) { map::iterator it = handles.find(handle); if(it != handles.end()) return (*it).second; else return 0; } */ Excel::_WorksheetPtr getWorksheet(int handle) { map::iterator it = handles.find(handle); if(it != handles.end()) return (*it).second; else return 0; } JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setDouble(JNIEnv *env, jobject, jint handle, jint row, jint column, jdouble value) { SIMANTICS_DEBUG("setDouble(%d, %d, %f)\r\n", row, column, value); Excel::_WorksheetPtr sheet = getWorksheet(handle); if(!sheet) return -1; Excel::RangePtr range = sheet->Cells; if(!range) return -2; range->Item[row+1][column+1] = value; return 0; } JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setString(JNIEnv *env, jobject, jint handle, jint row, jint column, jstring value) { string val = getString(env, value); SIMANTICS_DEBUG("setString(%d, %d, %s)\r\n", row, column, val.c_str()); Excel::_WorksheetPtr sheet = getWorksheet(handle); if(!sheet) return -1; Excel::RangePtr range = sheet->Cells; if(!range) return -2; const char *text = val.c_str(); range->Item[row+1][column+1] = text; //range->Name[row+1][column+1] = text; return 0; } JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setName(JNIEnv *env, jobject, jint handle, jint row, jint column, jstring value) { string val = getString(env, value); SIMANTICS_DEBUG("setName(%d, %d, %s)\r\n", row, column, val.c_str()); Excel::_WorksheetPtr sheet = getWorksheet(handle); if(!sheet) return -1; //sheet->c Excel::RangePtr range = sheet->GetRange(_variant_t(cellName(row, column).c_str())); if(!range) return -2; range->Name = _variant_t(val.c_str()); //range->Item[row+1][column+1] = text; //range->Name[row+1][column+1] = text; return 0; } JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_setVisible(JNIEnv *env, jobject, jint handle, jboolean value) { SIMANTICS_DEBUG("setVisible(%d)\r\n", value); Excel::_WorksheetPtr sheet = getWorksheet(handle); if(!sheet) return -1; Excel::_ApplicationPtr application = sheet->Application; if(!application) return -2; if(value) { application->put_Interactive( 0, VARIANT_TRUE ); application->put_Visible( 0, VARIANT_TRUE ); } else { application->put_Interactive( 0, VARIANT_FALSE ); application->put_Visible( 0, VARIANT_FALSE ); } return 0; } JNIEXPORT jint JNICALL Java_org_simantics_excel_Excel_close(JNIEnv *env, jobject, jint handle) { SIMANTICS_DEBUG("closing handle %d\r\n", handle); Excel::_WorksheetPtr sheet = getWorksheet(handle); if(!sheet) return -1; Excel::_ApplicationPtr application = sheet->Application; if(!application) return -2; Excel::_WorkbookPtr workbook = (Excel::_WorkbookPtr)sheet->Parent; if(!workbook) return -3; // SIMANTICS_DEBUG("About to save\r\n"); HRESULT hr = workbook->Save(); // workbook->put_Saved(0, VARIANT_TRUE); if(FAILED(hr)) { SIMANTICS_DEBUG("Save failed with %d\r\n", hr); return hr; } // SIMANTICS_DEBUG("About to AcceptAllChanges\r\n"); // HRESULT hr = workbook->AcceptAllChanges(); // if(FAILED(hr)) { //SIMANTICS_DEBUG("Close failed with %d\r\n", hr); // return hr; //} // Release this reference for Close handles.erase(handle); map::iterator it = handles.begin(); for(;it != handles.end();++it) { Excel::_WorksheetPtr sheet2 = (*it).second; Excel::_WorkbookPtr book = (Excel::_WorkbookPtr)sheet2->Parent; // The book remains open if(book->Name == workbook->Name) return 0; } //SIMANTICS_DEBUG("About to PutUserControl\r\n"); //workbook->PutUserControl(VARIANT_FALSE); SIMANTICS_DEBUG("About to Close\r\n"); hr = workbook->Close(VARIANT_FALSE); if(FAILED(hr)) { SIMANTICS_DEBUG("Close failed with %d\r\n", hr); return hr; } long remaining = 0; application->Workbooks->get_Count(&remaining); if(!remaining) { application->put_Interactive( 0, VARIANT_FALSE ); application->put_Visible( 0, VARIANT_FALSE ); hr = application->Quit(); if(FAILED(hr)) { SIMANTICS_DEBUG("Close failed with %d\r\n", hr); return hr; } } // SIMANTICS_DEBUG("About to hide"); // application->put_Interactive( 0, VARIANT_FALSE ); // application->put_Visible( 0, VARIANT_FALSE ); // if(handles.empty()) // application->Quit(); return 0; } JNIEXPORT jdouble JNICALL Java_org_simantics_excel_Excel_getDouble(JNIEnv *env, jobject, jint handle, jint row, jint column) { SIMANTICS_DEBUG("getDouble(%d, %d)\r\n", row, column); Excel::_WorksheetPtr sheet = getWorksheet(handle); if(!sheet) return 0.0; // TODO: NAN Excel::RangePtr range = sheet->Cells; if(!range) return 0.0; // TODO: NAN variant_t val = range->Item[row+1][column+1]; if (val.vt != VT_NULL) { try { double d = val; SIMANTICS_DEBUG("%f\r\n",d); return d; } catch (...) { return 0.0; // TODO: NAN } } return 0.0; // TODO: NAN } JNIEXPORT jstring JNICALL Java_org_simantics_excel_Excel_getString(JNIEnv *env, jobject, jint handle, jint row, jint column) { USES_CONVERSION; //string val = getString(env, value); SIMANTICS_DEBUG("getString(%d, %d)\r\n", row, column); Excel::_WorksheetPtr sheet = getWorksheet(handle); if(!sheet) return NULL; Excel::RangePtr range = sheet->Cells; if(!range) return NULL; _bstr_t val = _bstr_t(range->Item[row + 1][column + 1]); //if (val.vt != VT_NULL) { // val.vt seems to be always VT_DISPATCH. //try { //this call will crash the application, if the cell is empty! //_bstr_t bstrt = val; //std::string text(val); //CString text(val); //text. //TCHAR text[1024]; // 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. //_stprintf(text, _T("%s"), (LPCTSTR)bstrt); //const char *text = bstrt; SIMANTICS_DEBUG("%s\r\n",text); string text(val); return env->NewStringUTF(text.c_str()); //} catch (...) { // return NULL; //} //} //SIMANTICS_DEBUG("%d\r\n",val.vt); //return NULL; }