I am building small components that will be used for a RPG later on, however my experience in this scale of project is very limited, which is why I choose to build them independant of each other. This part will cover character creation and handling.
So I have the following vector that stores class pointers of Gender. I know there will only be four genders, Unknown (for error-catching), Male, Female and Neuter.
std::vector<Gender*> mGenders;
However for some other vectors I do not know the exact amount.
std::vector<BClass*> mBClasses;
I have Creatures that have a mGenderID as well as a mBClassID. I have a game.h that initializes all genders and base classes (among many others). Let's say I have a
Creature* mPC = new Creature ("Name", GenderID, BClassID);
Should I then have a
Gender* Game::getGenderByID(int id) {
for (std::vector<Gender*>::iterator it = mGenders.begin(); it != mGenders.end(); ++i) {
if ((*it)->getID() == id) return (*it)
}
}
And use it the following way
std::cout << "Your name is " << mPC->getName() << ". Your gender is " << getCreatureByID(mPC->getGenderID())->getName();
So my question is, is this a good way of structuring the code? Imagine an infinite-engine like game, Baldur's Gate or so. Preferebly it should work for most, even if I were to do a Skyrim or GTA-like game.
Lastly, how easy would this be to port for C#? As I know C++ better than C#, I thought I'd give it a go in C++ first, to get the structure correct and work with something that can be used in larger-scale projects.
Edit:
Would it be better to directly store the Gender* in the Creature class? And no the ID of the creature?
Edit2:
class Gender {
public:
Gender::Gender(int id, std::string name, std::string desc, int coeBonus, int strBonus, int agiBonus, int attBonus, int intBonus, int chaBonus);
~Gender();
int getID () const;
std::string getName () const;
std::string getDesc () const;
int getStrBonus () const;
int getAgiBonus () const;
int getAttBonus () const;
int getIntBonus () const;
int getChaBonus () const;
int getCoeBonus () const;
private:
int mID;
std::string mName;
std::string mDesc;
int mStrBonus;
int mAgiBonus;
int mAttBonus;
int mIntBonus;
int mChaBonus;
int mCoeBonus;
};
The definition of gender.h
Thanks in advance
std::vector<Gender*> mGenders;
I can't see a good reason to be storing pointers in your vector. Why not just have a std::vector<Gender>?
Anyway, it seems like a strange idea to have a container of Genders. As you say, you have 4 possible genders, which you are then storing in this vector. So the vector is always size 4 and you never remove anything from it or add anything to it? And each element basically just represents a possible gender that a creature can have? That is, you're enumerating the possible genders. Sounds like you want an enum (or enum class) instead!
enum class gender {
unknown,
male,
female,
neuter
};
Then there's no need to mess around with ugly IDs that don't really mean anything (at least, they're hidden behind the enum now).
Then you could create a creature like so:
Creature mPC("Name", gender::male);
If you then want to print these out, you'll need some kind of mapping from enum value to strings. One way to do this is to just have a function that switches on the gender argument and returns an appropriate string. Alternatively, you can create a std::map like so:
std::map<gender, std::string> genderNames =
{{gender::unknown, "Unknown"}, /* ... */};
Then you can print a particular creatures gender just by doing:
std::cout << genderNames[mPC.getGender()];
You seem to have an unhealthy tendency to want to use dynamic allocation for your objects. Don't do it unless it's necessary, and when it is necessary, prefer smart pointers over raw pointers.
With much help from gamedev I am now happy with how much code is structed.
Instead of storing integers containing the IDs of genders, races, and so forth. I now store a pointer to them. Rendering the getGenderByID(int id) obsolete atm.
I am also currently working on a buff/debuff (effect) system instead of having all the different bonus variables.
These changes should make the code good enough for practice!
Gender::Gender(int id, std::string name, std::string desc, int coeBonus, int strBonus, int agiBonus, int attBonus, int intBonus, int chaBonus);
to
Gender(int id, std::string name, std::string desc, Effect* effect);
Currently working on the Effect class, so can't tell a lot about it.
Thanks for the comments.
Related
Let's say we have one structure :
[StructLayout(LayoutKind.Explicit, Size=8)] // using System.Runtime.InteropServices;
public struct AirportHeader {
[FieldOffset(0)]
[MarshalAs(UnmanagedType.I4)]
public int Ident; // a 4 bytes ASCII : "FIMP" { 0x46, 0x49, 0x4D, 0x50 }
[FieldOffset(4)]
[MarshalAs(UnmanagedType.I4)]
public int Offset;
}
What I want to have : Both direct access to type string and int values, for the field Ident in this structure, without breaking the 8 bytes size of the structure, nor having to compute a string value each time from the int value.
The field Ident in that structure as int is interesting because I can fast compare with other idents if they match, other idents may come from datas that are unrelated to this structure, but are in the same int format.
Question : Is there a way to define a field that is not part of the struture layout ? Like :
[StructLayout(LayoutKind.Explicit, Size=8)]
public struct AirportHeader {
[FieldOffset(0)]
[MarshalAs(UnmanagedType.I4)]
public int Ident; // a 4 bytes ASCII : "FIMP" { 0x46, 0x49, 0x4D, 0x50 }
[FieldOffset(4)]
[MarshalAs(UnmanagedType.I4)]
public int Offset;
[NoOffset()] // <- is there something I can do the like of this
string _identStr;
public string IdentStr {
get { // EDIT ! missed the getter on this property
if (string.IsNullOrEmpty(_identStr)) _identStr =
System.Text.Encoding.ASCII.GetString(Ident.GetBytes());
// do the above only once. May use an extra private bool field to go faster.
return _identStr;
}
}
}
PS : I use pointers ('*' and '&', unsafe) because I need to deal with endianness (Local system, binary files/file format, network) and fast type conversions, fast arrays filling. I also use many flavours of Marshal methods (fixing structures on byte arrays), and a little of PInvoke and COM interop. Too bad some assemblies I'm dealing with doesn't have their dotNet counterpart yet.
TL;DR; For details only
The question is all it is about, I just don't know the answer. The following should answer most questions like "other approaches", or "why not do this instead", but could be ignored as the answer would be straightforward. Anyway, I preemptively put everything so it's clear from the start what am I trying to do. :)
Options/Workaround I'm currently using (or thinking of using) :
Create a getter (not a field) that computes the string value each time :
public string IdentStr {
get { return System.Text.Encoding.ASCII.GetString(Ident.GetBytes()); }
// where GetBytes() is an extension method that converts an int to byte[]
}
This approach, while doing the job, performs poorly : The GUI displays aircraft from a database of default flights, and injects other flights from the network with a refresh rate of one second (I should increase that to 5 seconds). I have around 1200 flights within a area, relating to 2400 airports (departure and arrival), meaning I have 2400 calls to the above code each second to display the ident in a DataGrid.
Create another struct (or class), which only purpose is to manage
data on GUI side, when not reading/writing to a stream or file. That means, read
the data with the explicit layout struct. Create another struct with
the string version of the field. Work with GUI. That will perform
better on an overall point of view, but, in the process of defining
structures for the game binaries, I'm already at 143 structures of
the kind (just with older versions of the game datas; there are a bunch I didn't write yet, and I plan to add structures for the newest datas types). ATM, more than half of them require one or more extra
fields to be of meaningful use. It's okay if I were the only one to use the assembly, but
other users will probably get lost with AirportHeader,
AirportHeaderEx, AirportEntry, AirportEntryEx,
AirportCoords, AirportCoordsEx.... I would avoid doing that.
Optimize option 1 to make computations perform faster (thanks to SO,
there are a bunch of ideas to look for - currently working on the idea). For the Ident field, I
guess I could use pointers (and I will). Already doing it for fields I must display in little endian and read/write in big
endian. There are other values, like 4x4 grid informations that are
packed in a single Int64 (ulong), that needs bit shifting to
expose the actual values. Same for GUIDs or objects pitch/bank/yaw.
Try to take advantage of overlapping fields (on study). That would work for GUIDs. Perhaps it may work for the Ident example, if MarshalAs can constrain the
value to an ASCII string. Then I just need to specify the same
FieldOffset, '0' in this case. But I'm unsure setting the field
value (entry.FieldStr = "FMEP";) actually uses the Marshal constrain on the managed code side. My undestanding is it will store the string in Unicode on managed side (?).
Furthermore, that wouldn't work for packed bits (bytes that contains
several values, or consecutive bytes hosting values that have to be
bit shifted). I believe it is impossible to specify value position, length and format
at bit level.
Why bother ? context :
I'm defining a bunch of structures to parse binary datas from array of bytes (IO.File.ReadAllBytes) or streams, and write them back, datas related to a game. Application logic should use the structures to quickly access and manipulate the datas on demand. Assembly expected capabilities is read, validate, edit, create and write, outside the scope of the game (addon building, control) and inside the scope of the game (API, live modding or monitoring). Other purpose is to understand the content of binaries (hex) and make use of that understanding to build what's missing in the game.
The purpose of the assembly is to provide a ready to use basis components for a c# addon contributor (I don't plan to make the code portable). Creating applications for the game or processing addon from source to compilation into game binaries. It's nice to have a class that loads the entire content of a file in memory, but some context require you to not do that, and only retrieve from the file what is necessary, hence the choice of the struct pattern.
I need to figure out the trust and legal issues (copyrighted data) but that's outside the scope of the main concern. If that matter, Microsoft did provide over the years public freely accessible SDKs exposing binaries structures on previous versions of the game, for the purpose of what I'm doing (I'm not the first and probably not the last to do so). Though, I wouldn't dare to expose undocumented binaries (for the latest game datas for instance), nor facilitate a copyright breach on copyrighted materials/binaries.
I'm just asking confirmation if there is a way or not to have private fields not being part of the structure layout. Naive belief ATM is "that's impossible, but there are workarounds". It's just that my c# experience is pretty sparce, so maybe I'm wrong, why I ask. Thanks !
As suggested, there are several ways to get the job done. Here are the getters/setters I came up with within the structure. I'll measure how each code performs on various scenarios later. The dict approach is very seducing as on many scenarios, I would need a directly accessible global database of (59000) airports with runways and parking spots (not just the Ident), but a fast check between struct fields is also interesting.
public string IdentStr_Marshal {
get {
var output = "";
GCHandle pinnedHandle; // CS0165 for me (-> c# v5)
try { // Fast if no exception, (very) slow if exception thrown
pinnedHandle = GCHandle.Alloc(this, GCHandleType.Pinned);
IntPtr structPtr = pinnedHandle.AddrOfPinnedObject();
output = Marshal.PtrToStringAnsi(structPtr, 4);
// Cannot use UTF8 because the assembly should work in Framework v4.5
} finally { if (pinnedHandle.IsAllocated) pinnedHandle.Free(); }
return output;
}
set {
value.PadRight(4); // Must fill the blanks - initial while loop replaced (Charlieface's)
IntPtr intValuePtr = IntPtr.Zero;
// Cannot use UTF8 because some users are on Win7 with FlightSim 2004
try { // Put a try as a matter of habit, but not convinced it's gonna throw.
intValuePtr = Marshal.StringToHGlobalAnsi(value);
Ident = Marshal.ReadInt32(intValuePtr, 0).BinaryConvertToUInt32(); // Extension method to convert type.
} finally { Marshal.FreeHGlobal(intValuePtr); // freeing the right pointer }
}
}
public unsafe string IdentStr_Pointer {
get {
string output = "";
fixed (UInt32* ident = &Ident) { // Fixing the field
sbyte* bytes = (sbyte*)ident;
output = new string(bytes, 0, 4, System.Text.Encoding.ASCII); // Encoding added (#Charlieface)
}
return output;
}
set {
// value must not exceed a length of 4 and must be in Ansi [A-Z,0-9,whitespace 0x20].
// value validation at this point occurs outside the structure.
fixed (UInt32* ident = &Ident) { // Fixing the field
byte* bytes = (byte*)ident;
byte[] asciiArr = System.Text.Encoding.ASCII.GetBytes(value);
if (asciiArr.Length >= 4) // (asciiArr.Length == 4) would also work
for (Int32 i = 0; i < 4; i++) bytes[i] = asciiArr[i];
else {
for (Int32 i = 0; i < asciiArr.Length; i++) bytes[i] = asciiArr[i];
for (Int32 i = asciiArr.Length; i < 4; i++) bytes[i] = 0x20;
}
}
}
}
static Dictionary<UInt32, string> ps_dict = new Dictionary<UInt32, string>();
public string IdentStr_StaticDict {
get {
string output; // logic update with TryGetValue (#Charlieface)
if (ps_dict.TryGetValue(Ident, out output)) return output;
output = System.Text.Encoding.ASCII.GetString(Ident.ToBytes(EndiannessType.LittleEndian));
ps_dict.Add(Ident, output);
return output;
}
set { // input can be "FMEE", "DME" or "DK". length of 2 characters is the minimum.
var bytes = new byte[4]; // Need to convert value to a 4 byte array
byte[] asciiArr = System.Text.Encoding.ASCII.GetBytes(value); // should be 4 bytes or less
// Put the valid ASCII codes in the array.
if (asciiArr.Length >= 4) // (asciiArr.Length == 4) would also work
for (Int32 i = 0; i < 4; i++) bytes[i] = asciiArr[i];
else {
for (Int32 i = 0; i < asciiArr.Length; i++) bytes[i] = asciiArr[i];
for (Int32 i = asciiArr.Length; i < 4; i++) bytes[i] = 0x20;
}
Ident = BitConverter.ToUInt32(bytes, 0); // Set structure int value
if (!ps_dict.ContainsKey(Ident)) // Add if missing
ps_dict.Add(Ident, System.Text.Encoding.ASCII.GetString(bytes));
}
}
As mentioned by others, it is not possible to exclude a field from a struct for marshalling.
You also cannot use a pointer as a string in most places.
If the number of different possible strings is relatively small (and it probably will be, given it's only 4 characters), then you could use a static Dictionary<int, string> as a kind of string-interning mechanism.
Then you write a property to add/retrieve the real string.
Note that dictionary access is O(1), and hashing an int just returns itself, so it will be very, very fast, but will take up some memory.
[StructLayout(LayoutKind.Explicit, Size=8)]
public struct AirportHeader
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.I4)]
public int Ident; // a 4 bytes ASCII : "FIMP" { 0x46, 0x49, 0x4D, 0x50 }
[FieldOffset(4)]
[MarshalAs(UnmanagedType.I4)]
public int Offset;
static Dictionary<int, string> _identStrings = new Dictionary<int, string>();
public string IdentStr =>
_identStrings.TryGetValue(Ident, out var ret) ? ret :
(_identStrings[Ident] = Encoding.ASCII.GetString(Ident.GetBytes());
}
This is not possible because a structure must contain all of its values in a specific order. Usually this order is controlled by the CLR itself. If you want to change the order of the data order, you can use the StructLayout. However, you cannot exclude a field or that data would simply not exist in memory.
Instead of a string (which is a reference type) you can use a pointer to point directly to that string and use that in your structure in combination with the StructLayout. To get this string value, you can use a get-only property that reads directly from unmanaged memory.
I want to make a list of pointers to locations that contains a certain value in the process memory of another process. The value can be a short, int, long, string, bool or something else.
My idea is to use Generics for this. I have one problem with making it, how can I tell the compiler to what type he needs to convert the byte array?
This is what I made:
public List<IntPtr> ScanProccessFor<T>(T ItemToScanFor)
{
List<IntPtr> Output = new List<IntPtr>();
IntPtr StartOffset = SelectedProcess.MainModule.BaseAddress;
int ScanSize = SelectedProcess.MainModule.ModuleMemorySize;
for (int i = 0; i < ScanSize; i++)
if (ReadMemory(SelectedProcess, StartOffset + i, (UInt16)Marshal.SizeOf(ItemToScanFor)) == ItemToScanFor)
Output.Insert(Output.Count,StartOffset + i);
return Output;
}
How can I tell the compiler that he needs to convert the byte[] to type T?
Your question is a little bit confusing, but I'll try to answer what I can
Instead of taking a generic type, I would probably write a method that takes an instance of an interface like IConvertableToByteArray or something.
public IConvertableToByteArray
{
public byte[] ToByteArray();
}
Then If you needed to allow a specific type to be compatible with that method, you could make an encapsulating class
public IntConvertableToByteArray : IConvertableToByteArray
{
public int Value{get; set;}
public byte[] ToByteArray()
{
insert logic here
}
}
You could use Marshal.StructureToPtr to get an unmanaged representation of the structure (which has to be a 'simple' structure). You might need to special case strings though.
You should also think about the alignment constraints on what you are searching for -- advancing through memory 1 byte at a time will be very slow and wasteful if the item must be 4 or 8 byte aligned.
I am trying to port a rather large source from VB6 to C#. This is no easy task - especially for me being fairly new to C#.net. This source uses numerous Windows APIs as well as numerous Types. I know that there is no equivalent to the VB6 Type in C# but I'm sure there is a way to reach the same outcome. I will post some code below to further explain my request.
VB6:
Private Type ICONDIRENTRY
bWidth As Byte
bHeight As Byte
bColorCount As Byte
bReserved As Byte
wPlanes As Integer
wBitCount As Integer
dwBytesInRes As Long
dwImageOffset As Long
End Type
Dim tICONDIRENTRY() As ICONDIRENTRY
ReDim tICONDIRENTRY(tICONDIR.idCount - 1)
For i = 0 To tICONDIR.idCount - 1
Call ReadFile(lFile, tICONDIRENTRY(i), Len(tICONDIRENTRY(i)), lRet, ByVal 0&)
Next i
I have tried using structs and classes - but no luck so far.
I would like to see a conversion of this Type structure, but if someone had any clue as to how to convert the entire thing it would be unbelievably helpful. I have spent countless hours on this small project already.
If it makes any difference, this is strictly for educational purposes only.
Thank you for any help in advance,
Evan
struct is the equivalent. You'd express it like this:
struct IconDirEntry {
public byte Width;
public byte Height;
public byte ColorCount;
public byte Reserved;
public int Planes;
public int BitCount;
public long BytesInRes;
public long ImageOffset;
}
You declare a variable like this:
IconDirEntry entry;
Generally, in C#, type prefixes are not used, nor are all caps, except possibly for constants. structs are value types in C#, so that means that they are always passed by value. It looks like you're passing them in to a method that's populating them. If you want that usage, you'll have to use classes.
I'm not exactly sure what your issue is but this is a small ex of how to use a struct.
struct aStrt
{
public int A;
public int B;
}
static void Main(string[] args)
{
aStrt saStrt;
saStrt.A = 5;
}
Your question is not clear ..
What issues are you facing when you are using either struct or class and define those field members? Are you not able to access those members using an instance created for that class ??
Else, declare the class as static and make all the members inside the class also as static , so that u can access them without any instance being created!!
Maybe you trying to get something like this?
struct IconDirEntry
{
public byte Width;
// etc...
}
IconDirEntry[] tICONDIRENTRY = new IconDireEntry[tICONDIR.idCount - 1];
I have a block of code that i'm trying to covert from an old qt file into C# but i'm a little unclear what is going on in the struct within the union below. I'm not sure what the ':' does... i'm guessing it sets the size but could not find any documentation on this. Also since C# does not have unions what is the best practice for converting something like this. Thank you
union uAWord
{
uAWord()
: m_AWord(0) {}
struct sBcdAWord
{
quint32 m_O :8;
quint32 m_S :2;
quint32 m_D :18;
quint32 m_SS :3;
quint32 m_P :1;
}
sBcdAWord m_F;
quint32 m_AWord;
}
This is what is called BitFields. the portion sBcdWord is a 32 bit word, and each field is a portion of that word taking respectively 8,2,18,3,1 BIT:
So the word layout is as below:
Bit0-Bit7 m_0
Bit8-Bit9 m_S
Bit10-Bit27 m_D
Bit28-Bit30 m_ss
Bit31 m_P
How to port this in C# depends if you are convettually porting the code, or if you need to PInvoke. In the case of PInvoke the best solution is probably to map sBcdAWord as an Unit32, and create some accessor strategy to mask on reading writing. If it is a code port, use separeted properties would be good unless there is special needing in memory usage saving.
That syntax is used to declare bitfields. The number is the number of bits for that value. See for example http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Flanguage%2Fref%2Fclrc03defbitf.htm
A good conversion to C# depends on the case I guess. As long as you are not too space-conscious, I'd just keep all needed values in parallel in a class.
That initializes m_aWord to 0.
To answer your other question, in C# you'd likely want a struct, and you'd need to use attributes to get union-like behavior out of it.
This particular example could be somewhat like:
[StructLayout(LayoutKind.Explicit)]
struct uAWord {
[FieldOffset(0)]
private uint theWord = 0;
[FieldOffset(0)]
public int m_P;
[FieldOffset(1)]
public int m_S;
[FieldOffset(3)]
public int m_SS;
[FieldOffset(7)]
public int m_O;
[FieldOffset(18)]
public int m_D;
public uAWord(uint theWord){
this.theWord = theWord;
}
}
The LayoutKind.Explicit indicates you will tell it where in the memory to map each field and the FieldOffset(int) tells which bit to start each field on. See this for more details. You'd assign this struct by setting the uint theWord in the constructor, then each of the other properties would access a chunk starting at a different memory address.
Unfortunately, that actually isn't correct. You'll need to use properties and do some bitmasking/shifting to get it right. Like this:
struct uAWord {
private uint theWord = 0;
public int m_P {get {return (theWord & 0x01);}}
public int m_S {get {return (theWord & 0x02) << 2;}}
public int m_SS {get {return (theWord & 0x04) << 3;}}
public int m_0 {get {return (theWord & 0x18) << 6;}}
}
How do you recommend using #region / #endregion? To what extent should that replace using sub functions to clarify your code?
Not at all.
First of all, #regions are more a way of grouping many related functions/members into collapsible regions. They are not intended to structure a single multi-thousand line function into parts. (That being said, if you write a single method that's so long that you consider structuring it with #regions then you're probably doing something seriously wrong. Regions or not, that code would be unmaintainable. Period.)
Many people argue however, that it doesn't really help and that you should consider rewriting classes that actually need regions to be understandable. Also, regions tend to hide nasty code.
#region / #endregion is a way to logically group parts of the code belonging to the same class. Personally, I tend to group private field declarations, properties, public functions and private functions.
Sometimes I use those keywords to group some parts of the code which I need to look after and update often, for instance, calculation methods.
If you have more than one 'logical group of code' in a class, your class violates the single responsibility principle.
Sort that out and you no longer need regions.
Regions seem good in theory, but in my experience, it's a feature that is often abused.
Programmers love order; most folk love tidying things away into little boxes. They group messy code, fields, properties, constructors, methods, public methods, internal methods, private methods, helper methods, constants, interface implementations and God knows what else.
The only thing I can think of that irks me more is the use of partial classes to hide complexity.
Anyway, while over-use of regions is often a tell-tale sign of hiding a mess that shouldn't be there, I've also seen good code swamped by them. I've downloaded a few open source projects written by respected programmers. These fellows are writing some amazing code, but, oh, what's this?
One field? A field region!
Two properties? A property region!
One constructor? A constructor region!
One private method? A private method region!
I could go on.
To this very day, I am still astounded when I see this. In some cases, a region, a blank line, another blank line and the end region can take up 5x the space of the original code (5 lines with regions, 1 line without). It's basically a form of OCD; these regions may appeal to our sense of order during the act of writing software, but in practice they're useless -- pure noise. When I first started writing c# I abused them in this way, too. But then I realised how noisy my code was, and that hitting ctrl-k l every time I open a file is a sign that I was doing it wrong.
I can understand it when a class implements an interface that has a lot of properties (e.g. for databinding) or even a group of methods for implementing some related functionality, but for everything?. It makes no sense.
I still use regions now and then, but... I exercise a lot of restraint.
The only circumstance I've ever found where I felt using a region was totally okay is in the code below. Once I got it right, I never wanted to have to look at those constants again. Indeed, I use this class every day, and I think the only time I've uncollapsed this region in the last four years was when I needed to reimplement it in Python.
I think (hope, pray) that the circumstances of this code are an edge case. C# constants based on a VB3 type declaration that defines how the COBOL data structure returned by a C++ function is laid out. Yeah, I ported this to Python. I'm that good. I'm tempted to learn Haskell just so that I can rewrite my Python code in it, with an eye towards one day reimplementing my Haskell code in OCaml.
#region buffer_definition
/*
The buffer is a byte array that is passed to the underlying API. The VB representation of
the buffer's structure (using zero-based arrays, so each array has one more element than
its dimension) is this:
Public Type BUFFER_TYPE
Method As String * 50
Status As Integer
Msg As String * 200
DataLine As String * 1200
Prop(49) As String * 100
Fld(79) As String * 20
Fmt(79) As String * 50
Prompt(79) As String * 20
ValIn(79) As String * 80
ValOut(79) As String * 80
End Type
The constants defined here have the following prefixes:
len = field length
cnt = count of fields in an array
ptr = starting position within the buffer
*/
// data element lengths
private const int len_method = 50;
private const int len_status = 2;
private const int len_msg = 200;
private const int len_dataLine = 1200;
// array elements require both count and length:
private const int cnt_prop = 50;
private const int len_prop = 100;
private const int cnt_fld = 80;
private const int len_fld = 20;
private const int len_fmt = 50;
private const int len_prompt = 20;
private const int len_valIn = 80;
private const int len_valOut = 80;
// calculate the buffer length
private const int len_buffer =
len_method
+ len_status
+ len_msg
+ len_dataLine
+ (cnt_prop * len_prop)
+ (cnt_fld * (len_fld + len_fmt + len_prompt + len_valIn + len_valOut));
// calculate the pointers to the start of each field. These pointers are used
// in the marshalling methods to marshal data into and out of the buffer.
private const int PtrMethod = 0;
private const int PtrStatus = PtrMethod + len_method;
private const int PtrMsg = PtrStatus + len_status;
private const int PtrDataLine = PtrMsg + len_msg;
private const int PtrProp = PtrDataLine + len_dataLine;
private const int PtrFld = PtrProp + (cnt_prop * len_prop);
private const int PtrFmt = PtrFld + (cnt_fld * len_fld);
private const int PtrPrompt = PtrFmt + (cnt_fld * len_fmt);
private const int PtrValIn = PtrPrompt + (cnt_fld * len_prompt);
private const int PtrValOut = PtrValIn + (cnt_fld * len_valIn);
[MarshalAs(UnmanagedType.LPStr, SizeConst = len_buffer)]
private static byte[] buffer = new byte[len_buffer];
#endregion
I think that functions should only be used for reusable code. Thats what they were designed for. Nothing infurriates me more than seeing a function being created for something that is called only once.
Use a region.
If you need to do 500 lines then type the 500 lines in. If you want to neaten it up use a region, if there is anything reusable then use a function.