mummy
1.0.2
|
00001 //---------------------------------------------------------------------------- 00002 // 00003 // $Id: MummyCsharpGenerator.cxx 517 2010-11-11 15:00:41Z david.cole $ 00004 // 00005 // $Author: david.cole $ 00006 // $Date: 2010-11-11 10:00:41 -0500 (Thu, 11 Nov 2010) $ 00007 // $Revision: 517 $ 00008 // 00009 // Copyright (C) 2006-2009 Kitware, Inc. 00010 // 00011 //---------------------------------------------------------------------------- 00012 00013 #include "MummyCsharpGenerator.h" 00014 #include "MummyLineOrientedTextFileReader.h" 00015 #include "MummyLog.h" 00016 #include "MummySettings.h" 00017 00018 #include "cableArrayType.h" 00019 #include "cableClass.h" 00020 #include "cableClassType.h" 00021 #include "cableConstructor.h" 00022 #include "cableEnumeration.h" 00023 #include "cableEnumerationType.h" 00024 #include "cableField.h" 00025 #include "cableFunctionType.h" 00026 #include "cableFundamentalType.h" 00027 #include "cableMethod.h" 00028 #include "cablePointerType.h" 00029 #include "cableReferenceType.h" 00030 #include "cableType.h" 00031 #include "cableTypedef.h" 00032 00033 #include "cxxFundamentalType.h" 00034 00035 #include "gxsys/RegularExpression.hxx" 00036 #include "gxsys/SystemTools.hxx" 00037 #include "gxsys/ios/sstream" 00038 #include "gxsys/stl/algorithm" 00039 #include "gxsys/stl/map" 00040 #include "gxsys/stl/set" 00041 #include "gxsys/stl/string" 00042 #include "gxsys/stl/vector" 00043 00044 #include <string.h> // strstr 00045 #include <stdio.h> // sprintf 00046 00047 00048 //---------------------------------------------------------------------------- 00049 MummyCsharpGenerator::MummyCsharpGenerator() 00050 { 00051 this->CurrentMethodId = 0; 00052 this->ClassLineNumber = 0; 00053 //this->MethodIdMap; // empty, as constructed 00054 //this->TargetInterface; // empty, as constructed 00055 //this->HintsMap; // empty, as constructed 00056 } 00057 00058 00059 //---------------------------------------------------------------------------- 00060 MummyCsharpGenerator::~MummyCsharpGenerator() 00061 { 00062 } 00063 00064 00065 //---------------------------------------------------------------------------- 00066 bool MummyCsharpGenerator::GenerateWrappers() 00067 { 00068 gxsys_stl::string elDllVariableName(this->GetSettings()->GetGroup()); 00069 elDllVariableName += "EL_dll"; 00070 00071 this->EmitCSharpWrapperClass(*GetStream(), elDllVariableName.c_str(), 00072 GetTargetClass()); 00073 00074 if (this->GetSettings()->GetVerbose()) 00075 { 00076 gxsys_stl::map<const gxsys_stl::string, gxsys_stl::string>::iterator it; 00077 for (it = this->HintsMap.begin(); it != this->HintsMap.end(); ++it) 00078 { 00079 LogInfo(mi_VerboseInfo, << it->first << ": '" << it->second << "'"); 00080 } 00081 } 00082 00083 return true; 00084 } 00085 00086 00087 //---------------------------------------------------------------------------- 00088 void MummyCsharpGenerator::SetTargetClass(const cable::Class *c) 00089 { 00090 this->MummyGenerator::SetTargetClass(c); 00091 00092 // Ensure HeaderFileReader is always called first with the target class. 00093 // (Presently, there is only one cached HeaderFileReader and it only reads 00094 // the file when it is first called... Subsequent calls ignore the input 00095 // data and simply return the cached HeaderFileReader. Multiple readers 00096 // may eventually be necessary to support BTX/ETX exclusion fully...) 00097 // 00098 this->GetHeaderFileReader(c); 00099 00100 // Only populate the lookup entries with stuff from the *parent* class 00101 // (and its parents...) That way, we can use the existence of a signature 00102 // in the table as evidence that a virtual is being overridden (for C# 00103 // keyword override purposes) or that a static is being redefined at a 00104 // more derived level (hence hiding the parent's definition and requiring 00105 // use of the C# keyword "new" to avoid the warning about hiding...) 00106 // 00107 ClearLookupEntries(); 00108 AddLookupEntries(GetWrappableParentClass(c)); 00109 00110 // Cache a map of the externalHints file: 00111 // 00112 this->CacheExternalHints(this->GetSettings()->GetExternalHints(c)); 00113 } 00114 00115 00116 //---------------------------------------------------------------------------- 00117 void MummyCsharpGenerator::CacheExternalHints(const gxsys_stl::string& hintsfile) 00118 { 00119 gxsys_stl::vector<gxsys_stl::string> hints; 00120 gxsys_stl::string line; 00121 00122 gxsys::RegularExpression re; 00123 re.compile("([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)"); 00124 00125 MummyLineOrientedTextFileReader reader; 00126 reader.SetFileName(hintsfile.c_str()); 00127 00128 this->HintsMap.clear(); 00129 00130 unsigned int n = reader.GetNumberOfLines(); 00131 unsigned int i = 0; 00132 for (i= 1; i<=n; ++i) 00133 { 00134 line = reader.GetLine(i); 00135 00136 if (!line.empty()) 00137 { 00138 if (re.find(line)) 00139 { 00140 gxsys_stl::string className = re.match(1); 00141 gxsys_stl::string methodName = re.match(2); 00142 gxsys_stl::string type = re.match(3); 00143 gxsys_stl::string count = re.match(4); 00144 gxsys_stl::string key(className + "::" + methodName); 00145 00146 if (this->HintsMap.find(key) == this->HintsMap.end()) 00147 { 00148 this->HintsMap[key] = line; 00149 } 00150 else 00151 { 00152 LogFileLineWarningMsg(hintsfile, i, mw_MultipleHints, 00153 "More than one line in the hints file for " << className 00154 << "::" << methodName); 00155 } 00156 } 00157 } 00158 } 00159 } 00160 00161 00162 //---------------------------------------------------------------------------- 00163 void MummyCsharpGenerator::AddTargetInterface(const gxsys_stl::string& iface) 00164 { 00165 if (this->TargetInterface != "") 00166 { 00167 LogWarning(mw_MultipleTargetInterfaces, 00168 "AddTargetInterface being called more than once. " << 00169 "Implementation currently only supports 1 interface. " << 00170 "Clobbering existing target interface: " << 00171 this->TargetInterface); 00172 } 00173 00174 this->TargetInterface = iface; 00175 } 00176 00177 00178 //---------------------------------------------------------------------------- 00179 bool MummyCsharpGenerator::HasTargetInterface(const char *iface) const 00180 { 00181 if (iface) 00182 { 00183 return this->TargetInterface == iface; 00184 } 00185 00186 return false; 00187 } 00188 00189 00190 //---------------------------------------------------------------------------- 00191 bool MummyCsharpGenerator::IsKeyword(const char *p) 00192 { 00193 static gxsys_stl::set<gxsys_stl::string> keywords; 00194 00195 if (0 == keywords.size()) 00196 { 00197 keywords.insert("abstract"); 00198 keywords.insert("as"); 00199 keywords.insert("base"); 00200 keywords.insert("bool"); 00201 keywords.insert("break"); 00202 keywords.insert("byte"); 00203 keywords.insert("case"); 00204 keywords.insert("catch"); 00205 keywords.insert("char"); 00206 keywords.insert("checked"); 00207 keywords.insert("class"); 00208 keywords.insert("const"); 00209 keywords.insert("continue"); 00210 keywords.insert("decimal"); 00211 keywords.insert("default"); 00212 keywords.insert("delegate"); 00213 keywords.insert("do"); 00214 keywords.insert("double"); 00215 keywords.insert("else"); 00216 keywords.insert("enum"); 00217 keywords.insert("event"); 00218 keywords.insert("explicit"); 00219 keywords.insert("extern"); 00220 keywords.insert("false"); 00221 keywords.insert("finally"); 00222 keywords.insert("fixed"); 00223 keywords.insert("float"); 00224 keywords.insert("for"); 00225 keywords.insert("foreach"); 00226 keywords.insert("goto"); 00227 keywords.insert("if"); 00228 keywords.insert("implicit"); 00229 keywords.insert("in"); 00230 keywords.insert("int"); 00231 keywords.insert("interface"); 00232 keywords.insert("internal"); 00233 keywords.insert("is"); 00234 keywords.insert("lock"); 00235 keywords.insert("long"); 00236 keywords.insert("namespace"); 00237 keywords.insert("new"); 00238 keywords.insert("null"); 00239 keywords.insert("object"); 00240 keywords.insert("operator"); 00241 keywords.insert("out"); 00242 keywords.insert("override"); 00243 keywords.insert("params"); 00244 keywords.insert("private"); 00245 keywords.insert("protected"); 00246 keywords.insert("public"); 00247 keywords.insert("readonly"); 00248 keywords.insert("ref"); 00249 keywords.insert("return"); 00250 keywords.insert("sbyte"); 00251 keywords.insert("sealed"); 00252 keywords.insert("short"); 00253 keywords.insert("sizeof"); 00254 keywords.insert("stackalloc"); 00255 keywords.insert("static"); 00256 keywords.insert("string"); 00257 keywords.insert("struct"); 00258 keywords.insert("switch"); 00259 keywords.insert("this"); 00260 keywords.insert("throw"); 00261 keywords.insert("true"); 00262 keywords.insert("try"); 00263 keywords.insert("typeof"); 00264 keywords.insert("uint"); 00265 keywords.insert("ulong"); 00266 keywords.insert("unchecked"); 00267 keywords.insert("unsafe"); 00268 keywords.insert("ushort"); 00269 keywords.insert("using"); 00270 keywords.insert("virtual"); 00271 keywords.insert("void"); 00272 keywords.insert("volatile"); 00273 keywords.insert("while"); 00274 } 00275 00276 gxsys_stl::set<gxsys_stl::string>::iterator it = keywords.find(gxsys_stl::string(p)); 00277 if (it != keywords.end()) 00278 { 00279 return true; 00280 } 00281 00282 return false; 00283 } 00284 00285 00286 //---------------------------------------------------------------------------- 00287 bool MummyCsharpGenerator::IsReservedMethodName(const gxsys_stl::string &name) 00288 { 00289 return ( 00290 name == "Equals" || 00291 name == "Finalize" || 00292 name == "GetHashCode" || 00293 name == "GetType" || 00294 name == "MemberwiseClone" || 00295 name == "Object" || 00296 name == "ToString"); 00297 } 00298 00299 00300 //---------------------------------------------------------------------------- 00301 gxsys_stl::string MummyCsharpGenerator::GetFundamentalTypeString(const cable::Type *t) 00302 { 00303 gxsys_stl::string s; 00304 00305 if (cable::Type::FundamentalTypeId == t->GetTypeId()) 00306 { 00307 switch (cxx::FundamentalType::SafeDownCast(t->GetCxxType().GetType())->GetId()) 00308 { 00309 case cxx::FundamentalType::UnsignedChar: 00310 s = "byte"; 00311 break; 00312 00313 case cxx::FundamentalType::UnsignedShortInt: 00314 s = "ushort"; 00315 break; 00316 00317 case cxx::FundamentalType::UnsignedInt: 00318 case cxx::FundamentalType::UnsignedLongInt: 00319 s = "uint"; 00320 break; 00321 00322 case cxx::FundamentalType::SignedChar: 00323 case cxx::FundamentalType::Char: 00324 s = "sbyte"; 00325 break; 00326 00327 case cxx::FundamentalType::ShortInt: 00328 s = "short"; 00329 break; 00330 00331 case cxx::FundamentalType::Int: 00332 case cxx::FundamentalType::LongInt: 00333 s = "int"; 00334 break; 00335 00336 case cxx::FundamentalType::Bool: 00337 s = "bool"; 00338 break; 00339 00340 case cxx::FundamentalType::Float: 00341 s = "float"; 00342 break; 00343 00344 case cxx::FundamentalType::Double: 00345 s = "double"; 00346 break; 00347 00348 case cxx::FundamentalType::Void: 00349 s = "void"; 00350 break; 00351 00352 case cxx::FundamentalType::UnsignedLongLongInt: 00353 s = "ulong"; 00354 break; 00355 00356 case cxx::FundamentalType::LongLongInt: 00357 s = "long"; 00358 break; 00359 00360 //case cxx::FundamentalType::WChar_t: 00361 //case cxx::FundamentalType::LongDouble: 00362 //case cxx::FundamentalType::ComplexFloat: 00363 //case cxx::FundamentalType::ComplexDouble: 00364 //case cxx::FundamentalType::ComplexLongDouble: 00365 //case cxx::FundamentalType::NumberOfTypes: 00366 00367 default: 00368 break; 00369 } 00370 } 00371 00372 if (s == "") 00373 { 00374 LogError(me_UnknownFundamentalType, 00375 << "Unhandled variable type. GetFundamentalTypeString returning the empty string..."); 00376 } 00377 00378 return s; 00379 } 00380 00381 00382 //---------------------------------------------------------------------------- 00383 gxsys_stl::string MummyCsharpGenerator::GetWrappedMethodName(const cable::Method *m) 00384 { 00385 gxsys_stl::string name(m->GetName()); 00386 00387 if (IsReservedMethodName(name)) 00388 { 00389 name = name + "Wrapper"; 00390 00391 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_ReservedMethodName, 00392 << "Reserved method name '" << m->GetName() << "' used. Rename it to eliminate this warning..."); 00393 } 00394 00395 return name; 00396 } 00397 00398 00399 //---------------------------------------------------------------------------- 00400 gxsys_stl::string GetWrappedEnumName(const cable::Enumeration *e) 00401 { 00402 gxsys_stl::string ename(e->GetName()); 00403 00404 // Don't name unnamed enums with invalid C#/C++ identifiers like "$"... 00405 // 00406 if (ename == "" || 00407 strstr(ename.c_str(), "$")) 00408 { 00409 if (e->Begin() != e->End()) 00410 { 00411 ename = *(e->Begin()); 00412 ename += "_WrapperEnum"; 00413 } 00414 else 00415 { 00416 ename = "WARNING_unnamed_enum"; 00417 } 00418 00419 LogFileLineWarningMsg(e->GetFile(), e->GetLine(), mw_UnnamedEnum, 00420 "Unnamed enum found. Name it to eliminate this warning..."); 00421 } 00422 00423 return ename; 00424 } 00425 00426 00427 //---------------------------------------------------------------------------- 00428 bool ExtractTypeAndCountFromHintLine( 00429 const gxsys_stl::string& hint, 00430 gxsys_stl::string& type, 00431 gxsys_stl::string& count 00432 ) 00433 { 00434 gxsys::RegularExpression re; 00435 re.compile("([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)"); 00436 00437 if (re.find(hint)) 00438 { 00439 //className = re.match(1); 00440 //methodName = re.match(2); 00441 type = re.match(3); 00442 count = re.match(4); 00443 return true; 00444 } 00445 00446 return false; 00447 } 00448 00449 00450 //---------------------------------------------------------------------------- 00451 bool ReturnTypeMatchesHintType( 00452 cable::Type *t, 00453 const gxsys_stl::string& type 00454 ) 00455 { 00456 gxsys_stl::string utype = gxsys::SystemTools::UpperCase(type); 00457 00458 // Init with the "not a real enum value" value: 00459 // 00460 cxx::FundamentalType::Id ftid = cxx::FundamentalType::NumberOfTypes; 00461 00462 // Values of 'type' currently present in the VTK hints file are: 00463 // 00464 if (utype == "301") { ftid = cxx::FundamentalType::Float; } 00465 else if (utype == "304") { ftid = cxx::FundamentalType::Int; } 00466 else if (utype == "307") { ftid = cxx::FundamentalType::Double; } 00467 else if (utype == "30A") { ftid = cxx::FundamentalType::Int; } // vtkIdType (could be 32 or 64 bit...) 00468 else if (utype == "2307") { ftid = cxx::FundamentalType::Double; } // 0x2307 == double* + something? 00469 00470 if (cxx::FundamentalType::NumberOfTypes == ftid) 00471 { 00472 LogWarning(mw_UnknownHintDataType, "Unknown externalHints data type string '" << type << "'"); 00473 } 00474 else if (IsFundamentalPointer(t, ftid)) 00475 { 00476 return true; 00477 } 00478 00479 return false; 00480 } 00481 00482 00483 //---------------------------------------------------------------------------- 00484 bool ExtractCountFromMethodDeclarationLine( 00485 const gxsys_stl::string& line, 00486 gxsys_stl::string& count 00487 ) 00488 { 00489 // Grudgingly allow this VTK-ism to creep into the mummy codebase to avoid 00490 // introducing a list of regular expressions in the MummySettings.xml file 00491 // just for VTK-wrapping-hint-based array size specification... 00492 // 00493 // In VTK, in addition to the explicit external hints file VTK/Wrapping/hints, 00494 // the following macros from VTK/Common/vtkSetGet.h are also recognized as 00495 // implicitly having hint sizes associated with them: 00496 // 00497 gxsys::RegularExpression re; 00498 00499 re.compile("^[\t ]*vtkGetVector([0-9]+)Macro\\(.*,.*\\)"); 00500 if (re.find(line)) 00501 { 00502 count = re.match(1); 00503 return true; 00504 } 00505 00506 re.compile("^[\t ]*vtkGetVectorMacro\\(.*,.*,.*([0-9]+).*\\)"); 00507 if (re.find(line)) 00508 { 00509 count = re.match(1); 00510 return true; 00511 } 00512 00513 re.compile("^[\t ]*vtkViewportCoordinateMacro\\(.*\\)"); 00514 if (re.find(line)) 00515 { 00516 count = "2"; 00517 return true; 00518 } 00519 00520 re.compile("^[\t ]*vtkWorldCoordinateMacro\\(.*\\)"); 00521 if (re.find(line)) 00522 { 00523 count = "3"; 00524 return true; 00525 } 00526 00527 return false; 00528 } 00529 00530 00531 //---------------------------------------------------------------------------- 00532 // Callers of GetMethodArgumentArraySize pass this value as "i" to query 00533 // about the return value of the method. Otherwise, "i" is presumed to be an 00534 // index (0 to cArgs-1) of one of the method's arguments. 00535 #define RETURN_VALUE (0x84848484) 00536 00537 00538 //---------------------------------------------------------------------------- 00539 gxsys_stl::string MummyCsharpGenerator::GetMethodArgumentArraySize(const cable::Class *c, 00540 const cable::Method *m, const cable::FunctionType *ft, unsigned int i) 00541 { 00542 gxsys_stl::string argArraySize; 00543 cable::Type *retType = 0; 00544 00545 // First check for an attribute directly in the source code: 00546 // 00547 gxsys_stl::string atts; 00548 00549 if (RETURN_VALUE == i) 00550 { 00551 atts = m->GetAttributes(); 00552 } 00553 else 00554 { 00555 atts = ft->GetArgumentAttributes(i); 00556 } 00557 00558 if (atts != "") 00559 { 00560 argArraySize = ExtractArraySize(atts); 00561 } 00562 00563 // If no direct hint, check the externalHints file, if any: 00564 // 00565 if ((argArraySize == "") && (this->HintsMap.size() > 0)) 00566 { 00567 // The VTK/Wrapping/hints file only tells us about the size of the pointer 00568 // returned by the method. Only return a non-empty array size from a 00569 // VTK/Wrapping/hints-style file if this is for a return value of a method: 00570 // 00571 if (RETURN_VALUE == i) 00572 { 00573 retType = ft->GetReturns(); 00574 if (!IsVoid(retType)) 00575 { 00576 gxsys_stl::string methodName(m->GetName()); 00577 gxsys_stl::map<const gxsys_stl::string, gxsys_stl::string>::iterator it; 00578 00579 const cable::Class *cIt = c; 00580 while (cIt != NULL && (argArraySize == "")) 00581 { 00582 gxsys_stl::string fullClassName(GetFullyQualifiedNameForCPlusPlus(cIt)); 00583 gxsys_stl::string key(fullClassName + "::" + methodName); 00584 gxsys_stl::string hintline; 00585 00586 it = this->HintsMap.find(key); 00587 if (it != this->HintsMap.end()) 00588 { 00589 hintline = it->second; 00590 00591 gxsys_stl::string type; 00592 gxsys_stl::string count; 00593 if (ExtractTypeAndCountFromHintLine(hintline, type, count) && 00594 ReturnTypeMatchesHintType(retType, type)) 00595 { 00596 argArraySize = count; 00597 LogVerboseInfo("using external array size hint: " << argArraySize << " " << key); 00598 } 00599 } 00600 00601 // If not found yet, keep looking up at parent class hints to see 00602 // if it is inherited. Method name and return type should still match 00603 // even if the hint is at the parent class level. 00604 // 00605 if (argArraySize == "") 00606 { 00607 cIt = GetParentClass(cIt); 00608 } 00609 } 00610 } 00611 } 00612 } 00613 00614 // If still no hint, see if the line declaring the method in the header 00615 // file uses a macro that gives us a hint about the size of the array... 00616 // 00617 if (argArraySize == "") 00618 { 00619 if (RETURN_VALUE == i) 00620 { 00621 retType = ft->GetReturns(); 00622 if (!IsVoid(retType) && !IsObjectPointer(retType)) 00623 { 00624 gxsys_stl::string line(this->GetHeaderFileReader(c)->GetLine(m->GetLine())); 00625 gxsys_stl::string count; 00626 00627 if (ExtractCountFromMethodDeclarationLine(line, count)) 00628 { 00629 argArraySize = count; 00630 00631 if (this->GetSettings()->GetVerbose()) 00632 { 00633 LogFileLineInfoMsg(c->GetFile(), m->GetLine(), mi_VerboseInfo, 00634 "inferred array size hint '" << count << 00635 "' from method declaration '" << line << "'"); 00636 } 00637 } 00638 } 00639 } 00640 } 00641 00642 return argArraySize; 00643 } 00644 00645 00646 //---------------------------------------------------------------------------- 00647 // 00648 // GetMethodSignature is very similar to EmitCSharpMethodDeclaration. 00649 // Changes in either may need to be made in both places... 00650 // 00651 gxsys_stl::string MummyCsharpGenerator::GetMethodSignature(const cable::Class *c, const cable::Method *m) 00652 { 00653 gxsys_ios::ostringstream os; 00654 00655 cable::FunctionType *ft = m->GetFunctionType(); 00656 unsigned int cArgs = ft->GetNumberOfArguments(); 00657 unsigned int i = 0; 00658 cable::Type *argType = 0; 00659 00660 // Method name: 00661 Emit(os, GetWrappedMethodName(m).c_str()); 00662 00663 // Open args: 00664 Emit(os, "("); 00665 00666 // The C# arg types: 00667 for (i= 0; i<cArgs; ++i) 00668 { 00669 argType = ft->GetArgument(i); 00670 00671 // Is arg an array? 00672 // 00673 gxsys_stl::string argArraySize(GetMethodArgumentArraySize(c, m, ft, i)); 00674 00675 // arg type: 00676 Emit(os, GetCSharpTypeString(argType, false, argArraySize != "").c_str()); 00677 00678 // array notation: 00679 if (argArraySize != "") 00680 { 00681 Emit(os, "[]"); 00682 } 00683 00684 if (i<cArgs-1) 00685 { 00686 Emit(os, ", "); 00687 } 00688 } 00689 00690 // Close args: 00691 Emit(os, ")"); 00692 00693 return os.str(); 00694 } 00695 00696 00697 //---------------------------------------------------------------------------- 00698 const char *MummyCsharpGenerator::GetArgName(cable::FunctionType *ftype, unsigned int i) 00699 { 00700 const char *p = ftype->GetArgumentName(i); 00701 00702 if (p && *p && !IsKeyword(p)) 00703 { 00704 return p; 00705 } 00706 00707 // Hacky, but for now: 00708 static char buf[32]; 00709 sprintf(buf, "arg%u", i); 00710 return buf; 00711 } 00712 00713 00714 //---------------------------------------------------------------------------- 00715 bool MummyCsharpGenerator::FundamentalTypeIsWrappable(const cable::Type* t) 00716 { 00717 if (cable::Type::FundamentalTypeId == t->GetTypeId()) 00718 { 00719 switch (cxx::FundamentalType::SafeDownCast(t->GetCxxType().GetType())->GetId()) 00720 { 00721 case cxx::FundamentalType::UnsignedChar: 00722 case cxx::FundamentalType::UnsignedShortInt: 00723 case cxx::FundamentalType::UnsignedInt: 00724 case cxx::FundamentalType::UnsignedLongInt: 00725 case cxx::FundamentalType::SignedChar: 00726 case cxx::FundamentalType::Char: 00727 case cxx::FundamentalType::ShortInt: 00728 case cxx::FundamentalType::Int: 00729 case cxx::FundamentalType::LongInt: 00730 case cxx::FundamentalType::Bool: 00731 case cxx::FundamentalType::Float: 00732 case cxx::FundamentalType::Double: 00733 case cxx::FundamentalType::Void: 00734 case cxx::FundamentalType::UnsignedLongLongInt: 00735 case cxx::FundamentalType::LongLongInt: 00736 return true; 00737 break; 00738 00739 case cxx::FundamentalType::WChar_t: 00740 case cxx::FundamentalType::LongDouble: 00741 case cxx::FundamentalType::ComplexFloat: 00742 case cxx::FundamentalType::ComplexDouble: 00743 case cxx::FundamentalType::ComplexLongDouble: 00744 case cxx::FundamentalType::NumberOfTypes: 00745 default: 00746 break; 00747 } 00748 } 00749 00750 return false; 00751 } 00752 00753 00754 //---------------------------------------------------------------------------- 00755 bool MummyCsharpGenerator::TypeIsWrappable(const cable::Type* t) 00756 { 00757 bool wrappable = false; 00758 00759 switch (t->GetTypeId()) 00760 { 00761 case cable::Type::EnumerationTypeId: 00762 wrappable = true; 00763 break; 00764 00765 case cable::Type::FundamentalTypeId: 00766 wrappable = FundamentalTypeIsWrappable(t); 00767 break; 00768 00769 case cable::Type::ArrayTypeId: 00770 wrappable = false;//TypeIsWrappable(cable::ArrayType::SafeDownCast(t)->GetTarget()); 00771 break; 00772 00773 case cable::Type::ClassTypeId: 00774 wrappable = ClassIsWrappable(cable::ClassType::SafeDownCast(t)->GetClass()); 00775 break; 00776 00777 case cable::Type::PointerTypeId: 00778 { 00779 cable::Type *nested_type = cable::PointerType::SafeDownCast(t)->GetTarget(); 00780 cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId(); 00781 00782 // Only pointers to enums, fundamentals and objects are wrappable 00783 // and then only if the nested type is also wrappable... 00784 // 00785 // A function pointer is "nearly" wrappable (as a delegate definition) 00786 // if its return type and all of its argument types are wrappable. 00787 // And it has a typedef that names it within this class (because 00788 // that typedef is the thing that generates the delegate def in 00789 // the C# class...) 00790 // 00791 // (This is what prevents pointers to pointers from being wrapped 00792 // in the general case...) 00793 // 00794 if (cable::Type::EnumerationTypeId == nested_type_id || 00795 cable::Type::FundamentalTypeId == nested_type_id || 00796 cable::Type::ClassTypeId == nested_type_id) 00797 { 00798 wrappable = TypeIsWrappable(nested_type); 00799 } 00800 else if (cable::Type::FunctionTypeId == nested_type_id) 00801 { 00802 gxsys_stl::string s; 00803 00804 // Only really wrappable if nested_type is wrappable and an 00805 // equivalent typedef name exists: 00806 // 00807 wrappable = TypeIsWrappable(nested_type) && 00808 EquivalentTypedefNameExists(this->GetTargetClass(), 00809 cable::FunctionType::SafeDownCast(nested_type), s); 00810 } 00811 else 00812 { 00813 wrappable = false; // as initialized... 00814 } 00815 } 00816 break; 00817 00818 case cable::Type::ReferenceTypeId: 00819 { 00820 cable::Type *nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget(); 00821 cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId(); 00822 00823 wrappable = false; // as initialized... 00824 00825 if (cable::Type::EnumerationTypeId == nested_type_id || 00826 cable::Type::FundamentalTypeId == nested_type_id || 00827 cable::Type::ClassTypeId == nested_type_id) 00828 { 00829 wrappable = TypeIsWrappable(nested_type); 00830 } 00831 else if (cable::Type::PointerTypeId == nested_type_id) 00832 { 00833 // References to pointers are allowed, but only if the pointer points 00834 // to a wrappable class... 00835 // 00836 cable::Type *doubly_nested_type = cable::PointerType::SafeDownCast(nested_type)->GetTarget(); 00837 cable::Type::TypeIdType doubly_nested_type_id = doubly_nested_type->GetTypeId(); 00838 00839 if (cable::Type::ClassTypeId == doubly_nested_type_id) 00840 { 00841 wrappable = TypeIsWrappable(doubly_nested_type); 00842 } 00843 } 00844 } 00845 break; 00846 00847 case cable::Type::OffsetTypeId: 00848 case cable::Type::MethodTypeId: 00849 wrappable = false; 00850 break; 00851 00852 case cable::Type::FunctionTypeId: 00853 wrappable = FunctionTypeIsWrappable(cable::FunctionType::SafeDownCast(t)); 00854 break; 00855 00856 default: 00857 wrappable = false; 00858 break; 00859 } 00860 00861 return wrappable; 00862 } 00863 00864 00865 //---------------------------------------------------------------------------- 00866 bool IsCxxMainStyleParamPair(const cable::FunctionType* ft, unsigned int i) 00867 { 00868 // Special case C++ "main" style functions, as indicated by *this* *exact* 00869 // *signature* including arg names: 00870 // (..., int argc, char* argv[], ...) 00871 // 00872 if (i < ft->GetNumberOfArguments()-1 && 00873 gxsys_stl::string("argc") == ft->GetArgumentName(i) && 00874 cable::Type::FundamentalTypeId == ft->GetArgument(i)->GetTypeId() && 00875 cxx::FundamentalType::Int == cxx::FundamentalType::SafeDownCast(ft->GetArgument(i)->GetCxxType().GetType())->GetId() && 00876 gxsys_stl::string("argv") == ft->GetArgumentName(i+1) && 00877 IsCharPointerPointer(ft->GetArgument(i+1)) 00878 ) 00879 { 00880 return true; 00881 } 00882 00883 return false; 00884 } 00885 00886 00887 //---------------------------------------------------------------------------- 00888 bool MummyCsharpGenerator::FunctionTypeIsWrappable(const cable::FunctionType* ft) 00889 { 00890 bool wrappable = true; 00891 00892 cable::Type *argType = 0; 00893 cable::Type *retType = 0; 00894 unsigned int i = 0; 00895 unsigned int cArgs = ft->GetNumberOfArguments(); 00896 00897 retType = ft->GetReturns(); 00898 wrappable = TypeIsWrappable(retType); 00899 00900 for (i= 0; wrappable && i<cArgs; ++i) 00901 { 00902 argType = ft->GetArgument(i); 00903 wrappable = TypeIsWrappable(argType); 00904 00905 // If not wrappable because argType is "char**" but it is a cxx main style 00906 // param pair, then go ahead and say it is wrappable... 00907 // 00908 if (!wrappable && IsCxxMainStyleParamPair(ft, i-1)) 00909 { 00910 wrappable = true; 00911 } 00912 } 00913 00914 return wrappable; 00915 } 00916 00917 00918 //---------------------------------------------------------------------------- 00919 bool MummyCsharpGenerator::MethodWrappableAsEvent(const cable::Method* m, const cable::Context::Access& access) 00920 { 00921 bool wrappableAsEvent = false; 00922 gxsys_stl::string atts; 00923 00924 if (m) 00925 { 00926 if (cable::Context::Public == access) 00927 { 00928 if (cable::Function::FunctionId == m->GetFunctionId() || 00929 cable::Function::MethodId == m->GetFunctionId()) 00930 { 00931 wrappableAsEvent = HasAttribute(m, "gccxml(iwhEvent)"); 00932 } 00933 } 00934 } 00935 00936 return wrappableAsEvent; 00937 } 00938 00939 //---------------------------------------------------------------------------- 00940 bool MummyCsharpGenerator::MethodIsWrappable(const cable::Method* m, const cable::Context::Access& access) 00941 { 00942 bool wrappable = false; 00943 bool hasDeprecatedAttribute = false; 00944 bool hasExcludeAttribute = false; 00945 bool isExcludedViaBtxEtx = false; 00946 00947 if (m) 00948 { 00949 if (cable::Context::Public == access) 00950 { 00951 if (cable::Function::FunctionId == m->GetFunctionId() || 00952 cable::Function::MethodId == m->GetFunctionId()) 00953 { 00954 if (FunctionTypeIsWrappable(m->GetFunctionType())) 00955 { 00956 wrappable = true; 00957 } 00958 } 00959 } 00960 } 00961 00962 if (m && wrappable) 00963 { 00964 hasDeprecatedAttribute = HasAttribute(m, "deprecated"); 00965 hasExcludeAttribute = HasAttribute(m, "gccxml(iwhExclude)"); 00966 00967 if (hasDeprecatedAttribute || hasExcludeAttribute) 00968 { 00969 wrappable = false; 00970 } 00971 } 00972 00973 if (m && wrappable) 00974 { 00975 cable::Class* c = cable::Class::SafeDownCast(m->GetContext()); 00976 00977 // BTX ETX style exclusion can only be applied to methods of the current target 00978 // class... We need to add multiple HeaderFileReader support to enable BTX ETX style 00979 // exclusion fully (including parent class method exclusion for purposes of constructing 00980 // the initial "what virtual methods do I inherit?" table...) 00981 // 00982 if (c && c == this->GetTargetClass() && 00983 this->GetHeaderFileReader(c)->IsLineExcluded(m->GetLine())) 00984 { 00985 isExcludedViaBtxEtx = true; 00986 wrappable = false; 00987 } 00988 } 00989 00990 if (this->GetSettings()->GetVerbose()) 00991 { 00992 if (m) 00993 { 00994 if (cable::Context::Public == access) 00995 { 00996 if (cable::Function::FunctionId == m->GetFunctionId() || 00997 cable::Function::MethodId == m->GetFunctionId()) 00998 { 00999 if (wrappable) 01000 { 01001 LogInfo(mi_VerboseInfo, << m->GetNameOfClass() << " '" << m->GetName() 01002 << "' is wrappable..." << gxsys_ios::endl); 01003 } 01004 else 01005 { 01006 if (hasDeprecatedAttribute) 01007 { 01008 LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName() 01009 << "' could not be wrapped because it is marked with the 'deprecated' attribute..." << gxsys_ios::endl); 01010 } 01011 else if (hasExcludeAttribute) 01012 { 01013 LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName() 01014 << "' could not be wrapped because it is marked with the 'gccxml(iwhExclude)' attribute..." << gxsys_ios::endl); 01015 } 01016 else if (isExcludedViaBtxEtx) 01017 { 01018 LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName() 01019 << "' could not be wrapped because it is in between begin/end exclude markers (BTX/ETX)..." << gxsys_ios::endl); 01020 } 01021 else 01022 { 01023 LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName() 01024 << "' could not be wrapped because of its return type or one of its arguments' types..." << gxsys_ios::endl); 01025 } 01026 } 01027 } 01028 else 01029 { 01030 LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName() 01031 << "' could not be wrapped because it's not a function or method..." << gxsys_ios::endl); 01032 } 01033 } 01034 else 01035 { 01036 LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName() 01037 << "' is not considered for wrapping because of its non-public access level..." << gxsys_ios::endl); 01038 } 01039 } 01040 else 01041 { 01042 LogWarning(mw_CouldNotWrap, << "NULL m!!" << gxsys_ios::endl); 01043 } 01044 } 01045 01046 return wrappable; 01047 } 01048 01049 01050 //---------------------------------------------------------------------------- 01051 bool MummyCsharpGenerator::ClassIsWrappable(const cable::Class* c) 01052 { 01053 return MummyGenerator::ClassIsWrappable(c); 01054 } 01055 01056 01057 //---------------------------------------------------------------------------- 01058 const cable::Class* MummyCsharpGenerator::GetWrappableParentClass(const cable::Class *c) 01059 { 01060 const cable::Class* wrappableParent = GetParentClass(c); 01061 01062 while (wrappableParent && !this->ClassIsWrappable(wrappableParent)) 01063 { 01064 wrappableParent = GetParentClass(wrappableParent); 01065 } 01066 01067 return wrappableParent; 01068 } 01069 01070 01071 //---------------------------------------------------------------------------- 01072 // 01073 // WARNING: GetIsRefArg, GetPInvokeTypeString and GetCSharpTypeString need to 01074 // stay in sync. Changes in one likely imply that changes in the other are 01075 // also required... 01076 // 01077 // This function needs to stay in sync with the case in GetCSharpTypeString 01078 // where "ref " is prepended to the C# type string... If "ref " is prepended 01079 // then this function should return true. 01080 // 01081 bool MummyCsharpGenerator::GetIsRefArg(const cable::Type *t) 01082 { 01083 cable::Type *nested_type = 0; 01084 01085 if (cable::Type::ReferenceTypeId == t->GetTypeId()) 01086 { 01087 nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget(); 01088 cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId(); 01089 01090 if (cable::Type::EnumerationTypeId == nested_type_id || 01091 cable::Type::FundamentalTypeId == nested_type_id) 01092 { 01093 return true; 01094 } 01095 } 01096 01097 return false; 01098 } 01099 01100 01101 //---------------------------------------------------------------------------- 01102 gxsys_stl::string /* MummyCsharpGenerator:: */ GetEnumerationTypeString(const cable::Type *t) 01103 { 01104 gxsys_stl::string s; 01105 cable::Enumeration* e = cable::EnumerationType::SafeDownCast(t)->GetEnumeration(); 01106 01107 s = GetFullyQualifiedNameForCSharp(e); 01108 01109 // Don't name unnamed enums with invalid C#/C++ identifiers like "$"... 01110 // 01111 if (strstr(s.c_str(), "$")) 01112 { 01113 s = "uint /* WARNING_unnamed_enum */"; 01114 } 01115 01116 return s; 01117 } 01118 01119 01120 //---------------------------------------------------------------------------- 01121 // 01122 // WARNING: GetIsRefArg, GetPInvokeTypeString and GetCSharpTypeString need to 01123 // stay in sync. Changes in one likely imply that changes in the other are 01124 // also required... 01125 // 01126 gxsys_stl::string MummyCsharpGenerator::GetPInvokeTypeString(const cable::Type *t, bool forReturn, bool isArray, bool forDelegate) 01127 { 01128 gxsys_stl::string s; 01129 cable::Type *nested_type = 0; 01130 01131 switch (t->GetTypeId()) 01132 { 01133 case cable::Type::EnumerationTypeId: 01134 s = GetEnumerationTypeString(t); 01135 break; 01136 01137 case cable::Type::FundamentalTypeId: 01138 s = GetFundamentalTypeString(t); 01139 01140 // C# byte maps automatically to C++ bool via PInvoke 01141 // 01142 if (s == "bool") 01143 { 01144 s = "byte"; 01145 } 01146 break; 01147 01148 case cable::Type::ArrayTypeId: 01149 s = "ERROR_ArrayTypeId_not_yet_implemented"; 01150 LogError(me_InternalError, << s.c_str()); 01151 break; 01152 01153 case cable::Type::ClassTypeId: 01154 //s = cable::ClassType::SafeDownCast(t)->GetClass()->GetName(); 01155 s = GetWrappedClassNameFullyQualified(cable::ClassType::SafeDownCast(t)->GetClass()); 01156 break; 01157 01158 case cable::Type::PointerTypeId: 01159 nested_type = cable::PointerType::SafeDownCast(t)->GetTarget(); 01160 01161 if (IsObject(nested_type)) 01162 { 01163 if (forReturn || forDelegate) 01164 { 01165 s = "IntPtr"; 01166 } 01167 else 01168 { 01169 cable::Class *c = cable::ClassType::SafeDownCast(nested_type)->GetClass(); 01170 if (IsUtilityClass(c)) 01171 { 01172 //s = c->GetName(); 01173 s = GetWrappedClassNameFullyQualified(c); 01174 } 01175 else 01176 { 01177 s = "HandleRef"; 01178 } 01179 } 01180 } 01181 else if (IsChar(nested_type)) 01182 { 01183 if (forReturn) 01184 { 01185 s = "IntPtr"; 01186 } 01187 else 01188 { 01189 s = "string"; 01190 } 01191 } 01192 else if (IsVoid(nested_type)) 01193 { 01194 s = "IntPtr"; 01195 } 01196 else if (cable::Type::FundamentalTypeId == nested_type->GetTypeId()) 01197 { 01198 if (isArray && !forReturn) 01199 { 01200 s = GetPInvokeTypeString(nested_type, forReturn, isArray, forDelegate); 01201 } 01202 else 01203 { 01204 s = "IntPtr"; 01205 } 01206 } 01207 else if (cable::Type::PointerTypeId == nested_type->GetTypeId()) 01208 { 01209 if (IsCharPointer(nested_type)) 01210 { 01211 s = "[In, Out] string[]"; 01212 } 01213 else 01214 { 01215 s = "IntPtr /* pointer-to-pointer */"; 01216 } 01217 } 01218 else if (cable::Type::FunctionTypeId == nested_type->GetTypeId()) 01219 { 01220 if (!EquivalentTypedefNameExists(this->GetTargetClass(), 01221 cable::FunctionType::SafeDownCast(nested_type), s)) 01222 { 01223 s = "ERROR_No_equivalent_typedef_name_for_function_pointer"; 01224 LogError(me_InternalError, << s.c_str()); 01225 } 01226 } 01227 else 01228 { 01229 s = "ERROR_PointerTypeId_not_yet_implemented_for_nested_type"; 01230 LogError(me_InternalError, << s.c_str()); 01231 } 01232 break; 01233 01234 case cable::Type::ReferenceTypeId: 01235 { 01236 cable::Type *nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget(); 01237 cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId(); 01238 01239 s = "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type"; 01240 01241 if (cable::Type::EnumerationTypeId == nested_type_id || 01242 cable::Type::FundamentalTypeId == nested_type_id || 01243 cable::Type::ClassTypeId == nested_type_id) 01244 { 01245 s = GetPInvokeTypeString(nested_type, forReturn, isArray, forDelegate); 01246 01247 if (!isArray && (cable::Type::EnumerationTypeId == nested_type_id || 01248 cable::Type::FundamentalTypeId == nested_type_id)) 01249 { 01250 if (forReturn) 01251 { 01252 s = "IntPtr"; 01253 } 01254 else 01255 { 01256 s = gxsys_stl::string("ref ") + s; 01257 } 01258 } 01259 } 01260 else if (cable::Type::PointerTypeId == nested_type_id) 01261 { 01262 // References to pointers are allowed, but only if the pointer points 01263 // to a wrappable class... 01264 // 01265 cable::Type *doubly_nested_type = cable::PointerType::SafeDownCast(nested_type)->GetTarget(); 01266 cable::Type::TypeIdType doubly_nested_type_id = doubly_nested_type->GetTypeId(); 01267 01268 if (cable::Type::ClassTypeId == doubly_nested_type_id) 01269 { 01270 s = GetPInvokeTypeString(nested_type, forReturn, isArray, forDelegate); 01271 } 01272 } 01273 01274 if (s == "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type") 01275 { 01276 LogError(me_InternalError, << s.c_str()); 01277 } 01278 } 01279 break; 01280 01281 case cable::Type::OffsetTypeId: 01282 case cable::Type::MethodTypeId: 01283 case cable::Type::FunctionTypeId: 01284 default: 01285 s = "ERROR_No_CSharp_type_for_cable_Type_TypeId"; 01286 LogError(me_InternalError, << s.c_str()); 01287 break; 01288 } 01289 01290 return s; 01291 } 01292 01293 01294 //---------------------------------------------------------------------------- 01295 // 01296 // WARNING: GetIsRefArg, GetPInvokeTypeString and GetCSharpTypeString need to 01297 // stay in sync. Changes in one likely imply that changes in the other are 01298 // also required... 01299 // 01300 gxsys_stl::string MummyCsharpGenerator::GetCSharpTypeString(const cable::Type *t, bool forReturn, bool isArray) 01301 { 01302 gxsys_stl::string s; 01303 cable::Type *nested_type = 0; 01304 01305 switch (t->GetTypeId()) 01306 { 01307 case cable::Type::EnumerationTypeId: 01308 s = GetEnumerationTypeString(t); 01309 break; 01310 01311 case cable::Type::FundamentalTypeId: 01312 s = GetFundamentalTypeString(t); 01313 break; 01314 01315 case cable::Type::ArrayTypeId: 01316 s = "ERROR_ArrayTypeId_not_yet_implemented"; 01317 LogError(me_InternalError, << s.c_str()); 01318 break; 01319 01320 case cable::Type::ClassTypeId: 01321 //s = cable::ClassType::SafeDownCast(t)->GetClass()->GetName(); 01322 s = GetWrappedClassNameFullyQualified(cable::ClassType::SafeDownCast(t)->GetClass()); 01323 break; 01324 01325 case cable::Type::PointerTypeId: 01326 nested_type = cable::PointerType::SafeDownCast(t)->GetTarget(); 01327 01328 if (IsObject(nested_type)) 01329 { 01330 s = GetCSharpTypeString(nested_type, forReturn, isArray); 01331 } 01332 else if (IsChar(nested_type)) 01333 { 01334 s = "string"; 01335 } 01336 else if (IsVoid(nested_type)) 01337 { 01338 s = "IntPtr"; 01339 } 01340 else if (cable::Type::FundamentalTypeId == nested_type->GetTypeId()) 01341 { 01342 if (isArray) 01343 { 01344 s = GetCSharpTypeString(nested_type, forReturn, isArray); 01345 } 01346 else 01347 { 01348 s = "IntPtr"; 01349 } 01350 } 01351 else if (cable::Type::PointerTypeId == nested_type->GetTypeId()) 01352 { 01353 s = GetCSharpTypeString(nested_type, forReturn, isArray); 01354 01355 if (IsCharPointer(nested_type)) 01356 { 01357 s += "[]"; 01358 } 01359 else 01360 { 01361 s += " /* pointer-to-pointer */ "; 01362 } 01363 } 01364 else if (cable::Type::FunctionTypeId == nested_type->GetTypeId()) 01365 { 01366 s = GetCSharpTypeString(nested_type, forReturn, isArray); 01367 } 01368 else 01369 { 01370 s = "ERROR_PointerTypeId_not_yet_implemented_for_nested_type"; 01371 LogError(me_InternalError, << s.c_str()); 01372 } 01373 break; 01374 01375 case cable::Type::ReferenceTypeId: 01376 { 01377 cable::Type *nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget(); 01378 cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId(); 01379 01380 s = "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type"; 01381 01382 if (cable::Type::EnumerationTypeId == nested_type_id || 01383 cable::Type::FundamentalTypeId == nested_type_id || 01384 cable::Type::ClassTypeId == nested_type_id) 01385 { 01386 s = GetCSharpTypeString(nested_type, forReturn, isArray); 01387 01388 if (!isArray && (cable::Type::EnumerationTypeId == nested_type_id || 01389 cable::Type::FundamentalTypeId == nested_type_id)) 01390 { 01391 if (forReturn) 01392 { 01393 s = "IntPtr"; 01394 } 01395 else if (s == "bool") 01396 { 01397 // Special case: transform "ref bool" args to "ref byte" args so 01398 // that we can call the PInvoke method, which changes all "bool" 01399 // to "byte" -- we don't do it in the non-ref case because it works 01400 // automatically and "bool" is a nicer C# signature. But in the ref 01401 // case, we need: 01402 // 01403 s = gxsys_stl::string("ref byte"); 01404 } 01405 else 01406 { 01407 s = gxsys_stl::string("ref ") + s; 01408 } 01409 } 01410 } 01411 else if (cable::Type::PointerTypeId == nested_type_id) 01412 { 01413 // References to pointers are allowed, but only if the pointer points 01414 // to a wrappable class... 01415 // 01416 cable::Type *doubly_nested_type = cable::PointerType::SafeDownCast(nested_type)->GetTarget(); 01417 cable::Type::TypeIdType doubly_nested_type_id = doubly_nested_type->GetTypeId(); 01418 01419 if (cable::Type::ClassTypeId == doubly_nested_type_id) 01420 { 01421 s = GetCSharpTypeString(doubly_nested_type, forReturn, isArray); 01422 } 01423 } 01424 01425 if (s == "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type") 01426 { 01427 LogError(me_InternalError, << s.c_str()); 01428 } 01429 } 01430 break; 01431 01432 case cable::Type::FunctionTypeId: 01433 if (!EquivalentTypedefNameExists(this->GetTargetClass(), 01434 cable::FunctionType::SafeDownCast(t), s)) 01435 { 01436 s = "ERROR_No_equivalent_typedef_name_for_function_pointer"; 01437 LogError(me_InternalError, << s.c_str()); 01438 } 01439 break; 01440 01441 case cable::Type::OffsetTypeId: 01442 case cable::Type::MethodTypeId: 01443 default: 01444 s = "ERROR_No_CSharp_type_for_cable_Type_TypeId"; 01445 LogError(me_InternalError, << s.c_str()); 01446 break; 01447 } 01448 01449 return s; 01450 } 01451 01452 01453 //---------------------------------------------------------------------------- 01454 class MethodInstance 01455 { 01456 public: 01457 const cable::Class* Class; 01458 const cable::Method* Method; 01459 01460 MethodInstance(const cable::Class* c, const cable::Method* m) : 01461 Class(c), Method(m) 01462 { 01463 } 01464 }; 01465 01466 01467 //---------------------------------------------------------------------------- 01468 gxsys_stl::map<gxsys_stl::string, MethodInstance> OtherMethods; 01469 gxsys_stl::map<gxsys_stl::string, MethodInstance> StaticMethods; 01470 gxsys_stl::map<gxsys_stl::string, MethodInstance> VirtualMethods; 01471 gxsys_stl::map<gxsys_stl::string, MethodInstance> WrappedMethods; 01472 gxsys_stl::map<gxsys_stl::string, MethodInstance> WrappedEnums; // in this case all MethodInstance.Method members are null 01473 01474 01475 //---------------------------------------------------------------------------- 01476 void MummyCsharpGenerator::ClearLookupEntries() 01477 { 01478 OtherMethods.clear(); 01479 StaticMethods.clear(); 01480 VirtualMethods.clear(); 01481 WrappedMethods.clear(); 01482 WrappedEnums.clear(); 01483 01484 // Pretend that "System.Object" is in our inheritance chain and that its 01485 // virtual method signatures exist in our lookup map: 01486 // 01487 // VirtualMethods.insert(gxsys_stl::make_pair("Equals(object)", MethodInstance(0, 0))); 01488 // VirtualMethods.insert(gxsys_stl::make_pair("Finalize()", MethodInstance(0, 0))); 01489 // VirtualMethods.insert(gxsys_stl::make_pair("GetHashCode()", MethodInstance(0, 0))); 01490 // VirtualMethods.insert(gxsys_stl::make_pair("GetType()", MethodInstance(0, 0))); 01491 // VirtualMethods.insert(gxsys_stl::make_pair("MemberwiseClone()", MethodInstance(0, 0))); 01492 // VirtualMethods.insert(gxsys_stl::make_pair("Object()", MethodInstance(0, 0))); 01493 // VirtualMethods.insert(gxsys_stl::make_pair("ToString()", MethodInstance(0, 0))); 01494 } 01495 01496 01497 //---------------------------------------------------------------------------- 01498 void MummyCsharpGenerator::AddLookupEntries(const cable::Class* c) 01499 { 01500 if (c) 01501 { 01502 const cable::Class *parent = GetWrappableParentClass(c); 01503 01504 if (parent) 01505 { 01506 AddLookupEntries(parent); 01507 } 01508 01509 for(cable::Context::Iterator it = c->Begin(); it != c->End(); ++it) 01510 { 01511 cable::Method *m = cable::Method::SafeDownCast(*it); 01512 01513 if (m && MethodIsWrappable(m, it.GetAccess())) 01514 { 01515 if (m->GetVirtual()) 01516 { 01517 VirtualMethods.insert(gxsys_stl::make_pair(GetMethodSignature(c, m), MethodInstance(c, m))); 01518 } 01519 else if (m->GetStatic()) 01520 { 01521 StaticMethods.insert(gxsys_stl::make_pair(GetMethodSignature(c, m), MethodInstance(c, m))); 01522 } 01523 else 01524 { 01525 OtherMethods.insert(gxsys_stl::make_pair(GetMethodSignature(c, m), MethodInstance(c, m))); 01526 } 01527 } 01528 01529 if (!m) 01530 { 01531 cable::Enumeration *e = cable::Enumeration::SafeDownCast(*it); 01532 01533 if (e && (cable::Context::Public == it.GetAccess())) 01534 { 01535 WrappedEnums.insert(gxsys_stl::make_pair(GetWrappedEnumName(e), MethodInstance(c, 0))); 01536 } 01537 } 01538 } 01539 } 01540 } 01541 01542 01543 //---------------------------------------------------------------------------- 01544 void MummyCsharpGenerator::DumpLookupEntries() 01545 { 01546 gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it; 01547 01548 LogInfo(mi_Info, << "<DumpLookupEntries>"); 01549 LogInfo(mi_Info, << "inherited static methods:"); 01550 for (it= StaticMethods.begin(); it!=StaticMethods.end(); ++it) 01551 { 01552 LogInfo(mi_Info, << " " << it->first); 01553 } 01554 01555 LogInfo(mi_Info, << "inherited virtual methods:"); 01556 for (it= VirtualMethods.begin(); it!=VirtualMethods.end(); ++it) 01557 { 01558 LogInfo(mi_Info, << " " << it->first); 01559 } 01560 01561 LogInfo(mi_Info, << "inherited other methods:"); 01562 for (it= OtherMethods.begin(); it!=OtherMethods.end(); ++it) 01563 { 01564 LogInfo(mi_Info, << " " << it->first); 01565 } 01566 01567 LogInfo(mi_Info, << "wrapped methods:"); 01568 for (it= WrappedMethods.begin(); it!=WrappedMethods.end(); ++it) 01569 { 01570 LogInfo(mi_Info, << " " << it->first); 01571 } 01572 01573 LogInfo(mi_Info, << "wrapped enums:"); 01574 for (it= WrappedEnums.begin(); it!=WrappedEnums.end(); ++it) 01575 { 01576 LogInfo(mi_Info, << " " << it->first); 01577 } 01578 01579 LogInfo(mi_Info, << "</DumpLookupEntries>"); 01580 } 01581 01582 01583 //---------------------------------------------------------------------------- 01584 bool MummyCsharpGenerator::OtherMethodRedefined(const gxsys_stl::string &signature) 01585 { 01586 gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it = 01587 OtherMethods.find(signature); 01588 return it != OtherMethods.end(); 01589 } 01590 01591 01592 //---------------------------------------------------------------------------- 01593 bool MummyCsharpGenerator::StaticMethodRedefined(const gxsys_stl::string &signature) 01594 { 01595 gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it = 01596 StaticMethods.find(signature); 01597 return it != StaticMethods.end(); 01598 } 01599 01600 01601 //---------------------------------------------------------------------------- 01602 bool MummyCsharpGenerator::VirtualMethodOverridden(const gxsys_stl::string &signature) 01603 { 01604 gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it = 01605 VirtualMethods.find(signature); 01606 return it != VirtualMethods.end(); 01607 } 01608 01609 01610 //---------------------------------------------------------------------------- 01611 bool MummyCsharpGenerator::WrappedMethodExists(const gxsys_stl::string &signature) 01612 { 01613 gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it = 01614 WrappedMethods.find(signature); 01615 return it != WrappedMethods.end(); 01616 } 01617 01618 01619 //---------------------------------------------------------------------------- 01620 bool MummyCsharpGenerator::WrappedEnumExists(const gxsys_stl::string &name) 01621 { 01622 gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it = 01623 WrappedEnums.find(name); 01624 return it != WrappedEnums.end(); 01625 } 01626 01627 01628 //---------------------------------------------------------------------------- 01629 bool MummyCsharpGenerator::IsFactoryMethod(const cable::Class *c, const cable::Method *m) 01630 { 01631 if (m->GetStatic() && 01632 0 == m->GetFunctionType()->GetNumberOfArguments() && 01633 gxsys_stl::string(m->GetName()) == this->GetSettings()->GetFactoryMethod(c)) 01634 { 01635 return true; 01636 } 01637 01638 return false; 01639 } 01640 01641 01642 //---------------------------------------------------------------------------- 01643 bool MummyCsharpGenerator::IsDisposalMethod(const cable::Class *c, const cable::Method *m) 01644 { 01645 if (m->GetVirtual() && 01646 0 == m->GetFunctionType()->GetNumberOfArguments() && 01647 gxsys_stl::string(m->GetName()) == this->GetSettings()->GetDisposalMethod(c)) 01648 { 01649 return true; 01650 } 01651 01652 return false; 01653 } 01654 01655 01656 //---------------------------------------------------------------------------- 01657 bool MummyCsharpGenerator::MethodReturnValueIsCounted(const cable::Class *c, const cable::Method *m) 01658 { 01659 if (this->IsFactoryMethod(c, m)) 01660 { 01661 return true; 01662 } 01663 01664 if (HasAttribute(m, "gccxml(iwhCounted)")) 01665 { 01666 return true; 01667 } 01668 01669 gxsys_stl::string countedMethodsRegex(this->GetSettings()->GetCountedMethodsRegex(c)); 01670 if (!countedMethodsRegex.empty()) 01671 { 01672 gxsys::RegularExpression re; 01673 re.compile(countedMethodsRegex.c_str()); 01674 if (re.find(m->GetName())) 01675 { 01676 LogVerboseInfo( 01677 << "MethodReturnValueIsCounted match:" << gxsys_ios::endl 01678 << " countedMethodsRegex: " << countedMethodsRegex << gxsys_ios::endl 01679 << " method: " << c->GetName() << "::" << m->GetName() 01680 ); 01681 return true; 01682 } 01683 } 01684 01685 return false; 01686 } 01687 01688 01689 //---------------------------------------------------------------------------- 01690 gxsys_stl::string MummyCsharpGenerator::GetExportLayerFunctionName(const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname) 01691 { 01692 gxsys_stl::string s(GetFullyQualifiedName(c, "_")); 01693 s += "_"; 01694 s += mname; 01695 01696 if (this->IsFactoryMethod(c, m) || this->IsDisposalMethod(c, m) || mname == "new" || mname == "delete") 01697 { 01698 // No suffix... 01699 } 01700 else 01701 { 01702 // Append a unique-fying suffix... 01703 char idStr[32]; 01704 unsigned int methodId = 0; 01705 01706 gxsys_stl::map<const cable::Method*, unsigned int>::iterator it = this->MethodIdMap.find(m); 01707 if (it != this->MethodIdMap.end()) 01708 { 01709 methodId = it->second; 01710 } 01711 else 01712 { 01713 // Any methods passed in to here should have been inserted into the 01714 // MethodIdMap during a previous call to GatherWrappedMethods... 01715 // What happened...!?!? 01716 // 01717 LogError(me_InternalError, << "Could not find method in MethodIdMap."); 01718 } 01719 01720 sprintf(idStr, "%02u", methodId); 01721 s += "_"; 01722 s += idStr; 01723 } 01724 01725 return s; 01726 } 01727 01728 01729 //---------------------------------------------------------------------------- 01730 // 01731 // GetMethodSignature is very similar to EmitCSharpMethodDeclaration. 01732 // Changes in either may need to be made in both places... 01733 // 01734 void MummyCsharpGenerator::EmitCSharpMethodDeclaration(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, bool asProperty, bool useArg0AsReturn, const gxsys_stl::string& accessLevel) 01735 { 01736 gxsys_stl::string signature(GetMethodSignature(c, m)); 01737 01738 gxsys_stl::string arraySize; 01739 gxsys_stl::string s; 01740 cable::FunctionType *ft = m->GetFunctionType(); 01741 unsigned int cArgs = ft->GetNumberOfArguments(); 01742 unsigned int i = 0; 01743 cable::Type *argType = 0; 01744 cable::Type *retType = ft->GetReturns(); 01745 01746 i = RETURN_VALUE; 01747 01748 // If emitting a declaration based on a "property set" method, 01749 // the type of the first argument to the set method is the type 01750 // of the C# property... typically retType will be "void" when 01751 // this is the case... 01752 // 01753 if (asProperty && useArg0AsReturn) 01754 { 01755 if (!IsVoid(retType)) 01756 { 01757 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropSetReturnsNonVoid, 01758 "Method transformed to a property 'set' returns non-void. The return value will be ignored in generated code."); 01759 } 01760 01761 if (cArgs!=1) 01762 { 01763 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropSetUnexpectedArgCount, 01764 "Unexpected number of arguments for method transformed to a property 'set' - cArgs: " << cArgs); 01765 } 01766 01767 // :-) 01768 // 01769 // Pretend return type and attributes come from arg0 for the 01770 // rest of this method call: 01771 // 01772 if (cArgs!=0) 01773 { 01774 i = 0; 01775 retType = ft->GetArgument(0); 01776 } 01777 } 01778 01779 // Do attributes indicate an array? 01780 // 01781 arraySize = GetMethodArgumentArraySize(c, m, ft, i); 01782 01783 01784 // Public, protected, private, internal, hmmmm...? 01785 // 01786 Emit(os, accessLevel.c_str()); 01787 Emit(os, " "); 01788 01789 01790 if (m->GetStatic()) 01791 { 01792 // C# static == C++ static: 01793 // 01794 if (StaticMethodRedefined(signature)) 01795 { 01796 Emit(os, "new "); 01797 } 01798 01799 Emit(os, "static "); 01800 } 01801 01802 if (!asProperty) 01803 { 01804 if (m->GetVirtual()) 01805 { 01806 // C# : "virtual" or "override" ? 01807 // 01808 if (VirtualMethodOverridden(signature)) 01809 { 01810 Emit(os, "override "); 01811 } 01812 else 01813 { 01814 // If I am virtual, but my parent is not then: 01815 // 01816 if (OtherMethodRedefined(signature)) 01817 { 01818 Emit(os, "new "); 01819 } 01820 01821 Emit(os, "virtual "); 01822 } 01823 } 01824 else 01825 { 01826 if (OtherMethodRedefined(signature)) 01827 { 01828 Emit(os, "new "); 01829 } 01830 } 01831 } 01832 01833 // Return type. (Has special transformations for supporting collections 01834 // and enumerators. Method name + class supports target interface == 01835 // special generated code...) 01836 // 01837 gxsys_stl::string mname = m->GetName(); 01838 01839 if ((mname == "GetEnumerator") && 01840 this->HasTargetInterface("IEnumerable")) 01841 { 01842 Emit(os, "System.Collections.IEnumerator"); 01843 } 01844 else if ((mname == "GetCurrent") && 01845 this->HasTargetInterface("IEnumerator")) 01846 { 01847 Emit(os, "object"); 01848 } 01849 else 01850 { 01851 Emit(os, GetCSharpTypeString(retType, true, arraySize != "").c_str()); 01852 if (arraySize != "") 01853 { 01854 Emit(os, "[]"); 01855 } 01856 } 01857 01858 Emit(os, " "); 01859 01860 // Use the wrapped method name or the property name: 01861 // 01862 s = GetWrappedMethodName(m); 01863 if (asProperty) 01864 { 01865 s = ExtractDerivedName(s.c_str(), m, this->GetSettings()->GetVerbose()); 01866 } 01867 01868 Emit(os, s.c_str()); 01869 01870 if (!asProperty) 01871 { 01872 // Open args: 01873 Emit(os, "("); 01874 01875 // The C# args: 01876 for (i= 0; i<cArgs; ++i) 01877 { 01878 // If it's a CxxMain param pair, only declare the 2nd (string[] argv) part 01879 // of the pair... So, do nothing here and skip the 1st (int argc) part... 01880 // 01881 if (IsCxxMainStyleParamPair(ft, i)) 01882 { 01883 } 01884 else 01885 { 01886 argType = ft->GetArgument(i); 01887 01888 // Is arg an array? 01889 // 01890 arraySize = GetMethodArgumentArraySize(c, m, ft, i); 01891 01892 // arg type: 01893 Emit(os, GetCSharpTypeString(argType, false, arraySize != "").c_str()); 01894 01895 // array notation: 01896 if (arraySize != "") 01897 { 01898 Emit(os, "[]"); 01899 } 01900 01901 // arg name: 01902 Emit(os, " "); 01903 Emit(os, GetArgName(ft, i)); 01904 01905 if (i<cArgs-1) 01906 { 01907 Emit(os, ", "); 01908 } 01909 } 01910 } 01911 01912 // Close args: 01913 Emit(os, ")"); 01914 } 01915 } 01916 01917 01918 //---------------------------------------------------------------------------- 01919 void MummyCsharpGenerator::EmitCSharpDllImportDeclaration(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, const char *f, bool emitExceptionParams) 01920 { 01921 gxsys_stl::string arraySize; 01922 cable::FunctionType *ft = m->GetFunctionType(); 01923 unsigned int cArgs = ft->GetNumberOfArguments(); 01924 unsigned int cArgsEmitted = 0; 01925 unsigned int i = 0; 01926 cable::Type *argType = 0; 01927 cable::Type *retType = ft->GetReturns(); 01928 01929 Emit(os, "[DllImport("); 01930 Emit(os, dllname); 01931 Emit(os, ", EntryPoint = \""); 01932 Emit(os, f); 01933 Emit(os, "\")]"); 01934 Emit(os, "\n"); 01935 01936 // Does method return an array? 01937 // 01938 arraySize = GetMethodArgumentArraySize(c, m, ft, RETURN_VALUE); 01939 01940 EmitIndent(os); 01941 Emit(os, "internal static extern "); 01942 01943 if (mname == "new") 01944 { 01945 Emit(os, "IntPtr "); 01946 Emit(os, f); 01947 Emit(os, "(ref uint mteStatus, ref uint mteIndex, ref uint rawRefCount"); 01948 cArgsEmitted += 3; 01949 01950 if (emitExceptionParams) 01951 { 01952 Emit(os, ", ref uint mteExceptionIndex, ref IntPtr clonedException"); 01953 cArgsEmitted += 2; 01954 } 01955 01956 Emit(os, ");"); 01957 } 01958 else if (mname == "delete") 01959 { 01960 Emit(os, "void "); 01961 Emit(os, f); 01962 Emit(os, "(HandleRef pThis"); 01963 cArgsEmitted += 1; 01964 01965 if (emitExceptionParams) 01966 { 01967 Emit(os, ", ref uint mteExceptionIndex, ref IntPtr clonedException"); 01968 cArgsEmitted += 2; 01969 } 01970 01971 Emit(os, ");"); 01972 } 01973 else 01974 { 01975 Emit(os, GetPInvokeTypeString(retType, true, arraySize != "", false).c_str()); 01976 Emit(os, " "); 01977 Emit(os, f); 01978 Emit(os, "("); 01979 01980 if (!m->GetStatic()) 01981 { 01982 Emit(os, "HandleRef pThis"); 01983 cArgsEmitted += 1; 01984 01985 if (cArgs!=0) 01986 { 01987 Emit(os, ", "); 01988 } 01989 } 01990 01991 for (i= 0; i<cArgs; ++i) 01992 { 01993 argType = ft->GetArgument(i); 01994 01995 // Is arg an array? 01996 // 01997 arraySize = GetMethodArgumentArraySize(c, m, ft, i); 01998 01999 // array MarshalAs directive: 02000 if (arraySize != "") 02001 { 02002 Emit(os, "[MarshalAs(UnmanagedType.LPArray, SizeConst = "); 02003 Emit(os, arraySize.c_str()); 02004 Emit(os, ")] "); 02005 } 02006 02007 // arg type: 02008 Emit(os, GetPInvokeTypeString(argType, false, arraySize != "", false).c_str()); 02009 02010 // array notation: 02011 if (arraySize != "") 02012 { 02013 Emit(os, "[]"); 02014 } 02015 02016 // arg name: 02017 Emit(os, " "); 02018 Emit(os, GetArgName(ft, i)); 02019 02020 cArgsEmitted += 1; 02021 02022 if (i<cArgs-1) 02023 { 02024 Emit(os, ", "); 02025 } 02026 } 02027 02028 // Add "generated args" to method signatures that return object pointers: 02029 // 02030 if (!HasMapToType(retType) && IsObjectPointer(retType)) 02031 { 02032 if (cArgsEmitted) 02033 { 02034 Emit(os, ", "); 02035 } 02036 02037 Emit(os, "ref uint mteStatus, ref uint mteIndex, ref uint rawRefCount"); 02038 cArgsEmitted += 3; 02039 } 02040 02041 // And to those that handle wrapped exceptions: 02042 // 02043 if (emitExceptionParams) 02044 { 02045 if (cArgsEmitted) 02046 { 02047 Emit(os, ", "); 02048 } 02049 02050 Emit(os, "ref uint mteExceptionIndex, ref IntPtr clonedException"); 02051 cArgsEmitted += 2; 02052 } 02053 02054 // Close args: 02055 // 02056 Emit(os, ");"); 02057 } 02058 } 02059 02060 02061 //---------------------------------------------------------------------------- 02062 gxsys_stl::string GetQualifiedEventName(const cable::Method *m) 02063 { 02064 const cable::Class *c = cable::ClassType::SafeDownCast( 02065 cable::PointerType::SafeDownCast( 02066 m->GetFunctionType()->GetReturns() 02067 )->GetTarget())->GetClass(); 02068 02069 gxsys_stl::string eventName; 02070 02071 if (c && c->GetContext()) 02072 { 02073 eventName = c->GetContext()->GetName(); 02074 eventName += GetWrappedClassName(c); 02075 } 02076 else 02077 { 02078 eventName = "ERROR_invalid_input_to_GetQualifiedEventName"; 02079 LogError(me_InvalidArg, << eventName.c_str()); 02080 } 02081 02082 return eventName; 02083 } 02084 02085 02086 //---------------------------------------------------------------------------- 02087 gxsys_stl::string GetEventName(const cable::Method *m) 02088 { 02089 gxsys_stl::string eventName = GetWrappedClassName( 02090 cable::ClassType::SafeDownCast(cable::PointerType::SafeDownCast( 02091 m->GetFunctionType()->GetReturns() 02092 )->GetTarget())->GetClass() 02093 ); 02094 02095 return eventName; 02096 } 02097 02098 02099 //---------------------------------------------------------------------------- 02100 void MummyCsharpGenerator::EmitCSharpEvent(gxsys_ios::ostream& os, const char *, const cable::Class* c, const cable::Method* m, const gxsys_stl::string& eventName) 02101 { 02102 // Caller provides eventName because caller is the one with the knowledge 02103 // about whether there are multiple events with the same unqualified name 02104 // due to classes with the same name existing in multiple namespaces. 02105 // So, if there are not, eventName will be from "GetEventName", but if 02106 // there are, eventName will be from "GetQualifiedEventName"... 02107 // 02108 gxsys_stl::string e(eventName); 02109 gxsys_stl::string eFull; 02110 gxsys_stl::string mname(m->GetName()); 02111 02112 // An "event method" is expected to return a pointer to the event class 02113 // that it is supposed to wrap... If that's not true, the code generated 02114 // by this following block is likely not to compile! So make sure it's 02115 // true in your sources to be wrapped. 02116 // 02117 cable::FunctionType *ft = m->GetFunctionType(); 02118 cable::Type *retType = ft->GetReturns(); 02119 02120 if (retType->GetTypeId() != cable::Type::PointerTypeId) 02121 { 02122 LogFileLineErrorMsg(m->GetFile(), m->GetLine(), me_EventMethodIncorrectReturnType, 02123 "iwhEvent method '" << mname << "' does not return a pointer to an event object"); 02124 return; 02125 } 02126 02127 if (cable::PointerType::SafeDownCast(retType)->GetTarget()->GetTypeId() != 02128 cable::Type::ClassTypeId) 02129 { 02130 LogFileLineErrorMsg(m->GetFile(), m->GetLine(), me_EventMethodIncorrectReturnType, 02131 "iwhEvent method '" << mname << "' does not return a pointer to an event object"); 02132 return; 02133 } 02134 02135 eFull = GetWrappedClassNameFullyQualified(cable::ClassType::SafeDownCast( 02136 cable::PointerType::SafeDownCast(retType)->GetTarget())->GetClass()); 02137 02138 // Assumptions: 02139 // 02140 // (These could all be codified and made into non-assumptions, but for now 02141 // they all *are* assumptions...) 02142 // 02143 // There's a type called "Handler" in the Event class (typedef to a function pointer in unmanaged C++) 02144 // The typedef signature is "void blah(object sender, object args)" 02145 // There's a corresponding EventArgs class named the same but with "EventArgs" at the end 02146 // There's an AddHandler method in the Event class 02147 // There's a RemoveHandler method in the Event class 02148 // The handler is id'able by a C# "uint" 02149 02150 // Make this next section collapsible inside a "region": 02151 // 02152 EmitIndent(os); 02153 Emit(os, "#region "); 02154 Emit(os, e.c_str()); 02155 Emit(os, " event implementation details\n"); 02156 Emit(os, "\n"); 02157 02158 // A data member (*Impl) to hold the managed listeners: 02159 // 02160 EmitIndent(os); 02161 Emit(os, "private "); 02162 Emit(os, e.c_str()); 02163 Emit(os, "EventHandler "); 02164 Emit(os, e.c_str()); 02165 Emit(os, "Impl;\n"); 02166 02167 // A data member (*Instance) to cache the managed wrapper of the unmanaged 02168 // event object: 02169 // 02170 EmitIndent(os); 02171 Emit(os, "private "); 02172 Emit(os, eFull.c_str()); 02173 Emit(os, " "); 02174 Emit(os, e.c_str()); 02175 Emit(os, "Instance;\n"); 02176 02177 // A data member (*RelayHandler) and an id (*RelayHandlerId) for the handler 02178 // when we are actively connected... 02179 // 02180 EmitIndent(os); 02181 Emit(os, "private "); 02182 Emit(os, eFull.c_str()); 02183 Emit(os, ".Handler "); 02184 Emit(os, e.c_str()); 02185 Emit(os, "RelayHandler;\n"); 02186 EmitIndent(os); 02187 Emit(os, "private uint "); 02188 Emit(os, e.c_str()); 02189 Emit(os, "RelayHandlerId;\n"); 02190 Emit(os, "\n"); 02191 02192 // A listener to receive events from the unmanaged code and relay them on to 02193 // managed listeners. Conforms to event's "unmanaged" delegate signature. 02194 // (The delegate named "Handler" in the event class itself.) One improvement 02195 // we could make here would be to generate RelayHandler's signature based 02196 // on the actual signature of "Handler." 02197 // 02198 EmitIndent(os); 02199 Emit(os, "private void "); 02200 Emit(os, e.c_str()); 02201 Emit(os, "RelayHandlerMethod(IntPtr rawSender, IntPtr rawArgs)\n"); 02202 EmitIndent(os); 02203 Emit(os, "{\n"); 02204 EmitIndent(os, 2); 02205 Emit(os, "if (this."); 02206 Emit(os, e.c_str()); 02207 Emit(os, "Impl != null)\n"); 02208 EmitIndent(os, 2); 02209 Emit(os, "{\n"); 02210 EmitIndent(os, 3); 02211 Emit(os, eFull.c_str()); 02212 Emit(os, "EventArgs rv = null;\n"); 02213 EmitIndent(os, 3); 02214 Emit(os, "if (IntPtr.Zero != rawArgs)\n"); 02215 EmitIndent(os, 3); 02216 Emit(os, "{\n"); 02217 02218 02219 02220 02221 const cable::Class* cRetType = cable::ClassType::SafeDownCast( 02222 cable::PointerType::SafeDownCast(retType)->GetTarget() 02223 )->GetClass(); 02224 02225 gxsys_stl::string registerMethod = this->GetSettings()->GetRegisterMethod(cRetType); 02226 gxsys_stl::string unRegisterMethod = this->GetSettings()->GetUnRegisterMethod(cRetType); 02227 02228 02229 02230 02231 // Technique #1 : using "new" (and ignoring potential issues with 02232 // the mummy Runtime table... 02233 // 02234 EmitIndent(os, 4); 02235 Emit(os, "rv = new "); 02236 Emit(os, eFull.c_str()); 02237 Emit(os, "EventArgs(rawArgs, "); 02238 02239 if (!registerMethod.empty()) 02240 { 02241 Emit(os, "true"); 02242 } 02243 else 02244 { 02245 Emit(os, "false"); 02246 } 02247 02248 Emit(os, ", false);\n"); 02249 02250 if (!registerMethod.empty()) 02251 { 02252 EmitIndent(os, 4); 02253 Emit(os, "rv."); 02254 Emit(os, registerMethod.c_str()); 02255 Emit(os, ";\n"); 02256 } 02257 02258 02259 02260 02261 // Technique #2 : using "CreateWrappedObject" (and forcing a call 02262 // back across the boundary to "Register" the EventArgs if the wrapper 02263 // was just created...) 02264 // 02265 // This imposes an additional assumption/constraint on Event and EventArgs 02266 // classes. They must share Register/UnRegister methods for this to work 02267 // properly... 02268 // 02269 // Either that, or we need to get a "cable::Class*" to the EventArgs class 02270 // somehow (which we may or may not be able to do depending on how the 02271 // gccxml step and the input header files were crafted...) 02272 // 02273 //unsigned int indent = 3; 02274 //EmitIndent(os, indent+1); 02275 //Emit(os, "bool mteCreated;\n"); 02276 //EmitIndent(os, indent+1); 02277 //Emit(os, "rv = ("); 02278 //Emit(os, eFull.c_str()); 02279 //Emit(os, "EventArgs)\n"); 02280 //EmitIndent(os, indent+2); 02281 //Emit(os, "Kitware.mummy.Runtime.Methods.CreateWrappedObject(\n"); 02282 //EmitIndent(os, indent+3); 02283 //Emit(os, "\"class "); 02284 //Emit(os, eFull.c_str()); 02285 //Emit(os, "EventArgs\", rawArgs, "); 02286 02287 //if (!unRegisterMethod.empty()) 02288 // { 02289 // Emit(os, "true"); 02290 // } 02291 //else 02292 // { 02293 // Emit(os, "false"); 02294 // } 02295 02296 //Emit(os, ", out mteCreated"); 02297 //Emit(os, ");\n"); 02298 02299 //if (!registerMethod.empty()) 02300 // { 02301 // //if (this->MethodReturnValueIsCounted(c, m)) 02302 // // { 02303 // // EmitIndent(os, indent+1); 02304 // // Emit(os, "Returned object is counted already, (factory method or iwhCounted hint),\n"); 02305 // // EmitIndent(os, indent+1); 02306 // // Emit(os, "// no 'rv."); 02307 // // Emit(os, registerMethod.c_str()); 02308 // // Emit(os, "' call is necessary...\n"); 02309 // // } 02310 // //else 02311 // // { 02312 // EmitIndent(os, indent+1); 02313 // Emit(os, "if (mteCreated)\n"); 02314 // EmitIndent(os, indent+1); 02315 // Emit(os, "{\n"); 02316 // EmitIndent(os, indent+2); 02317 // Emit(os, "rv."); 02318 // Emit(os, registerMethod.c_str()); 02319 // Emit(os, ";\n"); 02320 // EmitIndent(os, indent+1); 02321 // Emit(os, "}\n"); 02322 // // } 02323 // } 02324 02325 02326 02327 02328 EmitIndent(os, 3); 02329 Emit(os, "}\n"); 02330 EmitIndent(os, 3); 02331 Emit(os, "this."); 02332 Emit(os, e.c_str()); 02333 Emit(os, "Impl(this, rv);\n"); 02334 EmitIndent(os, 2); 02335 Emit(os, "}\n"); 02336 EmitIndent(os); 02337 Emit(os, "}\n"); 02338 Emit(os, "\n"); 02339 02340 // Methods to add and remove the RelayHandler: 02341 // 02342 EmitIndent(os); 02343 Emit(os, "private void Add"); 02344 Emit(os, e.c_str()); 02345 Emit(os, "RelayHandler()\n"); 02346 EmitIndent(os); 02347 Emit(os, "{\n"); 02348 EmitIndent(os, 2); 02349 Emit(os, "if (0 == this."); 02350 Emit(os, e.c_str()); 02351 Emit(os, "RelayHandlerId)\n"); 02352 EmitIndent(os, 2); 02353 Emit(os, "{\n"); 02354 02355 EmitIndent(os, 3); 02356 Emit(os, "this."); 02357 Emit(os, e.c_str()); 02358 Emit(os, "RelayHandler =\n"); 02359 EmitIndent(os, 4); 02360 Emit(os, "new "); 02361 Emit(os, eFull.c_str()); 02362 Emit(os, ".Handler(\n"); 02363 EmitIndent(os, 5); 02364 Emit(os, "this."); 02365 Emit(os, e.c_str()); 02366 Emit(os, "RelayHandlerMethod);\n"); 02367 Emit(os, "\n"); 02368 02369 EmitIndent(os, 3); 02370 Emit(os, "this."); 02371 Emit(os, e.c_str()); 02372 Emit(os, "Instance =\n"); 02373 EmitIndent(os, 4); 02374 Emit(os, "this."); 02375 Emit(os, mname.c_str()); 02376 Emit(os, "();\n"); 02377 Emit(os, "\n"); 02378 02379 EmitIndent(os, 3); 02380 Emit(os, "this."); 02381 Emit(os, e.c_str()); 02382 Emit(os, "RelayHandlerId =\n"); 02383 EmitIndent(os, 4); 02384 Emit(os, "this."); 02385 Emit(os, e.c_str()); 02386 Emit(os, "Instance.AddHandler(\n"); 02387 EmitIndent(os, 5); 02388 Emit(os, "this."); 02389 Emit(os, e.c_str()); 02390 Emit(os, "RelayHandler);\n"); 02391 02392 EmitIndent(os, 2); 02393 Emit(os, "}\n"); 02394 EmitIndent(os); 02395 Emit(os, "}\n"); 02396 Emit(os, "\n"); 02397 02398 EmitIndent(os); 02399 Emit(os, "private void Remove"); 02400 Emit(os, e.c_str()); 02401 Emit(os, "RelayHandler()\n"); 02402 EmitIndent(os); 02403 Emit(os, "{\n"); 02404 EmitIndent(os, 2); 02405 Emit(os, "if (0 != this."); 02406 Emit(os, e.c_str()); 02407 Emit(os, "RelayHandlerId)\n"); 02408 EmitIndent(os, 2); 02409 Emit(os, "{\n"); 02410 02411 EmitIndent(os, 3); 02412 Emit(os, "if (System.IntPtr.Zero != this."); 02413 Emit(os, e.c_str()); 02414 Emit(os, "Instance.GetCppThis().Handle)\n"); 02415 EmitIndent(os, 3); 02416 Emit(os, "{\n"); 02417 EmitIndent(os, 4); 02418 Emit(os, "this."); 02419 Emit(os, e.c_str()); 02420 Emit(os, "Instance.RemoveHandler(\n"); 02421 EmitIndent(os, 5); 02422 Emit(os, "this."); 02423 Emit(os, e.c_str()); 02424 Emit(os, "RelayHandlerId);\n"); 02425 EmitIndent(os, 3); 02426 Emit(os, "}\n"); 02427 Emit(os, "\n"); 02428 02429 EmitIndent(os, 3); 02430 Emit(os, "this."); 02431 Emit(os, e.c_str()); 02432 Emit(os, "Instance = null;\n"); 02433 02434 EmitIndent(os, 3); 02435 Emit(os, "this."); 02436 Emit(os, e.c_str()); 02437 Emit(os, "RelayHandler = null;\n"); 02438 02439 EmitIndent(os, 3); 02440 Emit(os, "this."); 02441 Emit(os, e.c_str()); 02442 Emit(os, "RelayHandlerId = 0;\n"); 02443 02444 EmitIndent(os, 2); 02445 Emit(os, "}\n"); 02446 EmitIndent(os); 02447 Emit(os, "}\n"); 02448 Emit(os, "\n"); 02449 02450 // End the private details "region": 02451 // 02452 EmitIndent(os); 02453 Emit(os, "#endregion\n"); 02454 Emit(os, "\n"); 02455 Emit(os, "\n"); 02456 02457 // A delegate definition that managed C# handlers must conform to in order 02458 // to listen to this event: 02459 // 02460 EmitIndent(os); 02461 Emit(os, "/// <summary>\n"); 02462 EmitIndent(os); 02463 Emit(os, "/// Delegate signature for the "); 02464 Emit(os, e.c_str()); 02465 Emit(os, " event.\n"); 02466 EmitIndent(os); 02467 Emit(os, "/// </summary>\n"); 02468 EmitIndent(os); 02469 Emit(os, "public delegate void "); 02470 Emit(os, e.c_str()); 02471 Emit(os, "EventHandler("); 02472 Emit(os, c->GetName()); 02473 Emit(os, " sender, "); 02474 Emit(os, eFull.c_str()); 02475 Emit(os, "EventArgs args);\n"); 02476 Emit(os, "\n"); 02477 Emit(os, "\n"); 02478 02479 // Documentation: 02480 gxsys_stl::vector<gxsys_stl::string> docblock; 02481 this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber); 02482 EmitDocumentationBlock(os, docblock, 1); 02483 02484 // The actual event with add and remove handlers. 02485 // 02486 EmitIndent(os); 02487 Emit(os, "public event "); 02488 Emit(os, e.c_str()); 02489 Emit(os, "EventHandler "); 02490 Emit(os, e.c_str()); 02491 Emit(os, "\n"); 02492 02493 EmitIndent(os); 02494 Emit(os, "{\n"); 02495 02496 EmitIndent(os, 2); 02497 Emit(os, "add\n"); 02498 EmitIndent(os, 2); 02499 Emit(os, "{\n"); 02500 EmitIndent(os, 3); 02501 Emit(os, "if (this."); 02502 Emit(os, e.c_str()); 02503 Emit(os, "Impl == null)\n"); 02504 EmitIndent(os, 3); 02505 Emit(os, "{\n"); 02506 EmitIndent(os, 4); 02507 Emit(os, "Add"); 02508 Emit(os, e.c_str()); 02509 Emit(os, "RelayHandler();\n"); 02510 EmitIndent(os, 3); 02511 Emit(os, "}\n"); 02512 Emit(os, "\n"); 02513 EmitIndent(os, 3); 02514 Emit(os, "this."); 02515 Emit(os, e.c_str()); 02516 Emit(os, "Impl += value;\n"); 02517 EmitIndent(os, 2); 02518 Emit(os, "}\n"); 02519 Emit(os, "\n"); 02520 02521 EmitIndent(os, 2); 02522 Emit(os, "remove\n"); 02523 EmitIndent(os, 2); 02524 Emit(os, "{\n"); 02525 EmitIndent(os, 3); 02526 Emit(os, "this."); 02527 Emit(os, e.c_str()); 02528 Emit(os, "Impl -= value;\n"); 02529 Emit(os, "\n"); 02530 EmitIndent(os, 3); 02531 Emit(os, "if (this."); 02532 Emit(os, e.c_str()); 02533 Emit(os, "Impl == null)\n"); 02534 EmitIndent(os, 3); 02535 Emit(os, "{\n"); 02536 EmitIndent(os, 4); 02537 Emit(os, "Remove"); 02538 Emit(os, e.c_str()); 02539 Emit(os, "RelayHandler();\n"); 02540 EmitIndent(os, 3); 02541 Emit(os, "}\n"); 02542 EmitIndent(os, 2); 02543 Emit(os, "}\n"); 02544 02545 EmitIndent(os); 02546 Emit(os, "}\n"); 02547 } 02548 02549 02550 //---------------------------------------------------------------------------- 02551 void MummyCsharpGenerator::EmitCSharpProperty(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *propGetMethod, const cable::Method *propSetMethod, bool emitExceptionParams) 02552 { 02553 gxsys_stl::string fGet; 02554 gxsys_stl::string fSet; 02555 unsigned int indent = 3; 02556 const cable::Method *declMethod = propGetMethod; 02557 02558 // Declare the DllImport functions. 02559 // 02560 if (propGetMethod) 02561 { 02562 fGet = GetExportLayerFunctionName(c, propGetMethod, propGetMethod->GetName()); 02563 EmitIndent(os); 02564 EmitCSharpDllImportDeclaration(os, dllname, c, propGetMethod, propGetMethod->GetName(), fGet.c_str(), emitExceptionParams); 02565 Emit(os, "\n"); 02566 Emit(os, "\n"); 02567 } 02568 02569 if (propSetMethod) 02570 { 02571 fSet = GetExportLayerFunctionName(c, propSetMethod, propSetMethod->GetName()); 02572 EmitIndent(os); 02573 EmitCSharpDllImportDeclaration(os, dllname, c, propSetMethod, propSetMethod->GetName(), fSet.c_str(), emitExceptionParams); 02574 Emit(os, "\n"); 02575 Emit(os, "\n"); 02576 02577 if (!declMethod) 02578 { 02579 declMethod = propSetMethod; 02580 } 02581 } 02582 02583 if (!declMethod) 02584 { 02585 // What? no propGetMethod or propSetMethod? Caller has made a mistake somewhere... 02586 // 02587 LogError(me_InternalError, << "No declMethod in MummyCsharpGenerator::EmitCSharpProperty."); 02588 return; 02589 } 02590 02591 // Documentation: 02592 gxsys_stl::vector<gxsys_stl::string> docblock; 02593 this->GetHeaderFileReader(c)->GetCommentBlockBefore(declMethod->GetLine(), docblock, this->ClassLineNumber); 02594 EmitDocumentationBlock(os, docblock, 1); 02595 02596 // Declaration: 02597 EmitIndent(os); 02598 EmitCSharpMethodDeclaration(os, c, declMethod, true, declMethod == propSetMethod, "public"); 02599 Emit(os, "\n"); 02600 02601 // Open body: 02602 EmitIndent(os); 02603 Emit(os, "{"); 02604 Emit(os, "\n"); 02605 02606 // The "get" body: 02607 if (propGetMethod) 02608 { 02609 EmitIndent(os, 2); 02610 Emit(os, "get\n"); 02611 EmitIndent(os, 2); 02612 Emit(os, "{\n"); 02613 EmitIndent(os, 3); 02614 Emit(os, "// iwhPropGet\n"); 02615 EmitCSharpMethodBody(os, 3, c, propGetMethod, fGet, 0, emitExceptionParams); 02616 indent = 3; 02617 EmitIndent(os, 2); 02618 Emit(os, "}\n"); 02619 } 02620 02621 // The "set" body: 02622 if (propSetMethod) 02623 { 02624 if (propGetMethod) 02625 { 02626 Emit(os, "\n"); 02627 } 02628 02629 EmitIndent(os, 2); 02630 Emit(os, "set\n"); 02631 EmitIndent(os, 2); 02632 Emit(os, "{\n"); 02633 EmitIndent(os, 3); 02634 Emit(os, "// iwhPropSet\n"); 02635 EmitCSharpMethodBody(os, 3, c, propSetMethod, fSet, "value", emitExceptionParams); 02636 indent = 3; 02637 EmitIndent(os, 2); 02638 Emit(os, "}\n"); 02639 } 02640 02641 // Close body: 02642 EmitIndent(os); 02643 Emit(os, "}"); 02644 Emit(os, "\n"); 02645 } 02646 02647 02648 //---------------------------------------------------------------------------- 02649 void EmitThrowClonedException(gxsys_ios::ostream &os, unsigned int indent) 02650 { 02651 EmitIndent(os, indent); 02652 Emit(os, "if (IntPtr.Zero != clonedException)\n"); 02653 EmitIndent(os, indent); 02654 Emit(os, "{\n"); 02655 02656 EmitIndent(os, indent+1); 02657 Emit(os, "bool mteCreatedException;\n"); 02658 EmitIndent(os, indent+1); 02659 Emit(os, "System.Exception wrappedException = (System.Exception)\n"); 02660 EmitIndent(os, indent+2); 02661 Emit(os, "Kitware.mummy.Runtime.Methods.CreateWrappedObject(\n"); 02662 EmitIndent(os, indent+3); 02663 Emit(os, "0, mteExceptionIndex, 0, clonedException, true, out mteCreatedException);\n"); 02664 EmitIndent(os, indent+1); 02665 Emit(os, "throw wrappedException;\n"); 02666 02667 //EmitIndent(os, indent+1); 02668 //Emit(os, "System.Exception exc = new System.Exception(\"received clonedException from unmanaged layer...\");\n"); 02669 //EmitIndent(os, indent+1); 02670 //Emit(os, "throw exc;\n"); 02671 02672 EmitIndent(os, indent); 02673 Emit(os, "}\n"); 02674 } 02675 02676 02677 //---------------------------------------------------------------------------- 02678 void MummyCsharpGenerator::EmitCSharpMethodBody(gxsys_ios::ostream &os, unsigned int indent, const cable::Class *c, const cable::Method *m, gxsys_stl::string& f, const char *impliedArg0, bool emitExceptionParams) 02679 { 02680 // need qualified name? 02681 gxsys_stl::string cname(c->GetName()); 02682 02683 gxsys_stl::string retArraySize; 02684 gxsys_stl::string argArraySize; 02685 cable::FunctionType *ft = m->GetFunctionType(); 02686 unsigned int cArgs = ft->GetNumberOfArguments(); 02687 unsigned int cArgsEmitted = 0; 02688 unsigned int i = 0; 02689 cable::Type *argType = 0; 02690 cable::Type *retType = ft->GetReturns(); 02691 bool voidReturn = false; 02692 gxsys_stl::string rvType; 02693 gxsys_stl::string rvpType; 02694 bool argIsRef = false; 02695 gxsys_stl::string argTypeString; 02696 gxsys_stl::string emittedArg; 02697 bool callGetCppThis = false; 02698 02699 // Does method return anything? 02700 // 02701 if (IsVoid(retType)) 02702 { 02703 voidReturn = true; 02704 } 02705 02706 // Does method return an array? 02707 // 02708 retArraySize = GetMethodArgumentArraySize(c, m, ft, RETURN_VALUE); 02709 02710 rvpType = GetPInvokeTypeString(retType, true, retArraySize != "", false); 02711 rvType = GetCSharpTypeString(retType, true, retArraySize != ""); 02712 02713 02714 // Body: 02715 // 02716 02717 02718 // Set up to handle wrapped exceptions if this class may throw them: 02719 // 02720 if (emitExceptionParams) 02721 { 02722 EmitIndent(os, indent); 02723 Emit(os, "uint mteExceptionIndex = 0;\n"); 02724 EmitIndent(os, indent); 02725 Emit(os, "IntPtr clonedException = IntPtr.Zero;\n"); 02726 Emit(os, "\n"); 02727 } 02728 02729 // Delegate the call through the PInvoke/DllImport layer: 02730 // 02731 EmitIndent(os, indent); 02732 02733 if (!voidReturn) 02734 { 02735 if (retArraySize != "") 02736 { 02737 Emit(os, rvpType.c_str()); 02738 Emit(os, " rvp = "); // rvp == return value pointer 02739 } 02740 else if (IsObjectPointer(retType)) 02741 { 02742 Emit(os, rvType.c_str()); 02743 Emit(os, " rv = null;\n"); 02744 02745 Emit(os, "\n"); 02746 02747 EmitIndent(os, indent); 02748 Emit(os, "uint mteStatus = 0;\n"); 02749 EmitIndent(os, indent); 02750 Emit(os, "uint mteIndex = UInt32.MaxValue;\n"); 02751 EmitIndent(os, indent); 02752 Emit(os, "uint rawRefCount = 0;\n"); 02753 02754 EmitIndent(os, indent); 02755 Emit(os, rvpType.c_str()); 02756 Emit(os, " rvp = "); // rvp == return value pointer 02757 } 02758 else 02759 { 02760 Emit(os, rvType.c_str()); 02761 Emit(os, " rv = "); // rv == return value 02762 } 02763 } 02764 02765 // Open any special marshalling blocks required: 02766 // 02767 if (IsCharPointer(retType)) 02768 { 02769 Emit(os, "Marshal.PtrToStringAnsi("); 02770 } 02771 02772 // Call the DllImport function: 02773 // 02774 Emit(os, f.c_str()); 02775 Emit(os, "("); 02776 02777 // Arguments, 'this' first, then loop over C++ method formal params: 02778 // 02779 if (!m->GetStatic()) 02780 { 02781 Emit(os, "this.GetCppThis()"); 02782 cArgsEmitted += 1; 02783 02784 if (cArgs!=0) 02785 { 02786 Emit(os, ", "); 02787 } 02788 } 02789 02790 for (i= 0; i<cArgs; ++i) 02791 { 02792 // If it's a CxxMain param pair, use the length of the 2nd (string[] argv) 02793 // part as the value of the 1st (int argc) part... 02794 // 02795 if (IsCxxMainStyleParamPair(ft, i)) 02796 { 02797 Emit(os, GetArgName(ft, i+1)); 02798 Emit(os, ".Length"); 02799 } 02800 else 02801 { 02802 argType = ft->GetArgument(i); 02803 02804 // Is arg an array? 02805 // 02806 argArraySize = GetMethodArgumentArraySize(c, m, ft, i); 02807 02808 argIsRef = false; 02809 if (argArraySize == "" && GetIsRefArg(argType)) 02810 { 02811 argIsRef = true; 02812 Emit(os, "ref "); 02813 } 02814 02815 argTypeString = GetCSharpTypeString(argType, true, argArraySize != ""); 02816 if (!argIsRef && (argTypeString == "bool")) 02817 { 02818 Emit(os, "(byte)("); 02819 } 02820 02821 if (impliedArg0 && 0==i) 02822 { 02823 emittedArg = impliedArg0; 02824 } 02825 else 02826 { 02827 emittedArg = GetArgName(ft, i); 02828 } 02829 02830 Emit(os, emittedArg.c_str()); 02831 02832 if (argIsRef) 02833 { 02834 LogInfo(mi_InfoRefArgEncountered, 02835 << "reference arg: " 02836 << cname << "." << m->GetName() 02837 << " " << argType->GetCxxType().GetName() << " " << emittedArg 02838 << " (arg " << i << ")" 02839 ); 02840 } 02841 02842 callGetCppThis = false; 02843 02844 if (IsObjectPointer(argType)) 02845 { 02846 const cable::Class* argClass = cable::ClassType::SafeDownCast( 02847 cable::PointerType::SafeDownCast(argType)->GetTarget())->GetClass(); 02848 if (!IsUtilityClass(argClass)) 02849 { 02850 callGetCppThis = true; 02851 } 02852 } 02853 else if (IsObjectPointerReference(argType)) 02854 { 02855 const cable::PointerType* ptrClass = cable::PointerType::SafeDownCast( 02856 cable::ReferenceType::SafeDownCast(argType)->GetTarget()); 02857 const cable::Class* argClass = cable::ClassType::SafeDownCast( 02858 ptrClass->GetTarget())->GetClass(); 02859 if (!IsUtilityClass(argClass)) 02860 { 02861 callGetCppThis = true; 02862 } 02863 } 02864 02865 if (callGetCppThis) 02866 { 02867 Emit(os, " == null ? new HandleRef() : "); 02868 Emit(os, emittedArg.c_str()); 02869 Emit(os, ".GetCppThis()"); 02870 } 02871 02872 if (!argIsRef && (argTypeString == "bool")) 02873 { 02874 Emit(os, " ? 1 : 0)"); 02875 } 02876 } 02877 02878 cArgsEmitted += 1; 02879 02880 if (i<cArgs-1) 02881 { 02882 Emit(os, ", "); 02883 } 02884 } 02885 02886 if (IsObjectPointer(retType)) 02887 { 02888 if (cArgsEmitted) 02889 { 02890 Emit(os, ", "); 02891 } 02892 02893 Emit(os, "ref mteStatus, ref mteIndex, ref rawRefCount"); 02894 cArgsEmitted += 3; 02895 } 02896 02897 if (emitExceptionParams) 02898 { 02899 if (cArgsEmitted) 02900 { 02901 Emit(os, ", "); 02902 } 02903 02904 Emit(os, "ref mteExceptionIndex, ref clonedException"); 02905 cArgsEmitted += 2; 02906 } 02907 02908 Emit(os, ")"); 02909 02910 // Close special marshalling for object casting or char * to string mapping 02911 // or handle bool/byte specially for PInvoke: 02912 // 02913 if (IsObjectPointer(retType)) 02914 { 02915 const cable::Class* cRetType = cable::ClassType::SafeDownCast( 02916 cable::PointerType::SafeDownCast(retType)->GetTarget() 02917 )->GetClass(); 02918 02919 gxsys_stl::string registerMethod = this->GetSettings()->GetRegisterMethod(cRetType); 02920 gxsys_stl::string unRegisterMethod = this->GetSettings()->GetUnRegisterMethod(cRetType); 02921 02922 Emit(os, ";\n"); 02923 02924 EmitIndent(os, indent); 02925 Emit(os, "if (IntPtr.Zero != rvp)\n"); 02926 EmitIndent(os, indent); 02927 Emit(os, "{\n"); 02928 02929 EmitIndent(os, indent+1); 02930 Emit(os, "bool mteCreated;\n"); 02931 EmitIndent(os, indent+1); 02932 Emit(os, "rv = ("); 02933 Emit(os, rvType.c_str()); 02934 Emit(os, ")\n"); 02935 EmitIndent(os, indent+2); 02936 Emit(os, "Kitware.mummy.Runtime.Methods.CreateWrappedObject(\n"); 02937 EmitIndent(os, indent+3); 02938 Emit(os, "mteStatus, mteIndex, rawRefCount, rvp, "); 02939 02940 if (!unRegisterMethod.empty()) 02941 { 02942 Emit(os, "true"); 02943 } 02944 else 02945 { 02946 Emit(os, "false"); 02947 } 02948 02949 Emit(os, ", out mteCreated"); 02950 Emit(os, ");\n"); 02951 02952 if (!registerMethod.empty()) 02953 { 02954 if (this->MethodReturnValueIsCounted(c, m)) 02955 { 02956 EmitIndent(os, indent+1); 02957 Emit(os, "// Returned object is counted already, (factory method or iwhCounted hint),\n"); 02958 EmitIndent(os, indent+1); 02959 Emit(os, "// no 'rv."); 02960 Emit(os, registerMethod.c_str()); 02961 Emit(os, "' call is necessary...\n"); 02962 } 02963 else 02964 { 02965 EmitIndent(os, indent+1); 02966 Emit(os, "if (mteCreated)\n"); 02967 EmitIndent(os, indent+1); 02968 Emit(os, "{\n"); 02969 EmitIndent(os, indent+2); 02970 Emit(os, "rv."); 02971 Emit(os, registerMethod.c_str()); 02972 Emit(os, ";\n"); 02973 EmitIndent(os, indent+1); 02974 Emit(os, "}\n"); 02975 } 02976 } 02977 02978 EmitIndent(os, indent); 02979 Emit(os, "}\n"); 02980 02981 Emit(os, "\n"); 02982 } 02983 else if (IsCharPointer(retType)) 02984 { 02985 Emit(os, ");\n"); 02986 } 02987 else if (rvType == "bool") 02988 { 02989 Emit(os, " == 0 ? false : true;\n"); 02990 } 02991 else 02992 { 02993 Emit(os, ";\n"); 02994 } 02995 02996 02997 if (emitExceptionParams) 02998 { 02999 Emit(os, "\n"); 03000 EmitThrowClonedException(os, indent); 03001 Emit(os, "\n"); 03002 } 03003 03004 03005 // Specially marshal array return values: 03006 if (retArraySize != "") 03007 { 03008 EmitIndent(os, indent); 03009 Emit(os, rvType.c_str()); 03010 Emit(os, "[] rv = null;"); 03011 Emit(os, "\n"); 03012 03013 EmitIndent(os, indent); 03014 Emit(os, "if (IntPtr.Zero != rvp)"); 03015 Emit(os, "\n"); 03016 EmitIndent(os, indent); 03017 Emit(os, "{"); 03018 Emit(os, "\n"); 03019 EmitIndent(os, indent+1); 03020 Emit(os, "rv = new "); 03021 Emit(os, rvType.c_str()); 03022 Emit(os, "["); 03023 Emit(os, retArraySize.c_str()); 03024 Emit(os, "];"); 03025 Emit(os, "\n"); 03026 03027 // Special case "uint" since Marshal.Copy does not have 03028 // a "uint" overload... 03029 // 03030 if (rvType == "uint") 03031 { 03032 EmitIndent(os, indent+1); 03033 Emit(os, "int[] rv2 = new int["); 03034 Emit(os, retArraySize.c_str()); 03035 Emit(os, "];"); 03036 Emit(os, "\n"); 03037 03038 EmitIndent(os, indent+1); 03039 Emit(os, "Marshal.Copy(rvp, rv2, 0, rv.Length);"); 03040 Emit(os, "\n"); 03041 03042 EmitIndent(os, indent+1); 03043 Emit(os, "for (int rv2i = 0; rv2i < "); 03044 Emit(os, retArraySize.c_str()); 03045 Emit(os, "; ++rv2i)"); 03046 Emit(os, "\n"); 03047 03048 EmitIndent(os, indent+1); 03049 Emit(os, "{"); 03050 Emit(os, "\n"); 03051 03052 EmitIndent(os, indent+2); 03053 Emit(os, "rv[rv2i] = (uint)rv2[rv2i];"); 03054 Emit(os, "\n"); 03055 03056 EmitIndent(os, indent+1); 03057 Emit(os, "}"); 03058 Emit(os, "\n"); 03059 } 03060 else 03061 { 03062 EmitIndent(os, indent+1); 03063 Emit(os, "Marshal.Copy(rvp, rv, 0, rv.Length);"); 03064 Emit(os, "\n"); 03065 } 03066 03067 EmitIndent(os, indent); 03068 Emit(os, "}"); 03069 Emit(os, "\n"); 03070 } 03071 03072 // Return statement: 03073 if (!voidReturn) 03074 { 03075 EmitIndent(os, indent); 03076 Emit(os, "return rv;"); 03077 Emit(os, "\n"); 03078 } 03079 } 03080 03081 03082 //---------------------------------------------------------------------------- 03083 void MummyCsharpGenerator::EmitCSharpMethod(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, const gxsys_stl::string& accessLevel, bool emitExceptionParams) 03084 { 03085 gxsys_stl::string f(GetExportLayerFunctionName(c, m, mname)); 03086 03087 // First declare the DllImport function. This gets called within the method body. 03088 // 03089 EmitIndent(os); 03090 EmitCSharpDllImportDeclaration(os, dllname, c, m, mname, f.c_str(), emitExceptionParams); 03091 Emit(os, "\n"); 03092 Emit(os, "\n"); 03093 03094 // Documentation: 03095 gxsys_stl::vector<gxsys_stl::string> docblock; 03096 this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber); 03097 EmitDocumentationBlock(os, docblock, 1); 03098 03099 // Declaration: 03100 EmitIndent(os); 03101 EmitCSharpMethodDeclaration(os, c, m, false, false, accessLevel); 03102 Emit(os, "\n"); 03103 03104 // Open body: 03105 EmitIndent(os); 03106 Emit(os, "{"); 03107 Emit(os, "\n"); 03108 03109 // Body: 03110 EmitCSharpMethodBody(os, 2, c, m, f, 0, emitExceptionParams); 03111 03112 // Close body: 03113 EmitIndent(os); 03114 Emit(os, "}"); 03115 Emit(os, "\n"); 03116 } 03117 03118 03119 //---------------------------------------------------------------------------- 03120 void MummyCsharpGenerator::EmitCSharpEnums(gxsys_ios::ostream &os, const cable::Class *c) 03121 { 03122 gxsys_stl::vector<gxsys_stl::string> docblock; 03123 03124 for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it) 03125 { 03126 cable::Enumeration *e = cable::Enumeration::SafeDownCast(*it); 03127 03128 if (e && (cable::Context::Public == it.GetAccess())) 03129 { 03130 gxsys_stl::string ename(GetWrappedEnumName(e)); 03131 03132 LogVerboseInfo(<< "public enum - wrapped name: " << ename); 03133 03134 Emit(os, "\n"); 03135 Emit(os, "\n"); 03136 03137 docblock.clear(); 03138 this->GetHeaderFileReader(c)->GetCommentBlockBefore(e->GetLine(), docblock, this->ClassLineNumber); 03139 EmitDocumentationBlock(os, docblock, 1); 03140 03141 EmitIndent(os); 03142 Emit(os, "public "); 03143 if (WrappedEnumExists(ename)) 03144 { 03145 Emit(os, "new "); 03146 } 03147 Emit(os, "enum "); 03148 Emit(os, ename.c_str()); 03149 Emit(os, "\n"); 03150 03151 EmitIndent(os); 03152 Emit(os, "{\n"); 03153 03154 for (cable::Enumeration::Iterator eit = e->Begin(); eit != e->End(); ++eit) 03155 { 03156 EmitIndent(os, 2); 03157 Emit(os, "/// <summary>enum member</summary>\n"); 03158 03159 EmitIndent(os, 2); 03160 Emit(os, *eit); 03161 Emit(os, " = "); 03162 EmitInt(os, eit.GetValue()); 03163 Emit(os, ","); 03164 Emit(os, "\n"); 03165 03166 Emit(os, "\n"); 03167 } 03168 03169 EmitIndent(os); 03170 Emit(os, "}\n"); 03171 } 03172 } 03173 } 03174 03175 03176 //---------------------------------------------------------------------------- 03177 void MummyCsharpGenerator::EmitCSharpConstructor(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, bool emitExceptionParams) 03178 { 03179 // need qualified name? 03180 gxsys_stl::string cname(c->GetName()); 03181 gxsys_stl::string f; 03182 03183 if (this->GetSettings()->GetUseShadow(c)) 03184 { 03185 // Special case shadow class factory method since m might be NULL 03186 // (like it *is* with vtkCommand...) 03187 // 03188 f = cname + "Shadow_CreateShadow"; 03189 03190 EmitIndent(os); 03191 Emit(os, "[DllImport("); 03192 Emit(os, dllname); 03193 Emit(os, ", EntryPoint = \""); 03194 Emit(os, f.c_str()); 03195 Emit(os, "\")]"); 03196 Emit(os, "\n"); 03197 03198 EmitIndent(os); 03199 Emit(os, "static extern IntPtr "); 03200 Emit(os, f.c_str()); 03201 Emit(os, "(IntPtr primary);\n"); 03202 03203 Emit(os, "\n"); 03204 03205 // Documentation: 03206 gxsys_stl::vector<gxsys_stl::string> docblock; 03207 this->GetHeaderFileReader(c)->GetCommentBlockBefore( 03208 (m ? m->GetLine() : c->GetLine()), docblock, this->ClassLineNumber); 03209 EmitDocumentationBlock(os, docblock, 1); 03210 03211 EmitIndent(os); 03212 Emit(os, "public "); 03213 Emit(os, cname.c_str()); 03214 Emit(os, "() : this(IntPtr.Zero, false, false)\n"); 03215 03216 EmitIndent(os); 03217 Emit(os, "{\n"); 03218 03219 EmitIndent(os, 2); 03220 Emit(os, "IntPtr primary = Marshal.GetIDispatchForObject(this);\n"); 03221 03222 EmitIndent(os, 2); 03223 Emit(os, "this.SetCppThis("); 03224 Emit(os, f.c_str()); 03225 Emit(os, "(primary), true, false);\n"); 03226 03227 EmitIndent(os, 2); 03228 Emit(os, "Marshal.Release(primary);\n"); 03229 03230 EmitIndent(os); 03231 Emit(os, "}\n"); 03232 } 03233 else 03234 { 03235 f = GetExportLayerFunctionName(c, m, mname); 03236 03237 // Explanation of the "emitDefaultFactoryMethod" MummySettings.xml attribute. 03238 // ========================================================================== 03239 // 03240 // Either: emit the factory method itself, including the DllImport declaration, 03241 // and then emit the default C# constructor, too, which gives two ways to get an 03242 // instance of an object of class c... 03243 // (emitDefaultFactoryMethod="true" in MummySettings.xml) 03244 // 03245 // Or: emit just the DllImport declaration and the default C# constructor and 03246 // *skip* emitting the factory method itself, which only gives one way to get an 03247 // instance of class c. 03248 // (emitDefaultFactoryMethod="false" in or absent from MummySettings.xml) 03249 // 03250 // We code for both ways because we have some clients who want abstract C# classes 03251 // to be really abstract and *uncreatable* (even via a separate factory method) at 03252 // this class level. Only concrete subclasses can even be instantiated. 03253 // 03254 // On the other hand, we also have clients (think VTK and its ubiquitous New method) 03255 // that want the factory method behavior specifically so that abstract class instances 03256 // *can* be created, even though behind the scenes a concrete subclass of the factory 03257 // method's choice is the thing actually being instantiated. 03258 // 03259 if (this->GetSettings()->GetEmitDefaultFactoryMethod(c)) 03260 { 03261 EmitCSharpMethod(os, dllname, c, m, mname, "public", emitExceptionParams); 03262 } 03263 else 03264 { 03265 EmitIndent(os); 03266 EmitCSharpDllImportDeclaration(os, dllname, c, m, mname, f.c_str(), emitExceptionParams); 03267 } 03268 03269 Emit(os, "\n"); 03270 Emit(os, "\n"); 03271 03272 // Documentation: 03273 gxsys_stl::vector<gxsys_stl::string> docblock; 03274 this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber); 03275 EmitDocumentationBlock(os, docblock, 1); 03276 03277 EmitIndent(os); 03278 Emit(os, "public "); 03279 Emit(os, cname.c_str()); 03280 Emit(os, "()\n"); 03281 EmitIndent(os, 2); 03282 Emit(os, ": base(IntPtr.Zero, false, false)\n"); 03283 03284 EmitIndent(os); 03285 Emit(os, "{\n"); 03286 03287 EmitIndent(os, 2); 03288 Emit(os, "// mummy generated default C# constructor\n"); 03289 EmitIndent(os, 2); 03290 Emit(os, "uint mteStatus = 0;\n"); 03291 EmitIndent(os, 2); 03292 Emit(os, "uint mteIndex = UInt32.MaxValue;\n"); 03293 EmitIndent(os, 2); 03294 Emit(os, "uint rawRefCount = 0;\n"); 03295 Emit(os, "\n"); 03296 03297 if (emitExceptionParams) 03298 { 03299 EmitIndent(os, 2); 03300 Emit(os, "uint mteExceptionIndex = UInt32.MaxValue;\n"); 03301 EmitIndent(os, 2); 03302 Emit(os, "IntPtr clonedException = IntPtr.Zero;\n"); 03303 Emit(os, "\n"); 03304 } 03305 03306 EmitIndent(os, 2); 03307 Emit(os, "IntPtr rawCppThis = "); 03308 Emit(os, f.c_str()); 03309 Emit(os, "(ref mteStatus, ref mteIndex, ref rawRefCount"); 03310 03311 if (emitExceptionParams) 03312 { 03313 Emit(os, ", ref mteExceptionIndex, ref clonedException"); 03314 } 03315 03316 Emit(os, ");\n"); 03317 03318 if (emitExceptionParams) 03319 { 03320 Emit(os, "\n"); 03321 EmitThrowClonedException(os, 2); 03322 Emit(os, "\n"); 03323 } 03324 03325 EmitIndent(os, 2); 03326 Emit(os, "this.SetCppThis(rawCppThis, true, (0==mteStatus || rawRefCount<2 ? false : true));\n"); 03327 03328 EmitIndent(os); 03329 Emit(os, "}\n"); 03330 } 03331 } 03332 03333 03334 //---------------------------------------------------------------------------- 03335 void MummyCsharpGenerator::EmitCSharpRegister(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, bool emitExceptionParams) 03336 { 03337 EmitCSharpMethod(os, dllname, c, m, mname, "public", emitExceptionParams); 03338 } 03339 03340 03341 //---------------------------------------------------------------------------- 03342 void MummyCsharpGenerator::EmitCSharpDispose(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, const unsigned int eventCount, bool emitExceptionParams) 03343 { 03344 cable::FunctionType *ft = 0; 03345 cable::Type *argType = 0; 03346 unsigned int cArgs = 0; 03347 unsigned int i = 0; 03348 gxsys_stl::string f; 03349 03350 if (m) 03351 { 03352 ft = m->GetFunctionType(); 03353 cArgs = ft->GetNumberOfArguments(); 03354 03355 // need qualified name? 03356 f = GetExportLayerFunctionName(c, m, mname); 03357 03358 EmitIndent(os); 03359 EmitCSharpDllImportDeclaration(os, dllname, c, m, mname, f.c_str(), emitExceptionParams); 03360 Emit(os, "\n"); 03361 Emit(os, "\n"); 03362 03363 // Documentation: 03364 gxsys_stl::vector<gxsys_stl::string> docblock; 03365 this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber); 03366 EmitDocumentationBlock(os, docblock, 1); 03367 } 03368 else 03369 { 03370 EmitIndent(os); 03371 Emit(os, "/// <summary>\n"); 03372 EmitIndent(os); 03373 Emit(os, "/// Automatically generated protected Dispose method - called from\n"); 03374 EmitIndent(os); 03375 Emit(os, "/// public Dispose or the C# destructor. DO NOT call directly.\n"); 03376 EmitIndent(os); 03377 Emit(os, "/// </summary>\n"); 03378 } 03379 03380 03381 EmitIndent(os); 03382 Emit(os, "protected override void Dispose(bool disposing)\n"); 03383 EmitIndent(os); 03384 Emit(os, "{\n"); 03385 03386 03387 // If we are going to emit any code other than "base.Dispose(disposing);" 03388 // then make sure it is wrapped in a try/finally block so that we still call 03389 // base.Dispose if one of these other bits of code we're calling throws 03390 // an exception... 03391 // 03392 bool openedTryFinally = false; 03393 unsigned int indent = 2; 03394 if ((0 != eventCount) || m) 03395 { 03396 openedTryFinally = true; 03397 indent = 3; 03398 03399 EmitIndent(os, indent-1); 03400 Emit(os, "try\n"); 03401 EmitIndent(os, indent-1); 03402 Emit(os, "{\n"); 03403 } 03404 03405 03406 if (0 != eventCount) 03407 { 03408 EmitIndent(os, indent); 03409 Emit(os, "this.RemoveAllRelayHandlers();\n"); 03410 } 03411 03412 if (m) 03413 { 03414 EmitIndent(os, indent); 03415 Emit(os, "if (this.GetCallDisposalMethod())\n"); 03416 EmitIndent(os, indent); 03417 Emit(os, "{\n"); 03418 03419 if (emitExceptionParams) 03420 { 03421 EmitIndent(os, indent+1); 03422 Emit(os, "uint mteExceptionIndex = 0;\n"); 03423 EmitIndent(os, indent+1); 03424 Emit(os, "IntPtr clonedException = IntPtr.Zero;\n"); 03425 Emit(os, "\n"); 03426 } 03427 03428 EmitIndent(os, indent+1); 03429 Emit(os, f.c_str()); 03430 Emit(os, "(this.GetCppThis()"); 03431 03432 for (i = 0; i<cArgs; ++i) 03433 { 03434 argType = ft->GetArgument(i); 03435 03436 if (IsObjectPointer(argType)) 03437 { 03438 Emit(os, ", new HandleRef()"); 03439 } 03440 else if (IsVoidPointer(argType)) 03441 { 03442 Emit(os, ", System.IntPtr.Zero"); 03443 } 03444 else 03445 { 03446 Emit(os, ", 0"); 03447 } 03448 } 03449 03450 if (emitExceptionParams) 03451 { 03452 Emit(os, ", ref mteExceptionIndex, ref clonedException"); 03453 } 03454 03455 Emit(os, ");\n"); 03456 EmitIndent(os, indent+1); 03457 Emit(os, "this.ClearCppThis();\n"); 03458 03459 if (emitExceptionParams) 03460 { 03461 Emit(os, "\n"); 03462 EmitThrowClonedException(os, indent+1); 03463 } 03464 03465 EmitIndent(os, indent); 03466 Emit(os, "}\n"); 03467 Emit(os, "\n"); 03468 } 03469 03470 if (openedTryFinally) 03471 { 03472 EmitIndent(os, indent-1); 03473 Emit(os, "}\n"); 03474 EmitIndent(os, indent-1); 03475 Emit(os, "finally\n"); 03476 EmitIndent(os, indent-1); 03477 Emit(os, "{\n"); 03478 } 03479 03480 EmitIndent(os, indent); 03481 Emit(os, "base.Dispose(disposing);\n"); 03482 03483 if (openedTryFinally) 03484 { 03485 EmitIndent(os, indent-1); 03486 Emit(os, "}\n"); 03487 } 03488 03489 EmitIndent(os); 03490 Emit(os, "}\n"); 03491 } 03492 03493 03494 //---------------------------------------------------------------------------- 03495 struct SortByFieldOffset 03496 { 03497 bool operator()(const cable::Field* f1, const cable::Field* f2) 03498 { 03499 return f1->GetOffset() < f2->GetOffset(); 03500 } 03501 }; 03502 03503 03504 //---------------------------------------------------------------------------- 03505 void MummyCsharpGenerator::EmitCSharpWrapperClassAsStruct(gxsys_ios::ostream &os, const cable::Class *c) 03506 { 03507 gxsys_stl::vector<cable::Field*> fields; 03508 gxsys_stl::vector<cable::Field*>::iterator fit; 03509 gxsys_stl::string derivedName; 03510 gxsys_stl::string fieldType; 03511 gxsys_stl::vector<gxsys_stl::string> docblock; 03512 bool isPartial = this->GetSettings()->GetPartialClass(c); 03513 bool fieldAccess = !HasAttribute(c, "gccxml(iwhNoFieldAccess)"); 03514 03515 // First iterate and collect all the fields in a local vector: 03516 // 03517 for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it) 03518 { 03519 cable::Field* f = cable::Field::SafeDownCast(*it); 03520 if (f) 03521 { 03522 fields.push_back(f); 03523 } 03524 } 03525 03526 // Sort the vector so that we can emit the fields in the same order 03527 // in which they appear in the original C++ struct/class: 03528 // 03529 gxsys_stl::sort(fields.begin(), fields.end(), SortByFieldOffset()); 03530 03531 // Emit class opening: 03532 // 03533 Emit(os, "public "); 03534 if (isPartial) 03535 { 03536 Emit(os, "partial "); 03537 } 03538 Emit(os, "struct "); 03539 Emit(os, GetWrappedClassName(c).c_str()); 03540 Emit(os, "\n"); 03541 Emit(os, "{\n"); 03542 03543 // Enums: 03544 // 03545 EmitCSharpEnums(os, c); 03546 03547 // Now iterate and emit a private data member for each field: 03548 // 03549 for (fit = fields.begin(); fit != fields.end(); ++fit) 03550 { 03551 cable::Field* f = *fit; 03552 if (f) 03553 { 03554 derivedName = ExtractDerivedName(f->GetName(), f, this->GetSettings()->GetVerbose()); 03555 fieldType = GetCSharpTypeString(f->GetType(), false, false); 03556 03557 // "bool" is special - help it marshal properly to a C++ bool struct 03558 // data member... 03559 // 03560 // Using C# bool here causes an InteropServices.MarshalDirectiveException 03561 // with a message that says the type cannot be marshalled via PInvoke. 03562 // So we use C# byte instead and make it look like a bool through the 03563 // public accessors emitted in the next step. 03564 // 03565 if (fieldType == "bool") 03566 { 03567 fieldType = "byte"; 03568 } 03569 03570 EmitIndent(os); 03571 Emit(os, "private "); 03572 Emit(os, fieldType.c_str()); 03573 Emit(os, " m_"); 03574 Emit(os, derivedName.c_str()); 03575 Emit(os, ";"); 03576 Emit(os, "\n"); 03577 } 03578 } 03579 03580 // Iterate and emit public accessors for each private data member: 03581 // 03582 for (fit = fields.begin(); fieldAccess && fit != fields.end(); ++fit) 03583 { 03584 cable::Field* f = *fit; 03585 if (f) 03586 { 03587 derivedName = ExtractDerivedName(f->GetName(), f, false); 03588 fieldType = GetCSharpTypeString(f->GetType(), false, false); 03589 03590 Emit(os, "\n"); 03591 03592 this->GetHeaderFileReader(c)->GetCommentBlockBefore(f->GetLine(), docblock, this->ClassLineNumber); 03593 EmitDocumentationBlock(os, docblock, 1); 03594 docblock.clear(); 03595 03596 EmitIndent(os); 03597 Emit(os, "public "); 03598 Emit(os, fieldType.c_str()); 03599 Emit(os, " "); 03600 Emit(os, derivedName.c_str()); 03601 Emit(os, "\n"); 03602 03603 EmitIndent(os); 03604 Emit(os, "{"); 03605 Emit(os, "\n"); 03606 03607 EmitIndent(os, 2); 03608 Emit(os, "get\n"); 03609 03610 EmitIndent(os, 2); 03611 Emit(os, "{\n"); 03612 03613 EmitIndent(os, 3); 03614 Emit(os, "return this.m_"); 03615 Emit(os, derivedName.c_str()); 03616 if (fieldType == "bool") 03617 { 03618 // "bool" is special -- see above comments... 03619 // 03620 Emit(os, " == 0 ? false : true"); 03621 } 03622 Emit(os, ";\n"); 03623 03624 EmitIndent(os, 2); 03625 Emit(os, "}\n"); 03626 03627 Emit(os, "\n"); 03628 03629 EmitIndent(os, 2); 03630 Emit(os, "set\n"); 03631 03632 EmitIndent(os, 2); 03633 Emit(os, "{\n"); 03634 03635 EmitIndent(os, 3); 03636 Emit(os, "this.m_"); 03637 Emit(os, derivedName.c_str()); 03638 Emit(os, " = "); 03639 if (fieldType == "bool") 03640 { 03641 // "bool" is special -- see above comments... 03642 // 03643 Emit(os, "(byte)(value ? 1 : 0)"); 03644 } 03645 else 03646 { 03647 Emit(os, "value"); 03648 } 03649 Emit(os, ";\n"); 03650 03651 EmitIndent(os, 2); 03652 Emit(os, "}\n"); 03653 03654 EmitIndent(os); 03655 Emit(os, "}"); 03656 Emit(os, "\n"); 03657 } 03658 } 03659 03660 // Caller emits closing brace for struct so that he can emit 03661 // extraCSharpCode if necessary before the closing brace... 03662 } 03663 03664 03665 //---------------------------------------------------------------------------- 03666 void MummyCsharpGenerator::GatherWrappedMethods( 03667 const cable::Class *c, 03668 gxsys_stl::vector<cable::Method*>& wrapped_methods, 03669 cable::Method*& factoryM, 03670 cable::Method*& disposalM, 03671 cable::Method*& registerM, 03672 cable::Method*& unRegisterM, 03673 bool includeParentMethods 03674 ) 03675 { 03676 // When recursion hits the top of the class hierarchy, we're done: 03677 // 03678 if (!c) 03679 { 03680 return; 03681 } 03682 03683 gxsys_stl::string factoryMethod(this->GetSettings()->GetFactoryMethod(c)); 03684 gxsys_stl::string disposalMethod(this->GetSettings()->GetDisposalMethod(c)); 03685 gxsys_stl::string registerMethod(this->GetSettings()->GetRegisterMethod(c)); 03686 gxsys_stl::string unRegisterMethod(this->GetSettings()->GetUnRegisterMethod(c)); 03687 03688 // Reset state only if we are iterating the methods of the *target* class. 03689 // (And only track factory method if iterating the target class...) 03690 // 03691 if (c == this->GetTargetClass()) 03692 { 03693 this->CurrentMethodId = 0; 03694 this->MethodIdMap.clear(); 03695 WrappedMethods.clear(); 03696 wrapped_methods.clear(); 03697 factoryM = 0; 03698 disposalM = 0; 03699 registerM = 0; 03700 unRegisterM = 0; 03701 } 03702 03703 // If including parents, do so first so that the list of methods is in 03704 // "superclass first" order... And so that tracked pointers get set 03705 // to the most derived override possible. 03706 // 03707 if (includeParentMethods) 03708 { 03709 this->GatherWrappedMethods(GetWrappableParentClass(c), wrapped_methods, 03710 factoryM, disposalM, registerM, unRegisterM, true); 03711 } 03712 03713 // Iterate class c's methods, adding wrappable ones to wrapped_methods and 03714 // tracking "special" methods as we encounter them: 03715 // 03716 for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it) 03717 { 03718 cable::Method *m = cable::Method::SafeDownCast(*it); 03719 03720 if (m && MethodIsWrappable(m, it.GetAccess())) 03721 { 03722 gxsys_stl::string signature(GetMethodSignature(c, m)); 03723 03724 if ((c == this->GetTargetClass()) && signature == factoryMethod + "()") 03725 { 03726 LogVerboseInfo(<< "Found factory method, signature: " << signature); 03727 factoryM = m; 03728 this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId)); 03729 } 03730 else if (signature == disposalMethod + "()") 03731 { 03732 LogVerboseInfo(<< "Found disposal method, signature: " << signature); 03733 disposalM = m; 03734 this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId)); 03735 } 03736 else if (gxsys::SystemTools::StringStartsWith(registerMethod.c_str(), 03737 (gxsys_stl::string(m->GetName())+"(").c_str())) 03738 { 03739 LogVerboseInfo(<< "Found register method, signature: " << signature); 03740 registerM = m; 03741 this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId)); 03742 } 03743 else if (gxsys::SystemTools::StringStartsWith(unRegisterMethod.c_str(), 03744 (gxsys_stl::string(m->GetName())+"(").c_str())) 03745 { 03746 LogVerboseInfo(<< "Found unregister method, signature: " << signature); 03747 unRegisterM = m; 03748 this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId)); 03749 } 03750 else if (!WrappedMethodExists(signature)) 03751 { 03752 WrappedMethods.insert(gxsys_stl::make_pair(signature, MethodInstance(c, m))); 03753 wrapped_methods.push_back(m); 03754 this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId)); 03755 } 03756 else 03757 { 03758 if (this->GetSettings()->GetVerbose()) 03759 { 03760 //Emit(os, "//WARNING: "); 03761 //Emit(os, GetAccessString(it.GetAccess())); 03762 //Emit(os, " "); 03763 //Emit(os, (*it)->GetNameOfClass()); 03764 //Emit(os, " '"); 03765 //Emit(os, (*it)->GetName()); 03766 //Emit(os, "' wrappable method *NOT WRAPPED* because its signature matches a method that was already wrapped...\n"); 03767 } 03768 } 03769 } 03770 03771 if (this->GetSettings()->GetVerbose()) 03772 { 03773 if (!m) 03774 { 03775 LogInfo(mi_VerboseInfo, << GetAccessString(it.GetAccess()) 03776 << " " 03777 << (*it)->GetNameOfClass() 03778 << " '" 03779 << (*it)->GetName() 03780 << "' not wrapped because it's not a method...\n" 03781 ); 03782 } 03783 } 03784 } 03785 } 03786 03787 03788 //---------------------------------------------------------------------------- 03789 struct SortByMethodDeclarationLineNumber 03790 { 03791 bool operator()(const cable::Method* m1, const cable::Method* m2) 03792 { 03793 return m1->GetLine() < m2->GetLine(); 03794 } 03795 }; 03796 03797 03798 //---------------------------------------------------------------------------- 03799 bool MummyCsharpGenerator::ValidateWrappedMethods( 03800 const cable::Class *, 03801 gxsys_stl::vector<cable::Method*>& wrapped_methods, 03802 cable::Method*&, 03803 cable::Method*&, 03804 cable::Method*&, 03805 cable::Method*& 03806 ) 03807 { 03808 bool valid = true; 03809 gxsys_stl::vector<cable::Method*> wrapped_methods_local; 03810 gxsys_stl::vector<cable::Method*>::iterator mit; 03811 cable::Method* m = 0; 03812 gxsys::RegularExpression reGet; 03813 gxsys::RegularExpression reSet; 03814 03815 reGet.compile("^[Gg]et"); 03816 reSet.compile("^[Ss]et"); 03817 03818 // Make a local copy of the wrapped_methods vector so we can sort it by 03819 // "method declaration line number"... 03820 // 03821 gxsys_stl::copy(wrapped_methods.begin(), wrapped_methods.end(), 03822 gxsys_stl::back_inserter(wrapped_methods_local)); 03823 03824 // Sort the vector so that we can emit the fields in the same order 03825 // in which they appear in the original C++ struct/class: 03826 // 03827 gxsys_stl::sort(wrapped_methods_local.begin(), wrapped_methods_local.end(), 03828 SortByMethodDeclarationLineNumber()); 03829 03830 for (mit = wrapped_methods_local.begin(); mit != wrapped_methods_local.end(); ++mit) 03831 { 03832 m = *mit; 03833 03834 cable::FunctionType *ft = m->GetFunctionType(); 03835 unsigned int cArgs = ft->GetNumberOfArguments(); 03836 unsigned int cReqArgs = ft->GetNumberOfRequiredArguments(); 03837 cable::Type *retType = ft->GetReturns(); 03838 bool voidReturn = false; 03839 bool iwhPropGetExempt = false; 03840 03841 if (IsVoid(retType)) 03842 { 03843 voidReturn = true; 03844 } 03845 03846 if (cArgs != cReqArgs) 03847 { 03848 // Method has at least one default arg... Warn that mummy is ignoring 03849 // any default argument values... 03850 // 03851 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_DefaultArgumentValuesIgnored, 03852 "ignoring default argument values for method '" << m->GetName() << "'."); 03853 } 03854 03855 if (reGet.find(m->GetName())) 03856 { 03857 // 03858 // It's a "getter" : warn if it returns "void" or if it's not a const 03859 // method or if it's missing the iwhPropGet hint... 03860 // 03861 03862 if (gxsys_stl::string("GetEnumerator") == m->GetName()) 03863 { 03864 iwhPropGetExempt = true; 03865 } 03866 03867 // The mw_PropGetReturnsVoid and mw_PropGetHasArgs warnings are based on 03868 // the desire that a simple getter method should return one and only one 03869 // thing by return value, not through one or more "byref" arguments... 03870 // 03871 if (voidReturn) 03872 { 03873 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropGetReturnsVoid, 03874 "'Getter' method '" << m->GetName() << "' returns void."); 03875 } 03876 03877 if (cArgs) 03878 { 03879 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropGetHasArgs, 03880 "'Getter' method '" << m->GetName() << "' has arguments. Should it?"); 03881 } 03882 03883 if (!iwhPropGetExempt && !HasAttribute(m, "gccxml(iwhPropGet)")) 03884 { 03885 if (!voidReturn && 0==cArgs) 03886 { 03887 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_SeriousMissingPropGetHint, 03888 "'Getter' method '" << m->GetName() << "' is a perfect candidate for the 'iwhPropGet' hint. Add the 'iwhPropGet' hint to eliminate this warning."); 03889 } 03890 else 03891 { 03892 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_MissingPropGetHint, 03893 "'Getter' method '" << m->GetName() << "' does not have the 'iwhPropGet' hint. Should it?"); 03894 } 03895 } 03896 03897 if (!m->GetConst() && !m->GetStatic()) 03898 { 03899 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropGetNotConst, 03900 "'Getter' method '" << m->GetName() << "' is not const. Should it be const?"); 03901 } 03902 } 03903 03904 if (reSet.find(m->GetName())) 03905 { 03906 // It's a "setter" : warn if it's missing the iwhPropSet hint: 03907 // 03908 if (!HasAttribute(m, "gccxml(iwhPropSet)")) 03909 { 03910 if (voidReturn && 1==cArgs) 03911 { 03912 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_SeriousMissingPropSetHint, 03913 "'Setter' method '" << m->GetName() << "' is a perfect candidate for the 'iwhPropSet' hint. Add the 'iwhPropSet' hint to eliminate this warning."); 03914 } 03915 else 03916 { 03917 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_MissingPropSetHint, 03918 "'Setter' method '" << m->GetName() << "' does not have the 'iwhPropSet' hint. Should it?"); 03919 } 03920 } 03921 03922 if (cArgs!=1) 03923 { 03924 LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropSetUnexpectedArgCount, 03925 "'Setter' method '" << m->GetName() << "' has " << cArgs << " arguments. Should it have exactly one argument instead?"); 03926 } 03927 } 03928 } 03929 03930 return valid; 03931 } 03932 03933 03934 //---------------------------------------------------------------------------- 03935 void MummyCsharpGenerator::BuildPropGetsAndSetsMap( 03936 gxsys_stl::vector<cable::Method*>& wrapped_methods, 03937 gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >& wrapped_properties 03938 ) 03939 { 03940 gxsys_stl::vector<cable::Method*>::iterator mit; 03941 gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >::iterator gsit; 03942 bool addingPropGet = false; 03943 bool addingPropSet = false; 03944 cable::Method* propGetMethod = 0; 03945 cable::Method* propSetMethod = 0; 03946 gxsys_stl::string propName; 03947 03948 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 03949 { 03950 addingPropGet = HasAttribute(*mit, "gccxml(iwhPropGet)"); 03951 addingPropSet = addingPropGet ? false : HasAttribute(*mit, "gccxml(iwhPropSet)"); 03952 03953 if (addingPropGet || addingPropSet) 03954 { 03955 if (addingPropGet) 03956 { 03957 propGetMethod = *mit; 03958 } 03959 else 03960 { 03961 propGetMethod = 0; 03962 } 03963 03964 if (addingPropSet) 03965 { 03966 propSetMethod = *mit; 03967 } 03968 else 03969 { 03970 propSetMethod = 0; 03971 } 03972 03973 propName = ExtractDerivedName(GetWrappedMethodName(*mit).c_str(), *mit, 03974 this->GetSettings()->GetVerbose()); 03975 03976 gsit = wrapped_properties.find(propName); 03977 03978 if (gsit == wrapped_properties.end()) 03979 { 03980 // propName not in our map yet, add it: 03981 // 03982 wrapped_properties.insert(gxsys_stl::make_pair(propName, 03983 gxsys_stl::make_pair(propGetMethod, propSetMethod))); 03984 } 03985 else 03986 { 03987 // We already have an entry for propName... 03988 // This should be the "other" half of the pair. 03989 // So, if we are adding the *get*, then save the 03990 // existing "set" that's already in the map and 03991 // vice versa. 03992 // 03993 if (addingPropGet) 03994 { 03995 propSetMethod = gsit->second.second; 03996 } 03997 03998 if (addingPropSet) 03999 { 04000 propGetMethod = gsit->second.first; 04001 } 04002 04003 // The iterator points to the real map entry. Just 04004 // overwrite it: 04005 // 04006 gsit->second = gxsys_stl::make_pair(propGetMethod, propSetMethod); 04007 } 04008 } 04009 } 04010 04011 04012 // Analyze wrapped_properties and report anything suspicious. 04013 // Or just report info if verbose... 04014 // 04015 bool verbose = this->GetSettings()->GetVerbose(); 04016 if (!wrapped_properties.empty()) 04017 { 04018 gxsys_stl::string comment; 04019 04020 if (verbose) 04021 { 04022 LogInfo(mi_VerboseInfo, << "Properties:"); 04023 } 04024 04025 for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit) 04026 { 04027 if (gsit->second.first!=0 && gsit->second.second!=0) 04028 { 04029 comment = "ReadWrite property."; 04030 } 04031 else if (gsit->second.first!=0) 04032 { 04033 comment = "ReadOnly property."; 04034 } 04035 else if (gsit->second.second!=0) 04036 { 04037 LogFileLineWarningMsg(gsit->second.second->GetFile(), 04038 gsit->second.second->GetLine(), 04039 mw_WriteOnlyProperty, 04040 "A WriteOnly property '" << gsit->first << 04041 "' is very unusual - did you forget to mark the 'Get' method with 'iwhPropGet'?"); 04042 } 04043 else 04044 { 04045 LogError(me_InternalError, "Property with no 'get' and no 'set'... Impossible!"); 04046 } 04047 04048 if (verbose) 04049 { 04050 LogInfo(mi_VerboseInfo, << comment << " propName: " << gsit->first 04051 << " propGetMethod: " << gsit->second.first 04052 << " propSetMethod: " << gsit->second.second 04053 ); 04054 } 04055 } 04056 } 04057 } 04058 04059 04060 //---------------------------------------------------------------------------- 04061 void MummyCsharpGenerator::EmitCSharpWrapperClass(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c) 04062 { 04063 // Gather wrapped elements: 04064 // 04065 gxsys_stl::vector<cable::Method*> wrapped_methods; 04066 gxsys_stl::vector<cable::Method*>::iterator mit; 04067 cable::Method *factoryM = 0; 04068 cable::Method *disposalM = 0; 04069 cable::Method *registerM = 0; 04070 cable::Method *unRegisterM = 0; 04071 bool verbose = this->GetSettings()->GetVerbose(); 04072 gxsys_stl::string atts(c->GetAttributes()); 04073 gxsys_stl::string mname; 04074 04075 // The "package" directive from the gccxml input is used as a base 04076 // namespace. If it's not empty, prepend it to the class's namespace. 04077 // 04078 gxsys_stl::string target_namespace; 04079 gxsys_stl::string base_namespace(this->GetSettings()->GetPackage()); 04080 gxsys_stl::string class_namespace(GetFullyQualifiedNameForCSharp(c->GetContext())); 04081 04082 // C++ global scope means "no namespace please" 04083 // 04084 if (class_namespace == "::") 04085 { 04086 class_namespace = ""; 04087 } 04088 04089 if (base_namespace == "") 04090 { 04091 target_namespace = class_namespace; 04092 } 04093 else if (class_namespace == "") 04094 { 04095 target_namespace = base_namespace; 04096 } 04097 else 04098 { 04099 target_namespace = base_namespace + "." + class_namespace; 04100 } 04101 04102 04103 // Emit code: 04104 // 04105 EmitMummyVersionComments(os, "//"); 04106 04107 04108 // If the class maps directly to a builtin type, then DO NOT emit any code. 04109 // 04110 gxsys_stl::string mapToType = ExtractMapToType(c); 04111 if (mapToType != "") 04112 { 04113 Emit(os, "\n"); 04114 Emit(os, "//----------------------------------------------------------------------------\n"); 04115 Emit(os, "// Unmanaged class '"); 04116 Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str()); 04117 Emit(os, "' maps directly to type '"); 04118 Emit(os, mapToType.c_str()); 04119 Emit(os, "'.\n"); 04120 Emit(os, "// No code generated for '"); 04121 Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str()); 04122 Emit(os, "'...\n"); 04123 04124 if (verbose) 04125 { 04126 LogInfo(mi_VerboseInfo, << "Skipping code generation because class maps directly to native type."); 04127 } 04128 04129 return; 04130 } 04131 04132 04133 Emit(os, "\n"); 04134 Emit(os, "//----------------------------------------------------------------------------\n"); 04135 Emit(os, "using System;\n"); 04136 Emit(os, "using System.Runtime.InteropServices; // DllImport and HandleRef both live here\n"); 04137 Emit(os, "\n"); 04138 04139 04140 // If this project depends on "using" any other C# namespaces, they will be listed 04141 // as "Reference" elements in MummySettings.xml... 04142 // 04143 gxsys_stl::vector<gxsys_stl::string> refs; 04144 this->GetSettings()->GetReferences(refs); 04145 if (refs.size()) 04146 { 04147 Emit(os, "// References\n"); 04148 gxsys_stl::vector<gxsys_stl::string>::iterator rit; 04149 for (rit = refs.begin(); rit != refs.end(); ++rit) 04150 { 04151 Emit(os, "using "); 04152 Emit(os, rit->c_str()); 04153 Emit(os, ";\n"); 04154 } 04155 Emit(os, "\n"); 04156 } 04157 04158 04159 // Open the (optional) namespace: 04160 // 04161 if (target_namespace != "") 04162 { 04163 Emit(os, "namespace "); 04164 Emit(os, target_namespace.c_str()); 04165 Emit(os, "\n"); 04166 Emit(os, "{\n"); 04167 Emit(os, "\n"); 04168 } 04169 04170 04171 // Documentation: 04172 // 04173 gxsys_stl::vector<gxsys_stl::string> docblock; 04174 this->ClassLineNumber = c->GetLine(); 04175 04176 if (gxsys::SystemTools::StringStartsWith(GetFullyQualifiedNameForCPlusPlus(c).c_str(), "vtk")) 04177 { 04178 this->GetHeaderFileReader(c)->GetFirstCommentBlock(docblock); 04179 } 04180 else 04181 { 04182 this->GetHeaderFileReader(c)->GetCommentBlockBefore(c->GetLine(), docblock, 1); 04183 } 04184 04185 EmitDocumentationBlock(os, docblock, 0, true); 04186 04187 04188 if (IsUtilityClass(c)) 04189 { 04190 // Verify no virtual methods... If any, emit error: 04191 // 04192 cable::Method* um = 0; 04193 bool bVirtual = false; 04194 for (cable::Context::Iterator umit = c->Begin(); !bVirtual && umit != c->End(); ++umit) 04195 { 04196 um = cable::Method::SafeDownCast(*umit); 04197 if (um && um->GetVirtual()) 04198 { 04199 bVirtual = true; 04200 } 04201 } 04202 04203 if (bVirtual) 04204 { 04205 LogFileLineErrorMsg(um->GetFile(), um->GetLine(), me_NoVirtualMethodsAllowed, 04206 "A utility class cannot have any virtual methods. The '" << um->GetName() << 04207 "' method should not be virtual."); 04208 return; 04209 } 04210 04211 // Utility classes get wrapped as structs: 04212 // 04213 EmitCSharpWrapperClassAsStruct(os, c); 04214 } 04215 else 04216 { 04217 if (verbose) 04218 { 04219 LogInfo(mi_VerboseInfo, << "Calling GatherWrappedMethods..."); 04220 } 04221 04222 this->GatherWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM, false); 04223 04224 if (verbose) 04225 { 04226 DumpLookupEntries(); 04227 } 04228 04229 this->ValidateWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM); 04230 04231 // Filter out prop gets and sets, putting them in their very own data structure. 04232 // Key in the map is the name of the property. 1st method in pair is propget, 04233 // 2nd method is propset. 04234 // 04235 gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> > wrapped_properties; 04236 this->BuildPropGetsAndSetsMap(wrapped_methods, wrapped_properties); 04237 04238 // Now remove any entries found in the props *map* from the methods *vector*. 04239 // Otherwise, we'd end up with all of the properties "repeated" as methods, too. 04240 // 04241 gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >::iterator gsit; 04242 for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit) 04243 { 04244 if (gsit->second.first) 04245 { 04246 mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(), 04247 gsit->second.first); 04248 if (mit != wrapped_methods.end()) 04249 { 04250 wrapped_methods.erase(mit); 04251 } 04252 else 04253 { 04254 LogWarning(mw_InternalWarning, << "Unexpected unfound propget method..."); 04255 } 04256 } 04257 04258 if (gsit->second.second) 04259 { 04260 mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(), 04261 gsit->second.second); 04262 if (mit != wrapped_methods.end()) 04263 { 04264 wrapped_methods.erase(mit); 04265 } 04266 else 04267 { 04268 LogWarning(mw_InternalWarning, << "Unexpected unfound propset method..."); 04269 } 04270 } 04271 } 04272 04273 04274 ClassWrappingSettings cws; 04275 if (!this->GetSettings()->FindClassWrappingSettings(GetFullyQualifiedNameForCPlusPlus(c).c_str(), &cws)) 04276 { 04277 LogError(me_NoClassWrappingSettings, 04278 << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str()); 04279 } 04280 04281 const cable::Class *parent = GetWrappableParentClass(c); 04282 bool isPartial = cws.partialClass; 04283 bool emitExceptionParams = !cws.exceptionBaseClass.empty(); 04284 04285 // Class declaration: 04286 // 04287 Emit(os, "public "); 04288 if (c->GetAbstract()) 04289 { 04290 Emit(os, "abstract "); 04291 } 04292 if (isPartial) 04293 { 04294 Emit(os, "partial "); 04295 } 04296 Emit(os, "class "); 04297 Emit(os, GetWrappedClassName(c).c_str()); 04298 Emit(os, " : "); 04299 if (parent) 04300 { 04301 Emit(os, GetWrappedClassNameFullyQualified(parent).c_str()); 04302 } 04303 else 04304 { 04305 gxsys_stl::string wrappedObjectBase(cws.wrappedObjectBase); 04306 04307 if (wrappedObjectBase.empty()) 04308 { 04309 wrappedObjectBase = "Kitware.mummy.Runtime.WrappedObject"; 04310 } 04311 04312 Emit(os, wrappedObjectBase.c_str()); 04313 } 04314 04315 04316 // Any interface(s)? david.cole::fix - allow potentially many interfaces, 04317 // extract a list here if necessary rather than just one string... 04318 // 04319 gxsys_stl::string iface(ExtractImplementsInterface(atts)); 04320 04321 if (!iface.empty()) 04322 { 04323 if (iface == "IEnumerable") 04324 { 04325 this->AddTargetInterface(iface); 04326 Emit(os, ", System.Collections.IEnumerable"); 04327 } 04328 else if (iface == "IEnumerator") 04329 { 04330 this->AddTargetInterface(iface); 04331 Emit(os, ", System.Collections.IEnumerator"); 04332 } 04333 else 04334 { 04335 this->AddTargetInterface(iface); 04336 Emit(os, ", "); 04337 Emit(os, iface.c_str()); 04338 } 04339 } 04340 04341 Emit(os, "\n"); 04342 04343 04344 // Open class: 04345 // 04346 Emit(os, "{\n"); 04347 04348 04349 // david.cole::fix - GetFullyQualifiedNameForCSharp should handle 04350 // target_namespace being set in the gccxml input file, but it currently 04351 // does not. It relies on exact mapping of the C++ namespaces, which does 04352 // not allow for "pushing" stuff in the global C++ namespace into a C# 04353 // namespace as we do in the Vehicles example and Kitware.VTK wrappers... 04354 // 04355 gxsys_stl::string fullCSharpName; 04356 if (target_namespace != "") 04357 { 04358 fullCSharpName = target_namespace + "." + GetWrappedClassName(c); 04359 } 04360 else 04361 { 04362 fullCSharpName = GetWrappedClassName(c); 04363 } 04364 04365 04366 // Register type info with the mummy.Runtime for *all* classes, 04367 // even abstract classes. Type registration needs to occur even 04368 // if the first call to the dll is a static method on an abstract 04369 // class (which forces the static constructor to run prior to 04370 // entering the static method...) 04371 // 04372 EmitIndent(os); 04373 Emit(os, "/// <summary>\n"); 04374 EmitIndent(os); 04375 Emit(os, "/// Automatically generated type registration mechanics.\n"); 04376 EmitIndent(os); 04377 Emit(os, "/// </summary>\n"); 04378 EmitIndent(os); 04379 Emit(os, "public new static readonly string MRClassNameKey = \""); 04380 Emit(os, GetFullyQualifiedCPlusPlusTypeIdName(c).c_str()); 04381 Emit(os, "\";\n"); 04382 Emit(os, "\n"); 04383 04384 EmitIndent(os); 04385 Emit(os, "/// <summary>\n"); 04386 EmitIndent(os); 04387 Emit(os, "/// Automatically generated type registration mechanics.\n"); 04388 EmitIndent(os); 04389 Emit(os, "/// </summary>\n"); 04390 EmitIndent(os); 04391 Emit(os, "public new const string MRFullTypeName = \""); 04392 Emit(os, fullCSharpName.c_str()); 04393 Emit(os, "\";\n"); 04394 Emit(os, "\n"); 04395 04396 EmitIndent(os); 04397 Emit(os, "/// <summary>\n"); 04398 EmitIndent(os); 04399 Emit(os, "/// Automatically generated type registration mechanics.\n"); 04400 EmitIndent(os); 04401 Emit(os, "/// </summary>\n"); 04402 EmitIndent(os); 04403 Emit(os, "static "); 04404 Emit(os, GetWrappedClassName(c).c_str()); 04405 Emit(os, "()\n"); 04406 EmitIndent(os); 04407 Emit(os, "{\n"); 04408 04409 EmitIndent(os, 2); 04410 Emit(os, "Kitware.mummy.Runtime.Methods.RegisterType(\n"); 04411 EmitIndent(os, 3); 04412 Emit(os, "System.Reflection.Assembly.GetExecutingAssembly(),\n"); 04413 EmitIndent(os, 3); 04414 Emit(os, "MRClassNameKey,\n"); 04415 EmitIndent(os, 3); 04416 Emit(os, "System.Type.GetType(MRFullTypeName)\n"); 04417 EmitIndent(os, 3); 04418 Emit(os, ");\n"); 04419 04420 EmitIndent(os); 04421 Emit(os, "}\n"); 04422 04423 Emit(os, "\n"); 04424 Emit(os, "\n"); 04425 04426 04427 // Count events *now* before EmitCSharpDisposalMethod. 04428 // But emit code for the events further below. 04429 // 04430 // Also, examine the full set of events to be generated for this class. 04431 // For any duplicate names, use GetQualifiedEventName instead of 04432 // GetEventName in the methodEventNames map. 04433 // 04434 unsigned int eventCount = 0; 04435 gxsys_stl::map<gxsys_stl::string, int> event_name_counter; 04436 gxsys_stl::map<const cable::Method*, gxsys_stl::string> methodEventNames; 04437 gxsys_stl::string eventName; 04438 04439 // Count events and fill in event_name_counter as we go: 04440 // 04441 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 04442 { 04443 if (MethodWrappableAsEvent(*mit, cable::Context::Public)) 04444 { 04445 ++eventCount; 04446 04447 eventName = GetEventName(*mit); 04448 04449 event_name_counter[eventName]++; 04450 } 04451 } 04452 04453 // Use event_name_counter to build a map of cable::Method* to event names. 04454 // If a method's GetEventName is a duplicate according to event_name_counter 04455 // then use GetQualifiedEventName for that method's event name... With this 04456 // data, we can simply look up the proper event name when given the 04457 // cable::Method* later when we are calling EmitCSharpEvent. 04458 // 04459 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 04460 { 04461 if (MethodWrappableAsEvent(*mit, cable::Context::Public)) 04462 { 04463 eventName = GetEventName(*mit); 04464 04465 if (1 == event_name_counter[eventName]) 04466 { 04467 methodEventNames[*mit] = eventName; 04468 } 04469 else 04470 { 04471 methodEventNames[*mit] = GetQualifiedEventName(*mit); 04472 } 04473 } 04474 } 04475 04476 // Now verify that we have non-duplicate event names. Reset event_name_counter 04477 // and this time analyze whether there are duplicate strings within the 04478 // methodEventNames map. 04479 // 04480 gxsys_stl::map<const cable::Method*, gxsys_stl::string>::iterator menIt; 04481 event_name_counter.clear(); 04482 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 04483 { 04484 if (MethodWrappableAsEvent(*mit, cable::Context::Public)) 04485 { 04486 menIt = methodEventNames.find(*mit); 04487 04488 if (menIt != methodEventNames.end()) 04489 { 04490 eventName = menIt->second; 04491 event_name_counter[eventName]++; 04492 04493 if (event_name_counter[eventName] > 1) 04494 { 04495 LogFileLineWarningMsg((*mit)->GetFile(), (*mit)->GetLine(), mw_DuplicateGeneratedName, 04496 << "duplicate event name found: " << eventName.c_str() 04497 << " (a C# compile error will likely follow...)" 04498 ); 04499 } 04500 } 04501 else 04502 { 04503 LogFileLineErrorMsg((*mit)->GetFile(), (*mit)->GetLine(), me_InternalError, 04504 << "event method not found in methodEventNames map..."); 04505 } 04506 } 04507 } 04508 04509 04510 // Constructor(s): 04511 // 04512 gxsys_stl::string ctorModifier(this->GetSettings()->GetCsharpConstructorModifier(c)); 04513 if (ctorModifier.empty()) 04514 { 04515 ctorModifier = "public"; 04516 } 04517 EmitIndent(os); 04518 Emit(os, "/// <summary>\n"); 04519 EmitIndent(os); 04520 Emit(os, "/// Automatically generated constructor - called from generated code.\n"); 04521 EmitIndent(os); 04522 Emit(os, "/// DO NOT call directly.\n"); 04523 EmitIndent(os); 04524 Emit(os, "/// </summary>\n"); 04525 EmitIndent(os); 04526 Emit(os, ctorModifier.c_str()); 04527 Emit(os, " "); 04528 Emit(os, GetWrappedClassName(c).c_str()); 04529 Emit(os, "(IntPtr rawCppThis, bool callDisposalMethod, bool strong) :\n"); 04530 EmitIndent(os, 2); 04531 Emit(os, "base(rawCppThis, callDisposalMethod, strong)\n"); 04532 EmitIndent(os); 04533 Emit(os, "{\n"); 04534 EmitIndent(os); 04535 Emit(os, "}\n"); 04536 04537 04538 // Factory method: 04539 // 04540 const cable::Method* fmp = 0; 04541 gxsys_stl::string factoryMethod = this->GetSettings()->GetFactoryMethod(c); 04542 const cable::Constructor* ctor = FindNonAbstractPublicDefaultConstructor(c); 04543 04544 if (!factoryMethod.empty() && factoryMethod!="new") 04545 { 04546 if (factoryM) 04547 { 04548 fmp = factoryM; 04549 mname = fmp->GetName(); 04550 } 04551 } 04552 else 04553 { 04554 fmp = ctor; 04555 mname = "new"; 04556 } 04557 04558 if (fmp || this->GetSettings()->GetUseShadow(c)) 04559 { 04560 Emit(os, "\n"); 04561 Emit(os, "\n"); 04562 EmitCSharpConstructor(os, dllname, c, fmp, mname, emitExceptionParams); 04563 } 04564 04565 04566 // Register method: 04567 // 04568 if (registerM) 04569 { 04570 mname = registerM->GetName(); 04571 04572 Emit(os, "\n"); 04573 Emit(os, "\n"); 04574 EmitCSharpRegister(os, dllname, c, registerM, mname, emitExceptionParams); 04575 } 04576 04577 04578 // Disposal method: 04579 // 04580 // (disposalM/unRegisterM may be NULL, but we always emit a Dispose... 04581 // the guts of it vary based on disposalM/unRegisterM, but it's always 04582 // there and can be used as a cleaning spot for disconnecting any 04583 // outstanding event RelayHandler delegates...) 04584 // 04585 // If this is a ref-counted class, then use unRegisterM instead of disposalM: 04586 // 04587 const cable::Method* dmp = 0; 04588 gxsys_stl::string disposalMethod = this->GetSettings()->GetDisposalMethod(c); 04589 gxsys_stl::string unRegisterMethod = this->GetSettings()->GetUnRegisterMethod(c); 04590 04591 if (!unRegisterMethod.empty()) 04592 { 04593 if (unRegisterM) 04594 { 04595 dmp = unRegisterM; 04596 mname = dmp->GetName(); 04597 } 04598 } 04599 else if (!disposalMethod.empty()) 04600 { 04601 if (disposalM) 04602 { 04603 dmp = disposalM; 04604 mname = dmp->GetName(); 04605 } 04606 } 04607 else 04608 { 04609 dmp = ctor; 04610 mname = "delete"; 04611 } 04612 04613 // Call EmitCSharpDispose even if dmp is NULL... 04614 // 04615 Emit(os, "\n"); 04616 Emit(os, "\n"); 04617 EmitCSharpDispose(os, dllname, c, dmp, mname, eventCount, emitExceptionParams); 04618 04619 04620 // Enums: 04621 // 04622 EmitCSharpEnums(os, c); 04623 04624 04625 // Delegates: 04626 // 04627 for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it) 04628 { 04629 cable::Typedef *t = cable::Typedef::SafeDownCast(*it); 04630 04631 if (t && (cable::Context::Public == it.GetAccess())) 04632 { 04633 bool isDelegate = false; 04634 gxsys_stl::string tname(t->GetName()); 04635 04636 //isDelegate = HasAttribute(t, "gccxml(iwhDelegate)"); 04637 04638 cable::PointerType *pt = cable::PointerType::SafeDownCast(t->GetType()); 04639 cable::FunctionType *ft = 0; 04640 if (pt) 04641 { 04642 ft = cable::FunctionType::SafeDownCast(pt->GetTarget()); 04643 } 04644 if (ft) 04645 { 04646 isDelegate = true; 04647 } 04648 04649 if (isDelegate) 04650 { 04651 Emit(os, "\n"); 04652 Emit(os, "\n"); 04653 04654 docblock.clear(); 04655 this->GetHeaderFileReader(c)->GetCommentBlockBefore(t->GetLine(), docblock, this->ClassLineNumber); 04656 EmitDocumentationBlock(os, docblock, 1); 04657 04658 EmitIndent(os); 04659 Emit(os, "public delegate "); 04660 04661 unsigned int cArgs = ft->GetNumberOfArguments(); 04662 cable::Type *argType = 0; 04663 cable::Type *retType = ft->GetReturns(); 04664 04665 // The following chunk is a near-copy of the bottom of 04666 // EmitCSharpMethodDeclaration... 04667 // <Chunk> 04668 04669 // Does method return an array? 04670 // 04671 gxsys_stl::string arraySize = ""; 04672 atts = t->GetAttributes(); 04673 if (atts != "") 04674 { 04675 // Use ExtractArraySize instead of GetMethodArgumentArraySize here. 04676 // This is a delegate definition and cannot be in the VTK hints file. 04677 // (since the hints file only covers "normal" C++ methods...) 04678 // GetMethodArgumentArraySize uses ExtractArraySize internally, and 04679 // if there is no inline hint, it then examines the externalHints 04680 // file to see if there's a match. In this case, there could be no 04681 // match anyhow (as evidenced by the fact that we do not have access 04682 // to a cable::Method here...) so simply use ExtractArraySize directly. 04683 // Same reasoning applies below with the next use of ExtractArraySize. 04684 // 04685 arraySize = ExtractArraySize(atts); 04686 } 04687 04688 // Return type: 04689 Emit(os, GetPInvokeTypeString(retType, true, arraySize != "", true).c_str()); 04690 if (arraySize != "") 04691 { 04692 Emit(os, "[]"); 04693 } 04694 Emit(os, " "); 04695 04696 // Use the typedef name: 04697 Emit(os, t->GetName()); 04698 04699 // Open args: 04700 Emit(os, "("); 04701 04702 // The C# args: 04703 unsigned int i; 04704 for (i= 0; i<cArgs; ++i) 04705 { 04706 argType = ft->GetArgument(i); 04707 04708 // Is arg an array? 04709 // 04710 arraySize = ""; 04711 atts = ft->GetArgumentAttributes(i); 04712 if (atts != "") 04713 { 04714 // See comments above regarding direct use of ExtractArraySize 04715 // instead of GetMethodArgumentArraySize. 04716 // 04717 arraySize = ExtractArraySize(atts); 04718 } 04719 04720 // arg type: 04721 Emit(os, GetPInvokeTypeString(argType, false, arraySize != "", true).c_str()); 04722 04723 // array notation: 04724 if (arraySize != "") 04725 { 04726 Emit(os, "[]"); 04727 } 04728 04729 // arg name: 04730 Emit(os, " "); 04731 Emit(os, GetArgName(ft, i)); 04732 04733 if (i<cArgs-1) 04734 { 04735 Emit(os, ", "); 04736 } 04737 } 04738 04739 // Close args: 04740 Emit(os, ")"); 04741 04742 // </Chunk> 04743 04744 04745 Emit(os, ";\n"); 04746 } 04747 } 04748 } 04749 04750 04751 // Events: 04752 // 04753 if (0 != eventCount) 04754 { 04755 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 04756 { 04757 if (MethodWrappableAsEvent(*mit, cable::Context::Public)) 04758 { 04759 Emit(os, "\n"); 04760 Emit(os, "\n"); 04761 04762 menIt = methodEventNames.find(*mit); 04763 if (menIt != methodEventNames.end()) 04764 { 04765 eventName = menIt->second; 04766 } 04767 else 04768 { 04769 eventName = GetEventName(*mit); 04770 LogFileLineErrorMsg((*mit)->GetFile(), (*mit)->GetLine(), me_InternalError, 04771 << "event method not found in methodEventNames map..."); 04772 } 04773 04774 EmitCSharpEvent(os, dllname, c, *mit, eventName); 04775 } 04776 } 04777 04778 // Add a special "disconnect all" method that can be called at Dispose 04779 // time so that the unmanaged side does not end up with a stale pointer 04780 // to a garbage collected event RelayHandler... 04781 // 04782 Emit(os, "\n"); 04783 Emit(os, "\n"); 04784 EmitIndent(os); 04785 Emit(os, "/// <summary>\n"); 04786 EmitIndent(os); 04787 Emit(os, "/// Method to disconnect all RelayHandler event members.\n"); 04788 EmitIndent(os); 04789 Emit(os, "/// Called automatically from Dispose. DO NOT call directly.\n"); 04790 EmitIndent(os); 04791 Emit(os, "/// </summary>\n"); 04792 EmitIndent(os); 04793 Emit(os, "private void RemoveAllRelayHandlers()\n"); 04794 EmitIndent(os); 04795 Emit(os, "{\n"); 04796 04797 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 04798 { 04799 if (MethodWrappableAsEvent(*mit, cable::Context::Public)) 04800 { 04801 menIt = methodEventNames.find(*mit); 04802 if (menIt != methodEventNames.end()) 04803 { 04804 eventName = menIt->second; 04805 } 04806 else 04807 { 04808 eventName = GetEventName(*mit); 04809 LogFileLineErrorMsg((*mit)->GetFile(), (*mit)->GetLine(), me_InternalError, 04810 << "event method not found in methodEventNames map..."); 04811 } 04812 04813 EmitIndent(os, 2); 04814 Emit(os, "this.Remove"); 04815 Emit(os, eventName.c_str()); 04816 Emit(os, "RelayHandler();\n"); 04817 } 04818 } 04819 04820 EmitIndent(os); 04821 Emit(os, "}\n"); 04822 } 04823 04824 04825 // Properties: 04826 // 04827 for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit) 04828 { 04829 Emit(os, "\n"); 04830 Emit(os, "\n"); 04831 EmitCSharpProperty(os, dllname, c, gsit->second.first, gsit->second.second, emitExceptionParams); 04832 } 04833 04834 04835 // Plain old methods: 04836 // 04837 for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit) 04838 { 04839 Emit(os, "\n"); 04840 Emit(os, "\n"); 04841 EmitCSharpMethod(os, dllname, c, *mit, (*mit)->GetName(), "public", emitExceptionParams); 04842 } 04843 } 04844 04845 04846 // Hand written shtuff: 04847 // 04848 // If there is extraCSharpCode, emit it *within* the class definition. 04849 // If it's there, it's the name of a file that we are to include in 04850 // its entirety... 04851 // 04852 gxsys_stl::string extraCode = this->GetSettings()->GetExtraCsharpCode(c); 04853 if (extraCode != "") 04854 { 04855 Emit(os, "\n"); 04856 Emit(os, "\n"); 04857 Emit(os, "// Begin extraCsharpCode\n"); 04858 Emit(os, "\n"); 04859 EmitFile(os, extraCode.c_str()); 04860 Emit(os, "\n"); 04861 Emit(os, "// End extraCsharpCode\n"); 04862 Emit(os, "\n"); 04863 } 04864 04865 04866 // Close the struct/class: 04867 // 04868 Emit(os, "}\n"); 04869 04870 04871 // Close the namespace: 04872 // 04873 if (target_namespace != "") 04874 { 04875 Emit(os, "\n"); 04876 Emit(os, "}\n"); 04877 } 04878 }